// 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 holds a collection of updates to apply atomically to a DB.//// The updates are applied in the order in which they are added// to the WriteBatch. For example, the value of "key" will be "v3"// after the following batch is written://// batch.Put("key", "v1");// batch.Delete("key");// batch.Put("key", "v2");// batch.Put("key", "v3");//// Multiple threads can invoke const methods on a WriteBatch without// external synchronization, but if any of the threads may call a// non-const method, all threads accessing the same WriteBatch must use// external synchronization.#ifndef STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_#define STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_#include <string>#include "leveldb/status.h"namespace leveldb {class Slice;class WriteBatch{public:WriteBatch();~WriteBatch();// Store the mapping "key->value" in the database.void Put(const Slice& key, const Slice& value);// If the database contains a mapping for "key", erase it. Else do nothing.void Delete(const Slice& key);// Clear all updates buffered in this batch.void Clear();// Support for iterating over the contents of a batch.class Handler {public:virtual ~Handler();virtual void Put(const Slice& key, const Slice& value) = 0;virtual void Delete(const Slice& key) = 0;};Status Iterate(Handler* handler) const;private:friend class WriteBatchInternal;std::string rep_; // See comment in write_batch.cc for the format of rep_// Intentionally copyable};} // namespace leveldb#endif // STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_// 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 |// 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 header has an 8-byte sequence number followed by a 4-byte count.// 头8个字节为uint 64 位的sequence序列号,后面是4个字节的数量字段 countstatic const size_t kHeader = 12;WriteBatch::WriteBatch() {Clear();}WriteBatch::~WriteBatch() {}WriteBatch::Handler::~Handler(){ }void WriteBatch::Clear() {rep_.clear();rep_.resize( kHeader );}Status WriteBatch::Iterate( Handler* handler ) const {Slice input( rep_ );if ( input.size() < kHeader ) {return Status::Corruption("malformed WriteBatch (too small)");}input.remove_prefix( kHeader );Slice key, value;int found = 0;while ( !input.empty() ) {found++;// record格式,第一个字节为tagchar tag = input[0];input.remove_prefix(1);switch ( tag ){case kTypeValue:if ( GetLengthPrefixedSlice(&input, &key) &&GetLengthPrefixedSlice(&input, &value) ){handler->Put( key, value );}else{return Status::Corruption("bad WriteBatch Put");}break;case kTypeDeletion:if ( GetLengthPrefixedSlice( &input, &key ) ){handler->Delete( key );} else {return Status::Corruption("bad WriteBatch Delete");}break;default:return Status::Corruption("unknown WriteBatch tag");}}if ( found != WriteBatchInternal::Count( this ) ){return Status::Corruption("WriteBatch has wrong count");} else {return Status::OK();}}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<char>(kTypeValue) );PutLengthPrefixedSlice( &rep_, key );PutLengthPrefixedSlice( &rep_, value );}void WriteBatch::Delete( const Slice& key ) {WriteBatchInternal::SetCount( this, WriteBatchInternal::Count(this) + 1 );rep_.push_back( static_cast<char>(kTypeDeletion) );PutLengthPrefixedSlice( &rep_, key );}namespace{class MemTableInserter : public WriteBatch::Handler{public:SequenceNumber sequence_;MemTable* mem_;virtual void Put( const Slice& key, const Slice& value ) {mem_->Add( sequence_, kTypeValue, key, value );sequence_++;}virtual void Delete(const Slice& key) {mem_->Add( sequence_, kTypeDeletion, key, Slice() );sequence_++;}};} // namespaceStatus WriteBatchInternal::InsertInto( const WriteBatch* b,MemTable* memtable ){MemTableInserter inserter;inserter.sequence_ = WriteBatchInternal::Sequence(b);inserter.mem_ = memtable;return b->Iterate( &inserter );}void WriteBatchInternal::SetContents( WriteBatch* b, const Slice& contents ){assert( contents.size() >= kHeader );b->rep_.assign( contents.data(), contents.size() );}void WriteBatchInternal::Append( WriteBatch* dst, const WriteBatch* src ){SetCount( dst, Count(dst) + Count(src) );assert( src->rep_.size() >= kHeader );dst->rep_.append( src->rep_.data() + kHeader, src->rep_.size() - kHeader );}} // namespace leveldb