github.com/df-mc/goleveldb@v1.1.9/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 "io" 13 14 "github.com/df-mc/goleveldb/leveldb/errors" 15 "github.com/df-mc/goleveldb/leveldb/memdb" 16 "github.com/df-mc/goleveldb/leveldb/storage" 17 ) 18 19 // ErrBatchCorrupted records reason of batch corruption. This error will be 20 // wrapped with errors.ErrCorrupted. 21 type ErrBatchCorrupted struct { 22 Reason string 23 } 24 25 func (e *ErrBatchCorrupted) Error() string { 26 return fmt.Sprintf("leveldb: batch corrupted: %s", e.Reason) 27 } 28 29 func newErrBatchCorrupted(reason string) error { 30 return errors.NewErrCorrupted(storage.FileDesc{}, &ErrBatchCorrupted{reason}) 31 } 32 33 const ( 34 batchHeaderLen = 8 + 4 35 batchGrowRec = 3000 36 batchBufioSize = 16 37 ) 38 39 // BatchReplay wraps basic batch operations. 40 type BatchReplay interface { 41 Put(key, value []byte) 42 Delete(key []byte) 43 } 44 45 type batchIndex struct { 46 keyType keyType 47 keyPos, keyLen int 48 valuePos, valueLen int 49 } 50 51 func (index batchIndex) k(data []byte) []byte { 52 return data[index.keyPos : index.keyPos+index.keyLen] 53 } 54 55 func (index batchIndex) v(data []byte) []byte { 56 if index.valueLen != 0 { 57 return data[index.valuePos : index.valuePos+index.valueLen] 58 } 59 return nil 60 } 61 62 func (index batchIndex) kv(data []byte) (key, value []byte) { 63 return index.k(data), index.v(data) 64 } 65 66 // Batch is a write batch. 67 type Batch struct { 68 data []byte 69 index []batchIndex 70 71 // internalLen is sums of key/value pair length plus 8-bytes internal key. 72 internalLen int 73 } 74 75 func (b *Batch) grow(n int) { 76 o := len(b.data) 77 if cap(b.data)-o < n { 78 div := 1 79 if len(b.index) > batchGrowRec { 80 div = len(b.index) / batchGrowRec 81 } 82 ndata := make([]byte, o, o+n+o/div) 83 copy(ndata, b.data) 84 b.data = ndata 85 } 86 } 87 88 func (b *Batch) appendRec(kt keyType, key, value []byte) { 89 n := 1 + binary.MaxVarintLen32 + len(key) 90 if kt == keyTypeVal { 91 n += binary.MaxVarintLen32 + len(value) 92 } 93 b.grow(n) 94 index := batchIndex{keyType: kt} 95 o := len(b.data) 96 data := b.data[:o+n] 97 data[o] = byte(kt) 98 o++ 99 o += binary.PutUvarint(data[o:], uint64(len(key))) 100 index.keyPos = o 101 index.keyLen = len(key) 102 o += copy(data[o:], key) 103 if kt == keyTypeVal { 104 o += binary.PutUvarint(data[o:], uint64(len(value))) 105 index.valuePos = o 106 index.valueLen = len(value) 107 o += copy(data[o:], value) 108 } 109 b.data = data[:o] 110 b.index = append(b.index, index) 111 b.internalLen += index.keyLen + index.valueLen + 8 112 } 113 114 // Put appends 'put operation' of the given key/value pair to the batch. 115 // It is safe to modify the contents of the argument after Put returns but not 116 // before. 117 func (b *Batch) Put(key, value []byte) { 118 b.appendRec(keyTypeVal, key, value) 119 } 120 121 // Delete appends 'delete operation' of the given key to the batch. 122 // It is safe to modify the contents of the argument after Delete returns but 123 // not before. 124 func (b *Batch) Delete(key []byte) { 125 b.appendRec(keyTypeDel, key, nil) 126 } 127 128 // Dump dumps batch contents. The returned slice can be loaded into the 129 // batch using Load method. 130 // The returned slice is not its own copy, so the contents should not be 131 // modified. 132 func (b *Batch) Dump() []byte { 133 return b.data 134 } 135 136 // Load loads given slice into the batch. Previous contents of the batch 137 // will be discarded. 138 // The given slice will not be copied and will be used as batch buffer, so 139 // it is not safe to modify the contents of the slice. 140 func (b *Batch) Load(data []byte) error { 141 return b.decode(data, -1) 142 } 143 144 // Replay replays batch contents. 145 func (b *Batch) Replay(r BatchReplay) error { 146 for _, index := range b.index { 147 switch index.keyType { 148 case keyTypeVal: 149 r.Put(index.k(b.data), index.v(b.data)) 150 case keyTypeDel: 151 r.Delete(index.k(b.data)) 152 } 153 } 154 return nil 155 } 156 157 // Len returns number of records in the batch. 158 func (b *Batch) Len() int { 159 return len(b.index) 160 } 161 162 // Reset resets the batch. 163 func (b *Batch) Reset() { 164 b.data = b.data[:0] 165 b.index = b.index[:0] 166 b.internalLen = 0 167 } 168 169 func (b *Batch) replayInternal(fn func(i int, kt keyType, k, v []byte) error) error { 170 for i, index := range b.index { 171 if err := fn(i, index.keyType, index.k(b.data), index.v(b.data)); err != nil { 172 return err 173 } 174 } 175 return nil 176 } 177 178 func (b *Batch) append(p *Batch) { 179 ob := len(b.data) 180 oi := len(b.index) 181 b.data = append(b.data, p.data...) 182 b.index = append(b.index, p.index...) 183 b.internalLen += p.internalLen 184 185 // Updating index offset. 186 if ob != 0 { 187 for ; oi < len(b.index); oi++ { 188 index := &b.index[oi] 189 index.keyPos += ob 190 if index.valueLen != 0 { 191 index.valuePos += ob 192 } 193 } 194 } 195 } 196 197 func (b *Batch) decode(data []byte, expectedLen int) error { 198 b.data = data 199 b.index = b.index[:0] 200 b.internalLen = 0 201 err := decodeBatch(data, func(i int, index batchIndex) error { 202 b.index = append(b.index, index) 203 b.internalLen += index.keyLen + index.valueLen + 8 204 return nil 205 }) 206 if err != nil { 207 return err 208 } 209 if expectedLen >= 0 && len(b.index) != expectedLen { 210 return newErrBatchCorrupted(fmt.Sprintf("invalid records length: %d vs %d", expectedLen, len(b.index))) 211 } 212 return nil 213 } 214 215 func (b *Batch) putMem(seq uint64, mdb *memdb.DB) error { 216 var ik []byte 217 for i, index := range b.index { 218 ik = makeInternalKey(ik, index.k(b.data), seq+uint64(i), index.keyType) 219 if err := mdb.Put(ik, index.v(b.data)); err != nil { 220 return err 221 } 222 } 223 return nil 224 } 225 226 func (b *Batch) revertMem(seq uint64, mdb *memdb.DB) error { 227 var ik []byte 228 for i, index := range b.index { 229 ik = makeInternalKey(ik, index.k(b.data), seq+uint64(i), index.keyType) 230 if err := mdb.Delete(ik); err != nil { 231 return err 232 } 233 } 234 return nil 235 } 236 237 func newBatch() interface{} { 238 return &Batch{} 239 } 240 241 // MakeBatch returns empty batch with preallocated buffer. 242 func MakeBatch(n int) *Batch { 243 return &Batch{data: make([]byte, 0, n)} 244 } 245 246 func decodeBatch(data []byte, fn func(i int, index batchIndex) error) error { 247 var index batchIndex 248 for i, o := 0, 0; o < len(data); i++ { 249 // Key type. 250 index.keyType = keyType(data[o]) 251 if index.keyType > keyTypeVal { 252 return newErrBatchCorrupted(fmt.Sprintf("bad record: invalid type %#x", uint(index.keyType))) 253 } 254 o++ 255 256 // Key. 257 x, n := binary.Uvarint(data[o:]) 258 o += n 259 if n <= 0 || o+int(x) > len(data) { 260 return newErrBatchCorrupted("bad record: invalid key length") 261 } 262 index.keyPos = o 263 index.keyLen = int(x) 264 o += index.keyLen 265 266 // Value. 267 if index.keyType == keyTypeVal { 268 x, n = binary.Uvarint(data[o:]) 269 o += n 270 if n <= 0 || o+int(x) > len(data) { 271 return newErrBatchCorrupted("bad record: invalid value length") 272 } 273 index.valuePos = o 274 index.valueLen = int(x) 275 o += index.valueLen 276 } else { 277 index.valuePos = 0 278 index.valueLen = 0 279 } 280 281 if err := fn(i, index); err != nil { 282 return err 283 } 284 } 285 return nil 286 } 287 288 func decodeBatchToMem(data []byte, expectSeq uint64, mdb *memdb.DB) (seq uint64, batchLen int, err error) { 289 seq, batchLen, err = decodeBatchHeader(data) 290 if err != nil { 291 return 0, 0, err 292 } 293 if seq < expectSeq { 294 return 0, 0, newErrBatchCorrupted("invalid sequence number") 295 } 296 data = data[batchHeaderLen:] 297 var ik []byte 298 var decodedLen int 299 err = decodeBatch(data, func(i int, index batchIndex) error { 300 if i >= batchLen { 301 return newErrBatchCorrupted("invalid records length") 302 } 303 ik = makeInternalKey(ik, index.k(data), seq+uint64(i), index.keyType) 304 if err := mdb.Put(ik, index.v(data)); err != nil { 305 return err 306 } 307 decodedLen++ 308 return nil 309 }) 310 if err == nil && decodedLen != batchLen { 311 err = newErrBatchCorrupted(fmt.Sprintf("invalid records length: %d vs %d", batchLen, decodedLen)) 312 } 313 return 314 } 315 316 func encodeBatchHeader(dst []byte, seq uint64, batchLen int) []byte { 317 dst = ensureBuffer(dst, batchHeaderLen) 318 binary.LittleEndian.PutUint64(dst, seq) 319 binary.LittleEndian.PutUint32(dst[8:], uint32(batchLen)) 320 return dst 321 } 322 323 func decodeBatchHeader(data []byte) (seq uint64, batchLen int, err error) { 324 if len(data) < batchHeaderLen { 325 return 0, 0, newErrBatchCorrupted("too short") 326 } 327 328 seq = binary.LittleEndian.Uint64(data) 329 batchLen = int(binary.LittleEndian.Uint32(data[8:])) 330 if batchLen < 0 { 331 return 0, 0, newErrBatchCorrupted("invalid records length") 332 } 333 return 334 } 335 336 func batchesLen(batches []*Batch) int { 337 batchLen := 0 338 for _, batch := range batches { 339 batchLen += batch.Len() 340 } 341 return batchLen 342 } 343 344 func writeBatchesWithHeader(wr io.Writer, batches []*Batch, seq uint64) error { 345 if _, err := wr.Write(encodeBatchHeader(nil, seq, batchesLen(batches))); err != nil { 346 return err 347 } 348 for _, batch := range batches { 349 if _, err := wr.Write(batch.data); err != nil { 350 return err 351 } 352 } 353 return nil 354 }