1179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
2179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// Use of this source code is governed by a BSD-style license that can be
3179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// found in the LICENSE file. See the AUTHORS file for names of contributors.
4179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org//
5179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// WriteBatch::rep_ :=
6179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org//    sequence: fixed64
7179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org//    count: fixed32
8179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org//    data: record[count]
9179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// record :=
10179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org//    kTypeValue varstring varstring         |
11179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org//    kTypeDeletion varstring
12179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// varstring :=
13179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org//    len: varint32
14179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org//    data: uint8[len]
15179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
16fbd97aa4c5325eace57d24b89845b9581bac9324jorlow@chromium.org#include "leveldb/write_batch.h"
17179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
18fbd97aa4c5325eace57d24b89845b9581bac9324jorlow@chromium.org#include "leveldb/db.h"
19179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "db/dbformat.h"
20179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "db/memtable.h"
21179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "db/write_batch_internal.h"
22179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "util/coding.h"
23179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
24179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgnamespace leveldb {
25179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
2613daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.com// WriteBatch header has an 8-byte sequence number followed by a 4-byte count.
2713daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.comstatic const size_t kHeader = 12;
2813daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.com
29179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgWriteBatch::WriteBatch() {
30179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  Clear();
31179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
32179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
33179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgWriteBatch::~WriteBatch() { }
34179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
35a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.orgWriteBatch::Handler::~Handler() { }
36a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org
37179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgvoid WriteBatch::Clear() {
38179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  rep_.clear();
3913daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.com  rep_.resize(kHeader);
40179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
41179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
42a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.orgStatus WriteBatch::Iterate(Handler* handler) const {
43a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org  Slice input(rep_);
4413daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.com  if (input.size() < kHeader) {
45a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org    return Status::Corruption("malformed WriteBatch (too small)");
46a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org  }
47a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org
4813daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.com  input.remove_prefix(kHeader);
49a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org  Slice key, value;
50a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org  int found = 0;
51a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org  while (!input.empty()) {
52a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org    found++;
53a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org    char tag = input[0];
54a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org    input.remove_prefix(1);
55a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org    switch (tag) {
56a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org      case kTypeValue:
57a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org        if (GetLengthPrefixedSlice(&input, &key) &&
58a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org            GetLengthPrefixedSlice(&input, &value)) {
59a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org          handler->Put(key, value);
60a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org        } else {
61a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org          return Status::Corruption("bad WriteBatch Put");
62a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org        }
63a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org        break;
64a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org      case kTypeDeletion:
65a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org        if (GetLengthPrefixedSlice(&input, &key)) {
66a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org          handler->Delete(key);
67a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org        } else {
68a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org          return Status::Corruption("bad WriteBatch Delete");
69a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org        }
70a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org        break;
71a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org      default:
72a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org        return Status::Corruption("unknown WriteBatch tag");
73a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org    }
74a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org  }
75a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org  if (found != WriteBatchInternal::Count(this)) {
76a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org    return Status::Corruption("WriteBatch has wrong count");
77a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org  } else {
78a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org    return Status::OK();
79a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org  }
80a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org}
81a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org
82179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgint WriteBatchInternal::Count(const WriteBatch* b) {
83179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  return DecodeFixed32(b->rep_.data() + 8);
84179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
85179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
86179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgvoid WriteBatchInternal::SetCount(WriteBatch* b, int n) {
87179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  EncodeFixed32(&b->rep_[8], n);
88179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
89179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
90179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgSequenceNumber WriteBatchInternal::Sequence(const WriteBatch* b) {
91179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  return SequenceNumber(DecodeFixed64(b->rep_.data()));
92179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
93179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
94179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgvoid WriteBatchInternal::SetSequence(WriteBatch* b, SequenceNumber seq) {
95179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  EncodeFixed64(&b->rep_[0], seq);
96179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
97179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
98179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgvoid WriteBatch::Put(const Slice& key, const Slice& value) {
99179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1);
100179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  rep_.push_back(static_cast<char>(kTypeValue));
101179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  PutLengthPrefixedSlice(&rep_, key);
102179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  PutLengthPrefixedSlice(&rep_, value);
103179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
104179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
105179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgvoid WriteBatch::Delete(const Slice& key) {
106179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1);
107179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  rep_.push_back(static_cast<char>(kTypeDeletion));
108179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  PutLengthPrefixedSlice(&rep_, key);
109179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
110179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
111a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.orgnamespace {
112a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.orgclass MemTableInserter : public WriteBatch::Handler {
113a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org public:
114a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org  SequenceNumber sequence_;
115a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org  MemTable* mem_;
116a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org
117a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org  virtual void Put(const Slice& key, const Slice& value) {
118a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org    mem_->Add(sequence_, kTypeValue, key, value);
119a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org    sequence_++;
120179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
121a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org  virtual void Delete(const Slice& key) {
122a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org    mem_->Add(sequence_, kTypeDeletion, key, Slice());
123a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org    sequence_++;
124179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
125a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org};
12645b9940be332834440bd5299419f396e38085ebehans@chromium.org}  // namespace
127a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org
128a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.orgStatus WriteBatchInternal::InsertInto(const WriteBatch* b,
129a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org                                      MemTable* memtable) {
130a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org  MemTableInserter inserter;
131a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org  inserter.sequence_ = WriteBatchInternal::Sequence(b);
132a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org  inserter.mem_ = memtable;
133a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org  return b->Iterate(&inserter);
134179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
135179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
136179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgvoid WriteBatchInternal::SetContents(WriteBatch* b, const Slice& contents) {
13713daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.com  assert(contents.size() >= kHeader);
138179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  b->rep_.assign(contents.data(), contents.size());
139179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
140179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
14113daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.comvoid WriteBatchInternal::Append(WriteBatch* dst, const WriteBatch* src) {
14213daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.com  SetCount(dst, Count(dst) + Count(src));
14313daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.com  assert(src->rep_.size() >= kHeader);
14413daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.com  dst->rep_.append(src->rep_.data() + kHeader, src->rep_.size() - kHeader);
14513daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.com}
14613daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.com
14745b9940be332834440bd5299419f396e38085ebehans@chromium.org}  // namespace leveldb
148