github.com/cockroachdb/pebble@v1.1.1-0.20240513155919-3622ade60459/read_compaction_queue.go (about)

     1  package pebble
     2  
     3  import "github.com/cockroachdb/pebble/internal/base"
     4  
     5  // The maximum number of elements in the readCompactions queue.
     6  // We want to limit the number of elements so that we only do
     7  // compactions for ranges which are being read recently.
     8  const readCompactionMaxQueueSize = 5
     9  
    10  // The readCompactionQueue is a queue of read compactions with
    11  // 0 overlapping ranges.
    12  type readCompactionQueue struct {
    13  	// Invariant: A contiguous prefix of the queue contains
    14  	// all the elements in the queue, in order of insertion.
    15  	// When we remove duplicates from the queue, we break
    16  	// the invariant that a contiguous prefix of the queue
    17  	// has all the elements in it. To fix this, we shift
    18  	// the elements of the queue to the left. This is cheap
    19  	// because the queue has a max length of 5.
    20  	queue [readCompactionMaxQueueSize]*readCompaction
    21  
    22  	// The size of the queue which is occupied.
    23  	// A size of k, implies that the first k elements
    24  	// of the queue are occupied.
    25  	// The size will be <= readCompactionMaxQueueSize.
    26  	size int
    27  }
    28  
    29  // combine should be used to combine an older queue with a newer
    30  // queue.
    31  func (qu *readCompactionQueue) combine(newQu *readCompactionQueue, cmp base.Compare) {
    32  
    33  	for i := 0; i < newQu.size; i++ {
    34  		qu.add(newQu.queue[i], cmp)
    35  	}
    36  }
    37  
    38  // add adds read compactions to the queue, while maintaining the invariant
    39  // that there are no overlapping ranges in the queue.
    40  func (qu *readCompactionQueue) add(rc *readCompaction, cmp base.Compare) {
    41  	sz := qu.size
    42  	for i := 0; i < sz; i++ {
    43  		left := qu.queue[i]
    44  		right := rc
    45  		if cmp(left.start, right.start) > 0 {
    46  			left, right = right, left
    47  		}
    48  		if cmp(right.start, left.end) <= 0 {
    49  			qu.queue[i] = nil
    50  			qu.size--
    51  		}
    52  	}
    53  
    54  	// Get rid of the holes which may have been formed
    55  	// in the queue.
    56  	qu.shiftLeft()
    57  
    58  	if qu.size == readCompactionMaxQueueSize {
    59  		// Make space at the end.
    60  		copy(qu.queue[0:], qu.queue[1:])
    61  		qu.queue[qu.size-1] = rc
    62  	} else {
    63  		qu.size++
    64  		qu.queue[qu.size-1] = rc
    65  	}
    66  }
    67  
    68  // Shifts the non-nil elements of the queue to the left so
    69  // that a continguous prefix of the queue is non-nil.
    70  func (qu *readCompactionQueue) shiftLeft() {
    71  	nilPos := -1
    72  	for i := 0; i < readCompactionMaxQueueSize; i++ {
    73  		if qu.queue[i] == nil && nilPos == -1 {
    74  			nilPos = i
    75  		} else if qu.queue[i] != nil && nilPos != -1 {
    76  			qu.queue[nilPos] = qu.queue[i]
    77  			qu.queue[i] = nil
    78  			nilPos++
    79  		}
    80  	}
    81  }
    82  
    83  // remove will remove the oldest element from the queue.
    84  func (qu *readCompactionQueue) remove() *readCompaction {
    85  	if qu.size == 0 {
    86  		return nil
    87  	}
    88  
    89  	c := qu.queue[0]
    90  	copy(qu.queue[0:], qu.queue[1:])
    91  	qu.queue[qu.size-1] = nil
    92  	qu.size--
    93  	return c
    94  }