filiptepper-leveldb-ruby 0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. data/LICENSE +24 -0
  2. data/README +72 -0
  3. data/ext/leveldb/extconf.rb +14 -0
  4. data/ext/leveldb/leveldb.cc +530 -0
  5. data/ext/leveldb/platform.rb +83 -0
  6. data/leveldb/Makefile +191 -0
  7. data/leveldb/build_detect_platform +160 -0
  8. data/leveldb/db/builder.cc +88 -0
  9. data/leveldb/db/builder.h +34 -0
  10. data/leveldb/db/c.cc +581 -0
  11. data/leveldb/db/corruption_test.cc +359 -0
  12. data/leveldb/db/db_bench.cc +970 -0
  13. data/leveldb/db/db_impl.cc +1448 -0
  14. data/leveldb/db/db_impl.h +194 -0
  15. data/leveldb/db/db_iter.cc +299 -0
  16. data/leveldb/db/db_iter.h +26 -0
  17. data/leveldb/db/db_test.cc +1901 -0
  18. data/leveldb/db/dbformat.cc +140 -0
  19. data/leveldb/db/dbformat.h +227 -0
  20. data/leveldb/db/dbformat_test.cc +112 -0
  21. data/leveldb/db/filename.cc +139 -0
  22. data/leveldb/db/filename.h +80 -0
  23. data/leveldb/db/filename_test.cc +122 -0
  24. data/leveldb/db/log_format.h +35 -0
  25. data/leveldb/db/log_reader.cc +259 -0
  26. data/leveldb/db/log_reader.h +108 -0
  27. data/leveldb/db/log_test.cc +500 -0
  28. data/leveldb/db/log_writer.cc +103 -0
  29. data/leveldb/db/log_writer.h +48 -0
  30. data/leveldb/db/memtable.cc +145 -0
  31. data/leveldb/db/memtable.h +91 -0
  32. data/leveldb/db/repair.cc +389 -0
  33. data/leveldb/db/skiplist.h +379 -0
  34. data/leveldb/db/skiplist_test.cc +378 -0
  35. data/leveldb/db/snapshot.h +66 -0
  36. data/leveldb/db/table_cache.cc +121 -0
  37. data/leveldb/db/table_cache.h +61 -0
  38. data/leveldb/db/version_edit.cc +266 -0
  39. data/leveldb/db/version_edit.h +107 -0
  40. data/leveldb/db/version_edit_test.cc +46 -0
  41. data/leveldb/db/version_set.cc +1402 -0
  42. data/leveldb/db/version_set.h +370 -0
  43. data/leveldb/db/version_set_test.cc +179 -0
  44. data/leveldb/db/write_batch.cc +147 -0
  45. data/leveldb/db/write_batch_internal.h +49 -0
  46. data/leveldb/db/write_batch_test.cc +120 -0
  47. data/leveldb/helpers/memenv/memenv.cc +374 -0
  48. data/leveldb/helpers/memenv/memenv.h +20 -0
  49. data/leveldb/helpers/memenv/memenv_test.cc +232 -0
  50. data/leveldb/include/leveldb/c.h +275 -0
  51. data/leveldb/include/leveldb/cache.h +99 -0
  52. data/leveldb/include/leveldb/comparator.h +63 -0
  53. data/leveldb/include/leveldb/db.h +161 -0
  54. data/leveldb/include/leveldb/env.h +323 -0
  55. data/leveldb/include/leveldb/filter_policy.h +70 -0
  56. data/leveldb/include/leveldb/iterator.h +100 -0
  57. data/leveldb/include/leveldb/options.h +195 -0
  58. data/leveldb/include/leveldb/slice.h +109 -0
  59. data/leveldb/include/leveldb/status.h +106 -0
  60. data/leveldb/include/leveldb/table.h +85 -0
  61. data/leveldb/include/leveldb/table_builder.h +92 -0
  62. data/leveldb/include/leveldb/write_batch.h +64 -0
  63. data/leveldb/port/atomic_pointer.h +144 -0
  64. data/leveldb/port/port.h +21 -0
  65. data/leveldb/port/port_android.cc +64 -0
  66. data/leveldb/port/port_android.h +159 -0
  67. data/leveldb/port/port_example.h +125 -0
  68. data/leveldb/port/port_posix.cc +50 -0
  69. data/leveldb/port/port_posix.h +129 -0
  70. data/leveldb/port/win/stdint.h +24 -0
  71. data/leveldb/table/block.cc +267 -0
  72. data/leveldb/table/block.h +44 -0
  73. data/leveldb/table/block_builder.cc +109 -0
  74. data/leveldb/table/block_builder.h +57 -0
  75. data/leveldb/table/filter_block.cc +111 -0
  76. data/leveldb/table/filter_block.h +68 -0
  77. data/leveldb/table/filter_block_test.cc +128 -0
  78. data/leveldb/table/format.cc +145 -0
  79. data/leveldb/table/format.h +108 -0
  80. data/leveldb/table/iterator.cc +67 -0
  81. data/leveldb/table/iterator_wrapper.h +63 -0
  82. data/leveldb/table/merger.cc +197 -0
  83. data/leveldb/table/merger.h +26 -0
  84. data/leveldb/table/table.cc +276 -0
  85. data/leveldb/table/table_builder.cc +270 -0
  86. data/leveldb/table/table_test.cc +838 -0
  87. data/leveldb/table/two_level_iterator.cc +182 -0
  88. data/leveldb/table/two_level_iterator.h +34 -0
  89. data/leveldb/util/arena.cc +68 -0
  90. data/leveldb/util/arena.h +68 -0
  91. data/leveldb/util/arena_test.cc +68 -0
  92. data/leveldb/util/bloom.cc +95 -0
  93. data/leveldb/util/bloom_test.cc +159 -0
  94. data/leveldb/util/cache.cc +328 -0
  95. data/leveldb/util/cache_test.cc +186 -0
  96. data/leveldb/util/coding.cc +194 -0
  97. data/leveldb/util/coding.h +104 -0
  98. data/leveldb/util/coding_test.cc +173 -0
  99. data/leveldb/util/comparator.cc +76 -0
  100. data/leveldb/util/crc32c.cc +332 -0
  101. data/leveldb/util/crc32c.h +45 -0
  102. data/leveldb/util/crc32c_test.cc +72 -0
  103. data/leveldb/util/env.cc +96 -0
  104. data/leveldb/util/env_posix.cc +609 -0
  105. data/leveldb/util/env_test.cc +104 -0
  106. data/leveldb/util/filter_policy.cc +11 -0
  107. data/leveldb/util/hash.cc +45 -0
  108. data/leveldb/util/hash.h +19 -0
  109. data/leveldb/util/histogram.cc +139 -0
  110. data/leveldb/util/histogram.h +42 -0
  111. data/leveldb/util/logging.cc +81 -0
  112. data/leveldb/util/logging.h +47 -0
  113. data/leveldb/util/mutexlock.h +39 -0
  114. data/leveldb/util/options.cc +29 -0
  115. data/leveldb/util/posix_logger.h +98 -0
  116. data/leveldb/util/random.h +59 -0
  117. data/leveldb/util/status.cc +75 -0
  118. data/leveldb/util/testharness.cc +77 -0
  119. data/leveldb/util/testharness.h +138 -0
  120. data/leveldb/util/testutil.cc +51 -0
  121. data/leveldb/util/testutil.h +53 -0
  122. data/lib/leveldb.rb +76 -0
  123. metadata +175 -0
