filiptepper-leveldb-ruby 0.14
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +24 -0
- data/README +72 -0
- data/ext/leveldb/extconf.rb +14 -0
- data/ext/leveldb/leveldb.cc +530 -0
- data/ext/leveldb/platform.rb +83 -0
- data/leveldb/Makefile +191 -0
- data/leveldb/build_detect_platform +160 -0
- data/leveldb/db/builder.cc +88 -0
- data/leveldb/db/builder.h +34 -0
- data/leveldb/db/c.cc +581 -0
- data/leveldb/db/corruption_test.cc +359 -0
- data/leveldb/db/db_bench.cc +970 -0
- data/leveldb/db/db_impl.cc +1448 -0
- data/leveldb/db/db_impl.h +194 -0
- data/leveldb/db/db_iter.cc +299 -0
- data/leveldb/db/db_iter.h +26 -0
- data/leveldb/db/db_test.cc +1901 -0
- data/leveldb/db/dbformat.cc +140 -0
- data/leveldb/db/dbformat.h +227 -0
- data/leveldb/db/dbformat_test.cc +112 -0
- data/leveldb/db/filename.cc +139 -0
- data/leveldb/db/filename.h +80 -0
- data/leveldb/db/filename_test.cc +122 -0
- data/leveldb/db/log_format.h +35 -0
- data/leveldb/db/log_reader.cc +259 -0
- data/leveldb/db/log_reader.h +108 -0
- data/leveldb/db/log_test.cc +500 -0
- data/leveldb/db/log_writer.cc +103 -0
- data/leveldb/db/log_writer.h +48 -0
- data/leveldb/db/memtable.cc +145 -0
- data/leveldb/db/memtable.h +91 -0
- data/leveldb/db/repair.cc +389 -0
- data/leveldb/db/skiplist.h +379 -0
- data/leveldb/db/skiplist_test.cc +378 -0
- data/leveldb/db/snapshot.h +66 -0
- data/leveldb/db/table_cache.cc +121 -0
- data/leveldb/db/table_cache.h +61 -0
- data/leveldb/db/version_edit.cc +266 -0
- data/leveldb/db/version_edit.h +107 -0
- data/leveldb/db/version_edit_test.cc +46 -0
- data/leveldb/db/version_set.cc +1402 -0
- data/leveldb/db/version_set.h +370 -0
- data/leveldb/db/version_set_test.cc +179 -0
- data/leveldb/db/write_batch.cc +147 -0
- data/leveldb/db/write_batch_internal.h +49 -0
- data/leveldb/db/write_batch_test.cc +120 -0
- 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/c.h +275 -0
- data/leveldb/include/leveldb/cache.h +99 -0
- data/leveldb/include/leveldb/comparator.h +63 -0
- data/leveldb/include/leveldb/db.h +161 -0
- data/leveldb/include/leveldb/env.h +323 -0
- data/leveldb/include/leveldb/filter_policy.h +70 -0
- data/leveldb/include/leveldb/iterator.h +100 -0
- data/leveldb/include/leveldb/options.h +195 -0
- data/leveldb/include/leveldb/slice.h +109 -0
- data/leveldb/include/leveldb/status.h +106 -0
- data/leveldb/include/leveldb/table.h +85 -0
- data/leveldb/include/leveldb/table_builder.h +92 -0
- data/leveldb/include/leveldb/write_batch.h +64 -0
- data/leveldb/port/atomic_pointer.h +144 -0
- data/leveldb/port/port.h +21 -0
- data/leveldb/port/port_android.cc +64 -0
- data/leveldb/port/port_android.h +159 -0
- data/leveldb/port/port_example.h +125 -0
- data/leveldb/port/port_posix.cc +50 -0
- data/leveldb/port/port_posix.h +129 -0
- data/leveldb/port/win/stdint.h +24 -0
- data/leveldb/table/block.cc +267 -0
- data/leveldb/table/block.h +44 -0
- data/leveldb/table/block_builder.cc +109 -0
- data/leveldb/table/block_builder.h +57 -0
- data/leveldb/table/filter_block.cc +111 -0
- data/leveldb/table/filter_block.h +68 -0
- data/leveldb/table/filter_block_test.cc +128 -0
- data/leveldb/table/format.cc +145 -0
- data/leveldb/table/format.h +108 -0
- data/leveldb/table/iterator.cc +67 -0
- data/leveldb/table/iterator_wrapper.h +63 -0
- data/leveldb/table/merger.cc +197 -0
- data/leveldb/table/merger.h +26 -0
- data/leveldb/table/table.cc +276 -0
- data/leveldb/table/table_builder.cc +270 -0
- data/leveldb/table/table_test.cc +838 -0
- data/leveldb/table/two_level_iterator.cc +182 -0
- data/leveldb/table/two_level_iterator.h +34 -0
- data/leveldb/util/arena.cc +68 -0
- data/leveldb/util/arena.h +68 -0
- data/leveldb/util/arena_test.cc +68 -0
- data/leveldb/util/bloom.cc +95 -0
- data/leveldb/util/bloom_test.cc +159 -0
- data/leveldb/util/cache.cc +328 -0
- data/leveldb/util/cache_test.cc +186 -0
- data/leveldb/util/coding.cc +194 -0
- data/leveldb/util/coding.h +104 -0
- data/leveldb/util/coding_test.cc +173 -0
- data/leveldb/util/comparator.cc +76 -0
- data/leveldb/util/crc32c.cc +332 -0
- data/leveldb/util/crc32c.h +45 -0
- data/leveldb/util/crc32c_test.cc +72 -0
- data/leveldb/util/env.cc +96 -0
- data/leveldb/util/env_posix.cc +609 -0
- data/leveldb/util/env_test.cc +104 -0
- data/leveldb/util/filter_policy.cc +11 -0
- data/leveldb/util/hash.cc +45 -0
- data/leveldb/util/hash.h +19 -0
- data/leveldb/util/histogram.cc +139 -0
- data/leveldb/util/histogram.h +42 -0
- data/leveldb/util/logging.cc +81 -0
- data/leveldb/util/logging.h +47 -0
- data/leveldb/util/mutexlock.h +39 -0
- data/leveldb/util/options.cc +29 -0
- data/leveldb/util/posix_logger.h +98 -0
- data/leveldb/util/random.h +59 -0
- data/leveldb/util/status.cc +75 -0
- data/leveldb/util/testharness.cc +77 -0
- data/leveldb/util/testharness.h +138 -0
- data/leveldb/util/testutil.cc +51 -0
- data/leveldb/util/testutil.h +53 -0
- data/lib/leveldb.rb +76 -0
- metadata +175 -0
@@ -0,0 +1,47 @@
|
|
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
|
+
// Must not be included from any .h files to avoid polluting the namespace
|
6
|
+
// with macros.
|
7
|
+
|
8
|
+
#ifndef STORAGE_LEVELDB_UTIL_LOGGING_H_
|
9
|
+
#define STORAGE_LEVELDB_UTIL_LOGGING_H_
|
10
|
+
|
11
|
+
#include <stdio.h>
|
12
|
+
#include <stdint.h>
|
13
|
+
#include <string>
|
14
|
+
#include "port/port.h"
|
15
|
+
|
16
|
+
namespace leveldb {
|
17
|
+
|
18
|
+
class Slice;
|
19
|
+
class WritableFile;
|
20
|
+
|
21
|
+
// Append a human-readable printout of "num" to *str
|
22
|
+
extern void AppendNumberTo(std::string* str, uint64_t num);
|
23
|
+
|
24
|
+
// Append a human-readable printout of "value" to *str.
|
25
|
+
// Escapes any non-printable characters found in "value".
|
26
|
+
extern void AppendEscapedStringTo(std::string* str, const Slice& value);
|
27
|
+
|
28
|
+
// Return a human-readable printout of "num"
|
29
|
+
extern std::string NumberToString(uint64_t num);
|
30
|
+
|
31
|
+
// Return a human-readable version of "value".
|
32
|
+
// Escapes any non-printable characters found in "value".
|
33
|
+
extern std::string EscapeString(const Slice& value);
|
34
|
+
|
35
|
+
// If *in starts with "c", advances *in past the first character and
|
36
|
+
// returns true. Otherwise, returns false.
|
37
|
+
extern bool ConsumeChar(Slice* in, char c);
|
38
|
+
|
39
|
+
// Parse a human-readable number from "*in" into *value. On success,
|
40
|
+
// advances "*in" past the consumed number and sets "*val" to the
|
41
|
+
// numeric value. Otherwise, returns false and leaves *in in an
|
42
|
+
// unspecified state.
|
43
|
+
extern bool ConsumeDecimalNumber(Slice* in, uint64_t* val);
|
44
|
+
|
45
|
+
} // namespace leveldb
|
46
|
+
|
47
|
+
#endif // STORAGE_LEVELDB_UTIL_LOGGING_H_
|
@@ -0,0 +1,39 @@
|
|
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_MUTEXLOCK_H_
|
6
|
+
#define STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_
|
7
|
+
|
8
|
+
#include "port/port.h"
|
9
|
+
|
10
|
+
namespace leveldb {
|
11
|
+
|
12
|
+
// Helper class that locks a mutex on construction and unlocks the mutex when
|
13
|
+
// the destructor of the MutexLock object is invoked.
|
14
|
+
//
|
15
|
+
// Typical usage:
|
16
|
+
//
|
17
|
+
// void MyClass::MyMethod() {
|
18
|
+
// MutexLock l(&mu_); // mu_ is an instance variable
|
19
|
+
// ... some complex code, possibly with multiple return paths ...
|
20
|
+
// }
|
21
|
+
|
22
|
+
class MutexLock {
|
23
|
+
public:
|
24
|
+
explicit MutexLock(port::Mutex *mu) : mu_(mu) {
|
25
|
+
this->mu_->Lock();
|
26
|
+
}
|
27
|
+
~MutexLock() { this->mu_->Unlock(); }
|
28
|
+
|
29
|
+
private:
|
30
|
+
port::Mutex *const mu_;
|
31
|
+
// No copying allowed
|
32
|
+
MutexLock(const MutexLock&);
|
33
|
+
void operator=(const MutexLock&);
|
34
|
+
};
|
35
|
+
|
36
|
+
} // namespace leveldb
|
37
|
+
|
38
|
+
|
39
|
+
#endif // STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_
|
@@ -0,0 +1,29 @@
|
|
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/options.h"
|
6
|
+
|
7
|
+
#include "leveldb/comparator.h"
|
8
|
+
#include "leveldb/env.h"
|
9
|
+
|
10
|
+
namespace leveldb {
|
11
|
+
|
12
|
+
Options::Options()
|
13
|
+
: comparator(BytewiseComparator()),
|
14
|
+
create_if_missing(false),
|
15
|
+
error_if_exists(false),
|
16
|
+
paranoid_checks(false),
|
17
|
+
env(Env::Default()),
|
18
|
+
info_log(NULL),
|
19
|
+
write_buffer_size(4<<20),
|
20
|
+
max_open_files(1000),
|
21
|
+
block_cache(NULL),
|
22
|
+
block_size(4096),
|
23
|
+
block_restart_interval(16),
|
24
|
+
compression(kSnappyCompression),
|
25
|
+
filter_policy(NULL) {
|
26
|
+
}
|
27
|
+
|
28
|
+
|
29
|
+
} // namespace leveldb
|
@@ -0,0 +1,98 @@
|
|
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
|
+
// Logger implementation that can be shared by all environments
|
6
|
+
// where enough posix functionality is available.
|
7
|
+
|
8
|
+
#ifndef STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_
|
9
|
+
#define STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_
|
10
|
+
|
11
|
+
#include <algorithm>
|
12
|
+
#include <stdio.h>
|
13
|
+
#include <sys/time.h>
|
14
|
+
#include <time.h>
|
15
|
+
#include "leveldb/env.h"
|
16
|
+
|
17
|
+
namespace leveldb {
|
18
|
+
|
19
|
+
class PosixLogger : public Logger {
|
20
|
+
private:
|
21
|
+
FILE* file_;
|
22
|
+
uint64_t (*gettid_)(); // Return the thread id for the current thread
|
23
|
+
public:
|
24
|
+
PosixLogger(FILE* f, uint64_t (*gettid)()) : file_(f), gettid_(gettid) { }
|
25
|
+
virtual ~PosixLogger() {
|
26
|
+
fclose(file_);
|
27
|
+
}
|
28
|
+
virtual void Logv(const char* format, va_list ap) {
|
29
|
+
const uint64_t thread_id = (*gettid_)();
|
30
|
+
|
31
|
+
// We try twice: the first time with a fixed-size stack allocated buffer,
|
32
|
+
// and the second time with a much larger dynamically allocated buffer.
|
33
|
+
char buffer[500];
|
34
|
+
for (int iter = 0; iter < 2; iter++) {
|
35
|
+
char* base;
|
36
|
+
int bufsize;
|
37
|
+
if (iter == 0) {
|
38
|
+
bufsize = sizeof(buffer);
|
39
|
+
base = buffer;
|
40
|
+
} else {
|
41
|
+
bufsize = 30000;
|
42
|
+
base = new char[bufsize];
|
43
|
+
}
|
44
|
+
char* p = base;
|
45
|
+
char* limit = base + bufsize;
|
46
|
+
|
47
|
+
struct timeval now_tv;
|
48
|
+
gettimeofday(&now_tv, NULL);
|
49
|
+
const time_t seconds = now_tv.tv_sec;
|
50
|
+
struct tm t;
|
51
|
+
localtime_r(&seconds, &t);
|
52
|
+
p += snprintf(p, limit - p,
|
53
|
+
"%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ",
|
54
|
+
t.tm_year + 1900,
|
55
|
+
t.tm_mon + 1,
|
56
|
+
t.tm_mday,
|
57
|
+
t.tm_hour,
|
58
|
+
t.tm_min,
|
59
|
+
t.tm_sec,
|
60
|
+
static_cast<int>(now_tv.tv_usec),
|
61
|
+
static_cast<long long unsigned int>(thread_id));
|
62
|
+
|
63
|
+
// Print the message
|
64
|
+
if (p < limit) {
|
65
|
+
va_list backup_ap;
|
66
|
+
va_copy(backup_ap, ap);
|
67
|
+
p += vsnprintf(p, limit - p, format, backup_ap);
|
68
|
+
va_end(backup_ap);
|
69
|
+
}
|
70
|
+
|
71
|
+
// Truncate to available space if necessary
|
72
|
+
if (p >= limit) {
|
73
|
+
if (iter == 0) {
|
74
|
+
continue; // Try again with larger buffer
|
75
|
+
} else {
|
76
|
+
p = limit - 1;
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
// Add newline if necessary
|
81
|
+
if (p == base || p[-1] != '\n') {
|
82
|
+
*p++ = '\n';
|
83
|
+
}
|
84
|
+
|
85
|
+
assert(p <= limit);
|
86
|
+
fwrite(base, 1, p - base, file_);
|
87
|
+
fflush(file_);
|
88
|
+
if (base != buffer) {
|
89
|
+
delete[] base;
|
90
|
+
}
|
91
|
+
break;
|
92
|
+
}
|
93
|
+
}
|
94
|
+
};
|
95
|
+
|
96
|
+
} // namespace leveldb
|
97
|
+
|
98
|
+
#endif // STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_
|
@@ -0,0 +1,59 @@
|
|
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_RANDOM_H_
|
6
|
+
#define STORAGE_LEVELDB_UTIL_RANDOM_H_
|
7
|
+
|
8
|
+
#include <stdint.h>
|
9
|
+
|
10
|
+
namespace leveldb {
|
11
|
+
|
12
|
+
// A very simple random number generator. Not especially good at
|
13
|
+
// generating truly random bits, but good enough for our needs in this
|
14
|
+
// package.
|
15
|
+
class Random {
|
16
|
+
private:
|
17
|
+
uint32_t seed_;
|
18
|
+
public:
|
19
|
+
explicit Random(uint32_t s) : seed_(s & 0x7fffffffu) { }
|
20
|
+
uint32_t Next() {
|
21
|
+
static const uint32_t M = 2147483647L; // 2^31-1
|
22
|
+
static const uint64_t A = 16807; // bits 14, 8, 7, 5, 2, 1, 0
|
23
|
+
// We are computing
|
24
|
+
// seed_ = (seed_ * A) % M, where M = 2^31-1
|
25
|
+
//
|
26
|
+
// seed_ must not be zero or M, or else all subsequent computed values
|
27
|
+
// will be zero or M respectively. For all other values, seed_ will end
|
28
|
+
// up cycling through every number in [1,M-1]
|
29
|
+
uint64_t product = seed_ * A;
|
30
|
+
|
31
|
+
// Compute (product % M) using the fact that ((x << 31) % M) == x.
|
32
|
+
seed_ = static_cast<uint32_t>((product >> 31) + (product & M));
|
33
|
+
// The first reduction may overflow by 1 bit, so we may need to
|
34
|
+
// repeat. mod == M is not possible; using > allows the faster
|
35
|
+
// sign-bit-based test.
|
36
|
+
if (seed_ > M) {
|
37
|
+
seed_ -= M;
|
38
|
+
}
|
39
|
+
return seed_;
|
40
|
+
}
|
41
|
+
// Returns a uniformly distributed value in the range [0..n-1]
|
42
|
+
// REQUIRES: n > 0
|
43
|
+
uint32_t Uniform(int n) { return Next() % n; }
|
44
|
+
|
45
|
+
// Randomly returns true ~"1/n" of the time, and false otherwise.
|
46
|
+
// REQUIRES: n > 0
|
47
|
+
bool OneIn(int n) { return (Next() % n) == 0; }
|
48
|
+
|
49
|
+
// Skewed: pick "base" uniformly from range [0,max_log] and then
|
50
|
+
// return "base" random bits. The effect is to pick a number in the
|
51
|
+
// range [0,2^max_log-1] with exponential bias towards smaller numbers.
|
52
|
+
uint32_t Skewed(int max_log) {
|
53
|
+
return Uniform(1 << Uniform(max_log + 1));
|
54
|
+
}
|
55
|
+
};
|
56
|
+
|
57
|
+
} // namespace leveldb
|
58
|
+
|
59
|
+
#endif // STORAGE_LEVELDB_UTIL_RANDOM_H_
|
@@ -0,0 +1,75 @@
|
|
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 <stdio.h>
|
6
|
+
#include "port/port.h"
|
7
|
+
#include "leveldb/status.h"
|
8
|
+
|
9
|
+
namespace leveldb {
|
10
|
+
|
11
|
+
const char* Status::CopyState(const char* state) {
|
12
|
+
uint32_t size;
|
13
|
+
memcpy(&size, state, sizeof(size));
|
14
|
+
char* result = new char[size + 5];
|
15
|
+
memcpy(result, state, size + 5);
|
16
|
+
return result;
|
17
|
+
}
|
18
|
+
|
19
|
+
Status::Status(Code code, const Slice& msg, const Slice& msg2) {
|
20
|
+
assert(code != kOk);
|
21
|
+
const uint32_t len1 = msg.size();
|
22
|
+
const uint32_t len2 = msg2.size();
|
23
|
+
const uint32_t size = len1 + (len2 ? (2 + len2) : 0);
|
24
|
+
char* result = new char[size + 5];
|
25
|
+
memcpy(result, &size, sizeof(size));
|
26
|
+
result[4] = static_cast<char>(code);
|
27
|
+
memcpy(result + 5, msg.data(), len1);
|
28
|
+
if (len2) {
|
29
|
+
result[5 + len1] = ':';
|
30
|
+
result[6 + len1] = ' ';
|
31
|
+
memcpy(result + 7 + len1, msg2.data(), len2);
|
32
|
+
}
|
33
|
+
state_ = result;
|
34
|
+
}
|
35
|
+
|
36
|
+
std::string Status::ToString() const {
|
37
|
+
if (state_ == NULL) {
|
38
|
+
return "OK";
|
39
|
+
} else {
|
40
|
+
char tmp[30];
|
41
|
+
const char* type;
|
42
|
+
switch (code()) {
|
43
|
+
case kOk:
|
44
|
+
type = "OK";
|
45
|
+
break;
|
46
|
+
case kNotFound:
|
47
|
+
type = "NotFound: ";
|
48
|
+
break;
|
49
|
+
case kCorruption:
|
50
|
+
type = "Corruption: ";
|
51
|
+
break;
|
52
|
+
case kNotSupported:
|
53
|
+
type = "Not implemented: ";
|
54
|
+
break;
|
55
|
+
case kInvalidArgument:
|
56
|
+
type = "Invalid argument: ";
|
57
|
+
break;
|
58
|
+
case kIOError:
|
59
|
+
type = "IO error: ";
|
60
|
+
break;
|
61
|
+
default:
|
62
|
+
snprintf(tmp, sizeof(tmp), "Unknown code(%d): ",
|
63
|
+
static_cast<int>(code()));
|
64
|
+
type = tmp;
|
65
|
+
break;
|
66
|
+
}
|
67
|
+
std::string result(type);
|
68
|
+
uint32_t length;
|
69
|
+
memcpy(&length, state_, sizeof(length));
|
70
|
+
result.append(state_ + 5, length);
|
71
|
+
return result;
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
} // namespace leveldb
|
@@ -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 "util/testharness.h"
|
6
|
+
|
7
|
+
#include <string>
|
8
|
+
#include <stdlib.h>
|
9
|
+
#include <sys/stat.h>
|
10
|
+
#include <sys/types.h>
|
11
|
+
|
12
|
+
namespace leveldb {
|
13
|
+
namespace test {
|
14
|
+
|
15
|
+
namespace {
|
16
|
+
struct Test {
|
17
|
+
const char* base;
|
18
|
+
const char* name;
|
19
|
+
void (*func)();
|
20
|
+
};
|
21
|
+
std::vector<Test>* tests;
|
22
|
+
}
|
23
|
+
|
24
|
+
bool RegisterTest(const char* base, const char* name, void (*func)()) {
|
25
|
+
if (tests == NULL) {
|
26
|
+
tests = new std::vector<Test>;
|
27
|
+
}
|
28
|
+
Test t;
|
29
|
+
t.base = base;
|
30
|
+
t.name = name;
|
31
|
+
t.func = func;
|
32
|
+
tests->push_back(t);
|
33
|
+
return true;
|
34
|
+
}
|
35
|
+
|
36
|
+
int RunAllTests() {
|
37
|
+
const char* matcher = getenv("LEVELDB_TESTS");
|
38
|
+
|
39
|
+
int num = 0;
|
40
|
+
if (tests != NULL) {
|
41
|
+
for (int i = 0; i < tests->size(); i++) {
|
42
|
+
const Test& t = (*tests)[i];
|
43
|
+
if (matcher != NULL) {
|
44
|
+
std::string name = t.base;
|
45
|
+
name.push_back('.');
|
46
|
+
name.append(t.name);
|
47
|
+
if (strstr(name.c_str(), matcher) == NULL) {
|
48
|
+
continue;
|
49
|
+
}
|
50
|
+
}
|
51
|
+
fprintf(stderr, "==== Test %s.%s\n", t.base, t.name);
|
52
|
+
(*t.func)();
|
53
|
+
++num;
|
54
|
+
}
|
55
|
+
}
|
56
|
+
fprintf(stderr, "==== PASSED %d tests\n", num);
|
57
|
+
return 0;
|
58
|
+
}
|
59
|
+
|
60
|
+
std::string TmpDir() {
|
61
|
+
std::string dir;
|
62
|
+
Status s = Env::Default()->GetTestDirectory(&dir);
|
63
|
+
ASSERT_TRUE(s.ok()) << s.ToString();
|
64
|
+
return dir;
|
65
|
+
}
|
66
|
+
|
67
|
+
int RandomSeed() {
|
68
|
+
const char* env = getenv("TEST_RANDOM_SEED");
|
69
|
+
int result = (env != NULL ? atoi(env) : 301);
|
70
|
+
if (result <= 0) {
|
71
|
+
result = 301;
|
72
|
+
}
|
73
|
+
return result;
|
74
|
+
}
|
75
|
+
|
76
|
+
} // namespace test
|
77
|
+
} // namespace leveldb
|
@@ -0,0 +1,138 @@
|
|
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_TESTHARNESS_H_
|
6
|
+
#define STORAGE_LEVELDB_UTIL_TESTHARNESS_H_
|
7
|
+
|
8
|
+
#include <stdio.h>
|
9
|
+
#include <stdlib.h>
|
10
|
+
#include <sstream>
|
11
|
+
#include "leveldb/env.h"
|
12
|
+
#include "leveldb/slice.h"
|
13
|
+
#include "util/random.h"
|
14
|
+
|
15
|
+
namespace leveldb {
|
16
|
+
namespace test {
|
17
|
+
|
18
|
+
// Run some of the tests registered by the TEST() macro. If the
|
19
|
+
// environment variable "LEVELDB_TESTS" is not set, runs all tests.
|
20
|
+
// Otherwise, runs only the tests whose name contains the value of
|
21
|
+
// "LEVELDB_TESTS" as a substring. E.g., suppose the tests are:
|
22
|
+
// TEST(Foo, Hello) { ... }
|
23
|
+
// TEST(Foo, World) { ... }
|
24
|
+
// LEVELDB_TESTS=Hello will run the first test
|
25
|
+
// LEVELDB_TESTS=o will run both tests
|
26
|
+
// LEVELDB_TESTS=Junk will run no tests
|
27
|
+
//
|
28
|
+
// Returns 0 if all tests pass.
|
29
|
+
// Dies or returns a non-zero value if some test fails.
|
30
|
+
extern int RunAllTests();
|
31
|
+
|
32
|
+
// Return the directory to use for temporary storage.
|
33
|
+
extern std::string TmpDir();
|
34
|
+
|
35
|
+
// Return a randomization seed for this run. Typically returns the
|
36
|
+
// same number on repeated invocations of this binary, but automated
|
37
|
+
// runs may be able to vary the seed.
|
38
|
+
extern int RandomSeed();
|
39
|
+
|
40
|
+
// An instance of Tester is allocated to hold temporary state during
|
41
|
+
// the execution of an assertion.
|
42
|
+
class Tester {
|
43
|
+
private:
|
44
|
+
bool ok_;
|
45
|
+
const char* fname_;
|
46
|
+
int line_;
|
47
|
+
std::stringstream ss_;
|
48
|
+
|
49
|
+
public:
|
50
|
+
Tester(const char* f, int l)
|
51
|
+
: ok_(true), fname_(f), line_(l) {
|
52
|
+
}
|
53
|
+
|
54
|
+
~Tester() {
|
55
|
+
if (!ok_) {
|
56
|
+
fprintf(stderr, "%s:%d:%s\n", fname_, line_, ss_.str().c_str());
|
57
|
+
exit(1);
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
Tester& Is(bool b, const char* msg) {
|
62
|
+
if (!b) {
|
63
|
+
ss_ << " Assertion failure " << msg;
|
64
|
+
ok_ = false;
|
65
|
+
}
|
66
|
+
return *this;
|
67
|
+
}
|
68
|
+
|
69
|
+
Tester& IsOk(const Status& s) {
|
70
|
+
if (!s.ok()) {
|
71
|
+
ss_ << " " << s.ToString();
|
72
|
+
ok_ = false;
|
73
|
+
}
|
74
|
+
return *this;
|
75
|
+
}
|
76
|
+
|
77
|
+
#define BINARY_OP(name,op) \
|
78
|
+
template <class X, class Y> \
|
79
|
+
Tester& name(const X& x, const Y& y) { \
|
80
|
+
if (! (x op y)) { \
|
81
|
+
ss_ << " failed: " << x << (" " #op " ") << y; \
|
82
|
+
ok_ = false; \
|
83
|
+
} \
|
84
|
+
return *this; \
|
85
|
+
}
|
86
|
+
|
87
|
+
BINARY_OP(IsEq, ==)
|
88
|
+
BINARY_OP(IsNe, !=)
|
89
|
+
BINARY_OP(IsGe, >=)
|
90
|
+
BINARY_OP(IsGt, >)
|
91
|
+
BINARY_OP(IsLe, <=)
|
92
|
+
BINARY_OP(IsLt, <)
|
93
|
+
#undef BINARY_OP
|
94
|
+
|
95
|
+
// Attach the specified value to the error message if an error has occurred
|
96
|
+
template <class V>
|
97
|
+
Tester& operator<<(const V& value) {
|
98
|
+
if (!ok_) {
|
99
|
+
ss_ << " " << value;
|
100
|
+
}
|
101
|
+
return *this;
|
102
|
+
}
|
103
|
+
};
|
104
|
+
|
105
|
+
#define ASSERT_TRUE(c) ::leveldb::test::Tester(__FILE__, __LINE__).Is((c), #c)
|
106
|
+
#define ASSERT_OK(s) ::leveldb::test::Tester(__FILE__, __LINE__).IsOk((s))
|
107
|
+
#define ASSERT_EQ(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsEq((a),(b))
|
108
|
+
#define ASSERT_NE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsNe((a),(b))
|
109
|
+
#define ASSERT_GE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsGe((a),(b))
|
110
|
+
#define ASSERT_GT(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsGt((a),(b))
|
111
|
+
#define ASSERT_LE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsLe((a),(b))
|
112
|
+
#define ASSERT_LT(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsLt((a),(b))
|
113
|
+
|
114
|
+
#define TCONCAT(a,b) TCONCAT1(a,b)
|
115
|
+
#define TCONCAT1(a,b) a##b
|
116
|
+
|
117
|
+
#define TEST(base,name) \
|
118
|
+
class TCONCAT(_Test_,name) : public base { \
|
119
|
+
public: \
|
120
|
+
void _Run(); \
|
121
|
+
static void _RunIt() { \
|
122
|
+
TCONCAT(_Test_,name) t; \
|
123
|
+
t._Run(); \
|
124
|
+
} \
|
125
|
+
}; \
|
126
|
+
bool TCONCAT(_Test_ignored_,name) = \
|
127
|
+
::leveldb::test::RegisterTest(#base, #name, &TCONCAT(_Test_,name)::_RunIt); \
|
128
|
+
void TCONCAT(_Test_,name)::_Run()
|
129
|
+
|
130
|
+
// Register the specified test. Typically not used directly, but
|
131
|
+
// invoked via the macro expansion of TEST.
|
132
|
+
extern bool RegisterTest(const char* base, const char* name, void (*func)());
|
133
|
+
|
134
|
+
|
135
|
+
} // namespace test
|
136
|
+
} // namespace leveldb
|
137
|
+
|
138
|
+
#endif // STORAGE_LEVELDB_UTIL_TESTHARNESS_H_
|