filiptepper-leveldb-ruby 0.14

Sign up to get free protection for your applications and to get access to all the features.
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