@@ -0,0 +1,147 @@
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
+ // WriteBatch::rep_ :=
6
+ // sequence: fixed64
7
+ // count: fixed32
8
+ // data: record[count]
9
+ // record :=
10
+ // kTypeValue varstring varstring |
11
+ // kTypeDeletion varstring
12
+ // varstring :=
13
+ // len: varint32
14
+ // data: uint8[len]
15
+
16
+ #include "leveldb/write_batch.h"
17
+
18
+ #include "leveldb/db.h"
19
+ #include "db/dbformat.h"
20
+ #include "db/memtable.h"
21
+ #include "db/write_batch_internal.h"
22
+ #include "util/coding.h"
23
+
24
+ namespace leveldb {
25
+
26
+ // WriteBatch header has an 8-byte sequence number followed by a 4-byte count.
27
+ static const size_t kHeader = 12;
28
+
29
+ WriteBatch::WriteBatch() {
30
+ Clear();
31
+ }
32
+
33
+ WriteBatch::~WriteBatch() { }
34
+
35
+ WriteBatch::Handler::~Handler() { }
36
+
37
+ void WriteBatch::Clear() {
38
+ rep_.clear();
39
+ rep_.resize(kHeader);
40
+ }
41
+
42
+ Status WriteBatch::Iterate(Handler* handler) const {
43
+ Slice input(rep_);
44
+ if (input.size() < kHeader) {
45
+ return Status::Corruption("malformed WriteBatch (too small)");
46
+ }
47
+
48
+ input.remove_prefix(kHeader);
49
+ Slice key, value;
50
+ int found = 0;
51
+ while (!input.empty()) {
52
+ found++;
53
+ char tag = input[0];
54
+ input.remove_prefix(1);
55
+ switch (tag) {
56
+ case kTypeValue:
57
+ if (GetLengthPrefixedSlice(&input, &key) &&
58
+ GetLengthPrefixedSlice(&input, &value)) {
59
+ handler->Put(key, value);
60
+ } else {
61
+ return Status::Corruption("bad WriteBatch Put");
62
+ }
63
+ break;
64
+ case kTypeDeletion:
65
+ if (GetLengthPrefixedSlice(&input, &key)) {
66
+ handler->Delete(key);
67
+ } else {
68
+ return Status::Corruption("bad WriteBatch Delete");
69
+ }
70
+ break;
71
+ default:
72
+ return Status::Corruption("unknown WriteBatch tag");
73
+ }
74
+ }
75
+ if (found != WriteBatchInternal::Count(this)) {
76
+ return Status::Corruption("WriteBatch has wrong count");
77
+ } else {
78
+ return Status::OK();
79
+ }
80
+ }
81
+
82
+ int WriteBatchInternal::Count(const WriteBatch* b) {
83
+ return DecodeFixed32(b->rep_.data() + 8);
84
+ }
85
+
86
+ void WriteBatchInternal::SetCount(WriteBatch* b, int n) {
87
+ EncodeFixed32(&b->rep_[8], n);
88
+ }
89
+
90
+ SequenceNumber WriteBatchInternal::Sequence(const WriteBatch* b) {
91
+ return SequenceNumber(DecodeFixed64(b->rep_.data()));
92
+ }
93
+
94
+ void WriteBatchInternal::SetSequence(WriteBatch* b, SequenceNumber seq) {
95
+ EncodeFixed64(&b->rep_[0], seq);
96
+ }
97
+
98
+ void WriteBatch::Put(const Slice& key, const Slice& value) {
99
+ WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1);
100
+ rep_.push_back(static_cast<char>(kTypeValue));
101
+ PutLengthPrefixedSlice(&rep_, key);
102
+ PutLengthPrefixedSlice(&rep_, value);
103
+ }
104
+
105
+ void WriteBatch::Delete(const Slice& key) {
106
+ WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1);
107
+ rep_.push_back(static_cast<char>(kTypeDeletion));
108
+ PutLengthPrefixedSlice(&rep_, key);
109
+ }
110
+
111
+ namespace {
112
+ class MemTableInserter : public WriteBatch::Handler {
113
+ public:
114
+ SequenceNumber sequence_;
115
+ MemTable* mem_;
116
+
117
+ virtual void Put(const Slice& key, const Slice& value) {
118
+ mem_->Add(sequence_, kTypeValue, key, value);
119
+ sequence_++;
120
+ }
121
+ virtual void Delete(const Slice& key) {
122
+ mem_->Add(sequence_, kTypeDeletion, key, Slice());
123
+ sequence_++;
124
+ }
125
+ };
126
+ } // namespace
127
+
128
+ Status WriteBatchInternal::InsertInto(const WriteBatch* b,
129
+ MemTable* memtable) {
130
+ MemTableInserter inserter;
131
+ inserter.sequence_ = WriteBatchInternal::Sequence(b);
132
+ inserter.mem_ = memtable;
133
+ return b->Iterate(&inserter);
134
+ }
135
+
136
+ void WriteBatchInternal::SetContents(WriteBatch* b, const Slice& contents) {
137
+ assert(contents.size() >= kHeader);
138
+ b->rep_.assign(contents.data(), contents.size());
139
+ }
140
+
141
+ void WriteBatchInternal::Append(WriteBatch* dst, const WriteBatch* src) {
142
+ SetCount(dst, Count(dst) + Count(src));
143
+ assert(src->rep_.size() >= kHeader);
144
+ dst->rep_.append(src->rep_.data() + kHeader, src->rep_.size() - kHeader);
145
+ }
146
+
147
+ } // namespace leveldb
@@ -0,0 +1,49 @@
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_WRITE_BATCH_INTERNAL_H_
6
+ #define STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_
7
+
8
+ #include "leveldb/write_batch.h"
9
+
10
+ namespace leveldb {
11
+
12
+ class MemTable;
13
+
14
+ // WriteBatchInternal provides static methods for manipulating a
15
+ // WriteBatch that we don't want in the public WriteBatch interface.
16
+ class WriteBatchInternal {
17
+ public:
18
+ // Return the number of entries in the batch.
19
+ static int Count(const WriteBatch* batch);
20
+
21
+ // Set the count for the number of entries in the batch.
22
+ static void SetCount(WriteBatch* batch, int n);
23
+
24
+ // Return the seqeunce number for the start of this batch.
25
+ static SequenceNumber Sequence(const WriteBatch* batch);
26
+
27
+ // Store the specified number as the seqeunce number for the start of
28
+ // this batch.
29
+ static void SetSequence(WriteBatch* batch, SequenceNumber seq);
30
+
31
+ static Slice Contents(const WriteBatch* batch) {
32
+ return Slice(batch->rep_);
33
+ }
34
+
35
+ static size_t ByteSize(const WriteBatch* batch) {
36
+ return batch->rep_.size();
37
+ }
38
+
39
+ static void SetContents(WriteBatch* batch, const Slice& contents);
40
+
41
+ static Status InsertInto(const WriteBatch* batch, MemTable* memtable);
42
+
43
+ static void Append(WriteBatch* dst, const WriteBatch* src);
44
+ };
45
+
46
+ } // namespace leveldb
47
+
48
+
49
+ #endif // STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_
@@ -0,0 +1,120 @@
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 "leveldb/db.h"
6
+
7
+ #include "db/memtable.h"
8
+ #include "db/write_batch_internal.h"
9
+ #include "leveldb/env.h"
10
+ #include "util/logging.h"
11
+ #include "util/testharness.h"
12
+
13
+ namespace leveldb {
14
+
15
+ static std::string PrintContents(WriteBatch* b) {
16
+ InternalKeyComparator cmp(BytewiseComparator());
17
+ MemTable* mem = new MemTable(cmp);
18
+ mem->Ref();
19
+ std::string state;
20
+ Status s = WriteBatchInternal::InsertInto(b, mem);
21
+ int count = 0;
22
+ Iterator* iter = mem->NewIterator();
23
+ for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
24
+ ParsedInternalKey ikey;
25
+ ASSERT_TRUE(ParseInternalKey(iter->key(), &ikey));
26
+ switch (ikey.type) {
27
+ case kTypeValue:
28
+ state.append("Put(");
29
+ state.append(ikey.user_key.ToString());
30
+ state.append(", ");
31
+ state.append(iter->value().ToString());
32
+ state.append(")");
33
+ count++;
34
+ break;
35
+ case kTypeDeletion:
36
+ state.append("Delete(");
37
+ state.append(ikey.user_key.ToString());
38
+ state.append(")");
39
+ count++;
40
+ break;
41
+ }
42
+ state.append("@");
43
+ state.append(NumberToString(ikey.sequence));
44
+ }
45
+ delete iter;
46
+ if (!s.ok()) {
47
+ state.append("ParseError()");
48
+ } else if (count != WriteBatchInternal::Count(b)) {
49
+ state.append("CountMismatch()");
50
+ }
51
+ mem->Unref();
52
+ return state;
53
+ }
54
+
55
+ class WriteBatchTest { };
56
+
57
+ TEST(WriteBatchTest, Empty) {
58
+ WriteBatch batch;
59
+ ASSERT_EQ("", PrintContents(&batch));
60
+ ASSERT_EQ(0, WriteBatchInternal::Count(&batch));
61
+ }
62
+
63
+ TEST(WriteBatchTest, Multiple) {
64
+ WriteBatch batch;
65
+ batch.Put(Slice("foo"), Slice("bar"));
66
+ batch.Delete(Slice("box"));
67
+ batch.Put(Slice("baz"), Slice("boo"));
68
+ WriteBatchInternal::SetSequence(&batch, 100);
69
+ ASSERT_EQ(100, WriteBatchInternal::Sequence(&batch));
70
+ ASSERT_EQ(3, WriteBatchInternal::Count(&batch));
71
+ ASSERT_EQ("Put(baz, boo)@102"
72
+ "Delete(box)@101"
73
+ "Put(foo, bar)@100",
74
+ PrintContents(&batch));
75
+ }
76
+
77
+ TEST(WriteBatchTest, Corruption) {
78
+ WriteBatch batch;
79
+ batch.Put(Slice("foo"), Slice("bar"));
80
+ batch.Delete(Slice("box"));
81
+ WriteBatchInternal::SetSequence(&batch, 200);
82
+ Slice contents = WriteBatchInternal::Contents(&batch);
83
+ WriteBatchInternal::SetContents(&batch,
84
+ Slice(contents.data(),contents.size()-1));
85
+ ASSERT_EQ("Put(foo, bar)@200"
86
+ "ParseError()",
87
+ PrintContents(&batch));
88
+ }
89
+
90
+ TEST(WriteBatchTest, Append) {
91
+ WriteBatch b1, b2;
92
+ WriteBatchInternal::SetSequence(&b1, 200);
93
+ WriteBatchInternal::SetSequence(&b2, 300);
94
+ WriteBatchInternal::Append(&b1, &b2);
95
+ ASSERT_EQ("",
96
+ PrintContents(&b1));
97
+ b2.Put("a", "va");
98
+ WriteBatchInternal::Append(&b1, &b2);
99
+ ASSERT_EQ("Put(a, va)@200",
100
+ PrintContents(&b1));
101
+ b2.Clear();
102
+ b2.Put("b", "vb");
103
+ WriteBatchInternal::Append(&b1, &b2);
104
+ ASSERT_EQ("Put(a, va)@200"
105
+ "Put(b, vb)@201",
106
+ PrintContents(&b1));
107
+ b2.Delete("foo");
108
+ WriteBatchInternal::Append(&b1, &b2);
109
+ ASSERT_EQ("Put(a, va)@200"
110
+ "Put(b, vb)@202"
111
+ "Put(b, vb)@201"
112
+ "Delete(foo)@203",
113
+ PrintContents(&b1));
114
+ }
115
+
116
+ } // namespace leveldb
117
+
118
+ int main(int argc, char** argv) {
119
+ return leveldb::test::RunAllTests();
120
+ }
@@ -0,0 +1,374 @@
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 "helpers/memenv/memenv.h"
6
+
7
+ #include "leveldb/env.h"
8
+ #include "leveldb/status.h"
9
+ #include "port/port.h"
10
+ #include "util/mutexlock.h"
11
+ #include <map>
12
+ #include <string.h>
13
+ #include <string>
14
+ #include <vector>
15
+
16
+ namespace leveldb {
17
+
18
+ namespace {
19
+
20
+ class FileState {
21
+ public:
22
+ // FileStates are reference counted. The initial reference count is zero
23
+ // and the caller must call Ref() at least once.
24
+ FileState() : refs_(0), size_(0) {}
25
+
26
+ // Increase the reference count.
27
+ void Ref() {
28
+ MutexLock lock(&refs_mutex_);
29
+ ++refs_;
30
+ }
31
+
32
+ // Decrease the reference count. Delete if this is the last reference.
33
+ void Unref() {
34
+ bool do_delete = false;
35
+
36
+ {
37
+ MutexLock lock(&refs_mutex_);
38
+ --refs_;
39
+ assert(refs_ >= 0);
40
+ if (refs_ <= 0) {
41
+ do_delete = true;
42
+ }
43
+ }
44
+
45
+ if (do_delete) {
46
+ delete this;
47
+ }
48
+ }
49
+
50
+ uint64_t Size() const { return size_; }
51
+
52
+ Status Read(uint64_t offset, size_t n, Slice* result, char* scratch) const {
53
+ if (offset > size_) {
54
+ return Status::IOError("Offset greater than file size.");
55
+ }
56
+ const uint64_t available = size_ - offset;
57
+ if (n > available) {
58
+ n = available;
59
+ }
60
+ if (n == 0) {
61
+ *result = Slice();
62
+ return Status::OK();
63
+ }
64
+
65
+ size_t block = offset / kBlockSize;
66
+ size_t block_offset = offset % kBlockSize;
67
+
68
+ if (n <= kBlockSize - block_offset) {
69
+ // The requested bytes are all in the first block.
70
+ *result = Slice(blocks_[block] + block_offset, n);
71
+ return Status::OK();
72
+ }
73
+
74
+ size_t bytes_to_copy = n;
75
+ char* dst = scratch;
76
+
77
+ while (bytes_to_copy > 0) {
78
+ size_t avail = kBlockSize - block_offset;
79
+ if (avail > bytes_to_copy) {
80
+ avail = bytes_to_copy;
81
+ }
82
+ memcpy(dst, blocks_[block] + block_offset, avail);
83
+
84
+ bytes_to_copy -= avail;
85
+ dst += avail;
86
+ block++;
87
+ block_offset = 0;
88
+ }
89
+
90
+ *result = Slice(scratch, n);
91
+ return Status::OK();
92
+ }
93
+
94
+ Status Append(const Slice& data) {
95
+ const char* src = data.data();
96
+ size_t src_len = data.size();
97
+
98
+ while (src_len > 0) {
99
+ size_t avail;
100
+ size_t offset = size_ % kBlockSize;
101
+
102
+ if (offset != 0) {
103
+ // There is some room in the last block.
104
+ avail = kBlockSize - offset;
105
+ } else {
106
+ // No room in the last block; push new one.
107
+ blocks_.push_back(new char[kBlockSize]);
108
+ avail = kBlockSize;
109
+ }
110
+
111
+ if (avail > src_len) {
112
+ avail = src_len;
113
+ }
114
+ memcpy(blocks_.back() + offset, src, avail);
115
+ src_len -= avail;
116
+ src += avail;
117
+ size_ += avail;
118
+ }
119
+
120
+ return Status::OK();
121
+ }
122
+
123
+ private:
124
+ // Private since only Unref() should be used to delete it.
125
+ ~FileState() {
126
+ for (std::vector<char*>::iterator i = blocks_.begin(); i != blocks_.end();
127
+ ++i) {
128
+ delete [] *i;
129
+ }
130
+ }
131
+
132
+ // No copying allowed.
133
+ FileState(const FileState&);
134
+ void operator=(const FileState&);
135
+
136
+ port::Mutex refs_mutex_;
137
+ int refs_; // Protected by refs_mutex_;
138
+
139
+ // The following fields are not protected by any mutex. They are only mutable
140
+ // while the file is being written, and concurrent access is not allowed
141
+ // to writable files.
142
+ std::vector<char*> blocks_;
143
+ uint64_t size_;
144
+
145
+ enum { kBlockSize = 8 * 1024 };
146
+ };
147
+
148
+ class SequentialFileImpl : public SequentialFile {
149
+ public:
150
+ explicit SequentialFileImpl(FileState* file) : file_(file), pos_(0) {
151
+ file_->Ref();
152
+ }
153
+
154
+ ~SequentialFileImpl() {
155
+ file_->Unref();
156
+ }
157
+
158
+ virtual Status Read(size_t n, Slice* result, char* scratch) {
159
+ Status s = file_->Read(pos_, n, result, scratch);
160
+ if (s.ok()) {
161
+ pos_ += result->size();
162
+ }
163
+ return s;
164
+ }
165
+
166
+ virtual Status Skip(uint64_t n) {
167
+ if (pos_ > file_->Size()) {
168
+ return Status::IOError("pos_ > file_->Size()");
169
+ }
170
+ const size_t available = file_->Size() - pos_;
171
+ if (n > available) {
172
+ n = available;
173
+ }
174
+ pos_ += n;
175
+ return Status::OK();
176
+ }
177
+
178
+ private:
179
+ FileState* file_;
180
+ size_t pos_;
181
+ };
182
+
183
+ class RandomAccessFileImpl : public RandomAccessFile {
184
+ public:
185
+ explicit RandomAccessFileImpl(FileState* file) : file_(file) {
186
+ file_->Ref();
187
+ }
188
+
189
+ ~RandomAccessFileImpl() {
190
+ file_->Unref();
191
+ }
192
+
193
+ virtual Status Read(uint64_t offset, size_t n, Slice* result,
194
+ char* scratch) const {
195
+ return file_->Read(offset, n, result, scratch);
196
+ }
197
+
198
+ private:
199
+ FileState* file_;
200
+ };
201
+
202
+ class WritableFileImpl : public WritableFile {
203
+ public:
204
+ WritableFileImpl(FileState* file) : file_(file) {
205
+ file_->Ref();
206
+ }
207
+
208
+ ~WritableFileImpl() {
209
+ file_->Unref();
210
+ }
211
+
212
+ virtual Status Append(const Slice& data) {
213
+ return file_->Append(data);
214
+ }
215
+
216
+ virtual Status Close() { return Status::OK(); }
217
+ virtual Status Flush() { return Status::OK(); }
218
+ virtual Status Sync() { return Status::OK(); }
219
+
220
+ private:
221
+ FileState* file_;
222
+ };
223
+
224
+ class InMemoryEnv : public EnvWrapper {
225
+ public:
226
+ explicit InMemoryEnv(Env* base_env) : EnvWrapper(base_env) { }
227
+
228
+ virtual ~InMemoryEnv() {
229
+ for (FileSystem::iterator i = file_map_.begin(); i != file_map_.end(); ++i){
230
+ i->second->Unref();
231
+ }
232
+ }
233
+
234
+ // Partial implementation of the Env interface.
235
+ virtual Status NewSequentialFile(const std::string& fname,
236
+ SequentialFile** result) {
237
+ MutexLock lock(&mutex_);
238
+ if (file_map_.find(fname) == file_map_.end()) {
239
+ *result = NULL;
240
+ return Status::IOError(fname, "File not found");
241
+ }
242
+
243
+ *result = new SequentialFileImpl(file_map_[fname]);
244
+ return Status::OK();
245
+ }
246
+
247
+ virtual Status NewRandomAccessFile(const std::string& fname,
248
+ RandomAccessFile** result) {
249
+ MutexLock lock(&mutex_);
250
+ if (file_map_.find(fname) == file_map_.end()) {
251
+ *result = NULL;
252
+ return Status::IOError(fname, "File not found");
253
+ }
254
+
255
+ *result = new RandomAccessFileImpl(file_map_[fname]);
256
+ return Status::OK();
257
+ }
258
+
259
+ virtual Status NewWritableFile(const std::string& fname,
260
+ WritableFile** result) {
261
+ MutexLock lock(&mutex_);
262
+ if (file_map_.find(fname) != file_map_.end()) {
263
+ DeleteFileInternal(fname);
264
+ }
265
+
266
+ FileState* file = new FileState();
267
+ file->Ref();
268
+ file_map_[fname] = file;
269
+
270
+ *result = new WritableFileImpl(file);
271
+ return Status::OK();
272
+ }
273
+
274
+ virtual bool FileExists(const std::string& fname) {
275
+ MutexLock lock(&mutex_);
276
+ return file_map_.find(fname) != file_map_.end();
277
+ }
278
+
279
+ virtual Status GetChildren(const std::string& dir,
280
+ std::vector<std::string>* result) {
281
+ MutexLock lock(&mutex_);
282
+ result->clear();
283
+
284
+ for (FileSystem::iterator i = file_map_.begin(); i != file_map_.end(); ++i){
285
+ const std::string& filename = i->first;
286
+
287
+ if (filename.size() >= dir.size() + 1 && filename[dir.size()] == '/' &&
288
+ Slice(filename).starts_with(Slice(dir))) {
289
+ result->push_back(filename.substr(dir.size() + 1));
290
+ }
291
+ }
292
+
293
+ return Status::OK();
294
+ }
295
+
296
+ void DeleteFileInternal(const std::string& fname) {
297
+ if (file_map_.find(fname) == file_map_.end()) {
298
+ return;
299
+ }
300
+
301
+ file_map_[fname]->Unref();
302
+ file_map_.erase(fname);
303
+ }
304
+
305
+ virtual Status DeleteFile(const std::string& fname) {
306
+ MutexLock lock(&mutex_);
307
+ if (file_map_.find(fname) == file_map_.end()) {
308
+ return Status::IOError(fname, "File not found");
309
+ }
310
+
311
+ DeleteFileInternal(fname);
312
+ return Status::OK();
313
+ }
314
+
315
+ virtual Status CreateDir(const std::string& dirname) {
316
+ return Status::OK();
317
+ }
318
+
319
+ virtual Status DeleteDir(const std::string& dirname) {
320
+ return Status::OK();
321
+ }
322
+
323
+ virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) {
324
+ MutexLock lock(&mutex_);
325
+ if (file_map_.find(fname) == file_map_.end()) {
326
+ return Status::IOError(fname, "File not found");
327
+ }
328
+
329
+ *file_size = file_map_[fname]->Size();
330
+ return Status::OK();
331
+ }
332
+
333
+ virtual Status RenameFile(const std::string& src,
334
+ const std::string& target) {
335
+ MutexLock lock(&mutex_);
336
+ if (file_map_.find(src) == file_map_.end()) {
337
+ return Status::IOError(src, "File not found");
338
+ }
339
+
340
+ DeleteFileInternal(target);
341
+ file_map_[target] = file_map_[src];
342
+ file_map_.erase(src);
343
+ return Status::OK();
344
+ }
345
+
346
+ virtual Status LockFile(const std::string& fname, FileLock** lock) {
347
+ *lock = new FileLock;
348
+ return Status::OK();
349
+ }
350
+
351
+ virtual Status UnlockFile(FileLock* lock) {
352
+ delete lock;
353
+ return Status::OK();
354
+ }
355
+
356
+ virtual Status GetTestDirectory(std::string* path) {
357
+ *path = "/test";
358
+ return Status::OK();
359
+ }
360
+
361
+ private:
362
+ // Map from filenames to FileState objects, representing a simple file system.
363
+ typedef std::map<std::string, FileState*> FileSystem;
364
+ port::Mutex mutex_;
365
+ FileSystem file_map_; // Protected by mutex_.
366
+ };
367
+
368
+ } // namespace
369
+
370
+ Env* NewMemEnv(Env* base_env) {
371
+ return new InMemoryEnv(base_env);
372
+ }
373
+
374
+ } // namespace leveldb