1 // Copyright (c) 2011 The LevelDB Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. See the AUTHORS file for names of contributors. 4 // 5 // WriteBatch::rep_ := 6 // sequence: fixed64 7 // count: fixed32 8 // data: record[count] 9 // record := 10 // kTypeValue varstring varstring | 11 // kTypeDeletion varstring 12 // varstring := 13 // len: varint32 14 // data: uint8[len] 15 16 #include "leveldb/write_batch.h" 17 18 #include "leveldb/db.h" 19 #include "db/dbformat.h" 20 #include "db/memtable.h" 21 #include "db/write_batch_internal.h" 22 #include "util/coding.h" 23 24 namespace leveldb { 25 26 WriteBatch::WriteBatch() { 27 Clear(); 28 } 29 30 WriteBatch::~WriteBatch() { } 31 32 WriteBatch::Handler::~Handler() { } 33 34 void WriteBatch::Clear() { 35 rep_.clear(); 36 rep_.resize(12); 37 } 38 39 Status WriteBatch::Iterate(Handler* handler) const { 40 Slice input(rep_); 41 if (input.size() < 12) { 42 return Status::Corruption("malformed WriteBatch (too small)"); 43 } 44 45 input.remove_prefix(12); 46 Slice key, value; 47 int found = 0; 48 while (!input.empty()) { 49 found++; 50 char tag = input[0]; 51 input.remove_prefix(1); 52 switch (tag) { 53 case kTypeValue: 54 if (GetLengthPrefixedSlice(&input, &key) && 55 GetLengthPrefixedSlice(&input, &value)) { 56 handler->Put(key, value); 57 } else { 58 return Status::Corruption("bad WriteBatch Put"); 59 } 60 break; 61 case kTypeDeletion: 62 if (GetLengthPrefixedSlice(&input, &key)) { 63 handler->Delete(key); 64 } else { 65 return Status::Corruption("bad WriteBatch Delete"); 66 } 67 break; 68 default: 69 return Status::Corruption("unknown WriteBatch tag"); 70 } 71 } 72 if (found != WriteBatchInternal::Count(this)) { 73 return Status::Corruption("WriteBatch has wrong count"); 74 } else { 75 return Status::OK(); 76 } 77 } 78 79 int WriteBatchInternal::Count(const WriteBatch* b) { 80 return DecodeFixed32(b->rep_.data() + 8); 81 } 82 83 void WriteBatchInternal::SetCount(WriteBatch* b, int n) { 84 EncodeFixed32(&b->rep_[8], n); 85 } 86 87 SequenceNumber WriteBatchInternal::Sequence(const WriteBatch* b) { 88 return SequenceNumber(DecodeFixed64(b->rep_.data())); 89 } 90 91 void WriteBatchInternal::SetSequence(WriteBatch* b, SequenceNumber seq) { 92 EncodeFixed64(&b->rep_[0], seq); 93 } 94 95 void WriteBatch::Put(const Slice& key, const Slice& value) { 96 WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1); 97 rep_.push_back(static_cast<char>(kTypeValue)); 98 PutLengthPrefixedSlice(&rep_, key); 99 PutLengthPrefixedSlice(&rep_, value); 100 } 101 102 void WriteBatch::Delete(const Slice& key) { 103 WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1); 104 rep_.push_back(static_cast<char>(kTypeDeletion)); 105 PutLengthPrefixedSlice(&rep_, key); 106 } 107 108 namespace { 109 class MemTableInserter : public WriteBatch::Handler { 110 public: 111 SequenceNumber sequence_; 112 MemTable* mem_; 113 114 virtual void Put(const Slice& key, const Slice& value) { 115 mem_->Add(sequence_, kTypeValue, key, value); 116 sequence_++; 117 } 118 virtual void Delete(const Slice& key) { 119 mem_->Add(sequence_, kTypeDeletion, key, Slice()); 120 sequence_++; 121 } 122 }; 123 } 124 125 Status WriteBatchInternal::InsertInto(const WriteBatch* b, 126 MemTable* memtable) { 127 MemTableInserter inserter; 128 inserter.sequence_ = WriteBatchInternal::Sequence(b); 129 inserter.mem_ = memtable; 130 return b->Iterate(&inserter); 131 } 132 133 void WriteBatchInternal::SetContents(WriteBatch* b, const Slice& contents) { 134 assert(contents.size() >= 12); 135 b->rep_.assign(contents.data(), contents.size()); 136 } 137 138 } 139