// Copyright (c) 2011 The LevelDB Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. See the AUTHORS file for names of contributors. // // WriteBatch::rep_ := // sequence: fixed64 // count: fixed32 // data: record[count] // record := // kTypeValue varstring varstring | // kTypeLargeValueRef varstring varstring | // kTypeDeletion varstring // varstring := // len: varint32 // data: uint8[len] #include "leveldb/write_batch.h" #include "leveldb/db.h" #include "db/dbformat.h" #include "db/memtable.h" #include "db/write_batch_internal.h" #include "util/coding.h" namespace leveldb { WriteBatch::WriteBatch() { Clear(); } WriteBatch::~WriteBatch() { } void WriteBatch::Clear() { rep_.clear(); rep_.resize(12); } int WriteBatchInternal::Count(const WriteBatch* b) { return DecodeFixed32(b->rep_.data() + 8); } void WriteBatchInternal::SetCount(WriteBatch* b, int n) { EncodeFixed32(&b->rep_[8], n); } SequenceNumber WriteBatchInternal::Sequence(const WriteBatch* b) { return SequenceNumber(DecodeFixed64(b->rep_.data())); } void WriteBatchInternal::SetSequence(WriteBatch* b, SequenceNumber seq) { EncodeFixed64(&b->rep_[0], seq); } void WriteBatch::Put(const Slice& key, const Slice& value) { WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1); rep_.push_back(static_cast(kTypeValue)); PutLengthPrefixedSlice(&rep_, key); PutLengthPrefixedSlice(&rep_, value); } void WriteBatchInternal::PutLargeValueRef(WriteBatch* b, const Slice& key, const LargeValueRef& large_ref) { WriteBatchInternal::SetCount(b, WriteBatchInternal::Count(b) + 1); b->rep_.push_back(static_cast(kTypeLargeValueRef)); PutLengthPrefixedSlice(&b->rep_, key); PutLengthPrefixedSlice(&b->rep_, Slice(large_ref.data, sizeof(large_ref.data))); } void WriteBatch::Delete(const Slice& key) { WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1); rep_.push_back(static_cast(kTypeDeletion)); PutLengthPrefixedSlice(&rep_, key); } Status WriteBatchInternal::InsertInto(const WriteBatch* b, MemTable* memtable) { const int count = WriteBatchInternal::Count(b); int found = 0; Iterator it(*b); for (; !it.Done(); it.Next()) { switch (it.op()) { case kTypeDeletion: memtable->Add(it.sequence_number(), kTypeDeletion, it.key(), Slice()); break; case kTypeValue: memtable->Add(it.sequence_number(), kTypeValue, it.key(), it.value()); break; case kTypeLargeValueRef: memtable->Add(it.sequence_number(), kTypeLargeValueRef, it.key(), it.value()); break; } found++; } if (!it.status().ok()) { return it.status(); } else if (found != count) { return Status::Corruption("wrong count in WriteBatch"); } return Status::OK(); } void WriteBatchInternal::SetContents(WriteBatch* b, const Slice& contents) { assert(contents.size() >= 12); b->rep_.assign(contents.data(), contents.size()); } WriteBatchInternal::Iterator::Iterator(const WriteBatch& batch) : input_(WriteBatchInternal::Contents(&batch)), done_(false) { if (input_.size() < 12) { done_ = true; } else { seq_ = WriteBatchInternal::Sequence(&batch), input_.remove_prefix(12); GetNextEntry(); } } void WriteBatchInternal::Iterator::Next() { assert(!done_); seq_++; GetNextEntry(); } void WriteBatchInternal::Iterator::GetNextEntry() { if (input_.empty()) { done_ = true; return; } char tag = input_[0]; input_.remove_prefix(1); switch (tag) { case kTypeValue: case kTypeLargeValueRef: if (GetLengthPrefixedSlice(&input_, &key_) && GetLengthPrefixedSlice(&input_, &value_)) { op_ = static_cast(tag); } else { status_ = Status::Corruption("bad WriteBatch Put"); done_ = true; input_.clear(); } break; case kTypeDeletion: if (GetLengthPrefixedSlice(&input_, &key_)) { op_ = kTypeDeletion; } else { status_ = Status::Corruption("bad WriteBatch Delete"); done_ = true; input_.clear(); } break; default: status_ = Status::Corruption("unknown WriteBatch tag"); done_ = true; input_.clear(); break; } } }