leveldb-ruby 0.10 → 0.11

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 (116) hide show
  1. data/ext/leveldb/extconf.rb +2 -6
  2. data/ext/leveldb/leveldb.cc +377 -33
  3. data/ext/leveldb/platform.rb +83 -0
  4. data/leveldb/Makefile +29 -28
  5. data/leveldb/build_detect_platform +23 -4
  6. data/leveldb/db/builder.cc +1 -1
  7. data/leveldb/db/builder.h +1 -1
  8. data/leveldb/db/corruption_test.cc +1 -1
  9. data/leveldb/db/db_bench.cc +2 -2
  10. data/leveldb/db/db_impl.cc +8 -16
  11. data/leveldb/db/db_impl.h +1 -1
  12. data/leveldb/db/db_iter.cc +1 -1
  13. data/leveldb/db/db_iter.h +1 -1
  14. data/leveldb/db/db_test.cc +180 -9
  15. data/leveldb/db/dbformat.cc +9 -7
  16. data/leveldb/db/dbformat.h +2 -2
  17. data/leveldb/db/dbformat_test.cc +1 -1
  18. data/leveldb/db/filename.cc +6 -2
  19. data/leveldb/db/filename.h +1 -1
  20. data/leveldb/db/filename_test.cc +1 -1
  21. data/leveldb/db/log_format.h +2 -2
  22. data/leveldb/db/log_reader.cc +2 -2
  23. data/leveldb/db/log_reader.h +2 -2
  24. data/leveldb/db/log_test.cc +2 -2
  25. data/leveldb/db/log_writer.cc +2 -2
  26. data/leveldb/db/log_writer.h +2 -2
  27. data/leveldb/db/memtable.cc +1 -1
  28. data/leveldb/db/memtable.h +1 -1
  29. data/leveldb/db/repair.cc +2 -2
  30. data/leveldb/db/skiplist.h +1 -1
  31. data/leveldb/db/skiplist_test.cc +1 -1
  32. data/leveldb/db/snapshot.h +1 -1
  33. data/leveldb/db/table_cache.cc +1 -1
  34. data/leveldb/db/table_cache.h +1 -1
  35. data/leveldb/db/version_edit.cc +1 -1
  36. data/leveldb/db/version_edit.h +1 -1
  37. data/leveldb/db/version_edit_test.cc +1 -1
  38. data/leveldb/db/version_set.cc +39 -14
  39. data/leveldb/db/version_set.h +1 -1
  40. data/leveldb/db/version_set_test.cc +1 -1
  41. data/leveldb/db/write_batch.cc +2 -2
  42. data/leveldb/db/write_batch_internal.h +1 -1
  43. data/leveldb/db/write_batch_test.cc +1 -1
  44. data/leveldb/helpers/memenv/memenv.cc +374 -0
  45. data/leveldb/helpers/memenv/memenv.h +20 -0
  46. data/leveldb/helpers/memenv/memenv_test.cc +232 -0
  47. data/leveldb/include/leveldb/cache.h +1 -1
  48. data/leveldb/include/leveldb/comparator.h +1 -1
  49. data/leveldb/include/leveldb/db.h +1 -1
  50. data/leveldb/include/leveldb/env.h +1 -1
  51. data/leveldb/include/leveldb/iterator.h +1 -1
  52. data/leveldb/include/leveldb/options.h +1 -1
  53. data/leveldb/include/leveldb/slice.h +1 -1
  54. data/leveldb/include/leveldb/status.h +1 -1
  55. data/leveldb/include/leveldb/table.h +1 -1
  56. data/leveldb/include/leveldb/table_builder.h +1 -1
  57. data/leveldb/include/leveldb/write_batch.h +1 -1
  58. data/leveldb/port/atomic_pointer.h +2 -2
  59. data/leveldb/port/port_android.cc +2 -2
  60. data/leveldb/port/port_android.h +2 -2
  61. data/leveldb/port/port_example.h +2 -2
  62. data/leveldb/port/port_posix.cc +2 -2
  63. data/leveldb/port/port_posix.h +11 -3
  64. data/leveldb/table/block.cc +1 -1
  65. data/leveldb/table/block.h +1 -1
  66. data/leveldb/table/block_builder.cc +1 -1
  67. data/leveldb/table/block_builder.h +1 -1
  68. data/leveldb/table/format.cc +1 -1
  69. data/leveldb/table/format.h +1 -1
  70. data/leveldb/table/iterator.cc +2 -2
  71. data/leveldb/table/merger.cc +2 -2
  72. data/leveldb/table/merger.h +1 -1
  73. data/leveldb/table/table.cc +1 -1
  74. data/leveldb/table/table_builder.cc +1 -1
  75. data/leveldb/table/table_test.cc +3 -3
  76. data/leveldb/table/two_level_iterator.cc +2 -2
  77. data/leveldb/table/two_level_iterator.h +1 -1
  78. data/leveldb/util/arena.cc +1 -1
  79. data/leveldb/util/arena.h +1 -1
  80. data/leveldb/util/arena_test.cc +1 -1
  81. data/leveldb/util/cache.cc +1 -1
  82. data/leveldb/util/cache_test.cc +1 -1
  83. data/leveldb/util/coding.cc +1 -1
  84. data/leveldb/util/coding.h +1 -1
  85. data/leveldb/util/coding_test.cc +1 -1
  86. data/leveldb/util/comparator.cc +7 -4
  87. data/leveldb/util/crc32c.cc +2 -2
  88. data/leveldb/util/crc32c.h +2 -2
  89. data/leveldb/util/crc32c_test.cc +2 -2
  90. data/leveldb/util/env.cc +17 -3
  91. data/leveldb/util/env_posix.cc +2 -2
  92. data/leveldb/util/env_test.cc +13 -11
  93. data/leveldb/util/hash.cc +1 -1
  94. data/leveldb/util/histogram.cc +1 -1
  95. data/leveldb/util/histogram.h +1 -1
  96. data/leveldb/util/logging.cc +1 -1
  97. data/leveldb/util/logging.h +1 -1
  98. data/leveldb/util/mutexlock.h +1 -1
  99. data/leveldb/util/options.cc +1 -1
  100. data/leveldb/util/posix_logger.h +1 -1
  101. data/leveldb/util/random.h +1 -1
  102. data/leveldb/util/status.cc +1 -1
  103. data/leveldb/util/testharness.cc +2 -2
  104. data/leveldb/util/testharness.h +2 -2
  105. data/leveldb/util/testutil.cc +2 -2
  106. data/leveldb/util/testutil.h +2 -2
  107. data/lib/leveldb.rb +34 -2
  108. metadata +7 -13
  109. data/leveldb/port/port_chromium.cc +0 -80
  110. data/leveldb/port/port_chromium.h +0 -97
  111. data/leveldb/port/port_osx.cc +0 -50
  112. data/leveldb/port/port_osx.h +0 -125
  113. data/leveldb/port/sha1_portable.cc +0 -298
  114. data/leveldb/port/sha1_portable.h +0 -25
  115. data/leveldb/port/sha1_test.cc +0 -39
  116. data/leveldb/util/env_chromium.cc +0 -612
