// Copyright 2018 The LevelDB-Go and Pebble Authors. All rights reserved. Use // of this source code is governed by a BSD-style license that can be found in // the LICENSE file. package pebble import ( "runtime" "sync" "sync/atomic" "unsafe" "github.com/cockroachdb/pebble/record" ) // commitQueue is a lock-free fixed-size single-producer, multi-consumer // queue. The single producer can enqueue (push) to the head, and consumers can // dequeue (pop) from the tail. // // It has the added feature that it nils out unused slots to avoid unnecessary // retention of objects. type commitQueue struct { // headTail packs together a 32-bit head index and a 32-bit tail index. Both // are indexes into slots modulo len(slots)-1. // // tail = index of oldest data in queue // head = index of next slot to fill // // Slots in the range [tail, head) are owned by consumers. A consumer // continues to own a slot outside this range until it nils the slot, at // which point ownership passes to the producer. // // The head index is stored in the most-significant bits so that we can // atomically add to it and the overflow is harmless. headTail uint64 // slots is a ring buffer of values stored in this queue. The size must be a // power of 2. A slot is in use until *both* the tail index has moved beyond // it and the slot value has been set to nil. The slot value is set to nil // atomically by the consumer and read atomically by the producer. slots [record.SyncConcurrency]unsafe.Pointer } const dequeueBits = 32 func (q *commitQueue) unpack(ptrs uint64) (head, tail uint32) { const mask = 1<> dequeueBits) & mask) tail = uint32(ptrs & mask) return } func (q *commitQueue) pack(head, tail uint32) uint64 { const mask = 1<= nextSeqNum { return } count := nextSeqNum - logSeqNum _ = atomic.AddUint64(p.env.logSeqNum, uint64(count)) - uint64(count) atomic.StoreUint64(p.env.visibleSeqNum, nextSeqNum) }