github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/cmd/pebble/mvcc.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 main
     6  
     7  import (
     8  	"bytes"
     9  
    10  	"github.com/petermattis/pebble"
    11  	"github.com/petermattis/pebble/internal/bytealloc"
    12  )
    13  
    14  // MVCC encoding and decoding routines adapted from CockroachDB sources. Used
    15  // to perform apples-to-apples benchmarking for CockroachDB's usage of RocksDB.
    16  
    17  var mvccComparer = &pebble.Comparer{
    18  	Compare: mvccCompare,
    19  
    20  	AbbreviatedKey: func(k []byte) uint64 {
    21  		key, _, ok := mvccSplitKey(k)
    22  		if !ok {
    23  			return 0
    24  		}
    25  		return pebble.DefaultComparer.AbbreviatedKey(key)
    26  	},
    27  
    28  	Separator: func(dst, a, b []byte) []byte {
    29  		return append(dst, a...)
    30  	},
    31  
    32  	Successor: func(dst, a []byte) []byte {
    33  		return append(dst, a...)
    34  	},
    35  
    36  	Name: "cockroach_comparator",
    37  }
    38  
    39  func mvccSplitKey(mvccKey []byte) (key []byte, ts []byte, ok bool) {
    40  	if len(mvccKey) == 0 {
    41  		return nil, nil, false
    42  	}
    43  	n := len(mvccKey) - 1
    44  	tsLen := int(mvccKey[n])
    45  	if n < tsLen {
    46  		return nil, nil, false
    47  	}
    48  	key = mvccKey[:n-tsLen]
    49  	if tsLen > 0 {
    50  		ts = mvccKey[n-tsLen+1 : len(mvccKey)-1]
    51  	}
    52  	return key, ts, true
    53  }
    54  
    55  func mvccCompare(a, b []byte) int {
    56  	aKey, aTS, aOK := mvccSplitKey(a)
    57  	bKey, bTS, bOK := mvccSplitKey(b)
    58  	if !aOK || !bOK {
    59  		// This should never happen unless there is some sort of corruption of
    60  		// the keys.
    61  		return bytes.Compare(a, b)
    62  	}
    63  	if c := bytes.Compare(aKey, bKey); c != 0 {
    64  		return c
    65  	}
    66  	if len(aTS) == 0 {
    67  		if len(bTS) == 0 {
    68  			return 0
    69  		}
    70  		return -1
    71  	} else if len(bTS) == 0 {
    72  		return +1
    73  	}
    74  	return bytes.Compare(bTS, aTS)
    75  }
    76  
    77  // <key>\x00[<wall_time>[<logical>]]<#timestamp-bytes>
    78  func mvccEncode(dst, key []byte, walltime uint64, logical uint32) []byte {
    79  	dst = append(dst, key...)
    80  	dst = append(dst, 0)
    81  	if walltime != 0 || logical != 0 {
    82  		extra := byte(1 + 8)
    83  		dst = encodeUint64Ascending(dst, walltime)
    84  		if logical != 0 {
    85  			dst = encodeUint32Ascending(dst, logical)
    86  			extra += 4
    87  		}
    88  		dst = append(dst, extra)
    89  	}
    90  	return dst
    91  }
    92  
    93  func mvccForwardScan(d DB, start, end, ts []byte) (int, int64) {
    94  	it := d.NewIter(&pebble.IterOptions{
    95  		LowerBound: mvccEncode(nil, start, 0, 0),
    96  		UpperBound: mvccEncode(nil, end, 0, 0),
    97  	})
    98  	defer it.Close()
    99  
   100  	var data bytealloc.A
   101  	var count int
   102  	var nbytes int64
   103  
   104  	for valid := it.First(); valid; valid = it.Next() {
   105  		key, keyTS, _ := mvccSplitKey(it.Key())
   106  		if bytes.Compare(keyTS, ts) <= 0 {
   107  			data, _ = data.Copy(key)
   108  			data, _ = data.Copy(it.Value())
   109  		}
   110  		count++
   111  		nbytes += int64(len(it.Key()) + len(it.Value()))
   112  	}
   113  	return count, nbytes
   114  }
   115  
   116  func mvccReverseScan(d DB, start, end, ts []byte) (int, int64) {
   117  	it := d.NewIter(&pebble.IterOptions{
   118  		LowerBound: mvccEncode(nil, start, 0, 0),
   119  		UpperBound: mvccEncode(nil, end, 0, 0),
   120  	})
   121  	defer it.Close()
   122  
   123  	var data bytealloc.A
   124  	var count int
   125  	var nbytes int64
   126  
   127  	for valid := it.Last(); valid; valid = it.Prev() {
   128  		key, keyTS, _ := mvccSplitKey(it.Key())
   129  		if bytes.Compare(keyTS, ts) <= 0 {
   130  			data, _ = data.Copy(key)
   131  			data, _ = data.Copy(it.Value())
   132  		}
   133  		count++
   134  		nbytes += int64(len(it.Key()) + len(it.Value()))
   135  	}
   136  	return count, nbytes
   137  }