1
2
3
4
5
6
7 package leveldb
8
9 import (
10 "bufio"
11 "encoding/binary"
12 "io"
13 "strings"
14
15 "github.com/syndtr/goleveldb/leveldb/errors"
16 "github.com/syndtr/goleveldb/leveldb/storage"
17 )
18
19 type byteReader interface {
20 io.Reader
21 io.ByteReader
22 }
23
24
25 const (
26 recComparer = 1
27 recJournalNum = 2
28 recNextFileNum = 3
29 recSeqNum = 4
30 recCompPtr = 5
31 recDelTable = 6
32 recAddTable = 7
33
34 recPrevJournalNum = 9
35 )
36
37 type cpRecord struct {
38 level int
39 ikey internalKey
40 }
41
42 type atRecord struct {
43 level int
44 num int64
45 size int64
46 imin internalKey
47 imax internalKey
48 }
49
50 type dtRecord struct {
51 level int
52 num int64
53 }
54
55 type sessionRecord struct {
56 hasRec int
57 comparer string
58 journalNum int64
59 prevJournalNum int64
60 nextFileNum int64
61 seqNum uint64
62 compPtrs []cpRecord
63 addedTables []atRecord
64 deletedTables []dtRecord
65
66 scratch [binary.MaxVarintLen64]byte
67 err error
68 }
69
70 func (p *sessionRecord) has(rec int) bool {
71 return p.hasRec&(1<<uint(rec)) != 0
72 }
73
74 func (p *sessionRecord) setComparer(name string) {
75 p.hasRec |= 1 << recComparer
76 p.comparer = name
77 }
78
79 func (p *sessionRecord) setJournalNum(num int64) {
80 p.hasRec |= 1 << recJournalNum
81 p.journalNum = num
82 }
83
84 func (p *sessionRecord) setPrevJournalNum(num int64) {
85 p.hasRec |= 1 << recPrevJournalNum
86 p.prevJournalNum = num
87 }
88
89 func (p *sessionRecord) setNextFileNum(num int64) {
90 p.hasRec |= 1 << recNextFileNum
91 p.nextFileNum = num
92 }
93
94 func (p *sessionRecord) setSeqNum(num uint64) {
95 p.hasRec |= 1 << recSeqNum
96 p.seqNum = num
97 }
98
99 func (p *sessionRecord) addCompPtr(level int, ikey internalKey) {
100 p.hasRec |= 1 << recCompPtr
101 p.compPtrs = append(p.compPtrs, cpRecord{level, ikey})
102 }
103
104 func (p *sessionRecord) resetCompPtrs() {
105 p.hasRec &= ^(1 << recCompPtr)
106 p.compPtrs = p.compPtrs[:0]
107 }
108
109 func (p *sessionRecord) addTable(level int, num, size int64, imin, imax internalKey) {
110 p.hasRec |= 1 << recAddTable
111 p.addedTables = append(p.addedTables, atRecord{level, num, size, imin, imax})
112 }
113
114 func (p *sessionRecord) addTableFile(level int, t *tFile) {
115 p.addTable(level, t.fd.Num, t.size, t.imin, t.imax)
116 }
117
118 func (p *sessionRecord) resetAddedTables() {
119 p.hasRec &= ^(1 << recAddTable)
120 p.addedTables = p.addedTables[:0]
121 }
122
123 func (p *sessionRecord) delTable(level int, num int64) {
124 p.hasRec |= 1 << recDelTable
125 p.deletedTables = append(p.deletedTables, dtRecord{level, num})
126 }
127
128 func (p *sessionRecord) resetDeletedTables() {
129 p.hasRec &= ^(1 << recDelTable)
130 p.deletedTables = p.deletedTables[:0]
131 }
132
133 func (p *sessionRecord) putUvarint(w io.Writer, x uint64) {
134 if p.err != nil {
135 return
136 }
137 n := binary.PutUvarint(p.scratch[:], x)
138 _, p.err = w.Write(p.scratch[:n])
139 }
140
141 func (p *sessionRecord) putVarint(w io.Writer, x int64) {
142 if x < 0 {
143 panic("invalid negative value")
144 }
145 p.putUvarint(w, uint64(x))
146 }
147
148 func (p *sessionRecord) putBytes(w io.Writer, x []byte) {
149 if p.err != nil {
150 return
151 }
152 p.putUvarint(w, uint64(len(x)))
153 if p.err != nil {
154 return
155 }
156 _, p.err = w.Write(x)
157 }
158
159 func (p *sessionRecord) encode(w io.Writer) error {
160 p.err = nil
161 if p.has(recComparer) {
162 p.putUvarint(w, recComparer)
163 p.putBytes(w, []byte(p.comparer))
164 }
165 if p.has(recJournalNum) {
166 p.putUvarint(w, recJournalNum)
167 p.putVarint(w, p.journalNum)
168 }
169 if p.has(recNextFileNum) {
170 p.putUvarint(w, recNextFileNum)
171 p.putVarint(w, p.nextFileNum)
172 }
173 if p.has(recSeqNum) {
174 p.putUvarint(w, recSeqNum)
175 p.putUvarint(w, p.seqNum)
176 }
177 for _, r := range p.compPtrs {
178 p.putUvarint(w, recCompPtr)
179 p.putUvarint(w, uint64(r.level))
180 p.putBytes(w, r.ikey)
181 }
182 for _, r := range p.deletedTables {
183 p.putUvarint(w, recDelTable)
184 p.putUvarint(w, uint64(r.level))
185 p.putVarint(w, r.num)
186 }
187 for _, r := range p.addedTables {
188 p.putUvarint(w, recAddTable)
189 p.putUvarint(w, uint64(r.level))
190 p.putVarint(w, r.num)
191 p.putVarint(w, r.size)
192 p.putBytes(w, r.imin)
193 p.putBytes(w, r.imax)
194 }
195 return p.err
196 }
197
198 func (p *sessionRecord) readUvarintMayEOF(field string, r io.ByteReader, mayEOF bool) uint64 {
199 if p.err != nil {
200 return 0
201 }
202 x, err := binary.ReadUvarint(r)
203 if err != nil {
204 if err == io.ErrUnexpectedEOF || (!mayEOF && err == io.EOF) {
205 p.err = errors.NewErrCorrupted(storage.FileDesc{}, &ErrManifestCorrupted{field, "short read"})
206 } else if strings.HasPrefix(err.Error(), "binary:") {
207 p.err = errors.NewErrCorrupted(storage.FileDesc{}, &ErrManifestCorrupted{field, err.Error()})
208 } else {
209 p.err = err
210 }
211 return 0
212 }
213 return x
214 }
215
216 func (p *sessionRecord) readUvarint(field string, r io.ByteReader) uint64 {
217 return p.readUvarintMayEOF(field, r, false)
218 }
219
220 func (p *sessionRecord) readVarint(field string, r io.ByteReader) int64 {
221 x := int64(p.readUvarintMayEOF(field, r, false))
222 if x < 0 {
223 p.err = errors.NewErrCorrupted(storage.FileDesc{}, &ErrManifestCorrupted{field, "invalid negative value"})
224 }
225 return x
226 }
227
228 func (p *sessionRecord) readBytes(field string, r byteReader) []byte {
229 if p.err != nil {
230 return nil
231 }
232 n := p.readUvarint(field, r)
233 if p.err != nil {
234 return nil
235 }
236 x := make([]byte, n)
237 _, p.err = io.ReadFull(r, x)
238 if p.err != nil {
239 if p.err == io.ErrUnexpectedEOF {
240 p.err = errors.NewErrCorrupted(storage.FileDesc{}, &ErrManifestCorrupted{field, "short read"})
241 }
242 return nil
243 }
244 return x
245 }
246
247 func (p *sessionRecord) readLevel(field string, r io.ByteReader) int {
248 if p.err != nil {
249 return 0
250 }
251 x := p.readUvarint(field, r)
252 if p.err != nil {
253 return 0
254 }
255 return int(x)
256 }
257
258 func (p *sessionRecord) decode(r io.Reader) error {
259 br, ok := r.(byteReader)
260 if !ok {
261 br = bufio.NewReader(r)
262 }
263 p.err = nil
264 for p.err == nil {
265 rec := p.readUvarintMayEOF("field-header", br, true)
266 if p.err != nil {
267 if p.err == io.EOF {
268 return nil
269 }
270 return p.err
271 }
272 switch rec {
273 case recComparer:
274 x := p.readBytes("comparer", br)
275 if p.err == nil {
276 p.setComparer(string(x))
277 }
278 case recJournalNum:
279 x := p.readVarint("journal-num", br)
280 if p.err == nil {
281 p.setJournalNum(x)
282 }
283 case recPrevJournalNum:
284 x := p.readVarint("prev-journal-num", br)
285 if p.err == nil {
286 p.setPrevJournalNum(x)
287 }
288 case recNextFileNum:
289 x := p.readVarint("next-file-num", br)
290 if p.err == nil {
291 p.setNextFileNum(x)
292 }
293 case recSeqNum:
294 x := p.readUvarint("seq-num", br)
295 if p.err == nil {
296 p.setSeqNum(x)
297 }
298 case recCompPtr:
299 level := p.readLevel("comp-ptr.level", br)
300 ikey := p.readBytes("comp-ptr.ikey", br)
301 if p.err == nil {
302 p.addCompPtr(level, internalKey(ikey))
303 }
304 case recAddTable:
305 level := p.readLevel("add-table.level", br)
306 num := p.readVarint("add-table.num", br)
307 size := p.readVarint("add-table.size", br)
308 imin := p.readBytes("add-table.imin", br)
309 imax := p.readBytes("add-table.imax", br)
310 if p.err == nil {
311 p.addTable(level, num, size, imin, imax)
312 }
313 case recDelTable:
314 level := p.readLevel("del-table.level", br)
315 num := p.readVarint("del-table.num", br)
316 if p.err == nil {
317 p.delTable(level, num)
318 }
319 }
320 }
321
322 return p.err
323 }
324
View as plain text