File: ikey.go

package info (click to toggle)
golang-github-golang-leveldb 0.0~git20161231.0.3435554-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, buster-backports
  • size: 1,000 kB
  • sloc: cpp: 166; makefile: 11
file content (164 lines) | stat: -rw-r--r-- 5,144 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// Copyright 2012 The LevelDB-Go 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 leveldb

import (
	"bytes"

	"github.com/golang/leveldb/db"
)

// internalKey is a key used for the in-memory and on-disk partial DBs that
// make up a leveldb DB.
//
// It consists of the user key (as given by the arbitrary code that uses
// package leveldb) followed by an 8-byte trailer:
//   - 1 byte for the kind of internal key: delete or set,
//   - 7 bytes for a uint56 sequence number, in little-endian format.
type internalKey []byte

type internalKeyKind uint8

const (
	// These constants are part of the file format, and should not be changed.
	internalKeyKindDelete internalKeyKind = 0
	internalKeyKindSet    internalKeyKind = 1

	// This maximum value isn't part of the file format. It's unlikely,
	// but future extensions may increase this value.
	//
	// When constructing an internal key to pass to DB.Find, internalKeyComparer
	// sorts decreasing by kind (after sorting increasing by user key and
	// decreasing by sequence number). Thus, use internalKeyKindMax, which sorts
	// 'less than or equal to' any other valid internalKeyKind, when searching
	// for any kind of internal key formed by a certain user key and seqNum.
	internalKeyKindMax internalKeyKind = 1
)

// internalKeySeqNumMax is the largest valid sequence number.
const internalKeySeqNumMax = uint64(1<<56 - 1)

// makeInternalKey makes an internalKey from a user key, a kind, and a sequence
// number. The return value may be a slice of dst[:cap(dst)] if it is large
// enough. Otherwise, it may be a slice of a newly allocated buffer. In any
// case, all of dst[:cap(dst)] may be overwritten.
func makeInternalKey(dst internalKey, ukey []byte, kind internalKeyKind, seqNum uint64) internalKey {
	if cap(dst) < len(ukey)+8 {
		n := 256
		for n < len(ukey)+8 {
			n *= 2
		}
		dst = make(internalKey, n)
	}
	ikey := dst[:len(ukey)+8]
	i := copy(ikey, ukey)
	ikey[i+0] = uint8(kind)
	ikey[i+1] = uint8(seqNum)
	ikey[i+2] = uint8(seqNum >> 8)
	ikey[i+3] = uint8(seqNum >> 16)
	ikey[i+4] = uint8(seqNum >> 24)
	ikey[i+5] = uint8(seqNum >> 32)
	ikey[i+6] = uint8(seqNum >> 40)
	ikey[i+7] = uint8(seqNum >> 48)
	return ikey
}

// valid returns whether k is a valid internal key.
func (k internalKey) valid() bool {
	i := len(k) - 8
	return i >= 0 && internalKeyKind(k[i]) <= internalKeyKindMax
}

// ukey returns the user key portion of an internal key.
// ukey may panic if k is not valid.
func (k internalKey) ukey() []byte {
	return []byte(k[:len(k)-8])
}

// kind returns the kind of an internal key.
// kind may panic if k is not valid.
func (k internalKey) kind() internalKeyKind {
	return internalKeyKind(k[len(k)-8])
}

// seqNum returns the sequence number of an internal key.
// seqNum may panic if k is not valid.
func (k internalKey) seqNum() uint64 {
	i := len(k) - 7
	n := uint64(k[i+0])
	n |= uint64(k[i+1]) << 8
	n |= uint64(k[i+2]) << 16
	n |= uint64(k[i+3]) << 24
	n |= uint64(k[i+4]) << 32
	n |= uint64(k[i+5]) << 40
	n |= uint64(k[i+6]) << 48
	return n
}

// clone returns an internalKey that has the same contents but is backed by a
// different array.
func (k internalKey) clone() internalKey {
	x := make(internalKey, len(k))
	copy(x, k)
	return x
}

// internalKeyComparer is a db.Comparer that wraps another db.Comparer.
//
// It compares internal keys first by their user keys (as ordered by userCmp),
// then by sequence number (decreasing), then by kind (decreasing). The last
// step is only for completeness; for a given leveldb DB, no two internal keys
// should have the same sequence number.
//
// This ordering is designed so that when iterating through an internal table
// starting at (ukey0, seqNum0), one first encounters those entries with the
// same user key and lower sequence number (i.e. sets or deletes from earlier
// in time), followed by those entries with 'greater' user keys (where
// 'greater' is defined by userCmp). Specifically, one does not encounter
// entries with the same user key and higher sequence number (i.e. sets or
// deletes for ukey0 from the 'future' relative to the particular snapshot
// seqNum0 of the DB).
type internalKeyComparer struct {
	userCmp db.Comparer
}

var _ db.Comparer = internalKeyComparer{}

func (c internalKeyComparer) Compare(a, b []byte) int {
	ak, bk := internalKey(a), internalKey(b)
	if !ak.valid() {
		if bk.valid() {
			return -1
		}
		return bytes.Compare(a, b)
	}
	if !bk.valid() {
		return 1
	}
	if x := c.userCmp.Compare(ak.ukey(), bk.ukey()); x != 0 {
		return x
	}
	if an, bn := ak.seqNum(), bk.seqNum(); an < bn {
		return +1
	} else if an > bn {
		return -1
	}
	if ai, bi := ak.kind(), bk.kind(); ai < bi {
		return +1
	} else if ai > bi {
		return -1
	}
	return 0
}

func (c internalKeyComparer) Name() string {
	// This is the same name given by the C++ leveldb's InternalKeyComparator class.
	return "leveldb.InternalKeyComparator"
}

func (c internalKeyComparer) AppendSeparator(dst, a, b []byte) []byte {
	// TODO: this could be more sophisticated.
	return append(dst, a...)
}