github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/syndtr/goleveldb/leveldb/batch.go (about) 1 // Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com> 2 // All rights reserved. 3 // 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the LICENSE file. 6 7 package leveldb 8 9 import ( 10 "encoding/binary" 11 "fmt" 12 13 "github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/errors" 14 "github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/memdb" 15 "github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/storage" 16 ) 17 18 // ErrBatchCorrupted records reason of batch corruption. 19 type ErrBatchCorrupted struct { 20 Reason string 21 } 22 23 func (e *ErrBatchCorrupted) Error() string { 24 return fmt.Sprintf("leveldb: batch corrupted: %s", e.Reason) 25 } 26 27 func newErrBatchCorrupted(reason string) error { 28 return errors.NewErrCorrupted(storage.FileDesc{}, &ErrBatchCorrupted{reason}) 29 } 30 31 const ( 32 batchHdrLen = 8 + 4 33 batchGrowRec = 3000 34 ) 35 36 // BatchReplay wraps basic batch operations. 37 type BatchReplay interface { 38 Put(key, value []byte) 39 Delete(key []byte) 40 } 41 42 // Batch is a write batch. 43 type Batch struct { 44 data []byte 45 rLen, bLen int 46 seq uint64 47 sync bool 48 } 49 50 func (b *Batch) grow(n int) { 51 off := len(b.data) 52 if off == 0 { 53 off = batchHdrLen 54 if b.data != nil { 55 b.data = b.data[:off] 56 } 57 } 58 if cap(b.data)-off < n { 59 if b.data == nil { 60 b.data = make([]byte, off, off+n) 61 } else { 62 odata := b.data 63 div := 1 64 if b.rLen > batchGrowRec { 65 div = b.rLen / batchGrowRec 66 } 67 b.data = make([]byte, off, off+n+(off-batchHdrLen)/div) 68 copy(b.data, odata) 69 } 70 } 71 } 72 73 func (b *Batch) appendRec(kt keyType, key, value []byte) { 74 n := 1 + binary.MaxVarintLen32 + len(key) 75 if kt == keyTypeVal { 76 n += binary.MaxVarintLen32 + len(value) 77 } 78 b.grow(n) 79 off := len(b.data) 80 data := b.data[:off+n] 81 data[off] = byte(kt) 82 off++ 83 off += binary.PutUvarint(data[off:], uint64(len(key))) 84 copy(data[off:], key) 85 off += len(key) 86 if kt == keyTypeVal { 87 off += binary.PutUvarint(data[off:], uint64(len(value))) 88 copy(data[off:], value) 89 off += len(value) 90 } 91 b.data = data[:off] 92 b.rLen++ 93 // Include 8-byte ikey header 94 b.bLen += len(key) + len(value) + 8 95 } 96 97 // Put appends 'put operation' of the given key/value pair to the batch. 98 // It is safe to modify the contents of the argument after Put returns. 99 func (b *Batch) Put(key, value []byte) { 100 b.appendRec(keyTypeVal, key, value) 101 } 102 103 // Delete appends 'delete operation' of the given key to the batch. 104 // It is safe to modify the contents of the argument after Delete returns. 105 func (b *Batch) Delete(key []byte) { 106 b.appendRec(keyTypeDel, key, nil) 107 } 108 109 // Dump dumps batch contents. The returned slice can be loaded into the 110 // batch using Load method. 111 // The returned slice is not its own copy, so the contents should not be 112 // modified. 113 func (b *Batch) Dump() []byte { 114 return b.encode() 115 } 116 117 // Load loads given slice into the batch. Previous contents of the batch 118 // will be discarded. 119 // The given slice will not be copied and will be used as batch buffer, so 120 // it is not safe to modify the contents of the slice. 121 func (b *Batch) Load(data []byte) error { 122 return b.decode(0, data) 123 } 124 125 // Replay replays batch contents. 126 func (b *Batch) Replay(r BatchReplay) error { 127 return b.decodeRec(func(i int, kt keyType, key, value []byte) error { 128 switch kt { 129 case keyTypeVal: 130 r.Put(key, value) 131 case keyTypeDel: 132 r.Delete(key) 133 } 134 return nil 135 }) 136 } 137 138 // Len returns number of records in the batch. 139 func (b *Batch) Len() int { 140 return b.rLen 141 } 142 143 // Reset resets the batch. 144 func (b *Batch) Reset() { 145 b.data = b.data[:0] 146 b.seq = 0 147 b.rLen = 0 148 b.bLen = 0 149 b.sync = false 150 } 151 152 func (b *Batch) init(sync bool) { 153 b.sync = sync 154 } 155 156 func (b *Batch) append(p *Batch) { 157 if p.rLen > 0 { 158 b.grow(len(p.data) - batchHdrLen) 159 b.data = append(b.data, p.data[batchHdrLen:]...) 160 b.rLen += p.rLen 161 b.bLen += p.bLen 162 } 163 if p.sync { 164 b.sync = true 165 } 166 } 167 168 // size returns sums of key/value pair length plus 8-bytes ikey. 169 func (b *Batch) size() int { 170 return b.bLen 171 } 172 173 func (b *Batch) encode() []byte { 174 b.grow(0) 175 binary.LittleEndian.PutUint64(b.data, b.seq) 176 binary.LittleEndian.PutUint32(b.data[8:], uint32(b.rLen)) 177 178 return b.data 179 } 180 181 func (b *Batch) decode(prevSeq uint64, data []byte) error { 182 if len(data) < batchHdrLen { 183 return newErrBatchCorrupted("too short") 184 } 185 186 b.seq = binary.LittleEndian.Uint64(data) 187 if b.seq < prevSeq { 188 return newErrBatchCorrupted("invalid sequence number") 189 } 190 b.rLen = int(binary.LittleEndian.Uint32(data[8:])) 191 if b.rLen < 0 { 192 return newErrBatchCorrupted("invalid records length") 193 } 194 // No need to be precise at this point, it won't be used anyway 195 b.bLen = len(data) - batchHdrLen 196 b.data = data 197 198 return nil 199 } 200 201 func (b *Batch) decodeRec(f func(i int, kt keyType, key, value []byte) error) error { 202 off := batchHdrLen 203 for i := 0; i < b.rLen; i++ { 204 if off >= len(b.data) { 205 return newErrBatchCorrupted("invalid records length") 206 } 207 208 kt := keyType(b.data[off]) 209 if kt > keyTypeVal { 210 panic(kt) 211 return newErrBatchCorrupted("bad record: invalid type") 212 } 213 off++ 214 215 x, n := binary.Uvarint(b.data[off:]) 216 off += n 217 if n <= 0 || off+int(x) > len(b.data) { 218 return newErrBatchCorrupted("bad record: invalid key length") 219 } 220 key := b.data[off : off+int(x)] 221 off += int(x) 222 var value []byte 223 if kt == keyTypeVal { 224 x, n := binary.Uvarint(b.data[off:]) 225 off += n 226 if n <= 0 || off+int(x) > len(b.data) { 227 return newErrBatchCorrupted("bad record: invalid value length") 228 } 229 value = b.data[off : off+int(x)] 230 off += int(x) 231 } 232 233 if err := f(i, kt, key, value); err != nil { 234 return err 235 } 236 } 237 238 return nil 239 } 240 241 func (b *Batch) memReplay(to *memdb.DB) error { 242 var ikScratch []byte 243 return b.decodeRec(func(i int, kt keyType, key, value []byte) error { 244 ikScratch = makeInternalKey(ikScratch, key, b.seq+uint64(i), kt) 245 return to.Put(ikScratch, value) 246 }) 247 } 248 249 func (b *Batch) memDecodeAndReplay(prevSeq uint64, data []byte, to *memdb.DB) error { 250 if err := b.decode(prevSeq, data); err != nil { 251 return err 252 } 253 return b.memReplay(to) 254 } 255 256 func (b *Batch) revertMemReplay(to *memdb.DB) error { 257 var ikScratch []byte 258 return b.decodeRec(func(i int, kt keyType, key, value []byte) error { 259 ikScratch := makeInternalKey(ikScratch, key, b.seq+uint64(i), kt) 260 return to.Delete(ikScratch) 261 }) 262 }