forked from ngaut/unistore
/
block_builder.go
117 lines (97 loc) · 3.17 KB
/
block_builder.go
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
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
// This source code is licensed under both the GPLv2 (found in the
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).
//
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
// Copyright 2019-present PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
package rocksdb
import "github.com/pingcap/badger/y"
// 1-byte type + 32-bit crc
const blockTrailerSize = 5
// blockBuilder port from RocksDB's blockBuilder without Hash Index Support
type blockBuilder struct {
restartInterval int
counter int
estimate int
restarts []uint32
buf []byte
lastKey []byte
}
func newBlockBuilder(restartInterval int) *blockBuilder {
b := new(blockBuilder)
b.Init(restartInterval)
return b
}
func (b *blockBuilder) Init(restartInterval int) {
b.restartInterval = restartInterval
b.restarts = []uint32{0}
}
func (b *blockBuilder) Reset() {
b.counter = 0
b.estimate = 0
b.buf = b.buf[:0]
b.restarts = b.restarts[:1]
b.lastKey = b.lastKey[:0]
}
func (b *blockBuilder) Add(key, value []byte) {
y.Assert(b.counter <= b.restartInterval)
var prefixLen uint32
if b.counter >= b.restartInterval {
// Restart compression
b.restarts = append(b.restarts, uint32(len(b.buf)))
b.counter = 0
b.lastKey = y.SafeCopy(b.lastKey, key)
} else {
prefixLen = uint32(differenceOffset(key, b.lastKey))
b.lastKey = y.SafeCopy(b.lastKey, key)
}
currSz := len(b.buf)
b.buf = appendVarint32(b.buf, prefixLen)
b.buf = appendVarint32(b.buf, uint32(len(key))-prefixLen)
b.buf = appendVarint32(b.buf, uint32(len(value)))
b.buf = append(b.buf, key[prefixLen:]...)
b.buf = append(b.buf, value...)
b.counter++
b.estimate += len(b.buf) - currSz
}
func (b *blockBuilder) Empty() bool {
return len(b.buf) == 0
}
func (b *blockBuilder) Finish() []byte {
var encodeBuf [4]byte
for _, restart := range b.restarts {
rocksEndian.PutUint32(encodeBuf[:], restart)
b.buf = append(b.buf, encodeBuf[:]...)
}
rocksEndian.PutUint32(encodeBuf[:], uint32(len(b.restarts)))
return append(b.buf, encodeBuf[:]...)
}
func (b *blockBuilder) EstimateSize() int {
return b.estimate
}
func (b *blockBuilder) EstimateSizeAfterKV(key, value []byte) int {
estimate := b.EstimateSize()
estimate += len(key) + len(value)
if b.counter >= b.restartInterval {
// a new restart entry
estimate += 4
}
// Note: this is an imprecise estimate as we will have to encoded size, one
// for shared key and one for non-shared key.
estimate += 4 + 4 + 4
return estimate
}