@@ -1,298 +0,0 @@
1
- // Portions 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
- // This module provides a slow but portable implementation of
6
- // the SHA1 hash function.
7
- //
8
- // It is adapted from free code written by Paul E. Jones
9
- // <paulej@packetizer.com>. See http://www.packetizer.com/security/sha1/
10
- //
11
- // The license for the original code is:
12
- /*
13
- Copyright (C) 1998, 2009
14
- Paul E. Jones <paulej@packetizer.com>
15
-
16
- Freeware Public License (FPL)
17
-
18
- This software is licensed as "freeware." Permission to distribute
19
- this software in source and binary forms, including incorporation
20
- into other products, is hereby granted without a fee. THIS SOFTWARE
21
- IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED OR IMPLIED WARRANTIES,
22
- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
23
- AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHOR SHALL NOT BE HELD
24
- LIABLE FOR ANY DAMAGES RESULTING FROM THE USE OF THIS SOFTWARE, EITHER
25
- DIRECTLY OR INDIRECTLY, INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA
26
- OR DATA BEING RENDERED INACCURATE.
27
- */
28
-
29
- #include "port/sha1_portable.h"
30
- #include <stdio.h>
31
- #include <stdlib.h>
32
- #include <stdint.h>
33
-
34
- namespace leveldb {
35
- namespace port {
36
-
37
- /*
38
- * Description:
39
- * This class implements the Secure Hashing Standard as defined
40
- * in FIPS PUB 180-1 published April 17, 1995.
41
- */
42
-
43
- /*
44
- * This structure will hold context information for the hashing
45
- * operation
46
- */
47
- typedef struct SHA1Context {
48
- unsigned Message_Digest[5]; /* Message Digest (output) */
49
-
50
- unsigned Length_Low; /* Message length in bits */
51
- unsigned Length_High; /* Message length in bits */
52
-
53
- unsigned char Message_Block[64]; /* 512-bit message blocks */
54
- int Message_Block_Index; /* Index into message block array */
55
-
56
- bool Computed; /* Is the digest computed? */
57
- bool Corrupted; /* Is the message digest corruped? */
58
- } SHA1Context;
59
-
60
- /*
61
- * Portability Issues:
62
- * SHA-1 is defined in terms of 32-bit "words". This code was
63
- * written with the expectation that the processor has at least
64
- * a 32-bit machine word size. If the machine word size is larger,
65
- * the code should still function properly. One caveat to that
66
- * is that the input functions taking characters and character
67
- * arrays assume that only 8 bits of information are stored in each
68
- * character.
69
- */
70
-
71
- /*
72
- * Define the circular shift macro
73
- */
74
- #define SHA1CircularShift(bits,word) \
75
- ((((word) << (bits)) & 0xFFFFFFFF) | \
76
- ((word) >> (32-(bits))))
77
-
78
- /* Function prototypes */
79
- static void SHA1ProcessMessageBlock(SHA1Context *);
80
- static void SHA1PadMessage(SHA1Context *);
81
-
82
- // Initialize the SHA1Context in preparation for computing a new
83
- // message digest.
84
- static void SHA1Reset(SHA1Context* context) {
85
- context->Length_Low = 0;
86
- context->Length_High = 0;
87
- context->Message_Block_Index = 0;
88
-
89
- context->Message_Digest[0] = 0x67452301;
90
- context->Message_Digest[1] = 0xEFCDAB89;
91
- context->Message_Digest[2] = 0x98BADCFE;
92
- context->Message_Digest[3] = 0x10325476;
93
- context->Message_Digest[4] = 0xC3D2E1F0;
94
-
95
- context->Computed = false;
96
- context->Corrupted = false;
97
- }
98
-
99
- // This function will return the 160-bit message digest into the
100
- // Message_Digest array within the SHA1Context provided
101
- static bool SHA1Result(SHA1Context *context) {
102
- if (context->Corrupted) {
103
- return false;
104
- }
105
-
106
- if (!context->Computed) {
107
- SHA1PadMessage(context);
108
- context->Computed = true;
109
- }
110
- return true;
111
- }
112
-
113
- // This function accepts an array of bytes as the next portion of
114
- // the message.
115
- static void SHA1Input(SHA1Context *context,
116
- const unsigned char *message_array,
117
- unsigned length) {
118
- if (!length) return;
119
-
120
- if (context->Computed || context->Corrupted) {
121
- context->Corrupted = true;
122
- return;
123
- }
124
-
125
- while(length-- && !context->Corrupted) {
126
- context->Message_Block[context->Message_Block_Index++] =
127
- (*message_array & 0xFF);
128
-
129
- context->Length_Low += 8;
130
- /* Force it to 32 bits */
131
- context->Length_Low &= 0xFFFFFFFF;
132
- if (context->Length_Low == 0) {
133
- context->Length_High++;
134
- /* Force it to 32 bits */
135
- context->Length_High &= 0xFFFFFFFF;
136
- if (context->Length_High == 0)
137
- {
138
- /* Message is too long */
139
- context->Corrupted = true;
140
- }
141
- }
142
-
143
- if (context->Message_Block_Index == 64)
144
- {
145
- SHA1ProcessMessageBlock(context);
146
- }
147
-
148
- message_array++;
149
- }
150
- }
151
-
152
- // This function will process the next 512 bits of the message stored
153
- // in the Message_Block array.
154
- static void SHA1ProcessMessageBlock(SHA1Context *context) {
155
- const unsigned K[] = // Constants defined in SHA-1
156
- {
157
- 0x5A827999,
158
- 0x6ED9EBA1,
159
- 0x8F1BBCDC,
160
- 0xCA62C1D6
161
- };
162
- int t; // Loop counter
163
- unsigned temp; // Temporary word value
164
- unsigned W[80]; // Word sequence
165
- unsigned A, B, C, D, E; // Word buffers
166
-
167
- // Initialize the first 16 words in the array W
168
- for(t = 0; t < 16; t++) {
169
- W[t] = ((unsigned) context->Message_Block[t * 4]) << 24;
170
- W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16;
171
- W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8;
172
- W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]);
173
- }
174
-
175
- for(t = 16; t < 80; t++) {
176
- W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
177
- }
178
-
179
- A = context->Message_Digest[0];
180
- B = context->Message_Digest[1];
181
- C = context->Message_Digest[2];
182
- D = context->Message_Digest[3];
183
- E = context->Message_Digest[4];
184
-
185
- for(t = 0; t < 20; t++) {
186
- temp = SHA1CircularShift(5,A) +
187
- ((B & C) | ((~B) & D)) + E + W[t] + K[0];
188
- temp &= 0xFFFFFFFF;
189
- E = D;
190
- D = C;
191
- C = SHA1CircularShift(30,B);
192
- B = A;
193
- A = temp;
194
- }
195
-
196
- for(t = 20; t < 40; t++) {
197
- temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
198
- temp &= 0xFFFFFFFF;
199
- E = D;
200
- D = C;
201
- C = SHA1CircularShift(30,B);
202
- B = A;
203
- A = temp;
204
- }
205
-
206
- for(t = 40; t < 60; t++) {
207
- temp = SHA1CircularShift(5,A) +
208
- ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
209
- temp &= 0xFFFFFFFF;
210
- E = D;
211
- D = C;
212
- C = SHA1CircularShift(30,B);
213
- B = A;
214
- A = temp;
215
- }
216
-
217
- for(t = 60; t < 80; t++) {
218
- temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
219
- temp &= 0xFFFFFFFF;
220
- E = D;
221
- D = C;
222
- C = SHA1CircularShift(30,B);
223
- B = A;
224
- A = temp;
225
- }
226
-
227
- context->Message_Digest[0] = (context->Message_Digest[0] + A) & 0xFFFFFFFF;
228
- context->Message_Digest[1] = (context->Message_Digest[1] + B) & 0xFFFFFFFF;
229
- context->Message_Digest[2] = (context->Message_Digest[2] + C) & 0xFFFFFFFF;
230
- context->Message_Digest[3] = (context->Message_Digest[3] + D) & 0xFFFFFFFF;
231
- context->Message_Digest[4] = (context->Message_Digest[4] + E) & 0xFFFFFFFF;
232
-
233
- context->Message_Block_Index = 0;
234
- }
235
-
236
- // According to the standard, the message must be padded to an even
237
- // 512 bits. The first padding bit must be a '1'. The last 64 bits
238
- // represent the length of the original message. All bits in between
239
- // should be 0. This function will pad the message according to those
240
- // rules by filling the Message_Block array accordingly. It will also
241
- // call SHA1ProcessMessageBlock() appropriately. When it returns, it
242
- // can be assumed that the message digest has been computed.
243
- static void SHA1PadMessage(SHA1Context *context) {
244
- // Check to see if the current message block is too small to hold
245
- // the initial padding bits and length. If so, we will pad the
246
- // block, process it, and then continue padding into a second block.
247
- if (context->Message_Block_Index > 55) {
248
- context->Message_Block[context->Message_Block_Index++] = 0x80;
249
- while(context->Message_Block_Index < 64) {
250
- context->Message_Block[context->Message_Block_Index++] = 0;
251
- }
252
-
253
- SHA1ProcessMessageBlock(context);
254
-
255
- while(context->Message_Block_Index < 56) {
256
- context->Message_Block[context->Message_Block_Index++] = 0;
257
- }
258
- } else {
259
- context->Message_Block[context->Message_Block_Index++] = 0x80;
260
- while(context->Message_Block_Index < 56) {
261
- context->Message_Block[context->Message_Block_Index++] = 0;
262
- }
263
- }
264
-
265
- // Store the message length as the last 8 octets
266
- context->Message_Block[56] = (context->Length_High >> 24) & 0xFF;
267
- context->Message_Block[57] = (context->Length_High >> 16) & 0xFF;
268
- context->Message_Block[58] = (context->Length_High >> 8) & 0xFF;
269
- context->Message_Block[59] = (context->Length_High) & 0xFF;
270
- context->Message_Block[60] = (context->Length_Low >> 24) & 0xFF;
271
- context->Message_Block[61] = (context->Length_Low >> 16) & 0xFF;
272
- context->Message_Block[62] = (context->Length_Low >> 8) & 0xFF;
273
- context->Message_Block[63] = (context->Length_Low) & 0xFF;
274
-
275
- SHA1ProcessMessageBlock(context);
276
- }
277
-
278
-
279
- void SHA1_Hash_Portable(const char* data, size_t len, char* hash_array) {
280
- SHA1Context context;
281
- SHA1Reset(&context);
282
- SHA1Input(&context, reinterpret_cast<const unsigned char*>(data), len);
283
- bool ok = SHA1Result(&context);
284
- if (!ok) {
285
- fprintf(stderr, "Unexpected error in SHA1_Hash_Portable code\n");
286
- exit(1);
287
- }
288
- for (int i = 0; i < 5; i++) {
289
- uint32_t value = context.Message_Digest[i];
290
- hash_array[i*4 + 0] = (value >> 24) & 0xff;
291
- hash_array[i*4 + 1] = (value >> 16) & 0xff;
292
- hash_array[i*4 + 2] = (value >> 8) & 0xff;
293
- hash_array[i*4 + 3] = value & 0xff;
294
- }
295
- }
296
-
297
- }
298
- }
@@ -1,25 +0,0 @@
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_PORT_SHA1_PORTABLE_H_
6
- #define STORAGE_LEVELDB_PORT_SHA1_PORTABLE_H_
7
-
8
- #include <stddef.h>
9
-
10
- namespace leveldb {
11
- namespace port {
12
-
13
- // Compute the SHA1 hash value of "data[0..len-1]" and store it in
14
- // "hash_array[0..19]". hash_array must have 20 bytes of space available.
15
- //
16
- // This function is portable but may not be as fast as a version
17
- // optimized for your platform. It is provided as a default method
18
- // that can be used when porting leveldb to a new platform if no
19
- // better SHA1 hash implementation is available.
20
- void SHA1_Hash_Portable(const char* data, size_t len, char* hash_array);
21
-
22
- }
23
- }
24
-
25
- #endif // STORAGE_LEVELDB_PORT_SHA1_PORTABLE_H_
@@ -1,39 +0,0 @@
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 "port/port.h"
6
- #include "util/testharness.h"
7
-
8
- namespace leveldb {
9
- namespace port {
10
-
11
- class SHA1 { };
12
-
13
- static std::string TestSHA1(const char* data, size_t len) {
14
- char hash_val[20];
15
- SHA1_Hash(data, len, hash_val);
16
- char buf[41];
17
- for (int i = 0; i < 20; i++) {
18
- snprintf(buf + i * 2, 41 - i * 2,
19
- "%02x",
20
- static_cast<unsigned int>(static_cast<unsigned char>(
21
- hash_val[i])));
22
- }
23
- return std::string(buf, 40);
24
- }
25
-
26
- TEST(SHA1, Simple) {
27
- ASSERT_EQ("da39a3ee5e6b4b0d3255bfef95601890afd80709", TestSHA1("", 0));
28
- ASSERT_EQ("aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d", TestSHA1("hello", 5));
29
- std::string x(10000, 'x');
30
- ASSERT_EQ("f8c5cde791c5056cf515881e701c8a9ecb439a75",
31
- TestSHA1(x.data(), x.size()));
32
- }
33
-
34
- }
35
- }
36
-
37
- int main(int argc, char** argv) {
38
- return leveldb::test::RunAllTests();
39
- }
@@ -1,612 +0,0 @@
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
- }