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.
- data/ext/leveldb/extconf.rb +2 -6
- data/ext/leveldb/leveldb.cc +377 -33
- data/ext/leveldb/platform.rb +83 -0
- data/leveldb/Makefile +29 -28
- data/leveldb/build_detect_platform +23 -4
- data/leveldb/db/builder.cc +1 -1
- data/leveldb/db/builder.h +1 -1
- data/leveldb/db/corruption_test.cc +1 -1
- data/leveldb/db/db_bench.cc +2 -2
- data/leveldb/db/db_impl.cc +8 -16
- data/leveldb/db/db_impl.h +1 -1
- data/leveldb/db/db_iter.cc +1 -1
- data/leveldb/db/db_iter.h +1 -1
- data/leveldb/db/db_test.cc +180 -9
- data/leveldb/db/dbformat.cc +9 -7
- data/leveldb/db/dbformat.h +2 -2
- data/leveldb/db/dbformat_test.cc +1 -1
- data/leveldb/db/filename.cc +6 -2
- data/leveldb/db/filename.h +1 -1
- data/leveldb/db/filename_test.cc +1 -1
- data/leveldb/db/log_format.h +2 -2
- data/leveldb/db/log_reader.cc +2 -2
- data/leveldb/db/log_reader.h +2 -2
- data/leveldb/db/log_test.cc +2 -2
- data/leveldb/db/log_writer.cc +2 -2
- data/leveldb/db/log_writer.h +2 -2
- data/leveldb/db/memtable.cc +1 -1
- data/leveldb/db/memtable.h +1 -1
- data/leveldb/db/repair.cc +2 -2
- data/leveldb/db/skiplist.h +1 -1
- data/leveldb/db/skiplist_test.cc +1 -1
- data/leveldb/db/snapshot.h +1 -1
- data/leveldb/db/table_cache.cc +1 -1
- data/leveldb/db/table_cache.h +1 -1
- data/leveldb/db/version_edit.cc +1 -1
- data/leveldb/db/version_edit.h +1 -1
- data/leveldb/db/version_edit_test.cc +1 -1
- data/leveldb/db/version_set.cc +39 -14
- data/leveldb/db/version_set.h +1 -1
- data/leveldb/db/version_set_test.cc +1 -1
- data/leveldb/db/write_batch.cc +2 -2
- data/leveldb/db/write_batch_internal.h +1 -1
- data/leveldb/db/write_batch_test.cc +1 -1
- data/leveldb/helpers/memenv/memenv.cc +374 -0
- data/leveldb/helpers/memenv/memenv.h +20 -0
- data/leveldb/helpers/memenv/memenv_test.cc +232 -0
- data/leveldb/include/leveldb/cache.h +1 -1
- data/leveldb/include/leveldb/comparator.h +1 -1
- data/leveldb/include/leveldb/db.h +1 -1
- data/leveldb/include/leveldb/env.h +1 -1
- data/leveldb/include/leveldb/iterator.h +1 -1
- data/leveldb/include/leveldb/options.h +1 -1
- data/leveldb/include/leveldb/slice.h +1 -1
- data/leveldb/include/leveldb/status.h +1 -1
- data/leveldb/include/leveldb/table.h +1 -1
- data/leveldb/include/leveldb/table_builder.h +1 -1
- data/leveldb/include/leveldb/write_batch.h +1 -1
- data/leveldb/port/atomic_pointer.h +2 -2
- data/leveldb/port/port_android.cc +2 -2
- data/leveldb/port/port_android.h +2 -2
- data/leveldb/port/port_example.h +2 -2
- data/leveldb/port/port_posix.cc +2 -2
- data/leveldb/port/port_posix.h +11 -3
- data/leveldb/table/block.cc +1 -1
- data/leveldb/table/block.h +1 -1
- data/leveldb/table/block_builder.cc +1 -1
- data/leveldb/table/block_builder.h +1 -1
- data/leveldb/table/format.cc +1 -1
- data/leveldb/table/format.h +1 -1
- data/leveldb/table/iterator.cc +2 -2
- data/leveldb/table/merger.cc +2 -2
- data/leveldb/table/merger.h +1 -1
- data/leveldb/table/table.cc +1 -1
- data/leveldb/table/table_builder.cc +1 -1
- data/leveldb/table/table_test.cc +3 -3
- data/leveldb/table/two_level_iterator.cc +2 -2
- data/leveldb/table/two_level_iterator.h +1 -1
- data/leveldb/util/arena.cc +1 -1
- data/leveldb/util/arena.h +1 -1
- data/leveldb/util/arena_test.cc +1 -1
- data/leveldb/util/cache.cc +1 -1
- data/leveldb/util/cache_test.cc +1 -1
- data/leveldb/util/coding.cc +1 -1
- data/leveldb/util/coding.h +1 -1
- data/leveldb/util/coding_test.cc +1 -1
- data/leveldb/util/comparator.cc +7 -4
- data/leveldb/util/crc32c.cc +2 -2
- data/leveldb/util/crc32c.h +2 -2
- data/leveldb/util/crc32c_test.cc +2 -2
- data/leveldb/util/env.cc +17 -3
- data/leveldb/util/env_posix.cc +2 -2
- data/leveldb/util/env_test.cc +13 -11
- data/leveldb/util/hash.cc +1 -1
- data/leveldb/util/histogram.cc +1 -1
- data/leveldb/util/histogram.h +1 -1
- data/leveldb/util/logging.cc +1 -1
- data/leveldb/util/logging.h +1 -1
- data/leveldb/util/mutexlock.h +1 -1
- data/leveldb/util/options.cc +1 -1
- data/leveldb/util/posix_logger.h +1 -1
- data/leveldb/util/random.h +1 -1
- data/leveldb/util/status.cc +1 -1
- data/leveldb/util/testharness.cc +2 -2
- data/leveldb/util/testharness.h +2 -2
- data/leveldb/util/testutil.cc +2 -2
- data/leveldb/util/testutil.h +2 -2
- data/lib/leveldb.rb +34 -2
- metadata +7 -13
- data/leveldb/port/port_chromium.cc +0 -80
- data/leveldb/port/port_chromium.h +0 -97
- data/leveldb/port/port_osx.cc +0 -50
- data/leveldb/port/port_osx.h +0 -125
- data/leveldb/port/sha1_portable.cc +0 -298
- data/leveldb/port/sha1_portable.h +0 -25
- data/leveldb/port/sha1_test.cc +0 -39
- 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_
|
data/leveldb/port/sha1_test.cc
DELETED
@@ -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
|
-
}
|