github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/sstable/raw_block.go (about)

     1  // Copyright 2018 The LevelDB-Go and Pebble Authors. All rights reserved. Use
     2  // of this source code is governed by a BSD-style license that can be found in
     3  // the LICENSE file.
     4  
     5  package sstable
     6  
     7  import (
     8  	"encoding/binary"
     9  	"errors"
    10  	"sort"
    11  	"unsafe"
    12  )
    13  
    14  type rawBlockWriter struct {
    15  	blockWriter
    16  }
    17  
    18  func (w *rawBlockWriter) add(key InternalKey, value []byte) {
    19  	w.curKey, w.prevKey = w.prevKey, w.curKey
    20  
    21  	size := len(key.UserKey)
    22  	if cap(w.curKey) < size {
    23  		w.curKey = make([]byte, 0, size*2)
    24  	}
    25  	w.curKey = w.curKey[:size]
    26  	copy(w.curKey, key.UserKey)
    27  
    28  	w.store(size, value)
    29  }
    30  
    31  // rawBlockIter is an iterator over a single block of data. Unlike blockIter,
    32  // keys are stored in "raw" format (i.e. not as internal keys). Note that there
    33  // is significant similarity between this code and the code in blockIter. Yet
    34  // reducing duplication is difficult due to the blockIter being performance
    35  // critical.
    36  type rawBlockIter struct {
    37  	cmp         Compare
    38  	offset      int32
    39  	nextOffset  int32
    40  	restarts    int32
    41  	numRestarts int32
    42  	ptr         unsafe.Pointer
    43  	data        []byte
    44  	key, val    []byte
    45  	ikey        InternalKey
    46  	cached      []blockEntry
    47  	cachedBuf   []byte
    48  	err         error
    49  }
    50  
    51  func newRawBlockIter(cmp Compare, block block) (*rawBlockIter, error) {
    52  	i := &rawBlockIter{}
    53  	return i, i.init(cmp, block)
    54  }
    55  
    56  func (i *rawBlockIter) init(cmp Compare, block block) error {
    57  	numRestarts := int32(binary.LittleEndian.Uint32(block[len(block)-4:]))
    58  	if numRestarts == 0 {
    59  		return errors.New("pebble/table: invalid table (block has no restart points)")
    60  	}
    61  	i.cmp = cmp
    62  	i.restarts = int32(len(block)) - 4*(1+numRestarts)
    63  	i.numRestarts = numRestarts
    64  	i.ptr = unsafe.Pointer(&block[0])
    65  	i.data = block
    66  	if i.key == nil {
    67  		i.key = make([]byte, 0, 256)
    68  	} else {
    69  		i.key = i.key[:0]
    70  	}
    71  	i.val = nil
    72  	i.clearCache()
    73  	return nil
    74  }
    75  
    76  func (i *rawBlockIter) readEntry() {
    77  	ptr := unsafe.Pointer(uintptr(i.ptr) + uintptr(i.offset))
    78  	shared, ptr := decodeVarint(ptr)
    79  	unshared, ptr := decodeVarint(ptr)
    80  	value, ptr := decodeVarint(ptr)
    81  	i.key = append(i.key[:shared], getBytes(ptr, int(unshared))...)
    82  	i.key = i.key[:len(i.key):len(i.key)]
    83  	ptr = unsafe.Pointer(uintptr(ptr) + uintptr(unshared))
    84  	i.val = getBytes(ptr, int(value))
    85  	i.nextOffset = int32(uintptr(ptr)-uintptr(i.ptr)) + int32(value)
    86  }
    87  
    88  func (i *rawBlockIter) loadEntry() {
    89  	i.readEntry()
    90  	i.ikey.UserKey = i.key
    91  }
    92  
    93  func (i *rawBlockIter) clearCache() {
    94  	i.cached = i.cached[:0]
    95  	i.cachedBuf = i.cachedBuf[:0]
    96  }
    97  
    98  func (i *rawBlockIter) cacheEntry() {
    99  	var valStart int32
   100  	valSize := int32(len(i.val))
   101  	if valSize > 0 {
   102  		valStart = int32(uintptr(unsafe.Pointer(&i.val[0])) - uintptr(i.ptr))
   103  	}
   104  
   105  	i.cached = append(i.cached, blockEntry{
   106  		offset:   i.offset,
   107  		keyStart: int32(len(i.cachedBuf)),
   108  		keyEnd:   int32(len(i.cachedBuf) + len(i.key)),
   109  		valStart: valStart,
   110  		valSize:  valSize,
   111  	})
   112  	i.cachedBuf = append(i.cachedBuf, i.key...)
   113  }
   114  
   115  // SeekGE implements internalIterator.SeekGE, as documented in the pebble
   116  // package.
   117  func (i *rawBlockIter) SeekGE(key []byte) bool {
   118  	// Find the index of the smallest restart point whose key is > the key
   119  	// sought; index will be numRestarts if there is no such restart point.
   120  	i.offset = 0
   121  	index := sort.Search(int(i.numRestarts), func(j int) bool {
   122  		offset := int32(binary.LittleEndian.Uint32(i.data[int(i.restarts)+4*j:]))
   123  		// For a restart point, there are 0 bytes shared with the previous key.
   124  		// The varint encoding of 0 occupies 1 byte.
   125  		ptr := unsafe.Pointer(uintptr(i.ptr) + uintptr(offset+1))
   126  		// Decode the key at that restart point, and compare it to the key sought.
   127  		v1, ptr := decodeVarint(ptr)
   128  		_, ptr = decodeVarint(ptr)
   129  		s := getBytes(ptr, int(v1))
   130  		return i.cmp(key, s) < 0
   131  	})
   132  
   133  	// Since keys are strictly increasing, if index > 0 then the restart point at
   134  	// index-1 will be the largest whose key is <= the key sought.  If index ==
   135  	// 0, then all keys in this block are larger than the key sought, and offset
   136  	// remains at zero.
   137  	if index > 0 {
   138  		i.offset = int32(binary.LittleEndian.Uint32(i.data[int(i.restarts)+4*(index-1):]))
   139  	}
   140  	i.loadEntry()
   141  
   142  	// Iterate from that restart point to somewhere >= the key sought.
   143  	for valid := i.Valid(); valid; valid = i.Next() {
   144  		if i.cmp(key, i.key) <= 0 {
   145  			break
   146  		}
   147  	}
   148  	return i.Valid()
   149  }
   150  
   151  // SeekPrefixGE implements internalIterator.SeekPrefixGE, as documented in the
   152  // pebble package.
   153  func (i *rawBlockIter) SeekPrefixGE(key []byte) bool {
   154  	// This should never be called as prefix iteration is never used with raw blocks.
   155  	panic("pebble: SeekPrefixGE unimplemented")
   156  }
   157  
   158  // SeekLT implements internalIterator.SeekLT, as documented in the pebble
   159  // package.
   160  func (i *rawBlockIter) SeekLT(key []byte) bool {
   161  	panic("pebble/table: SeekLT unimplemented")
   162  }
   163  
   164  // First implements internalIterator.First, as documented in the pebble
   165  // package.
   166  func (i *rawBlockIter) First() bool {
   167  	i.offset = 0
   168  	i.loadEntry()
   169  	return i.Valid()
   170  }
   171  
   172  // Last implements internalIterator.Last, as documented in the pebble package.
   173  func (i *rawBlockIter) Last() bool {
   174  	// Seek forward from the last restart point.
   175  	i.offset = int32(binary.LittleEndian.Uint32(i.data[i.restarts+4*(i.numRestarts-1):]))
   176  
   177  	i.readEntry()
   178  	i.clearCache()
   179  	i.cacheEntry()
   180  
   181  	for i.nextOffset < i.restarts {
   182  		i.offset = i.nextOffset
   183  		i.readEntry()
   184  		i.cacheEntry()
   185  	}
   186  
   187  	i.ikey.UserKey = i.key
   188  	return i.Valid()
   189  }
   190  
   191  // Next implements internalIterator.Next, as documented in the pebble
   192  // package.
   193  func (i *rawBlockIter) Next() bool {
   194  	i.offset = i.nextOffset
   195  	if !i.Valid() {
   196  		return false
   197  	}
   198  	i.loadEntry()
   199  	return true
   200  }
   201  
   202  // Prev implements internalIterator.Prev, as documented in the pebble
   203  // package.
   204  func (i *rawBlockIter) Prev() bool {
   205  	if n := len(i.cached) - 1; n > 0 && i.cached[n].offset == i.offset {
   206  		i.nextOffset = i.offset
   207  		e := &i.cached[n-1]
   208  		i.offset = e.offset
   209  		i.val = getBytes(unsafe.Pointer(uintptr(i.ptr)+uintptr(e.valStart)), int(e.valSize))
   210  		i.ikey.UserKey = i.cachedBuf[e.keyStart:e.keyEnd]
   211  		i.cached = i.cached[:n]
   212  		return true
   213  	}
   214  
   215  	if i.offset == 0 {
   216  		i.offset = -1
   217  		i.nextOffset = 0
   218  		return false
   219  	}
   220  
   221  	targetOffset := i.offset
   222  	index := sort.Search(int(i.numRestarts), func(j int) bool {
   223  		offset := int32(binary.LittleEndian.Uint32(i.data[int(i.restarts)+4*j:]))
   224  		return offset >= targetOffset
   225  	})
   226  	i.offset = 0
   227  	if index > 0 {
   228  		i.offset = int32(binary.LittleEndian.Uint32(i.data[int(i.restarts)+4*(index-1):]))
   229  	}
   230  
   231  	i.readEntry()
   232  	i.clearCache()
   233  	i.cacheEntry()
   234  
   235  	for i.nextOffset < targetOffset {
   236  		i.offset = i.nextOffset
   237  		i.readEntry()
   238  		i.cacheEntry()
   239  	}
   240  
   241  	i.ikey.UserKey = i.key
   242  	return true
   243  }
   244  
   245  // Key implements internalIterator.Key, as documented in the pebble package.
   246  func (i *rawBlockIter) Key() InternalKey {
   247  	return i.ikey
   248  }
   249  
   250  // Value implements internalIterator.Value, as documented in the pebble
   251  // package.
   252  func (i *rawBlockIter) Value() []byte {
   253  	return i.val
   254  }
   255  
   256  func (i *rawBlockIter) valueOffset() uint64 {
   257  	ptr := unsafe.Pointer(uintptr(i.ptr) + uintptr(i.offset))
   258  	shared, ptr := decodeVarint(ptr)
   259  	unshared, _ := decodeVarint(ptr)
   260  	return uint64(i.offset) + uint64(shared+unshared)
   261  }
   262  
   263  // Valid implements internalIterator.Valid, as documented in the pebble
   264  // package.
   265  func (i *rawBlockIter) Valid() bool {
   266  	return i.offset >= 0 && i.offset < i.restarts
   267  }
   268  
   269  // Error implements internalIterator.Error, as documented in the pebble
   270  // package.
   271  func (i *rawBlockIter) Error() error {
   272  	return i.err
   273  }
   274  
   275  // Close implements internalIterator.Close, as documented in the pebble
   276  // package.
   277  func (i *rawBlockIter) Close() error {
   278  	i.val = nil
   279  	return i.err
   280  }