leveldb-ruby 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/README +17 -0
  2. data/ext/leveldb/extconf.rb +10 -0
  3. data/ext/leveldb/leveldb.cc +181 -0
  4. data/leveldb/Makefile +172 -0
  5. data/leveldb/db/builder.cc +90 -0
  6. data/leveldb/db/builder.h +36 -0
  7. data/leveldb/db/corruption_test.cc +354 -0
  8. data/leveldb/db/db_bench.cc +677 -0
  9. data/leveldb/db/db_impl.cc +1236 -0
  10. data/leveldb/db/db_impl.h +180 -0
  11. data/leveldb/db/db_iter.cc +298 -0
  12. data/leveldb/db/db_iter.h +26 -0
  13. data/leveldb/db/db_test.cc +1192 -0
  14. data/leveldb/db/dbformat.cc +87 -0
  15. data/leveldb/db/dbformat.h +165 -0
  16. data/leveldb/db/dbformat_test.cc +112 -0
  17. data/leveldb/db/filename.cc +135 -0
  18. data/leveldb/db/filename.h +80 -0
  19. data/leveldb/db/filename_test.cc +122 -0
  20. data/leveldb/db/log_format.h +35 -0
  21. data/leveldb/db/log_reader.cc +254 -0
  22. data/leveldb/db/log_reader.h +108 -0
  23. data/leveldb/db/log_test.cc +500 -0
  24. data/leveldb/db/log_writer.cc +103 -0
  25. data/leveldb/db/log_writer.h +48 -0
  26. data/leveldb/db/memtable.cc +108 -0
  27. data/leveldb/db/memtable.h +85 -0
  28. data/leveldb/db/repair.cc +384 -0
  29. data/leveldb/db/skiplist.h +378 -0
  30. data/leveldb/db/skiplist_test.cc +378 -0
  31. data/leveldb/db/snapshot.h +66 -0
  32. data/leveldb/db/table_cache.cc +95 -0
  33. data/leveldb/db/table_cache.h +50 -0
  34. data/leveldb/db/version_edit.cc +268 -0
  35. data/leveldb/db/version_edit.h +106 -0
  36. data/leveldb/db/version_edit_test.cc +46 -0
  37. data/leveldb/db/version_set.cc +1060 -0
  38. data/leveldb/db/version_set.h +306 -0
  39. data/leveldb/db/write_batch.cc +138 -0
  40. data/leveldb/db/write_batch_internal.h +45 -0
  41. data/leveldb/db/write_batch_test.cc +89 -0
  42. data/leveldb/include/leveldb/cache.h +99 -0
  43. data/leveldb/include/leveldb/comparator.h +63 -0
  44. data/leveldb/include/leveldb/db.h +148 -0
  45. data/leveldb/include/leveldb/env.h +302 -0
  46. data/leveldb/include/leveldb/iterator.h +100 -0
  47. data/leveldb/include/leveldb/options.h +198 -0
  48. data/leveldb/include/leveldb/slice.h +109 -0
  49. data/leveldb/include/leveldb/status.h +100 -0
  50. data/leveldb/include/leveldb/table.h +70 -0
  51. data/leveldb/include/leveldb/table_builder.h +91 -0
  52. data/leveldb/include/leveldb/write_batch.h +64 -0
  53. data/leveldb/port/port.h +23 -0
  54. data/leveldb/port/port_android.cc +64 -0
  55. data/leveldb/port/port_android.h +150 -0
  56. data/leveldb/port/port_chromium.cc +80 -0
  57. data/leveldb/port/port_chromium.h +97 -0
  58. data/leveldb/port/port_example.h +115 -0
  59. data/leveldb/port/port_osx.cc +50 -0
  60. data/leveldb/port/port_osx.h +125 -0
  61. data/leveldb/port/port_posix.cc +50 -0
  62. data/leveldb/port/port_posix.h +94 -0
  63. data/leveldb/port/sha1_portable.cc +298 -0
  64. data/leveldb/port/sha1_portable.h +25 -0
  65. data/leveldb/port/sha1_test.cc +39 -0
  66. data/leveldb/port/win/stdint.h +24 -0
  67. data/leveldb/table/block.cc +263 -0
  68. data/leveldb/table/block.h +43 -0
  69. data/leveldb/table/block_builder.cc +109 -0
  70. data/leveldb/table/block_builder.h +57 -0
  71. data/leveldb/table/format.cc +131 -0
  72. data/leveldb/table/format.h +103 -0
  73. data/leveldb/table/iterator.cc +67 -0
  74. data/leveldb/table/iterator_wrapper.h +63 -0
  75. data/leveldb/table/merger.cc +197 -0
  76. data/leveldb/table/merger.h +26 -0
  77. data/leveldb/table/table.cc +175 -0
  78. data/leveldb/table/table_builder.cc +227 -0
  79. data/leveldb/table/table_test.cc +845 -0
  80. data/leveldb/table/two_level_iterator.cc +182 -0
  81. data/leveldb/table/two_level_iterator.h +34 -0
  82. data/leveldb/util/arena.cc +68 -0
  83. data/leveldb/util/arena.h +68 -0
  84. data/leveldb/util/arena_test.cc +68 -0
  85. data/leveldb/util/cache.cc +255 -0
  86. data/leveldb/util/cache_test.cc +169 -0
  87. data/leveldb/util/coding.cc +194 -0
  88. data/leveldb/util/coding.h +104 -0
  89. data/leveldb/util/coding_test.cc +173 -0
  90. data/leveldb/util/comparator.cc +72 -0
  91. data/leveldb/util/crc32c.cc +332 -0
  92. data/leveldb/util/crc32c.h +45 -0
  93. data/leveldb/util/crc32c_test.cc +72 -0
  94. data/leveldb/util/env.cc +77 -0
  95. data/leveldb/util/env_chromium.cc +612 -0
  96. data/leveldb/util/env_posix.cc +606 -0
  97. data/leveldb/util/env_test.cc +102 -0
  98. data/leveldb/util/hash.cc +45 -0
  99. data/leveldb/util/hash.h +19 -0
  100. data/leveldb/util/histogram.cc +128 -0
  101. data/leveldb/util/histogram.h +41 -0
  102. data/leveldb/util/logging.cc +81 -0
  103. data/leveldb/util/logging.h +47 -0
  104. data/leveldb/util/mutexlock.h +39 -0
  105. data/leveldb/util/options.cc +28 -0
  106. data/leveldb/util/random.h +59 -0
  107. data/leveldb/util/status.cc +75 -0
  108. data/leveldb/util/testharness.cc +65 -0
  109. data/leveldb/util/testharness.h +129 -0
  110. data/leveldb/util/testutil.cc +51 -0
  111. data/leveldb/util/testutil.h +53 -0
  112. data/lib/leveldb.rb +36 -0
  113. metadata +183 -0
