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,45 @@
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_UTIL_CRC32C_H_
6
+ #define STORAGE_LEVELDB_UTIL_CRC32C_H_
7
+
8
+ #include <stddef.h>
9
+ #include <stdint.h>
10
+
11
+ namespace leveldb {
12
+ namespace crc32c {
13
+
14
+ // Return the crc32c of concat(A, data[0,n-1]) where init_crc is the
15
+ // crc32c of some string A. Extend() is often used to maintain the
16
+ // crc32c of a stream of data.
17
+ extern uint32_t Extend(uint32_t init_crc, const char* data, size_t n);
18
+
19
+ // Return the crc32c of data[0,n-1]
20
+ inline uint32_t Value(const char* data, size_t n) {
21
+ return Extend(0, data, n);
22
+ }
23
+
24
+ static const uint32_t kMaskDelta = 0xa282ead8ul;
25
+
26
+ // Return a masked representation of crc.
27
+ //
28
+ // Motivation: it is problematic to compute the CRC of a string that
29
+ // contains embedded CRCs. Therefore we recommend that CRCs stored
30
+ // somewhere (e.g., in files) should be masked before being stored.
31
+ inline uint32_t Mask(uint32_t crc) {
32
+ // Rotate right by 15 bits and add a constant.
33
+ return ((crc >> 15) | (crc << 17)) + kMaskDelta;
34
+ }
35
+
36
+ // Return the crc whose masked representation is masked_crc.
37
+ inline uint32_t Unmask(uint32_t masked_crc) {
38
+ uint32_t rot = masked_crc - kMaskDelta;
39
+ return ((rot >> 17) | (rot << 15));
40
+ }
41
+
42
+ }
43
+ }
44
+
45
+ #endif // STORAGE_LEVELDB_UTIL_CRC32C_H_
@@ -0,0 +1,72 @@
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 "util/crc32c.h"
6
+ #include "util/testharness.h"
7
+
8
+ namespace leveldb {
9
+ namespace crc32c {
10
+
11
+ class CRC { };
12
+
13
+ TEST(CRC, StandardResults) {
14
+ // From rfc3720 section B.4.
15
+ char buf[32];
16
+
17
+ memset(buf, 0, sizeof(buf));
18
+ ASSERT_EQ(0x8a9136aa, Value(buf, sizeof(buf)));
19
+
20
+ memset(buf, 0xff, sizeof(buf));
21
+ ASSERT_EQ(0x62a8ab43, Value(buf, sizeof(buf)));
22
+
23
+ for (int i = 0; i < 32; i++) {
24
+ buf[i] = i;
25
+ }
26
+ ASSERT_EQ(0x46dd794e, Value(buf, sizeof(buf)));
27
+
28
+ for (int i = 0; i < 32; i++) {
29
+ buf[i] = 31 - i;
30
+ }
31
+ ASSERT_EQ(0x113fdb5c, Value(buf, sizeof(buf)));
32
+
33
+ unsigned char data[48] = {
34
+ 0x01, 0xc0, 0x00, 0x00,
35
+ 0x00, 0x00, 0x00, 0x00,
36
+ 0x00, 0x00, 0x00, 0x00,
37
+ 0x00, 0x00, 0x00, 0x00,
38
+ 0x14, 0x00, 0x00, 0x00,
39
+ 0x00, 0x00, 0x04, 0x00,
40
+ 0x00, 0x00, 0x00, 0x14,
41
+ 0x00, 0x00, 0x00, 0x18,
42
+ 0x28, 0x00, 0x00, 0x00,
43
+ 0x00, 0x00, 0x00, 0x00,
44
+ 0x02, 0x00, 0x00, 0x00,
45
+ 0x00, 0x00, 0x00, 0x00,
46
+ };
47
+ ASSERT_EQ(0xd9963a56, Value(reinterpret_cast<char*>(data), sizeof(data)));
48
+ }
49
+
50
+ TEST(CRC, Values) {
51
+ ASSERT_NE(Value("a", 1), Value("foo", 3));
52
+ }
53
+
54
+ TEST(CRC, Extend) {
55
+ ASSERT_EQ(Value("hello world", 11),
56
+ Extend(Value("hello ", 6), "world", 5));
57
+ }
58
+
59
+ TEST(CRC, Mask) {
60
+ uint32_t crc = Value("foo", 3);
61
+ ASSERT_NE(crc, Mask(crc));
62
+ ASSERT_NE(crc, Mask(Mask(crc)));
63
+ ASSERT_EQ(crc, Unmask(Mask(crc)));
64
+ ASSERT_EQ(crc, Unmask(Unmask(Mask(Mask(crc)))));
65
+ }
66
+
67
+ }
68
+ }
69
+
70
+ int main(int argc, char** argv) {
71
+ return leveldb::test::RunAllTests();
72
+ }
@@ -0,0 +1,77 @@
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/env.h"
6
+
7
+ namespace leveldb {
8
+
9
+ Env::~Env() {
10
+ }
11
+
12
+ SequentialFile::~SequentialFile() {
13
+ }
14
+
15
+ RandomAccessFile::~RandomAccessFile() {
16
+ }
17
+
18
+ WritableFile::~WritableFile() {
19
+ }
20
+
21
+ FileLock::~FileLock() {
22
+ }
23
+
24
+ void Log(Env* env, WritableFile* info_log, const char* format, ...) {
25
+ va_list ap;
26
+ va_start(ap, format);
27
+ env->Logv(info_log, format, ap);
28
+ va_end(ap);
29
+ }
30
+
31
+ Status WriteStringToFile(Env* env, const Slice& data,
32
+ const std::string& fname) {
33
+ WritableFile* file;
34
+ Status s = env->NewWritableFile(fname, &file);
35
+ if (!s.ok()) {
36
+ return s;
37
+ }
38
+ s = file->Append(data);
39
+ if (s.ok()) {
40
+ s = file->Close();
41
+ }
42
+ delete file; // Will auto-close if we did not close above
43
+ if (!s.ok()) {
44
+ env->DeleteFile(fname);
45
+ }
46
+ return s;
47
+ }
48
+
49
+ Status ReadFileToString(Env* env, const std::string& fname, std::string* data) {
50
+ data->clear();
51
+ SequentialFile* file;
52
+ Status s = env->NewSequentialFile(fname, &file);
53
+ if (!s.ok()) {
54
+ return s;
55
+ }
56
+ static const int kBufferSize = 8192;
57
+ char* space = new char[kBufferSize];
58
+ while (true) {
59
+ Slice fragment;
60
+ s = file->Read(kBufferSize, &fragment, space);
61
+ if (!s.ok()) {
62
+ break;
63
+ }
64
+ data->append(fragment.data(), fragment.size());
65
+ if (fragment.empty()) {
66
+ break;
67
+ }
68
+ }
69
+ delete[] space;
70
+ delete file;
71
+ return s;
72
+ }
73
+
74
+ EnvWrapper::~EnvWrapper() {
75
+ }
76
+
77
+ }
@@ -0,0 +1,612 @@
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 <deque>
6
+ #include <errno.h>
7
+ #include <stdio.h>
8
+ #include "base/at_exit.h"
9
+ #include "base/file_path.h"
10
+ #include "base/file_util.h"
11
+ #include "base/lazy_instance.h"
12
+ #include "base/memory/ref_counted.h"
13
+ #include "base/message_loop.h"
14
+ #include "base/platform_file.h"
15
+ #include "base/process_util.h"
16
+ #include "base/synchronization/lock.h"
17
+ #include "base/sys_info.h"
18
+ #include "base/task.h"
19
+ #include "base/threading/platform_thread.h"
20
+ #include "base/threading/thread.h"
21
+ #include "base/utf_string_conversions.h"
22
+ #include "leveldb/env.h"
23
+ #include "leveldb/slice.h"
24
+ #include "port/port.h"
25
+ #include "util/logging.h"
26
+
27
+ #if defined(OS_WIN)
28
+ #include <io.h>
29
+ #include "base/win/win_util.h"
30
+ #endif
31
+
32
+ #if defined(OS_MACOSX) || defined(OS_WIN)
33
+ // The following are glibc-specific
34
+ namespace {
35
+
36
+ size_t fread_unlocked(void *ptr, size_t size, size_t n, FILE *file) {
37
+ return fread(ptr, size, n, file);
38
+ }
39
+
40
+ size_t fwrite_unlocked(const void *ptr, size_t size, size_t n, FILE *file) {
41
+ return fwrite(ptr, size, n, file);
42
+ }
43
+
44
+ int fflush_unlocked(FILE *file) {
45
+ return fflush(file);
46
+ }
47
+
48
+ int fdatasync(int fildes) {
49
+ #if defined(OS_WIN)
50
+ return _commit(fildes);
51
+ #else
52
+ return fsync(fildes);
53
+ #endif
54
+ }
55
+
56
+ }
57
+ #endif
58
+
59
+ namespace leveldb {
60
+
61
+ namespace {
62
+
63
+ class Thread;
64
+
65
+ static const ::FilePath::CharType kLevelDBTestDirectoryPrefix[]
66
+ = FILE_PATH_LITERAL("leveldb-test-");
67
+
68
+ ::FilePath CreateFilePath(const std::string& file_path) {
69
+ #if defined(OS_WIN)
70
+ return FilePath(UTF8ToUTF16(file_path));
71
+ #else
72
+ return FilePath(file_path);
73
+ #endif
74
+ }
75
+
76
+ std::string FilePathToString(const ::FilePath& file_path) {
77
+ #if defined(OS_WIN)
78
+ return UTF16ToUTF8(file_path.value());
79
+ #else
80
+ return file_path.value();
81
+ #endif
82
+ }
83
+
84
+ // TODO(jorlow): This should be moved into Chromium's base.
85
+ const char* PlatformFileErrorString(const ::base::PlatformFileError& error) {
86
+ switch (error) {
87
+ case ::base::PLATFORM_FILE_ERROR_FAILED:
88
+ return "Opening file failed.";
89
+ case ::base::PLATFORM_FILE_ERROR_IN_USE:
90
+ return "File currently in use.";
91
+ case ::base::PLATFORM_FILE_ERROR_EXISTS:
92
+ return "File already exists.";
93
+ case ::base::PLATFORM_FILE_ERROR_NOT_FOUND:
94
+ return "File not found.";
95
+ case ::base::PLATFORM_FILE_ERROR_ACCESS_DENIED:
96
+ return "Access denied.";
97
+ case ::base::PLATFORM_FILE_ERROR_TOO_MANY_OPENED:
98
+ return "Too many files open.";
99
+ case ::base::PLATFORM_FILE_ERROR_NO_MEMORY:
100
+ return "Out of memory.";
101
+ case ::base::PLATFORM_FILE_ERROR_NO_SPACE:
102
+ return "No space left on drive.";
103
+ case ::base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY:
104
+ return "Not a directory.";
105
+ case ::base::PLATFORM_FILE_ERROR_INVALID_OPERATION:
106
+ return "Invalid operation.";
107
+ case ::base::PLATFORM_FILE_ERROR_SECURITY:
108
+ return "Security error.";
109
+ case ::base::PLATFORM_FILE_ERROR_ABORT:
110
+ return "File operation aborted.";
111
+ case ::base::PLATFORM_FILE_ERROR_NOT_A_FILE:
112
+ return "The supplied path was not a file.";
113
+ case ::base::PLATFORM_FILE_ERROR_NOT_EMPTY:
114
+ return "The file was not empty.";
115
+ }
116
+ NOTIMPLEMENTED();
117
+ return "Unknown error.";
118
+ }
119
+
120
+ class ChromiumSequentialFile: public SequentialFile {
121
+ private:
122
+ std::string filename_;
123
+ FILE* file_;
124
+
125
+ public:
126
+ ChromiumSequentialFile(const std::string& fname, FILE* f)
127
+ : filename_(fname), file_(f) { }
128
+ virtual ~ChromiumSequentialFile() { fclose(file_); }
129
+
130
+ virtual Status Read(size_t n, Slice* result, char* scratch) {
131
+ Status s;
132
+ size_t r = fread_unlocked(scratch, 1, n, file_);
133
+ *result = Slice(scratch, r);
134
+ if (r < n) {
135
+ if (feof(file_)) {
136
+ // We leave status as ok if we hit the end of the file
137
+ } else {
138
+ // A partial read with an error: return a non-ok status
139
+ s = Status::IOError(filename_, strerror(errno));
140
+ }
141
+ }
142
+ return s;
143
+ }
144
+
145
+ virtual Status Skip(uint64_t n) {
146
+ if (fseek(file_, n, SEEK_CUR)) {
147
+ return Status::IOError(filename_, strerror(errno));
148
+ }
149
+ return Status::OK();
150
+ }
151
+ };
152
+
153
+ class ChromiumRandomAccessFile: public RandomAccessFile {
154
+ private:
155
+ std::string filename_;
156
+ ::base::PlatformFile file_;
157
+
158
+ public:
159
+ ChromiumRandomAccessFile(const std::string& fname, ::base::PlatformFile file)
160
+ : filename_(fname), file_(file) { }
161
+ virtual ~ChromiumRandomAccessFile() { ::base::ClosePlatformFile(file_); }
162
+
163
+ virtual Status Read(uint64_t offset, size_t n, Slice* result,
164
+ char* scratch) const {
165
+ Status s;
166
+ int r = ::base::ReadPlatformFile(file_, offset, scratch, n);
167
+ *result = Slice(scratch, (r < 0) ? 0 : r);
168
+ if (r < 0) {
169
+ // An error: return a non-ok status
170
+ s = Status::IOError(filename_, "Could not preform read");
171
+ }
172
+ return s;
173
+ }
174
+ };
175
+
176
+ class ChromiumWritableFile : public WritableFile {
177
+ private:
178
+ std::string filename_;
179
+ FILE* file_;
180
+
181
+ public:
182
+ ChromiumWritableFile(const std::string& fname, FILE* f)
183
+ : filename_(fname), file_(f) { }
184
+
185
+ ~ChromiumWritableFile() {
186
+ if (file_ != NULL) {
187
+ // Ignoring any potential errors
188
+ fclose(file_);
189
+ }
190
+ }
191
+
192
+ virtual Status Append(const Slice& data) {
193
+ size_t r = fwrite_unlocked(data.data(), 1, data.size(), file_);
194
+ Status result;
195
+ if (r != data.size()) {
196
+ result = Status::IOError(filename_, strerror(errno));
197
+ }
198
+ return result;
199
+ }
200
+
201
+ virtual Status Close() {
202
+ Status result;
203
+ if (fclose(file_) != 0) {
204
+ result = Status::IOError(filename_, strerror(errno));
205
+ }
206
+ file_ = NULL;
207
+ return result;
208
+ }
209
+
210
+ virtual Status Flush() {
211
+ Status result;
212
+ if (fflush_unlocked(file_) != 0) {
213
+ result = Status::IOError(filename_, strerror(errno));
214
+ }
215
+ return result;
216
+ }
217
+
218
+ virtual Status Sync() {
219
+ Status result;
220
+ if ((fflush_unlocked(file_) != 0) ||
221
+ (fdatasync(fileno(file_)) != 0)) {
222
+ result = Status::IOError(filename_, strerror(errno));
223
+ }
224
+ return result;
225
+ }
226
+ };
227
+
228
+ class ChromiumFileLock : public FileLock {
229
+ public:
230
+ ::base::PlatformFile file_;
231
+ };
232
+
233
+ class ChromiumEnv : public Env {
234
+ public:
235
+ ChromiumEnv();
236
+ virtual ~ChromiumEnv() {
237
+ fprintf(stderr, "Destroying Env::Default()\n");
238
+ exit(1);
239
+ }
240
+
241
+ virtual Status NewSequentialFile(const std::string& fname,
242
+ SequentialFile** result) {
243
+ FILE* f = fopen(fname.c_str(), "rb");
244
+ if (f == NULL) {
245
+ *result = NULL;
246
+ return Status::IOError(fname, strerror(errno));
247
+ } else {
248
+ *result = new ChromiumSequentialFile(fname, f);
249
+ return Status::OK();
250
+ }
251
+ }
252
+
253
+ virtual Status NewRandomAccessFile(const std::string& fname,
254
+ RandomAccessFile** result) {
255
+ int flags = ::base::PLATFORM_FILE_READ | ::base::PLATFORM_FILE_OPEN;
256
+ bool created;
257
+ ::base::PlatformFileError error_code;
258
+ ::base::PlatformFile file = ::base::CreatePlatformFile(
259
+ CreateFilePath(fname), flags, &created, &error_code);
260
+ if (error_code != ::base::PLATFORM_FILE_OK) {
261
+ *result = NULL;
262
+ return Status::IOError(fname, PlatformFileErrorString(error_code));
263
+ }
264
+ *result = new ChromiumRandomAccessFile(fname, file);
265
+ return Status::OK();
266
+ }
267
+
268
+ virtual Status NewWritableFile(const std::string& fname,
269
+ WritableFile** result) {
270
+ *result = NULL;
271
+ FILE* f = fopen(fname.c_str(), "wb");
272
+ if (f == NULL) {
273
+ return Status::IOError(fname, strerror(errno));
274
+ } else {
275
+ *result = new ChromiumWritableFile(fname, f);
276
+ return Status::OK();
277
+ }
278
+ }
279
+
280
+ virtual bool FileExists(const std::string& fname) {
281
+ return ::file_util::PathExists(CreateFilePath(fname));
282
+ }
283
+
284
+ virtual Status GetChildren(const std::string& dir,
285
+ std::vector<std::string>* result) {
286
+ result->clear();
287
+ ::file_util::FileEnumerator iter(
288
+ CreateFilePath(dir), false, ::file_util::FileEnumerator::FILES);
289
+ ::FilePath current = iter.Next();
290
+ while (!current.empty()) {
291
+ result->push_back(FilePathToString(current.BaseName()));
292
+ current = iter.Next();
293
+ }
294
+ // TODO(jorlow): Unfortunately, the FileEnumerator swallows errors, so
295
+ // we'll always return OK. Maybe manually check for error
296
+ // conditions like the file not existing?
297
+ return Status::OK();
298
+ }
299
+
300
+ virtual Status DeleteFile(const std::string& fname) {
301
+ Status result;
302
+ // TODO(jorlow): Should we assert this is a file?
303
+ if (!::file_util::Delete(CreateFilePath(fname), false)) {
304
+ result = Status::IOError(fname, "Could not delete file.");
305
+ }
306
+ return result;
307
+ };
308
+
309
+ virtual Status CreateDir(const std::string& name) {
310
+ Status result;
311
+ if (!::file_util::CreateDirectory(CreateFilePath(name))) {
312
+ result = Status::IOError(name, "Could not create directory.");
313
+ }
314
+ return result;
315
+ };
316
+
317
+ virtual Status DeleteDir(const std::string& name) {
318
+ Status result;
319
+ // TODO(jorlow): Should we assert this is a directory?
320
+ if (!::file_util::Delete(CreateFilePath(name), false)) {
321
+ result = Status::IOError(name, "Could not delete directory.");
322
+ }
323
+ return result;
324
+ };
325
+
326
+ virtual Status GetFileSize(const std::string& fname, uint64_t* size) {
327
+ Status s;
328
+ int64_t signed_size;
329
+ if (!::file_util::GetFileSize(CreateFilePath(fname), &signed_size)) {
330
+ *size = 0;
331
+ s = Status::IOError(fname, "Could not determine file size.");
332
+ } else {
333
+ *size = static_cast<uint64_t>(signed_size);
334
+ }
335
+ return s;
336
+ }
337
+
338
+ virtual Status RenameFile(const std::string& src, const std::string& dst) {
339
+ Status result;
340
+ if (!::file_util::ReplaceFile(CreateFilePath(src), CreateFilePath(dst))) {
341
+ result = Status::IOError(src, "Could not rename file.");
342
+ }
343
+ return result;
344
+ }
345
+
346
+ virtual Status LockFile(const std::string& fname, FileLock** lock) {
347
+ *lock = NULL;
348
+ Status result;
349
+ int flags = ::base::PLATFORM_FILE_OPEN_ALWAYS |
350
+ ::base::PLATFORM_FILE_READ |
351
+ ::base::PLATFORM_FILE_WRITE |
352
+ ::base::PLATFORM_FILE_EXCLUSIVE_READ |
353
+ ::base::PLATFORM_FILE_EXCLUSIVE_WRITE;
354
+ bool created;
355
+ ::base::PlatformFileError error_code;
356
+ ::base::PlatformFile file = ::base::CreatePlatformFile(
357
+ CreateFilePath(fname), flags, &created, &error_code);
358
+ if (error_code != ::base::PLATFORM_FILE_OK) {
359
+ result = Status::IOError(fname, PlatformFileErrorString(error_code));
360
+ } else {
361
+ ChromiumFileLock* my_lock = new ChromiumFileLock;
362
+ my_lock->file_ = file;
363
+ *lock = my_lock;
364
+ }
365
+ return result;
366
+ }
367
+
368
+ virtual Status UnlockFile(FileLock* lock) {
369
+ ChromiumFileLock* my_lock = reinterpret_cast<ChromiumFileLock*>(lock);
370
+ Status result;
371
+ if (!::base::ClosePlatformFile(my_lock->file_)) {
372
+ result = Status::IOError("Could not close lock file.");
373
+ }
374
+ delete my_lock;
375
+ return result;
376
+ }
377
+
378
+ virtual void Schedule(void (*function)(void*), void* arg);
379
+
380
+ virtual void StartThread(void (*function)(void* arg), void* arg);
381
+
382
+ virtual std::string UserIdentifier() {
383
+ #if defined(OS_WIN)
384
+ std::wstring user_sid;
385
+ bool ret = ::base::win::GetUserSidString(&user_sid);
386
+ DCHECK(ret);
387
+ return UTF16ToUTF8(user_sid);
388
+ #else
389
+ char buf[100];
390
+ snprintf(buf, sizeof(buf), "%d", int(geteuid()));
391
+ return buf;
392
+ #endif
393
+ }
394
+
395
+ virtual Status GetTestDirectory(std::string* path) {
396
+ mu_.Acquire();
397
+ if (test_directory_.empty()) {
398
+ if (!::file_util::CreateNewTempDirectory(kLevelDBTestDirectoryPrefix,
399
+ &test_directory_)) {
400
+ mu_.Release();
401
+ return Status::IOError("Could not create temp directory.");
402
+ }
403
+ }
404
+ *path = FilePathToString(test_directory_);
405
+ mu_.Release();
406
+ return Status::OK();
407
+ }
408
+
409
+ virtual void Logv(WritableFile* info_log, const char* format, va_list ap) {
410
+ // TODO(jorlow): We may want to just use Chromium's built in logging.
411
+
412
+ uint64_t thread_id = 0;
413
+ // Coppied from base/logging.cc.
414
+ #if defined(OS_WIN)
415
+ thread_id = GetCurrentThreadId();
416
+ #elif defined(OS_MACOSX)
417
+ thread_id = mach_thread_self();
418
+ #elif defined(OS_LINUX)
419
+ thread_id = syscall(__NR_gettid);
420
+ #elif defined(OS_FREEBSD) || defined(OS_NACL)
421
+ // TODO(BSD): find a better thread ID
422
+ pthread_t tid = pthread_self();
423
+ memcpy(&thread_id, &tid, min(sizeof(r), sizeof(tid)));
424
+ #endif
425
+
426
+ // We try twice: the first time with a fixed-size stack allocated buffer,
427
+ // and the second time with a much larger dynamically allocated buffer.
428
+ char buffer[500];
429
+ for (int iter = 0; iter < 2; iter++) {
430
+ char* base;
431
+ int bufsize;
432
+ if (iter == 0) {
433
+ bufsize = sizeof(buffer);
434
+ base = buffer;
435
+ } else {
436
+ bufsize = 30000;
437
+ base = new char[bufsize];
438
+ }
439
+ char* p = base;
440
+ char* limit = base + bufsize;
441
+
442
+ ::base::Time::Exploded t;
443
+ ::base::Time::Now().LocalExplode(&t);
444
+ p += snprintf(p, limit - p,
445
+ "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ",
446
+ t.year,
447
+ t.month,
448
+ t.day_of_month,
449
+ t.hour,
450
+ t.minute,
451
+ t.second,
452
+ static_cast<int>(t.millisecond) * 1000,
453
+ static_cast<long long unsigned int>(thread_id));
454
+
455
+ // Print the message
456
+ if (p < limit) {
457
+ va_list backup_ap;
458
+ va_copy(backup_ap, ap);
459
+ p += vsnprintf(p, limit - p, format, backup_ap);
460
+ va_end(backup_ap);
461
+ }
462
+
463
+ // Truncate to available space if necessary
464
+ if (p >= limit) {
465
+ if (iter == 0) {
466
+ continue; // Try again with larger buffer
467
+ } else {
468
+ p = limit - 1;
469
+ }
470
+ }
471
+
472
+ // Add newline if necessary
473
+ if (p == base || p[-1] != '\n') {
474
+ *p++ = '\n';
475
+ }
476
+
477
+ assert(p <= limit);
478
+ info_log->Append(Slice(base, p - base));
479
+ info_log->Flush();
480
+ if (base != buffer) {
481
+ delete[] base;
482
+ }
483
+ break;
484
+ }
485
+ }
486
+
487
+ virtual int AppendLocalTimeToBuffer(char* buffer, size_t size) {
488
+ ::base::Time::Exploded t;
489
+ ::base::Time::Now().LocalExplode(&t);
490
+ return snprintf(buffer, size,
491
+ "%04d/%02d/%02d-%02d:%02d:%02d.%06d",
492
+ t.year,
493
+ t.month,
494
+ t.day_of_month,
495
+ t.hour,
496
+ t.minute,
497
+ t.second,
498
+ static_cast<int>(t.millisecond) * 1000);
499
+ }
500
+
501
+ virtual uint64_t NowMicros() {
502
+ return ::base::TimeTicks::HighResNow().ToInternalValue();
503
+ }
504
+
505
+ virtual void SleepForMicroseconds(int micros) {
506
+ // Round up to the next millisecond.
507
+ ::base::PlatformThread::Sleep((micros + 999) / 1000);
508
+ }
509
+
510
+ private:
511
+ // BGThread() is the body of the background thread
512
+ void BGThread();
513
+ static void BGThreadWrapper(void* arg) {
514
+ reinterpret_cast<ChromiumEnv*>(arg)->BGThread();
515
+ }
516
+
517
+ FilePath test_directory_;
518
+
519
+ size_t page_size_;
520
+ ::base::Lock mu_;
521
+ ::base::ConditionVariable bgsignal_;
522
+ bool started_bgthread_;
523
+
524
+ // Entry per Schedule() call
525
+ struct BGItem { void* arg; void (*function)(void*); };
526
+ typedef std::deque<BGItem> BGQueue;
527
+ BGQueue queue_;
528
+ };
529
+
530
+ ChromiumEnv::ChromiumEnv()
531
+ : page_size_(::base::SysInfo::VMAllocationGranularity()),
532
+ bgsignal_(&mu_),
533
+ started_bgthread_(false) {
534
+ #if defined(OS_MACOSX)
535
+ ::base::EnableTerminationOnHeapCorruption();
536
+ ::base::EnableTerminationOnOutOfMemory();
537
+ #endif // OS_MACOSX
538
+ }
539
+
540
+ class Thread : public ::base::PlatformThread::Delegate {
541
+ public:
542
+ Thread(void (*function)(void* arg), void* arg)
543
+ : function_(function), arg_(arg) {
544
+ ::base::PlatformThreadHandle handle;
545
+ bool success = ::base::PlatformThread::Create(0, this, &handle);
546
+ DCHECK(success);
547
+ }
548
+ virtual ~Thread() {}
549
+ virtual void ThreadMain() {
550
+ (*function_)(arg_);
551
+ delete this;
552
+ }
553
+
554
+ private:
555
+ void (*function_)(void* arg);
556
+ void* arg_;
557
+ };
558
+
559
+ void ChromiumEnv::Schedule(void (*function)(void*), void* arg) {
560
+ mu_.Acquire();
561
+
562
+ // Start background thread if necessary
563
+ if (!started_bgthread_) {
564
+ started_bgthread_ = true;
565
+ StartThread(&ChromiumEnv::BGThreadWrapper, this);
566
+ }
567
+
568
+ // If the queue is currently empty, the background thread may currently be
569
+ // waiting.
570
+ if (queue_.empty()) {
571
+ bgsignal_.Signal();
572
+ }
573
+
574
+ // Add to priority queue
575
+ queue_.push_back(BGItem());
576
+ queue_.back().function = function;
577
+ queue_.back().arg = arg;
578
+
579
+ mu_.Release();
580
+ }
581
+
582
+ void ChromiumEnv::BGThread() {
583
+ while (true) {
584
+ // Wait until there is an item that is ready to run
585
+ mu_.Acquire();
586
+ while (queue_.empty()) {
587
+ bgsignal_.Wait();
588
+ }
589
+
590
+ void (*function)(void*) = queue_.front().function;
591
+ void* arg = queue_.front().arg;
592
+ queue_.pop_front();
593
+
594
+ mu_.Release();
595
+ (*function)(arg);
596
+ }
597
+ }
598
+
599
+ void ChromiumEnv::StartThread(void (*function)(void* arg), void* arg) {
600
+ new Thread(function, arg); // Will self-delete.
601
+ }
602
+
603
+ ::base::LazyInstance<ChromiumEnv, ::base::LeakyLazyInstanceTraits<ChromiumEnv> >
604
+ default_env(::base::LINKER_INITIALIZED);
605
+
606
+ }
607
+
608
+ Env* Env::Default() {
609
+ return default_env.Pointer();
610
+ }
611
+
612
+ }