-
Notifications
You must be signed in to change notification settings - Fork 0
/
encvalue.go
146 lines (124 loc) · 3.55 KB
/
encvalue.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
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
package edb
import (
"encoding/binary"
"fmt"
)
const (
valueFormatVer1 = 1
valueFormatVerLatest = valueFormatVer1
)
type valueFlags uint64
const (
vfVerBit0 = valueFlags(1 << iota)
vfVerBit1
vfVerBit2
vfVerBit3
vfCompressionBit0
vfVerMask = (vfVerBit0 | vfVerBit1 | vfVerBit2 | vfVerBit3)
vfVer1 = vfVerBit0
vfGzip = vfCompressionBit0
vfSupportedMask = (vfVer1 | vfGzip)
vfDefault = vfVer1
minValueSize = 5
maxValueHeaderSize = binary.MaxVarintLen64 * 5
maxSchemaVersion = 32768 // just a sanity value, can be increased
)
func (vf valueFlags) ver() valueFlags {
return vf & vfVerMask
}
func (vf valueFlags) encoding() encodingMethod {
return MsgPack
}
type value struct {
Flags valueFlags
SchemaVer uint64
ModCount uint64
Data []byte
Index []byte
}
func (vle value) ValueMeta() ValueMeta {
return ValueMeta{
SchemaVer: vle.SchemaVer,
ModCount: vle.ModCount,
}
}
func reserveValueHeader(buf []byte) []byte {
if len(buf) != 0 {
panic("value must be written to an empty buffer")
}
return buf[:maxValueHeaderSize]
}
func putValueHeader(buf []byte, flags valueFlags, schemaVer uint64, modCount uint64, indexOff int) []byte {
if indexOff > len(buf) {
panic(fmt.Errorf("invalid indexOff=%d", indexOff)) // sanity check
}
if (flags &^ vfSupportedMask) != 0 {
panic(fmt.Errorf("invalid flags %x", flags))
}
dataSize := indexOff - maxValueHeaderSize
indexSize := len(buf) - indexOff
var off = 0
n := binary.PutUvarint(buf[off:], uint64(flags))
off += n
n = binary.PutUvarint(buf[off:], uint64(schemaVer))
off += n
n = binary.PutUvarint(buf[off:], uint64(modCount))
off += n
n = binary.PutUvarint(buf[off:], uint64(dataSize))
off += n
n = binary.PutUvarint(buf[off:], uint64(indexSize))
off += n
headerSize := off
if headerSize > maxValueHeaderSize {
panic("internal error")
}
if headerSize < maxValueHeaderSize {
// move the header closer to data
start := maxValueHeaderSize - headerSize
copy(buf[start:maxValueHeaderSize], buf[:headerSize])
return buf[start:]
} else {
return buf
}
}
func (vle *value) decode(data []byte) error {
orig := data
if len(data) < minValueSize {
return dataErrf(orig, len(data)-len(orig), nil, "invalid value: at least %d bytes required", minValueSize)
}
v, n := binary.Uvarint(data)
if n <= 0 {
return dataErrf(orig, len(data)-len(orig), nil, "invalid value: bad flags")
}
if (v & ^uint64(vfSupportedMask)) != 0 {
return dataErrf(orig, len(data)-len(orig), nil, "invalid value: unsupported flags %x", v)
}
vle.Flags, data = valueFlags(v), data[n:]
v, n = binary.Uvarint(data)
if n <= 0 || v > maxSchemaVersion {
return dataErrf(orig, len(data)-len(orig), nil, "invalid value: bad schema version")
}
vle.SchemaVer, data = v, data[n:]
v, n = binary.Uvarint(data)
if n <= 0 {
return dataErrf(orig, len(data)-len(orig), nil, "invalid value: bad mod count")
}
vle.ModCount, data = v, data[n:]
dataSize, n := binary.Uvarint(data)
if n <= 0 {
return dataErrf(orig, len(data)-len(orig), nil, "invalid value: bad data size")
}
data = data[n:]
indexSize, n := binary.Uvarint(data)
if n <= 0 {
return dataErrf(orig, len(data)-len(orig), nil, "invalid value: bad data size")
}
data = data[n:]
expectedSize := dataSize + indexSize
if uint64(len(data)) != expectedSize {
return dataErrf(orig, len(data)-len(orig), nil, "invalid value: got %d bytes for data+index, expected %d bytes", len(data), expectedSize)
}
vle.Data, data = data[:dataSize], data[dataSize:]
vle.Index, data = data[:indexSize], data[indexSize:]
return nil
}