// 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个字节的数量字段 count
static 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格式,第一个字节为tag
char 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_++;
}
};
} // namespace
Status 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