You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
3.9 KiB
147 lines
3.9 KiB
// 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. |
|
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++; |
|
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
|
|
|