1*9507f98cSAndroid Build Coastguard Worker // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
2*9507f98cSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*9507f98cSAndroid Build Coastguard Worker // found in the LICENSE file. See the AUTHORS file for names of contributors.
4*9507f98cSAndroid Build Coastguard Worker
5*9507f98cSAndroid Build Coastguard Worker #include "leveldb/table_builder.h"
6*9507f98cSAndroid Build Coastguard Worker
7*9507f98cSAndroid Build Coastguard Worker #include <cassert>
8*9507f98cSAndroid Build Coastguard Worker
9*9507f98cSAndroid Build Coastguard Worker #include "leveldb/comparator.h"
10*9507f98cSAndroid Build Coastguard Worker #include "leveldb/env.h"
11*9507f98cSAndroid Build Coastguard Worker #include "leveldb/filter_policy.h"
12*9507f98cSAndroid Build Coastguard Worker #include "leveldb/options.h"
13*9507f98cSAndroid Build Coastguard Worker #include "table/block_builder.h"
14*9507f98cSAndroid Build Coastguard Worker #include "table/filter_block.h"
15*9507f98cSAndroid Build Coastguard Worker #include "table/format.h"
16*9507f98cSAndroid Build Coastguard Worker #include "util/coding.h"
17*9507f98cSAndroid Build Coastguard Worker #include "util/crc32c.h"
18*9507f98cSAndroid Build Coastguard Worker
19*9507f98cSAndroid Build Coastguard Worker namespace leveldb {
20*9507f98cSAndroid Build Coastguard Worker
21*9507f98cSAndroid Build Coastguard Worker struct TableBuilder::Rep {
Repleveldb::TableBuilder::Rep22*9507f98cSAndroid Build Coastguard Worker Rep(const Options& opt, WritableFile* f)
23*9507f98cSAndroid Build Coastguard Worker : options(opt),
24*9507f98cSAndroid Build Coastguard Worker index_block_options(opt),
25*9507f98cSAndroid Build Coastguard Worker file(f),
26*9507f98cSAndroid Build Coastguard Worker offset(0),
27*9507f98cSAndroid Build Coastguard Worker data_block(&options),
28*9507f98cSAndroid Build Coastguard Worker index_block(&index_block_options),
29*9507f98cSAndroid Build Coastguard Worker num_entries(0),
30*9507f98cSAndroid Build Coastguard Worker closed(false),
31*9507f98cSAndroid Build Coastguard Worker filter_block(opt.filter_policy == nullptr
32*9507f98cSAndroid Build Coastguard Worker ? nullptr
33*9507f98cSAndroid Build Coastguard Worker : new FilterBlockBuilder(opt.filter_policy)),
34*9507f98cSAndroid Build Coastguard Worker pending_index_entry(false) {
35*9507f98cSAndroid Build Coastguard Worker index_block_options.block_restart_interval = 1;
36*9507f98cSAndroid Build Coastguard Worker }
37*9507f98cSAndroid Build Coastguard Worker
38*9507f98cSAndroid Build Coastguard Worker Options options;
39*9507f98cSAndroid Build Coastguard Worker Options index_block_options;
40*9507f98cSAndroid Build Coastguard Worker WritableFile* file;
41*9507f98cSAndroid Build Coastguard Worker uint64_t offset;
42*9507f98cSAndroid Build Coastguard Worker Status status;
43*9507f98cSAndroid Build Coastguard Worker BlockBuilder data_block;
44*9507f98cSAndroid Build Coastguard Worker BlockBuilder index_block;
45*9507f98cSAndroid Build Coastguard Worker std::string last_key;
46*9507f98cSAndroid Build Coastguard Worker int64_t num_entries;
47*9507f98cSAndroid Build Coastguard Worker bool closed; // Either Finish() or Abandon() has been called.
48*9507f98cSAndroid Build Coastguard Worker FilterBlockBuilder* filter_block;
49*9507f98cSAndroid Build Coastguard Worker
50*9507f98cSAndroid Build Coastguard Worker // We do not emit the index entry for a block until we have seen the
51*9507f98cSAndroid Build Coastguard Worker // first key for the next data block. This allows us to use shorter
52*9507f98cSAndroid Build Coastguard Worker // keys in the index block. For example, consider a block boundary
53*9507f98cSAndroid Build Coastguard Worker // between the keys "the quick brown fox" and "the who". We can use
54*9507f98cSAndroid Build Coastguard Worker // "the r" as the key for the index block entry since it is >= all
55*9507f98cSAndroid Build Coastguard Worker // entries in the first block and < all entries in subsequent
56*9507f98cSAndroid Build Coastguard Worker // blocks.
57*9507f98cSAndroid Build Coastguard Worker //
58*9507f98cSAndroid Build Coastguard Worker // Invariant: r->pending_index_entry is true only if data_block is empty.
59*9507f98cSAndroid Build Coastguard Worker bool pending_index_entry;
60*9507f98cSAndroid Build Coastguard Worker BlockHandle pending_handle; // Handle to add to index block
61*9507f98cSAndroid Build Coastguard Worker
62*9507f98cSAndroid Build Coastguard Worker std::string compressed_output;
63*9507f98cSAndroid Build Coastguard Worker };
64*9507f98cSAndroid Build Coastguard Worker
TableBuilder(const Options & options,WritableFile * file)65*9507f98cSAndroid Build Coastguard Worker TableBuilder::TableBuilder(const Options& options, WritableFile* file)
66*9507f98cSAndroid Build Coastguard Worker : rep_(new Rep(options, file)) {
67*9507f98cSAndroid Build Coastguard Worker if (rep_->filter_block != nullptr) {
68*9507f98cSAndroid Build Coastguard Worker rep_->filter_block->StartBlock(0);
69*9507f98cSAndroid Build Coastguard Worker }
70*9507f98cSAndroid Build Coastguard Worker }
71*9507f98cSAndroid Build Coastguard Worker
~TableBuilder()72*9507f98cSAndroid Build Coastguard Worker TableBuilder::~TableBuilder() {
73*9507f98cSAndroid Build Coastguard Worker assert(rep_->closed); // Catch errors where caller forgot to call Finish()
74*9507f98cSAndroid Build Coastguard Worker delete rep_->filter_block;
75*9507f98cSAndroid Build Coastguard Worker delete rep_;
76*9507f98cSAndroid Build Coastguard Worker }
77*9507f98cSAndroid Build Coastguard Worker
ChangeOptions(const Options & options)78*9507f98cSAndroid Build Coastguard Worker Status TableBuilder::ChangeOptions(const Options& options) {
79*9507f98cSAndroid Build Coastguard Worker // Note: if more fields are added to Options, update
80*9507f98cSAndroid Build Coastguard Worker // this function to catch changes that should not be allowed to
81*9507f98cSAndroid Build Coastguard Worker // change in the middle of building a Table.
82*9507f98cSAndroid Build Coastguard Worker if (options.comparator != rep_->options.comparator) {
83*9507f98cSAndroid Build Coastguard Worker return Status::InvalidArgument("changing comparator while building table");
84*9507f98cSAndroid Build Coastguard Worker }
85*9507f98cSAndroid Build Coastguard Worker
86*9507f98cSAndroid Build Coastguard Worker // Note that any live BlockBuilders point to rep_->options and therefore
87*9507f98cSAndroid Build Coastguard Worker // will automatically pick up the updated options.
88*9507f98cSAndroid Build Coastguard Worker rep_->options = options;
89*9507f98cSAndroid Build Coastguard Worker rep_->index_block_options = options;
90*9507f98cSAndroid Build Coastguard Worker rep_->index_block_options.block_restart_interval = 1;
91*9507f98cSAndroid Build Coastguard Worker return Status::OK();
92*9507f98cSAndroid Build Coastguard Worker }
93*9507f98cSAndroid Build Coastguard Worker
Add(const Slice & key,const Slice & value)94*9507f98cSAndroid Build Coastguard Worker void TableBuilder::Add(const Slice& key, const Slice& value) {
95*9507f98cSAndroid Build Coastguard Worker Rep* r = rep_;
96*9507f98cSAndroid Build Coastguard Worker assert(!r->closed);
97*9507f98cSAndroid Build Coastguard Worker if (!ok()) return;
98*9507f98cSAndroid Build Coastguard Worker if (r->num_entries > 0) {
99*9507f98cSAndroid Build Coastguard Worker assert(r->options.comparator->Compare(key, Slice(r->last_key)) > 0);
100*9507f98cSAndroid Build Coastguard Worker }
101*9507f98cSAndroid Build Coastguard Worker
102*9507f98cSAndroid Build Coastguard Worker if (r->pending_index_entry) {
103*9507f98cSAndroid Build Coastguard Worker assert(r->data_block.empty());
104*9507f98cSAndroid Build Coastguard Worker r->options.comparator->FindShortestSeparator(&r->last_key, key);
105*9507f98cSAndroid Build Coastguard Worker std::string handle_encoding;
106*9507f98cSAndroid Build Coastguard Worker r->pending_handle.EncodeTo(&handle_encoding);
107*9507f98cSAndroid Build Coastguard Worker r->index_block.Add(r->last_key, Slice(handle_encoding));
108*9507f98cSAndroid Build Coastguard Worker r->pending_index_entry = false;
109*9507f98cSAndroid Build Coastguard Worker }
110*9507f98cSAndroid Build Coastguard Worker
111*9507f98cSAndroid Build Coastguard Worker if (r->filter_block != nullptr) {
112*9507f98cSAndroid Build Coastguard Worker r->filter_block->AddKey(key);
113*9507f98cSAndroid Build Coastguard Worker }
114*9507f98cSAndroid Build Coastguard Worker
115*9507f98cSAndroid Build Coastguard Worker r->last_key.assign(key.data(), key.size());
116*9507f98cSAndroid Build Coastguard Worker r->num_entries++;
117*9507f98cSAndroid Build Coastguard Worker r->data_block.Add(key, value);
118*9507f98cSAndroid Build Coastguard Worker
119*9507f98cSAndroid Build Coastguard Worker const size_t estimated_block_size = r->data_block.CurrentSizeEstimate();
120*9507f98cSAndroid Build Coastguard Worker if (estimated_block_size >= r->options.block_size) {
121*9507f98cSAndroid Build Coastguard Worker Flush();
122*9507f98cSAndroid Build Coastguard Worker }
123*9507f98cSAndroid Build Coastguard Worker }
124*9507f98cSAndroid Build Coastguard Worker
Flush()125*9507f98cSAndroid Build Coastguard Worker void TableBuilder::Flush() {
126*9507f98cSAndroid Build Coastguard Worker Rep* r = rep_;
127*9507f98cSAndroid Build Coastguard Worker assert(!r->closed);
128*9507f98cSAndroid Build Coastguard Worker if (!ok()) return;
129*9507f98cSAndroid Build Coastguard Worker if (r->data_block.empty()) return;
130*9507f98cSAndroid Build Coastguard Worker assert(!r->pending_index_entry);
131*9507f98cSAndroid Build Coastguard Worker WriteBlock(&r->data_block, &r->pending_handle);
132*9507f98cSAndroid Build Coastguard Worker if (ok()) {
133*9507f98cSAndroid Build Coastguard Worker r->pending_index_entry = true;
134*9507f98cSAndroid Build Coastguard Worker r->status = r->file->Flush();
135*9507f98cSAndroid Build Coastguard Worker }
136*9507f98cSAndroid Build Coastguard Worker if (r->filter_block != nullptr) {
137*9507f98cSAndroid Build Coastguard Worker r->filter_block->StartBlock(r->offset);
138*9507f98cSAndroid Build Coastguard Worker }
139*9507f98cSAndroid Build Coastguard Worker }
140*9507f98cSAndroid Build Coastguard Worker
WriteBlock(BlockBuilder * block,BlockHandle * handle)141*9507f98cSAndroid Build Coastguard Worker void TableBuilder::WriteBlock(BlockBuilder* block, BlockHandle* handle) {
142*9507f98cSAndroid Build Coastguard Worker // File format contains a sequence of blocks where each block has:
143*9507f98cSAndroid Build Coastguard Worker // block_data: uint8[n]
144*9507f98cSAndroid Build Coastguard Worker // type: uint8
145*9507f98cSAndroid Build Coastguard Worker // crc: uint32
146*9507f98cSAndroid Build Coastguard Worker assert(ok());
147*9507f98cSAndroid Build Coastguard Worker Rep* r = rep_;
148*9507f98cSAndroid Build Coastguard Worker Slice raw = block->Finish();
149*9507f98cSAndroid Build Coastguard Worker
150*9507f98cSAndroid Build Coastguard Worker Slice block_contents;
151*9507f98cSAndroid Build Coastguard Worker CompressionType type = r->options.compression;
152*9507f98cSAndroid Build Coastguard Worker // TODO(postrelease): Support more compression options: zlib?
153*9507f98cSAndroid Build Coastguard Worker switch (type) {
154*9507f98cSAndroid Build Coastguard Worker case kNoCompression:
155*9507f98cSAndroid Build Coastguard Worker block_contents = raw;
156*9507f98cSAndroid Build Coastguard Worker break;
157*9507f98cSAndroid Build Coastguard Worker
158*9507f98cSAndroid Build Coastguard Worker case kSnappyCompression: {
159*9507f98cSAndroid Build Coastguard Worker std::string* compressed = &r->compressed_output;
160*9507f98cSAndroid Build Coastguard Worker if (port::Snappy_Compress(raw.data(), raw.size(), compressed) &&
161*9507f98cSAndroid Build Coastguard Worker compressed->size() < raw.size() - (raw.size() / 8u)) {
162*9507f98cSAndroid Build Coastguard Worker block_contents = *compressed;
163*9507f98cSAndroid Build Coastguard Worker } else {
164*9507f98cSAndroid Build Coastguard Worker // Snappy not supported, or compressed less than 12.5%, so just
165*9507f98cSAndroid Build Coastguard Worker // store uncompressed form
166*9507f98cSAndroid Build Coastguard Worker block_contents = raw;
167*9507f98cSAndroid Build Coastguard Worker type = kNoCompression;
168*9507f98cSAndroid Build Coastguard Worker }
169*9507f98cSAndroid Build Coastguard Worker break;
170*9507f98cSAndroid Build Coastguard Worker }
171*9507f98cSAndroid Build Coastguard Worker }
172*9507f98cSAndroid Build Coastguard Worker WriteRawBlock(block_contents, type, handle);
173*9507f98cSAndroid Build Coastguard Worker r->compressed_output.clear();
174*9507f98cSAndroid Build Coastguard Worker block->Reset();
175*9507f98cSAndroid Build Coastguard Worker }
176*9507f98cSAndroid Build Coastguard Worker
WriteRawBlock(const Slice & block_contents,CompressionType type,BlockHandle * handle)177*9507f98cSAndroid Build Coastguard Worker void TableBuilder::WriteRawBlock(const Slice& block_contents,
178*9507f98cSAndroid Build Coastguard Worker CompressionType type, BlockHandle* handle) {
179*9507f98cSAndroid Build Coastguard Worker Rep* r = rep_;
180*9507f98cSAndroid Build Coastguard Worker handle->set_offset(r->offset);
181*9507f98cSAndroid Build Coastguard Worker handle->set_size(block_contents.size());
182*9507f98cSAndroid Build Coastguard Worker r->status = r->file->Append(block_contents);
183*9507f98cSAndroid Build Coastguard Worker if (r->status.ok()) {
184*9507f98cSAndroid Build Coastguard Worker char trailer[kBlockTrailerSize];
185*9507f98cSAndroid Build Coastguard Worker trailer[0] = type;
186*9507f98cSAndroid Build Coastguard Worker uint32_t crc = crc32c::Value(block_contents.data(), block_contents.size());
187*9507f98cSAndroid Build Coastguard Worker crc = crc32c::Extend(crc, trailer, 1); // Extend crc to cover block type
188*9507f98cSAndroid Build Coastguard Worker EncodeFixed32(trailer + 1, crc32c::Mask(crc));
189*9507f98cSAndroid Build Coastguard Worker r->status = r->file->Append(Slice(trailer, kBlockTrailerSize));
190*9507f98cSAndroid Build Coastguard Worker if (r->status.ok()) {
191*9507f98cSAndroid Build Coastguard Worker r->offset += block_contents.size() + kBlockTrailerSize;
192*9507f98cSAndroid Build Coastguard Worker }
193*9507f98cSAndroid Build Coastguard Worker }
194*9507f98cSAndroid Build Coastguard Worker }
195*9507f98cSAndroid Build Coastguard Worker
status() const196*9507f98cSAndroid Build Coastguard Worker Status TableBuilder::status() const { return rep_->status; }
197*9507f98cSAndroid Build Coastguard Worker
Finish()198*9507f98cSAndroid Build Coastguard Worker Status TableBuilder::Finish() {
199*9507f98cSAndroid Build Coastguard Worker Rep* r = rep_;
200*9507f98cSAndroid Build Coastguard Worker Flush();
201*9507f98cSAndroid Build Coastguard Worker assert(!r->closed);
202*9507f98cSAndroid Build Coastguard Worker r->closed = true;
203*9507f98cSAndroid Build Coastguard Worker
204*9507f98cSAndroid Build Coastguard Worker BlockHandle filter_block_handle, metaindex_block_handle, index_block_handle;
205*9507f98cSAndroid Build Coastguard Worker
206*9507f98cSAndroid Build Coastguard Worker // Write filter block
207*9507f98cSAndroid Build Coastguard Worker if (ok() && r->filter_block != nullptr) {
208*9507f98cSAndroid Build Coastguard Worker WriteRawBlock(r->filter_block->Finish(), kNoCompression,
209*9507f98cSAndroid Build Coastguard Worker &filter_block_handle);
210*9507f98cSAndroid Build Coastguard Worker }
211*9507f98cSAndroid Build Coastguard Worker
212*9507f98cSAndroid Build Coastguard Worker // Write metaindex block
213*9507f98cSAndroid Build Coastguard Worker if (ok()) {
214*9507f98cSAndroid Build Coastguard Worker BlockBuilder meta_index_block(&r->options);
215*9507f98cSAndroid Build Coastguard Worker if (r->filter_block != nullptr) {
216*9507f98cSAndroid Build Coastguard Worker // Add mapping from "filter.Name" to location of filter data
217*9507f98cSAndroid Build Coastguard Worker std::string key = "filter.";
218*9507f98cSAndroid Build Coastguard Worker key.append(r->options.filter_policy->Name());
219*9507f98cSAndroid Build Coastguard Worker std::string handle_encoding;
220*9507f98cSAndroid Build Coastguard Worker filter_block_handle.EncodeTo(&handle_encoding);
221*9507f98cSAndroid Build Coastguard Worker meta_index_block.Add(key, handle_encoding);
222*9507f98cSAndroid Build Coastguard Worker }
223*9507f98cSAndroid Build Coastguard Worker
224*9507f98cSAndroid Build Coastguard Worker // TODO(postrelease): Add stats and other meta blocks
225*9507f98cSAndroid Build Coastguard Worker WriteBlock(&meta_index_block, &metaindex_block_handle);
226*9507f98cSAndroid Build Coastguard Worker }
227*9507f98cSAndroid Build Coastguard Worker
228*9507f98cSAndroid Build Coastguard Worker // Write index block
229*9507f98cSAndroid Build Coastguard Worker if (ok()) {
230*9507f98cSAndroid Build Coastguard Worker if (r->pending_index_entry) {
231*9507f98cSAndroid Build Coastguard Worker r->options.comparator->FindShortSuccessor(&r->last_key);
232*9507f98cSAndroid Build Coastguard Worker std::string handle_encoding;
233*9507f98cSAndroid Build Coastguard Worker r->pending_handle.EncodeTo(&handle_encoding);
234*9507f98cSAndroid Build Coastguard Worker r->index_block.Add(r->last_key, Slice(handle_encoding));
235*9507f98cSAndroid Build Coastguard Worker r->pending_index_entry = false;
236*9507f98cSAndroid Build Coastguard Worker }
237*9507f98cSAndroid Build Coastguard Worker WriteBlock(&r->index_block, &index_block_handle);
238*9507f98cSAndroid Build Coastguard Worker }
239*9507f98cSAndroid Build Coastguard Worker
240*9507f98cSAndroid Build Coastguard Worker // Write footer
241*9507f98cSAndroid Build Coastguard Worker if (ok()) {
242*9507f98cSAndroid Build Coastguard Worker Footer footer;
243*9507f98cSAndroid Build Coastguard Worker footer.set_metaindex_handle(metaindex_block_handle);
244*9507f98cSAndroid Build Coastguard Worker footer.set_index_handle(index_block_handle);
245*9507f98cSAndroid Build Coastguard Worker std::string footer_encoding;
246*9507f98cSAndroid Build Coastguard Worker footer.EncodeTo(&footer_encoding);
247*9507f98cSAndroid Build Coastguard Worker r->status = r->file->Append(footer_encoding);
248*9507f98cSAndroid Build Coastguard Worker if (r->status.ok()) {
249*9507f98cSAndroid Build Coastguard Worker r->offset += footer_encoding.size();
250*9507f98cSAndroid Build Coastguard Worker }
251*9507f98cSAndroid Build Coastguard Worker }
252*9507f98cSAndroid Build Coastguard Worker return r->status;
253*9507f98cSAndroid Build Coastguard Worker }
254*9507f98cSAndroid Build Coastguard Worker
Abandon()255*9507f98cSAndroid Build Coastguard Worker void TableBuilder::Abandon() {
256*9507f98cSAndroid Build Coastguard Worker Rep* r = rep_;
257*9507f98cSAndroid Build Coastguard Worker assert(!r->closed);
258*9507f98cSAndroid Build Coastguard Worker r->closed = true;
259*9507f98cSAndroid Build Coastguard Worker }
260*9507f98cSAndroid Build Coastguard Worker
NumEntries() const261*9507f98cSAndroid Build Coastguard Worker uint64_t TableBuilder::NumEntries() const { return rep_->num_entries; }
262*9507f98cSAndroid Build Coastguard Worker
FileSize() const263*9507f98cSAndroid Build Coastguard Worker uint64_t TableBuilder::FileSize() const { return rep_->offset; }
264*9507f98cSAndroid Build Coastguard Worker
265*9507f98cSAndroid Build Coastguard Worker } // namespace leveldb
266