blob: b8eee3df2eb20e483a47aef03007609fb81db5bf [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// The representation of a DBImpl consists of a set of Versions. The
6// newest version is called "current". Older versions may be kept
7// around to provide a consistent view to live iterators.
8//
9// Each Version keeps track of a set of Table files per level. The
10// entire set of versions is maintained in a VersionSet.
11//
12// Version,VersionSet are thread-compatible, but require external
13// synchronization on all accesses.
14
15#ifndef STORAGE_LEVELDB_DB_VERSION_SET_H_
16#define STORAGE_LEVELDB_DB_VERSION_SET_H_
17
18#include <map>
19#include <set>
20#include <vector>
21#include "db/dbformat.h"
22#include "db/version_edit.h"
23#include "port/port.h"
24
25namespace leveldb {
26
27// Grouping of constants. We may want to make some of these
28// parameters set via options.
29namespace config {
30static const int kNumLevels = 7;
31}
32
33namespace log { class Writer; }
34
35class Compaction;
36class Iterator;
37class MemTable;
38class TableBuilder;
39class TableCache;
40class Version;
41class VersionSet;
42class WritableFile;
43
44class Version {
45 public:
46 // Append to *iters a sequence of iterators that will
47 // yield the contents of this Version when merged together.
48 // REQUIRES: This version has been saved (see VersionSet::SaveTo)
49 void AddIterators(const ReadOptions&, std::vector<Iterator*>* iters);
50
51 // Reference count management (so Versions do not disappear out from
52 // under live iterators)
53 void Ref();
54 void Unref();
55
56 // Return a human readable string that describes this version's contents.
57 std::string DebugString() const;
58
59 private:
60 friend class Compaction;
61 friend class VersionSet;
62
63 class LevelFileNumIterator;
64 Iterator* NewConcatenatingIterator(const ReadOptions&, int level) const;
65
66 VersionSet* vset_; // VersionSet to which this Version belongs
67 Version* next_; // Next version in linked list
68 int refs_; // Number of live refs to this version
69 MemTable* cleanup_mem_; // NULL, or table to delete when version dropped
70
71 // List of files per level
72 std::vector<FileMetaData*> files_[config::kNumLevels];
73
74 // Level that should be compacted next and its compaction score.
75 // Score < 1 means compaction is not strictly needed. These fields
76 // are initialized by Finalize().
77 double compaction_score_;
78 int compaction_level_;
79
80 explicit Version(VersionSet* vset)
81 : vset_(vset), next_(NULL), refs_(0),
82 cleanup_mem_(NULL),
83 compaction_score_(-1),
84 compaction_level_(-1) {
85 }
86
87 ~Version();
88
89 // No copying allowed
90 Version(const Version&);
91 void operator=(const Version&);
92};
93
94class VersionSet {
95 public:
96 VersionSet(const std::string& dbname,
97 const Options* options,
98 TableCache* table_cache,
99 const InternalKeyComparator*);
100 ~VersionSet();
101
102 // Apply *edit to the current version to form a new descriptor that
103 // is both saved to persistent state and installed as the new
104 // current version. Iff Apply() returns OK, arrange to delete
105 // cleanup_mem (if cleanup_mem != NULL) when it is no longer needed
106 // by older versions.
107 Status LogAndApply(VersionEdit* edit, MemTable* cleanup_mem);
108
109 // Recover the last saved descriptor from persistent storage.
110 Status Recover(uint64_t* log_number, SequenceNumber* last_sequence);
111
112 // Save current contents to *log
113 Status WriteSnapshot(log::Writer* log);
114
115 // Return the current version.
116 Version* current() const { return current_; }
117
118 // Return the current manifest file number
119 uint64_t ManifestFileNumber() const { return manifest_file_number_; }
120
121 // Allocate and return a new file number
122 uint64_t NewFileNumber() { return next_file_number_++; }
123
124 // Return the number of Table files at the specified level.
125 int NumLevelFiles(int level) const;
126
127 // Pick level and inputs for a new compaction.
128 // Returns NULL if there is no compaction to be done.
129 // Otherwise returns a pointer to a heap-allocated object that
130 // describes the compaction. Caller should delete the result.
131 Compaction* PickCompaction();
132
133 // Return a compaction object for compacting the range [begin,end] in
134 // the specified level. Returns NULL if there is nothing in that
135 // level that overlaps the specified range. Caller should delete
136 // the result.
137 Compaction* CompactRange(
138 int level,
139 const InternalKey& begin,
140 const InternalKey& end);
141
142 // Create an iterator that reads over the compaction inputs for "*c".
143 // The caller should delete the iterator when no longer needed.
144 Iterator* MakeInputIterator(Compaction* c);
145
146 // Returns true iff some level needs a compaction.
147 bool NeedsCompaction() const { return current_->compaction_score_ >= 1; }
148
149 // Add all files listed in any live version to *live.
150 // May also mutate some internal state.
151 void AddLiveFiles(std::set<uint64_t>* live);
152
153 // Return the approximate offset in the database of the data for
154 // "key" as of version "v".
155 uint64_t ApproximateOffsetOf(Version* v, const InternalKey& key);
156
157 // Register a reference to a large value with the specified
158 // large_ref from the specified file number. Returns "true" if this
159 // is the first recorded reference to the "large_ref" value in the
160 // database, and false otherwise.
161 bool RegisterLargeValueRef(const LargeValueRef& large_ref,
162 uint64_t filenum,
163 const InternalKey& internal_key);
164
165 // Cleanup the large value reference state by eliminating any
166 // references from files that are not includes in either "live_tables"
167 // or "log_file".
168 void CleanupLargeValueRefs(const std::set<uint64_t>& live_tables,
169 uint64_t log_file_num);
170
171 // Returns true if a large value with the given reference is live.
172 bool LargeValueIsLive(const LargeValueRef& large_ref);
173
174 private:
175 class Builder;
176
177 friend class Compaction;
178 friend class Version;
179
180 Status Finalize(Version* v);
181
182 // Delete any old versions that are no longer needed.
183 void MaybeDeleteOldVersions();
184
185 struct BySmallestKey;
186 Status SortLevel(Version* v, uint64_t level);
187
188 void GetOverlappingInputs(
189 int level,
190 const InternalKey& begin,
191 const InternalKey& end,
192 std::vector<FileMetaData*>* inputs);
193
194 void GetRange(const std::vector<FileMetaData*>& inputs,
195 InternalKey* smallest,
196 InternalKey* largest);
197
198 Env* const env_;
199 const std::string dbname_;
200 const Options* const options_;
201 TableCache* const table_cache_;
202 const InternalKeyComparator icmp_;
203 uint64_t next_file_number_;
204 uint64_t manifest_file_number_;
205
206 // Opened lazily
207 WritableFile* descriptor_file_;
208 log::Writer* descriptor_log_;
209
210 // Versions are kept in a singly linked list that is never empty
211 Version* current_; // Pointer to the last (newest) list entry
212 Version* oldest_; // Pointer to the first (oldest) list entry
213
214 // Map from large value reference to the set of <file numbers,internal_key>
215 // values containing references to the value. We keep the
216 // internal key as a std::string rather than as an InternalKey because
217 // we want to be able to easily use a set.
218 typedef std::set<std::pair<uint64_t, std::string> > LargeReferencesSet;
219 typedef std::map<LargeValueRef, LargeReferencesSet> LargeValueMap;
220 LargeValueMap large_value_refs_;
221
222 // Per-level key at which the next compaction at that level should start.
223 // Either an empty string, or a valid InternalKey.
224 std::string compact_pointer_[config::kNumLevels];
225
226 // No copying allowed
227 VersionSet(const VersionSet&);
228 void operator=(const VersionSet&);
229};
230
231// A Compaction encapsulates information about a compaction.
232class Compaction {
233 public:
234 ~Compaction();
235
236 // Return the level that is being compacted. Inputs from "level"
237 // and "level+1" will be merged to produce a set of "level+1" files.
238 int level() const { return level_; }
239
240 // Return the object that holds the edits to the descriptor done
241 // by this compaction.
242 VersionEdit* edit() { return &edit_; }
243
244 // "which" must be either 0 or 1
245 int num_input_files(int which) const { return inputs_[which].size(); }
246
247 // Return the ith input file at "level()+which" ("which" must be 0 or 1).
248 FileMetaData* input(int which, int i) const { return inputs_[which][i]; }
249
250 // Maximum size of files to build during this compaction.
251 uint64_t MaxOutputFileSize() const { return max_output_file_size_; }
252
253 // Add all inputs to this compaction as delete operations to *edit.
254 void AddInputDeletions(VersionEdit* edit);
255
256 // Returns true if the information we have available guarantees that
257 // the compaction is producing data in "level+1" for which no data exists
258 // in levels greater than "level+1".
259 bool IsBaseLevelForKey(const Slice& user_key);
260
261 // Release the input version for the compaction, once the compaction
262 // is successful.
263 void ReleaseInputs();
264
265 private:
266 friend class Version;
267 friend class VersionSet;
268
269 explicit Compaction(int level);
270
271 int level_;
272 uint64_t max_output_file_size_;
273 Version* input_version_;
274 VersionEdit edit_;
275
276 // Each compaction reads inputs from "level_" and "level_+1"
277 std::vector<FileMetaData*> inputs_[2]; // The two sets of inputs
278
279 // State for implementing IsBaseLevelForKey
280
281 // level_ptrs_ holds indices into input_version_->levels_: our state
282 // is that we are positioned at one of the file ranges for each
283 // higher level than the ones involved in this compaction (i.e. for
284 // all L >= level_ + 2).
285 int level_ptrs_[config::kNumLevels];
286};
287
288}
289
290#endif // STORAGE_LEVELDB_DB_VERSION_SET_H_