1 // Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
2 // All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
15 "github.com/syndtr/goleveldb/leveldb/errors"
16 "github.com/syndtr/goleveldb/leveldb/storage"
19 type byteReader interface {
24 // These numbers are written to disk and should not be changed.
33 // 8 was used for large value refs
37 type cpRecord struct {
42 type atRecord struct {
50 type dtRecord struct {
55 type sessionRecord struct {
63 addedTables []atRecord
64 deletedTables []dtRecord
66 scratch [binary.MaxVarintLen64]byte
70 func (p *sessionRecord) has(rec int) bool {
71 return p.hasRec&(1<<uint(rec)) != 0
74 func (p *sessionRecord) setComparer(name string) {
75 p.hasRec |= 1 << recComparer
79 func (p *sessionRecord) setJournalNum(num int64) {
80 p.hasRec |= 1 << recJournalNum
84 func (p *sessionRecord) setPrevJournalNum(num int64) {
85 p.hasRec |= 1 << recPrevJournalNum
86 p.prevJournalNum = num
89 func (p *sessionRecord) setNextFileNum(num int64) {
90 p.hasRec |= 1 << recNextFileNum
94 func (p *sessionRecord) setSeqNum(num uint64) {
95 p.hasRec |= 1 << recSeqNum
99 func (p *sessionRecord) addCompPtr(level int, ikey internalKey) {
100 p.hasRec |= 1 << recCompPtr
101 p.compPtrs = append(p.compPtrs, cpRecord{level, ikey})
104 func (p *sessionRecord) resetCompPtrs() {
105 p.hasRec &= ^(1 << recCompPtr)
106 p.compPtrs = p.compPtrs[:0]
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})
114 func (p *sessionRecord) addTableFile(level int, t *tFile) {
115 p.addTable(level, t.fd.Num, t.size, t.imin, t.imax)
118 func (p *sessionRecord) resetAddedTables() {
119 p.hasRec &= ^(1 << recAddTable)
120 p.addedTables = p.addedTables[:0]
123 func (p *sessionRecord) delTable(level int, num int64) {
124 p.hasRec |= 1 << recDelTable
125 p.deletedTables = append(p.deletedTables, dtRecord{level, num})
128 func (p *sessionRecord) resetDeletedTables() {
129 p.hasRec &= ^(1 << recDelTable)
130 p.deletedTables = p.deletedTables[:0]
133 func (p *sessionRecord) putUvarint(w io.Writer, x uint64) {
137 n := binary.PutUvarint(p.scratch[:], x)
138 _, p.err = w.Write(p.scratch[:n])
141 func (p *sessionRecord) putVarint(w io.Writer, x int64) {
143 panic("invalid negative value")
145 p.putUvarint(w, uint64(x))
148 func (p *sessionRecord) putBytes(w io.Writer, x []byte) {
152 p.putUvarint(w, uint64(len(x)))
156 _, p.err = w.Write(x)
159 func (p *sessionRecord) encode(w io.Writer) error {
161 if p.has(recComparer) {
162 p.putUvarint(w, recComparer)
163 p.putBytes(w, []byte(p.comparer))
165 if p.has(recJournalNum) {
166 p.putUvarint(w, recJournalNum)
167 p.putVarint(w, p.journalNum)
169 if p.has(recNextFileNum) {
170 p.putUvarint(w, recNextFileNum)
171 p.putVarint(w, p.nextFileNum)
173 if p.has(recSeqNum) {
174 p.putUvarint(w, recSeqNum)
175 p.putUvarint(w, p.seqNum)
177 for _, r := range p.compPtrs {
178 p.putUvarint(w, recCompPtr)
179 p.putUvarint(w, uint64(r.level))
180 p.putBytes(w, r.ikey)
182 for _, r := range p.deletedTables {
183 p.putUvarint(w, recDelTable)
184 p.putUvarint(w, uint64(r.level))
185 p.putVarint(w, r.num)
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)
198 func (p *sessionRecord) readUvarintMayEOF(field string, r io.ByteReader, mayEOF bool) uint64 {
202 x, err := binary.ReadUvarint(r)
204 if err == io.ErrUnexpectedEOF || (mayEOF == false && 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()})
216 func (p *sessionRecord) readUvarint(field string, r io.ByteReader) uint64 {
217 return p.readUvarintMayEOF(field, r, false)
220 func (p *sessionRecord) readVarint(field string, r io.ByteReader) int64 {
221 x := int64(p.readUvarintMayEOF(field, r, false))
223 p.err = errors.NewErrCorrupted(storage.FileDesc{}, &ErrManifestCorrupted{field, "invalid negative value"})
228 func (p *sessionRecord) readBytes(field string, r byteReader) []byte {
232 n := p.readUvarint(field, r)
237 _, p.err = io.ReadFull(r, x)
239 if p.err == io.ErrUnexpectedEOF {
240 p.err = errors.NewErrCorrupted(storage.FileDesc{}, &ErrManifestCorrupted{field, "short read"})
247 func (p *sessionRecord) readLevel(field string, r io.ByteReader) int {
251 x := p.readUvarint(field, r)
258 func (p *sessionRecord) decode(r io.Reader) error {
259 br, ok := r.(byteReader)
261 br = bufio.NewReader(r)
265 rec := p.readUvarintMayEOF("field-header", br, true)
274 x := p.readBytes("comparer", br)
276 p.setComparer(string(x))
279 x := p.readVarint("journal-num", br)
283 case recPrevJournalNum:
284 x := p.readVarint("prev-journal-num", br)
286 p.setPrevJournalNum(x)
289 x := p.readVarint("next-file-num", br)
294 x := p.readUvarint("seq-num", br)
299 level := p.readLevel("comp-ptr.level", br)
300 ikey := p.readBytes("comp-ptr.ikey", br)
302 p.addCompPtr(level, internalKey(ikey))
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)
311 p.addTable(level, num, size, imin, imax)
314 level := p.readLevel("del-table.level", br)
315 num := p.readVarint("del-table.num", br)
317 p.delTable(level, num)