@@ -0,0 +1,103 @@
1
+ // 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
+ #include "db/log_writer.h"
6
+
7
+ #include <stdint.h>
8
+ #include "leveldb/env.h"
9
+ #include "util/coding.h"
10
+ #include "util/crc32c.h"
11
+
12
+ namespace leveldb {
13
+ namespace log {
14
+
15
+ Writer::Writer(WritableFile* dest)
16
+ : dest_(dest),
17
+ block_offset_(0) {
18
+ for (int i = 0; i <= kMaxRecordType; i++) {
19
+ char t = static_cast<char>(i);
20
+ type_crc_[i] = crc32c::Value(&t, 1);
21
+ }
22
+ }
23
+
24
+ Writer::~Writer() {
25
+ }
26
+
27
+ Status Writer::AddRecord(const Slice& slice) {
28
+ const char* ptr = slice.data();
29
+ size_t left = slice.size();
30
+
31
+ // Fragment the record if necessary and emit it. Note that if slice
32
+ // is empty, we still want to iterate once to emit a single
33
+ // zero-length record
34
+ Status s;
35
+ bool begin = true;
36
+ do {
37
+ const int leftover = kBlockSize - block_offset_;
38
+ assert(leftover >= 0);
39
+ if (leftover < kHeaderSize) {
40
+ // Switch to a new block
41
+ if (leftover > 0) {
42
+ // Fill the trailer (literal below relies on kHeaderSize being 7)
43
+ assert(kHeaderSize == 7);
44
+ dest_->Append(Slice("\x00\x00\x00\x00\x00\x00", leftover));
45
+ }
46
+ block_offset_ = 0;
47
+ }
48
+
49
+ // Invariant: we never leave < kHeaderSize bytes in a block.
50
+ assert(kBlockSize - block_offset_ - kHeaderSize >= 0);
51
+
52
+ const size_t avail = kBlockSize - block_offset_ - kHeaderSize;
53
+ const size_t fragment_length = (left < avail) ? left : avail;
54
+
55
+ RecordType type;
56
+ const bool end = (left == fragment_length);
57
+ if (begin && end) {
58
+ type = kFullType;
59
+ } else if (begin) {
60
+ type = kFirstType;
61
+ } else if (end) {
62
+ type = kLastType;
63
+ } else {
64
+ type = kMiddleType;
65
+ }
66
+
67
+ s = EmitPhysicalRecord(type, ptr, fragment_length);
68
+ ptr += fragment_length;
69
+ left -= fragment_length;
70
+ begin = false;
71
+ } while (s.ok() && left > 0);
72
+ return s;
73
+ }
74
+
75
+ Status Writer::EmitPhysicalRecord(RecordType t, const char* ptr, size_t n) {
76
+ assert(n <= 0xffff); // Must fit in two bytes
77
+ assert(block_offset_ + kHeaderSize + n <= kBlockSize);
78
+
79
+ // Format the header
80
+ char buf[kHeaderSize];
81
+ buf[4] = static_cast<char>(n & 0xff);
82
+ buf[5] = static_cast<char>(n >> 8);
83
+ buf[6] = static_cast<char>(t);
84
+
85
+ // Compute the crc of the record type and the payload.
86
+ uint32_t crc = crc32c::Extend(type_crc_[t], ptr, n);
87
+ crc = crc32c::Mask(crc); // Adjust for storage
88
+ EncodeFixed32(buf, crc);
89
+
90
+ // Write the header and the payload
91
+ Status s = dest_->Append(Slice(buf, kHeaderSize));
92
+ if (s.ok()) {
93
+ s = dest_->Append(Slice(ptr, n));
94
+ if (s.ok()) {
95
+ s = dest_->Flush();
96
+ }
97
+ }
98
+ block_offset_ += kHeaderSize + n;
99
+ return s;
100
+ }
101
+
102
+ }
103
+ }
@@ -0,0 +1,48 @@
1
+ // 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
+ #ifndef STORAGE_LEVELDB_DB_LOG_WRITER_H_
6
+ #define STORAGE_LEVELDB_DB_LOG_WRITER_H_
7
+
8
+ #include <stdint.h>
9
+ #include "db/log_format.h"
10
+ #include "leveldb/slice.h"
11
+ #include "leveldb/status.h"
12
+
13
+ namespace leveldb {
14
+
15
+ class WritableFile;
16
+
17
+ namespace log {
18
+
19
+ class Writer {
20
+ public:
21
+ // Create a writer that will append data to "*dest".
22
+ // "*dest" must be initially empty.
23
+ // "*dest" must remain live while this Writer is in use.
24
+ explicit Writer(WritableFile* dest);
25
+ ~Writer();
26
+
27
+ Status AddRecord(const Slice& slice);
28
+
29
+ private:
30
+ WritableFile* dest_;
31
+ int block_offset_; // Current offset in block
32
+
33
+ // crc32c values for all supported record types. These are
34
+ // pre-computed to reduce the overhead of computing the crc of the
35
+ // record type stored in the header.
36
+ uint32_t type_crc_[kMaxRecordType + 1];
37
+
38
+ Status EmitPhysicalRecord(RecordType type, const char* ptr, size_t length);
39
+
40
+ // No copying allowed
41
+ Writer(const Writer&);
42
+ void operator=(const Writer&);
43
+ };
44
+
45
+ }
46
+ }
47
+
48
+ #endif // STORAGE_LEVELDB_DB_LOG_WRITER_H_
@@ -0,0 +1,108 @@
1
+ // 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
+ #include "db/memtable.h"
6
+ #include "db/dbformat.h"
7
+ #include "leveldb/comparator.h"
8
+ #include "leveldb/env.h"
9
+ #include "leveldb/iterator.h"
10
+ #include "util/coding.h"
11
+
12
+ namespace leveldb {
13
+
14
+ static Slice GetLengthPrefixedSlice(const char* data) {
15
+ uint32_t len;
16
+ const char* p = data;
17
+ p = GetVarint32Ptr(p, p + 5, &len); // +5: we assume "p" is not corrupted
18
+ return Slice(p, len);
19
+ }
20
+
21
+ MemTable::MemTable(const InternalKeyComparator& cmp)
22
+ : comparator_(cmp),
23
+ refs_(0),
24
+ table_(comparator_, &arena_) {
25
+ }
26
+
27
+ MemTable::~MemTable() {
28
+ assert(refs_ == 0);
29
+ }
30
+
31
+ size_t MemTable::ApproximateMemoryUsage() { return arena_.MemoryUsage(); }
32
+
33
+ int MemTable::KeyComparator::operator()(const char* aptr, const char* bptr)
34
+ const {
35
+ // Internal keys are encoded as length-prefixed strings.
36
+ Slice a = GetLengthPrefixedSlice(aptr);
37
+ Slice b = GetLengthPrefixedSlice(bptr);
38
+ return comparator.Compare(a, b);
39
+ }
40
+
41
+ // Encode a suitable internal key target for "target" and return it.
42
+ // Uses *scratch as scratch space, and the returned pointer will point
43
+ // into this scratch space.
44
+ static const char* EncodeKey(std::string* scratch, const Slice& target) {
45
+ scratch->clear();
46
+ PutVarint32(scratch, target.size());
47
+ scratch->append(target.data(), target.size());
48
+ return scratch->data();
49
+ }
50
+
51
+ class MemTableIterator: public Iterator {
52
+ public:
53
+ explicit MemTableIterator(MemTable::Table* table) : iter_(table) { }
54
+
55
+ virtual bool Valid() const { return iter_.Valid(); }
56
+ virtual void Seek(const Slice& k) { iter_.Seek(EncodeKey(&tmp_, k)); }
57
+ virtual void SeekToFirst() { iter_.SeekToFirst(); }
58
+ virtual void SeekToLast() { iter_.SeekToLast(); }
59
+ virtual void Next() { iter_.Next(); }
60
+ virtual void Prev() { iter_.Prev(); }
61
+ virtual Slice key() const { return GetLengthPrefixedSlice(iter_.key()); }
62
+ virtual Slice value() const {
63
+ Slice key_slice = GetLengthPrefixedSlice(iter_.key());
64
+ return GetLengthPrefixedSlice(key_slice.data() + key_slice.size());
65
+ }
66
+
67
+ virtual Status status() const { return Status::OK(); }
68
+
69
+ private:
70
+ MemTable::Table::Iterator iter_;
71
+ std::string tmp_; // For passing to EncodeKey
72
+
73
+ // No copying allowed
74
+ MemTableIterator(const MemTableIterator&);
75
+ void operator=(const MemTableIterator&);
76
+ };
77
+
78
+ Iterator* MemTable::NewIterator() {
79
+ return new MemTableIterator(&table_);
80
+ }
81
+
82
+ void MemTable::Add(SequenceNumber s, ValueType type,
83
+ const Slice& key,
84
+ const Slice& value) {
85
+ // Format of an entry is concatenation of:
86
+ // key_size : varint32 of internal_key.size()
87
+ // key bytes : char[internal_key.size()]
88
+ // value_size : varint32 of value.size()
89
+ // value bytes : char[value.size()]
90
+ size_t key_size = key.size();
91
+ size_t val_size = value.size();
92
+ size_t internal_key_size = key_size + 8;
93
+ const size_t encoded_len =
94
+ VarintLength(internal_key_size) + internal_key_size +
95
+ VarintLength(val_size) + val_size;
96
+ char* buf = arena_.Allocate(encoded_len);
97
+ char* p = EncodeVarint32(buf, internal_key_size);
98
+ memcpy(p, key.data(), key_size);
99
+ p += key_size;
100
+ EncodeFixed64(p, (s << 8) | type);
101
+ p += 8;
102
+ p = EncodeVarint32(p, val_size);
103
+ memcpy(p, value.data(), val_size);
104
+ assert((p + val_size) - buf == encoded_len);
105
+ table_.Insert(buf);
106
+ }
107
+
108
+ }
@@ -0,0 +1,85 @@
1
+ // 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
+ #ifndef STORAGE_LEVELDB_DB_MEMTABLE_H_
6
+ #define STORAGE_LEVELDB_DB_MEMTABLE_H_
7
+
8
+ #include <string>
9
+ #include "leveldb/db.h"
10
+ #include "db/dbformat.h"
11
+ #include "db/skiplist.h"
12
+ #include "util/arena.h"
13
+
14
+ namespace leveldb {
15
+
16
+ class InternalKeyComparator;
17
+ class Mutex;
18
+ class MemTableIterator;
19
+
20
+ class MemTable {
21
+ public:
22
+ // MemTables are reference counted. The initial reference count
23
+ // is zero and the caller must call Ref() at least once.
24
+ explicit MemTable(const InternalKeyComparator& comparator);
25
+
26
+ // Increase reference count.
27
+ void Ref() { ++refs_; }
28
+
29
+ // Drop reference count. Delete if no more references exist.
30
+ void Unref() {
31
+ --refs_;
32
+ assert(refs_ >= 0);
33
+ if (refs_ <= 0) {
34
+ delete this;
35
+ }
36
+ }
37
+
38
+ // Returns an estimate of the number of bytes of data in use by this
39
+ // data structure.
40
+ //
41
+ // REQUIRES: external synchronization to prevent simultaneous
42
+ // operations on the same MemTable.
43
+ size_t ApproximateMemoryUsage();
44
+
45
+ // Return an iterator that yields the contents of the memtable.
46
+ //
47
+ // The caller must ensure that the underlying MemTable remains live
48
+ // while the returned iterator is live. The keys returned by this
49
+ // iterator are internal keys encoded by AppendInternalKey in the
50
+ // db/format.{h,cc} module.
51
+ Iterator* NewIterator();
52
+
53
+ // Add an entry into memtable that maps key to value at the
54
+ // specified sequence number and with the specified type.
55
+ // Typically value will be empty if type==kTypeDeletion.
56
+ void Add(SequenceNumber seq, ValueType type,
57
+ const Slice& key,
58
+ const Slice& value);
59
+
60
+ private:
61
+ ~MemTable(); // Private since only Unref() should be used to delete it
62
+
63
+ struct KeyComparator {
64
+ const InternalKeyComparator comparator;
65
+ explicit KeyComparator(const InternalKeyComparator& c) : comparator(c) { }
66
+ int operator()(const char* a, const char* b) const;
67
+ };
68
+ friend class MemTableIterator;
69
+ friend class MemTableBackwardIterator;
70
+
71
+ typedef SkipList<const char*, KeyComparator> Table;
72
+
73
+ KeyComparator comparator_;
74
+ int refs_;
75
+ Arena arena_;
76
+ Table table_;
77
+
78
+ // No copying allowed
79
+ MemTable(const MemTable&);
80
+ void operator=(const MemTable&);
81
+ };
82
+
83
+ }
84
+
85
+ #endif // STORAGE_LEVELDB_DB_MEMTABLE_H_
@@ -0,0 +1,384 @@
1
+ // 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
+ // We recover the contents of the descriptor from the other files we find.
6
+ // (1) Any log files are first converted to tables
7
+ // (2) We scan every table to compute
8
+ // (a) smallest/largest for the table
9
+ // (b) largest sequence number in the table
10
+ // (3) We generate descriptor contents:
11
+ // - log number is set to zero
12
+ // - next-file-number is set to 1 + largest file number we found
13
+ // - last-sequence-number is set to largest sequence# found across
14
+ // all tables (see 2c)
15
+ // - compaction pointers are cleared
16
+ // - every table file is added at level 0
17
+ //
18
+ // Possible optimization 1:
19
+ // (a) Compute total size and use to pick appropriate max-level M
20
+ // (b) Sort tables by largest sequence# in the table
21
+ // (c) For each table: if it overlaps earlier table, place in level-0,
22
+ // else place in level-M.
23
+ // Possible optimization 2:
24
+ // Store per-table metadata (smallest, largest, largest-seq#, ...)
25
+ // in the table's meta section to speed up ScanTable.
26
+
27
+ #include "db/builder.h"
28
+ #include "db/db_impl.h"
29
+ #include "db/dbformat.h"
30
+ #include "db/filename.h"
31
+ #include "db/log_reader.h"
32
+ #include "db/log_writer.h"
33
+ #include "db/memtable.h"
34
+ #include "db/table_cache.h"
35
+ #include "db/version_edit.h"
36
+ #include "db/write_batch_internal.h"
37
+ #include "leveldb/comparator.h"
38
+ #include "leveldb/db.h"
39
+ #include "leveldb/env.h"
40
+
41
+ namespace leveldb {
42
+
43
+ namespace {
44
+
45
+ class Repairer {
46
+ public:
47
+ Repairer(const std::string& dbname, const Options& options)
48
+ : dbname_(dbname),
49
+ env_(options.env),
50
+ icmp_(options.comparator),
51
+ options_(SanitizeOptions(dbname, &icmp_, options)),
52
+ owns_info_log_(options_.info_log != options.info_log),
53
+ next_file_number_(1) {
54
+ // TableCache can be small since we expect each table to be opened once.
55
+ table_cache_ = new TableCache(dbname_, &options_, 10);
56
+ }
57
+
58
+ ~Repairer() {
59
+ delete table_cache_;
60
+ if (owns_info_log_) {
61
+ delete options_.info_log;
62
+ }
63
+ }
64
+
65
+ Status Run() {
66
+ Status status = FindFiles();
67
+ if (status.ok()) {
68
+ ConvertLogFilesToTables();
69
+ ExtractMetaData();
70
+ status = WriteDescriptor();
71
+ }
72
+ if (status.ok()) {
73
+ unsigned long long bytes = 0;
74
+ for (size_t i = 0; i < tables_.size(); i++) {
75
+ bytes += tables_[i].meta.file_size;
76
+ }
77
+ Log(env_, options_.info_log,
78
+ "**** Repaired leveldb %s; "
79
+ "recovered %d files; %llu bytes. "
80
+ "Some data may have been lost. "
81
+ "****",
82
+ dbname_.c_str(),
83
+ static_cast<int>(tables_.size()),
84
+ bytes);
85
+ }
86
+ return status;
87
+ }
88
+
89
+ private:
90
+ struct TableInfo {
91
+ FileMetaData meta;
92
+ SequenceNumber max_sequence;
93
+ };
94
+
95
+ std::string const dbname_;
96
+ Env* const env_;
97
+ InternalKeyComparator const icmp_;
98
+ Options const options_;
99
+ bool owns_info_log_;
100
+ TableCache* table_cache_;
101
+ VersionEdit edit_;
102
+
103
+ std::vector<std::string> manifests_;
104
+ std::vector<uint64_t> table_numbers_;
105
+ std::vector<uint64_t> logs_;
106
+ std::vector<TableInfo> tables_;
107
+ uint64_t next_file_number_;
108
+
109
+ Status FindFiles() {
110
+ std::vector<std::string> filenames;
111
+ Status status = env_->GetChildren(dbname_, &filenames);
112
+ if (!status.ok()) {
113
+ return status;
114
+ }
115
+ if (filenames.empty()) {
116
+ return Status::IOError(dbname_, "repair found no files");
117
+ }
118
+
119
+ uint64_t number;
120
+ FileType type;
121
+ for (size_t i = 0; i < filenames.size(); i++) {
122
+ if (ParseFileName(filenames[i], &number, &type)) {
123
+ if (type == kDescriptorFile) {
124
+ manifests_.push_back(filenames[i]);
125
+ } else {
126
+ if (number + 1 > next_file_number_) {
127
+ next_file_number_ = number + 1;
128
+ }
129
+ if (type == kLogFile) {
130
+ logs_.push_back(number);
131
+ } else if (type == kTableFile) {
132
+ table_numbers_.push_back(number);
133
+ } else {
134
+ // Ignore other files
135
+ }
136
+ }
137
+ }
138
+ }
139
+ return status;
140
+ }
141
+
142
+ void ConvertLogFilesToTables() {
143
+ for (size_t i = 0; i < logs_.size(); i++) {
144
+ std::string logname = LogFileName(dbname_, logs_[i]);
145
+ Status status = ConvertLogToTable(logs_[i]);
146
+ if (!status.ok()) {
147
+ Log(env_, options_.info_log, "Log #%llu: ignoring conversion error: %s",
148
+ (unsigned long long) logs_[i],
149
+ status.ToString().c_str());
150
+ }
151
+ ArchiveFile(logname);
152
+ }
153
+ }
154
+
155
+ Status ConvertLogToTable(uint64_t log) {
156
+ struct LogReporter : public log::Reader::Reporter {
157
+ Env* env;
158
+ WritableFile* info_log;
159
+ uint64_t lognum;
160
+ virtual void Corruption(size_t bytes, const Status& s) {
161
+ // We print error messages for corruption, but continue repairing.
162
+ Log(env, info_log, "Log #%llu: dropping %d bytes; %s",
163
+ (unsigned long long) lognum,
164
+ static_cast<int>(bytes),
165
+ s.ToString().c_str());
166
+ }
167
+ };
168
+
169
+ // Open the log file
170
+ std::string logname = LogFileName(dbname_, log);
171
+ SequentialFile* lfile;
172
+ Status status = env_->NewSequentialFile(logname, &lfile);
173
+ if (!status.ok()) {
174
+ return status;
175
+ }
176
+
177
+ // Create the log reader.
178
+ LogReporter reporter;
179
+ reporter.env = env_;
180
+ reporter.info_log = options_.info_log;
181
+ reporter.lognum = log;
182
+ // We intentially make log::Reader do checksumming so that
183
+ // corruptions cause entire commits to be skipped instead of
184
+ // propagating bad information (like overly large sequence
185
+ // numbers).
186
+ log::Reader reader(lfile, &reporter, false/*do not checksum*/,
187
+ 0/*initial_offset*/);
188
+
189
+ // Read all the records and add to a memtable
190
+ std::string scratch;
191
+ Slice record;
192
+ WriteBatch batch;
193
+ MemTable* mem = new MemTable(icmp_);
194
+ mem->Ref();
195
+ int counter = 0;
196
+ while (reader.ReadRecord(&record, &scratch)) {
197
+ if (record.size() < 12) {
198
+ reporter.Corruption(
199
+ record.size(), Status::Corruption("log record too small"));
200
+ continue;
201
+ }
202
+ WriteBatchInternal::SetContents(&batch, record);
203
+ status = WriteBatchInternal::InsertInto(&batch, mem);
204
+ if (status.ok()) {
205
+ counter += WriteBatchInternal::Count(&batch);
206
+ } else {
207
+ Log(env_, options_.info_log, "Log #%llu: ignoring %s",
208
+ (unsigned long long) log,
209
+ status.ToString().c_str());
210
+ status = Status::OK(); // Keep going with rest of file
211
+ }
212
+ }
213
+ delete lfile;
214
+
215
+ // We ignore any version edits generated by the conversion to a Table
216
+ // since ExtractMetaData() will also generate edits.
217
+ VersionEdit skipped;
218
+ FileMetaData meta;
219
+ meta.number = next_file_number_++;
220
+ Iterator* iter = mem->NewIterator();
221
+ status = BuildTable(dbname_, env_, options_, table_cache_, iter,
222
+ &meta, &skipped);
223
+ delete iter;
224
+ mem->Unref();
225
+ mem = NULL;
226
+ if (status.ok()) {
227
+ if (meta.file_size > 0) {
228
+ table_numbers_.push_back(meta.number);
229
+ }
230
+ }
231
+ Log(env_, options_.info_log, "Log #%llu: %d ops saved to Table #%llu %s",
232
+ (unsigned long long) log,
233
+ counter,
234
+ (unsigned long long) meta.number,
235
+ status.ToString().c_str());
236
+ return status;
237
+ }
238
+
239
+ void ExtractMetaData() {
240
+ std::vector<TableInfo> kept;
241
+ for (size_t i = 0; i < table_numbers_.size(); i++) {
242
+ TableInfo t;
243
+ t.meta.number = table_numbers_[i];
244
+ Status status = ScanTable(&t);
245
+ if (!status.ok()) {
246
+ std::string fname = TableFileName(dbname_, table_numbers_[i]);
247
+ Log(env_, options_.info_log, "Table #%llu: ignoring %s",
248
+ (unsigned long long) table_numbers_[i],
249
+ status.ToString().c_str());
250
+ ArchiveFile(fname);
251
+ } else {
252
+ tables_.push_back(t);
253
+ }
254
+ }
255
+ }
256
+
257
+ Status ScanTable(TableInfo* t) {
258
+ std::string fname = TableFileName(dbname_, t->meta.number);
259
+ int counter = 0;
260
+ Status status = env_->GetFileSize(fname, &t->meta.file_size);
261
+ if (status.ok()) {
262
+ Iterator* iter = table_cache_->NewIterator(
263
+ ReadOptions(), t->meta.number, t->meta.file_size);
264
+ bool empty = true;
265
+ ParsedInternalKey parsed;
266
+ t->max_sequence = 0;
267
+ for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
268
+ Slice key = iter->key();
269
+ if (!ParseInternalKey(key, &parsed)) {
270
+ Log(env_, options_.info_log, "Table #%llu: unparsable key %s",
271
+ (unsigned long long) t->meta.number,
272
+ EscapeString(key).c_str());
273
+ continue;
274
+ }
275
+
276
+ counter++;
277
+ if (empty) {
278
+ empty = false;
279
+ t->meta.smallest.DecodeFrom(key);
280
+ }
281
+ t->meta.largest.DecodeFrom(key);
282
+ if (parsed.sequence > t->max_sequence) {
283
+ t->max_sequence = parsed.sequence;
284
+ }
285
+ }
286
+ if (!iter->status().ok()) {
287
+ status = iter->status();
288
+ }
289
+ delete iter;
290
+ }
291
+ Log(env_, options_.info_log, "Table #%llu: %d entries %s",
292
+ (unsigned long long) t->meta.number,
293
+ counter,
294
+ status.ToString().c_str());
295
+ return status;
296
+ }
297
+
298
+ Status WriteDescriptor() {
299
+ std::string tmp = TempFileName(dbname_, 1);
300
+ WritableFile* file;
301
+ Status status = env_->NewWritableFile(tmp, &file);
302
+ if (!status.ok()) {
303
+ return status;
304
+ }
305
+
306
+ SequenceNumber max_sequence = 0;
307
+ for (size_t i = 0; i < tables_.size(); i++) {
308
+ if (max_sequence < tables_[i].max_sequence) {
309
+ max_sequence = tables_[i].max_sequence;
310
+ }
311
+ }
312
+
313
+ edit_.SetComparatorName(icmp_.user_comparator()->Name());
314
+ edit_.SetLogNumber(0);
315
+ edit_.SetNextFile(next_file_number_);
316
+ edit_.SetLastSequence(max_sequence);
317
+
318
+ for (size_t i = 0; i < tables_.size(); i++) {
319
+ // TODO(opt): separate out into multiple levels
320
+ const TableInfo& t = tables_[i];
321
+ edit_.AddFile(0, t.meta.number, t.meta.file_size,
322
+ t.meta.smallest, t.meta.largest);
323
+ }
324
+
325
+ //fprintf(stderr, "NewDescriptor:\n%s\n", edit_.DebugString().c_str());
326
+ {
327
+ log::Writer log(file);
328
+ std::string record;
329
+ edit_.EncodeTo(&record);
330
+ status = log.AddRecord(record);
331
+ }
332
+ if (status.ok()) {
333
+ status = file->Close();
334
+ }
335
+ delete file;
336
+ file = NULL;
337
+
338
+ if (!status.ok()) {
339
+ env_->DeleteFile(tmp);
340
+ } else {
341
+ // Discard older manifests
342
+ for (size_t i = 0; i < manifests_.size(); i++) {
343
+ ArchiveFile(dbname_ + "/" + manifests_[i]);
344
+ }
345
+
346
+ // Install new manifest
347
+ status = env_->RenameFile(tmp, DescriptorFileName(dbname_, 1));
348
+ if (status.ok()) {
349
+ status = SetCurrentFile(env_, dbname_, 1);
350
+ } else {
351
+ env_->DeleteFile(tmp);
352
+ }
353
+ }
354
+ return status;
355
+ }
356
+
357
+ void ArchiveFile(const std::string& fname) {
358
+ // Move into another directory. E.g., for
359
+ // dir/foo
360
+ // rename to
361
+ // dir/lost/foo
362
+ const char* slash = strrchr(fname.c_str(), '/');
363
+ std::string new_dir;
364
+ if (slash != NULL) {
365
+ new_dir.assign(fname.data(), slash - fname.data());
366
+ }
367
+ new_dir.append("/lost");
368
+ env_->CreateDir(new_dir); // Ignore error
369
+ std::string new_file = new_dir;
370
+ new_file.append("/");
371
+ new_file.append((slash == NULL) ? fname.c_str() : slash + 1);
372
+ Status s = env_->RenameFile(fname, new_file);
373
+ Log(env_, options_.info_log, "Archiving %s: %s\n",
374
+ fname.c_str(), s.ToString().c_str());
375
+ }
376
+ };
377
+ }
378
+
379
+ Status RepairDB(const std::string& dbname, const Options& options) {
380
+ Repairer repairer(dbname, options);
381
+ return repairer.Run();
382
+ }
383
+
384
+ }