blob: b6c4979d9167e5cc00188f1499061518aadb32b4 [file] [log] [blame]
jorlow@chromium.orgf67e15e2011-03-18 22:37:00 +00001// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file. See the AUTHORS file for names of contributors.
4//
5// WriteBatch::rep_ :=
6// sequence: fixed64
7// count: fixed32
8// data: record[count]
9// record :=
10// kTypeValue varstring varstring |
11// kTypeLargeValueRef varstring varstring |
12// kTypeDeletion varstring
13// varstring :=
14// len: varint32
15// data: uint8[len]
16
17#include "include/write_batch.h"
18
19#include "include/db.h"
20#include "db/dbformat.h"
21#include "db/memtable.h"
22#include "db/write_batch_internal.h"
23#include "util/coding.h"
24
25namespace leveldb {
26
27WriteBatch::WriteBatch() {
28 Clear();
29}
30
31WriteBatch::~WriteBatch() { }
32
33void WriteBatch::Clear() {
34 rep_.clear();
35 rep_.resize(12);
36}
37
38int WriteBatchInternal::Count(const WriteBatch* b) {
39 return DecodeFixed32(b->rep_.data() + 8);
40}
41
42void WriteBatchInternal::SetCount(WriteBatch* b, int n) {
43 EncodeFixed32(&b->rep_[8], n);
44}
45
46SequenceNumber WriteBatchInternal::Sequence(const WriteBatch* b) {
47 return SequenceNumber(DecodeFixed64(b->rep_.data()));
48}
49
50void WriteBatchInternal::SetSequence(WriteBatch* b, SequenceNumber seq) {
51 EncodeFixed64(&b->rep_[0], seq);
52}
53
54void WriteBatch::Put(const Slice& key, const Slice& value) {
55 WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1);
56 rep_.push_back(static_cast<char>(kTypeValue));
57 PutLengthPrefixedSlice(&rep_, key);
58 PutLengthPrefixedSlice(&rep_, value);
59}
60
61void WriteBatchInternal::PutLargeValueRef(WriteBatch* b,
62 const Slice& key,
63 const LargeValueRef& large_ref) {
64 WriteBatchInternal::SetCount(b, WriteBatchInternal::Count(b) + 1);
65 b->rep_.push_back(static_cast<char>(kTypeLargeValueRef));
66 PutLengthPrefixedSlice(&b->rep_, key);
67 PutLengthPrefixedSlice(&b->rep_,
68 Slice(large_ref.data, sizeof(large_ref.data)));
69}
70
71void WriteBatch::Delete(const Slice& key) {
72 WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1);
73 rep_.push_back(static_cast<char>(kTypeDeletion));
74 PutLengthPrefixedSlice(&rep_, key);
75}
76
77Status WriteBatchInternal::InsertInto(const WriteBatch* b,
78 MemTable* memtable) {
79 const int count = WriteBatchInternal::Count(b);
80 int found = 0;
81 Iterator it(*b);
82 for (; !it.Done(); it.Next()) {
83 switch (it.op()) {
84 case kTypeDeletion:
85 memtable->Add(it.sequence_number(), kTypeDeletion, it.key(), Slice());
86 break;
87 case kTypeValue:
88 memtable->Add(it.sequence_number(), kTypeValue, it.key(), it.value());
89 break;
90 case kTypeLargeValueRef:
91 memtable->Add(it.sequence_number(), kTypeLargeValueRef,
92 it.key(), it.value());
93 break;
94 }
95 found++;
96 }
97 if (!it.status().ok()) {
98 return it.status();
99 } else if (found != count) {
100 return Status::Corruption("wrong count in WriteBatch");
101 }
102 return Status::OK();
103}
104
105void WriteBatchInternal::SetContents(WriteBatch* b, const Slice& contents) {
106 assert(contents.size() >= 12);
107 b->rep_.assign(contents.data(), contents.size());
108}
109
110WriteBatchInternal::Iterator::Iterator(const WriteBatch& batch)
111 : input_(WriteBatchInternal::Contents(&batch)),
112 done_(false) {
113 if (input_.size() < 12) {
114 done_ = true;
115 } else {
116 seq_ = WriteBatchInternal::Sequence(&batch),
117 input_.remove_prefix(12);
118 GetNextEntry();
119 }
120}
121
122void WriteBatchInternal::Iterator::Next() {
123 assert(!done_);
124 seq_++;
125 GetNextEntry();
126}
127
128void WriteBatchInternal::Iterator::GetNextEntry() {
129 if (input_.empty()) {
130 done_ = true;
131 return;
132 }
133 char tag = input_[0];
134 input_.remove_prefix(1);
135 switch (tag) {
136 case kTypeValue:
137 case kTypeLargeValueRef:
138 if (GetLengthPrefixedSlice(&input_, &key_) &&
139 GetLengthPrefixedSlice(&input_, &value_)) {
140 op_ = static_cast<ValueType>(tag);
141 } else {
142 status_ = Status::Corruption("bad WriteBatch Put");
143 done_ = true;
144 input_.clear();
145 }
146 break;
147 case kTypeDeletion:
148 if (GetLengthPrefixedSlice(&input_, &key_)) {
149 op_ = kTypeDeletion;
150 } else {
151 status_ = Status::Corruption("bad WriteBatch Delete");
152 done_ = true;
153 input_.clear();
154 }
155 break;
156 default:
157 status_ = Status::Corruption("unknown WriteBatch tag");
158 done_ = true;
159 input_.clear();
160 break;
161 }
162}
163
164}