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  }