Fix actions/tour
This commit is contained in:
68
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/arena.cc
generated
vendored
Normal file
68
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/arena.cc
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "util/arena.h"
|
||||
#include <assert.h>
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
static const int kBlockSize = 4096;
|
||||
|
||||
Arena::Arena() : memory_usage_(0) {
|
||||
alloc_ptr_ = NULL; // First allocation will allocate a block
|
||||
alloc_bytes_remaining_ = 0;
|
||||
}
|
||||
|
||||
Arena::~Arena() {
|
||||
for (size_t i = 0; i < blocks_.size(); i++) {
|
||||
delete[] blocks_[i];
|
||||
}
|
||||
}
|
||||
|
||||
char* Arena::AllocateFallback(size_t bytes) {
|
||||
if (bytes > kBlockSize / 4) {
|
||||
// Object is more than a quarter of our block size. Allocate it separately
|
||||
// to avoid wasting too much space in leftover bytes.
|
||||
char* result = AllocateNewBlock(bytes);
|
||||
return result;
|
||||
}
|
||||
|
||||
// We waste the remaining space in the current block.
|
||||
alloc_ptr_ = AllocateNewBlock(kBlockSize);
|
||||
alloc_bytes_remaining_ = kBlockSize;
|
||||
|
||||
char* result = alloc_ptr_;
|
||||
alloc_ptr_ += bytes;
|
||||
alloc_bytes_remaining_ -= bytes;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* Arena::AllocateAligned(size_t bytes) {
|
||||
const int align = (sizeof(void*) > 8) ? sizeof(void*) : 8;
|
||||
assert((align & (align-1)) == 0); // Pointer size should be a power of 2
|
||||
size_t current_mod = reinterpret_cast<uintptr_t>(alloc_ptr_) & (align-1);
|
||||
size_t slop = (current_mod == 0 ? 0 : align - current_mod);
|
||||
size_t needed = bytes + slop;
|
||||
char* result;
|
||||
if (needed <= alloc_bytes_remaining_) {
|
||||
result = alloc_ptr_ + slop;
|
||||
alloc_ptr_ += needed;
|
||||
alloc_bytes_remaining_ -= needed;
|
||||
} else {
|
||||
// AllocateFallback always returned aligned memory
|
||||
result = AllocateFallback(bytes);
|
||||
}
|
||||
assert((reinterpret_cast<uintptr_t>(result) & (align-1)) == 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
char* Arena::AllocateNewBlock(size_t block_bytes) {
|
||||
char* result = new char[block_bytes];
|
||||
blocks_.push_back(result);
|
||||
memory_usage_.NoBarrier_Store(
|
||||
reinterpret_cast<void*>(MemoryUsage() + block_bytes + sizeof(char*)));
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
68
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/arena.h
generated
vendored
Normal file
68
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/arena.h
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_UTIL_ARENA_H_
|
||||
#define STORAGE_LEVELDB_UTIL_ARENA_H_
|
||||
|
||||
#include <vector>
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "port/port.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
class Arena {
|
||||
public:
|
||||
Arena();
|
||||
~Arena();
|
||||
|
||||
// Return a pointer to a newly allocated memory block of "bytes" bytes.
|
||||
char* Allocate(size_t bytes);
|
||||
|
||||
// Allocate memory with the normal alignment guarantees provided by malloc
|
||||
char* AllocateAligned(size_t bytes);
|
||||
|
||||
// Returns an estimate of the total memory usage of data allocated
|
||||
// by the arena.
|
||||
size_t MemoryUsage() const {
|
||||
return reinterpret_cast<uintptr_t>(memory_usage_.NoBarrier_Load());
|
||||
}
|
||||
|
||||
private:
|
||||
char* AllocateFallback(size_t bytes);
|
||||
char* AllocateNewBlock(size_t block_bytes);
|
||||
|
||||
// Allocation state
|
||||
char* alloc_ptr_;
|
||||
size_t alloc_bytes_remaining_;
|
||||
|
||||
// Array of new[] allocated memory blocks
|
||||
std::vector<char*> blocks_;
|
||||
|
||||
// Total memory usage of the arena.
|
||||
port::AtomicPointer memory_usage_;
|
||||
|
||||
// No copying allowed
|
||||
Arena(const Arena&);
|
||||
void operator=(const Arena&);
|
||||
};
|
||||
|
||||
inline char* Arena::Allocate(size_t bytes) {
|
||||
// The semantics of what to return are a bit messy if we allow
|
||||
// 0-byte allocations, so we disallow them here (we don't need
|
||||
// them for our internal use).
|
||||
assert(bytes > 0);
|
||||
if (bytes <= alloc_bytes_remaining_) {
|
||||
char* result = alloc_ptr_;
|
||||
alloc_ptr_ += bytes;
|
||||
alloc_bytes_remaining_ -= bytes;
|
||||
return result;
|
||||
}
|
||||
return AllocateFallback(bytes);
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_UTIL_ARENA_H_
|
||||
68
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/arena_test.cc
generated
vendored
Normal file
68
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/arena_test.cc
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "util/arena.h"
|
||||
|
||||
#include "util/random.h"
|
||||
#include "util/testharness.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
class ArenaTest { };
|
||||
|
||||
TEST(ArenaTest, Empty) {
|
||||
Arena arena;
|
||||
}
|
||||
|
||||
TEST(ArenaTest, Simple) {
|
||||
std::vector<std::pair<size_t, char*> > allocated;
|
||||
Arena arena;
|
||||
const int N = 100000;
|
||||
size_t bytes = 0;
|
||||
Random rnd(301);
|
||||
for (int i = 0; i < N; i++) {
|
||||
size_t s;
|
||||
if (i % (N / 10) == 0) {
|
||||
s = i;
|
||||
} else {
|
||||
s = rnd.OneIn(4000) ? rnd.Uniform(6000) :
|
||||
(rnd.OneIn(10) ? rnd.Uniform(100) : rnd.Uniform(20));
|
||||
}
|
||||
if (s == 0) {
|
||||
// Our arena disallows size 0 allocations.
|
||||
s = 1;
|
||||
}
|
||||
char* r;
|
||||
if (rnd.OneIn(10)) {
|
||||
r = arena.AllocateAligned(s);
|
||||
} else {
|
||||
r = arena.Allocate(s);
|
||||
}
|
||||
|
||||
for (size_t b = 0; b < s; b++) {
|
||||
// Fill the "i"th allocation with a known bit pattern
|
||||
r[b] = i % 256;
|
||||
}
|
||||
bytes += s;
|
||||
allocated.push_back(std::make_pair(s, r));
|
||||
ASSERT_GE(arena.MemoryUsage(), bytes);
|
||||
if (i > N/10) {
|
||||
ASSERT_LE(arena.MemoryUsage(), bytes * 1.10);
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < allocated.size(); i++) {
|
||||
size_t num_bytes = allocated[i].first;
|
||||
const char* p = allocated[i].second;
|
||||
for (size_t b = 0; b < num_bytes; b++) {
|
||||
// Check the "i"th allocation for the known bit pattern
|
||||
ASSERT_EQ(int(p[b]) & 0xff, i % 256);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return leveldb::test::RunAllTests();
|
||||
}
|
||||
95
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/bloom.cc
generated
vendored
Normal file
95
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/bloom.cc
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
// Copyright (c) 2012 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "leveldb/filter_policy.h"
|
||||
|
||||
#include "leveldb/slice.h"
|
||||
#include "util/hash.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
namespace {
|
||||
static uint32_t BloomHash(const Slice& key) {
|
||||
return Hash(key.data(), key.size(), 0xbc9f1d34);
|
||||
}
|
||||
|
||||
class BloomFilterPolicy : public FilterPolicy {
|
||||
private:
|
||||
size_t bits_per_key_;
|
||||
size_t k_;
|
||||
|
||||
public:
|
||||
explicit BloomFilterPolicy(int bits_per_key)
|
||||
: bits_per_key_(bits_per_key) {
|
||||
// We intentionally round down to reduce probing cost a little bit
|
||||
k_ = static_cast<size_t>(bits_per_key * 0.69); // 0.69 =~ ln(2)
|
||||
if (k_ < 1) k_ = 1;
|
||||
if (k_ > 30) k_ = 30;
|
||||
}
|
||||
|
||||
virtual const char* Name() const {
|
||||
return "leveldb.BuiltinBloomFilter2";
|
||||
}
|
||||
|
||||
virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const {
|
||||
// Compute bloom filter size (in both bits and bytes)
|
||||
size_t bits = n * bits_per_key_;
|
||||
|
||||
// For small n, we can see a very high false positive rate. Fix it
|
||||
// by enforcing a minimum bloom filter length.
|
||||
if (bits < 64) bits = 64;
|
||||
|
||||
size_t bytes = (bits + 7) / 8;
|
||||
bits = bytes * 8;
|
||||
|
||||
const size_t init_size = dst->size();
|
||||
dst->resize(init_size + bytes, 0);
|
||||
dst->push_back(static_cast<char>(k_)); // Remember # of probes in filter
|
||||
char* array = &(*dst)[init_size];
|
||||
for (int i = 0; i < n; i++) {
|
||||
// Use double-hashing to generate a sequence of hash values.
|
||||
// See analysis in [Kirsch,Mitzenmacher 2006].
|
||||
uint32_t h = BloomHash(keys[i]);
|
||||
const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits
|
||||
for (size_t j = 0; j < k_; j++) {
|
||||
const uint32_t bitpos = h % bits;
|
||||
array[bitpos/8] |= (1 << (bitpos % 8));
|
||||
h += delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool KeyMayMatch(const Slice& key, const Slice& bloom_filter) const {
|
||||
const size_t len = bloom_filter.size();
|
||||
if (len < 2) return false;
|
||||
|
||||
const char* array = bloom_filter.data();
|
||||
const size_t bits = (len - 1) * 8;
|
||||
|
||||
// Use the encoded k so that we can read filters generated by
|
||||
// bloom filters created using different parameters.
|
||||
const size_t k = array[len-1];
|
||||
if (k > 30) {
|
||||
// Reserved for potentially new encodings for short bloom filters.
|
||||
// Consider it a match.
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t h = BloomHash(key);
|
||||
const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits
|
||||
for (size_t j = 0; j < k; j++) {
|
||||
const uint32_t bitpos = h % bits;
|
||||
if ((array[bitpos/8] & (1 << (bitpos % 8))) == 0) return false;
|
||||
h += delta;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const FilterPolicy* NewBloomFilterPolicy(int bits_per_key) {
|
||||
return new BloomFilterPolicy(bits_per_key);
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
162
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/bloom_test.cc
generated
vendored
Normal file
162
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/bloom_test.cc
generated
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
// Copyright (c) 2012 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "leveldb/filter_policy.h"
|
||||
|
||||
#include "util/coding.h"
|
||||
#include "util/logging.h"
|
||||
#include "util/testharness.h"
|
||||
#include "util/testutil.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
static const int kVerbose = 1;
|
||||
|
||||
static Slice Key(int i, char* buffer) {
|
||||
EncodeFixed32(buffer, i);
|
||||
return Slice(buffer, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
class BloomTest {
|
||||
private:
|
||||
const FilterPolicy* policy_;
|
||||
std::string filter_;
|
||||
std::vector<std::string> keys_;
|
||||
|
||||
public:
|
||||
BloomTest() : policy_(NewBloomFilterPolicy(10)) { }
|
||||
|
||||
~BloomTest() {
|
||||
delete policy_;
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
keys_.clear();
|
||||
filter_.clear();
|
||||
}
|
||||
|
||||
void Add(const Slice& s) {
|
||||
keys_.push_back(s.ToString());
|
||||
}
|
||||
|
||||
void Build() {
|
||||
std::vector<Slice> key_slices;
|
||||
for (size_t i = 0; i < keys_.size(); i++) {
|
||||
key_slices.push_back(Slice(keys_[i]));
|
||||
}
|
||||
filter_.clear();
|
||||
policy_->CreateFilter(&key_slices[0], static_cast<int>(key_slices.size()),
|
||||
&filter_);
|
||||
keys_.clear();
|
||||
if (kVerbose >= 2) DumpFilter();
|
||||
}
|
||||
|
||||
size_t FilterSize() const {
|
||||
return filter_.size();
|
||||
}
|
||||
|
||||
void DumpFilter() {
|
||||
fprintf(stderr, "F(");
|
||||
for (size_t i = 0; i+1 < filter_.size(); i++) {
|
||||
const unsigned int c = static_cast<unsigned int>(filter_[i]);
|
||||
for (int j = 0; j < 8; j++) {
|
||||
fprintf(stderr, "%c", (c & (1 <<j)) ? '1' : '.');
|
||||
}
|
||||
}
|
||||
fprintf(stderr, ")\n");
|
||||
}
|
||||
|
||||
bool Matches(const Slice& s) {
|
||||
if (!keys_.empty()) {
|
||||
Build();
|
||||
}
|
||||
return policy_->KeyMayMatch(s, filter_);
|
||||
}
|
||||
|
||||
double FalsePositiveRate() {
|
||||
char buffer[sizeof(int)];
|
||||
int result = 0;
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
if (Matches(Key(i + 1000000000, buffer))) {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
return result / 10000.0;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(BloomTest, EmptyFilter) {
|
||||
ASSERT_TRUE(! Matches("hello"));
|
||||
ASSERT_TRUE(! Matches("world"));
|
||||
}
|
||||
|
||||
TEST(BloomTest, Small) {
|
||||
Add("hello");
|
||||
Add("world");
|
||||
ASSERT_TRUE(Matches("hello"));
|
||||
ASSERT_TRUE(Matches("world"));
|
||||
ASSERT_TRUE(! Matches("x"));
|
||||
ASSERT_TRUE(! Matches("foo"));
|
||||
}
|
||||
|
||||
static int NextLength(int length) {
|
||||
if (length < 10) {
|
||||
length += 1;
|
||||
} else if (length < 100) {
|
||||
length += 10;
|
||||
} else if (length < 1000) {
|
||||
length += 100;
|
||||
} else {
|
||||
length += 1000;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
TEST(BloomTest, VaryingLengths) {
|
||||
char buffer[sizeof(int)];
|
||||
|
||||
// Count number of filters that significantly exceed the false positive rate
|
||||
int mediocre_filters = 0;
|
||||
int good_filters = 0;
|
||||
|
||||
for (int length = 1; length <= 10000; length = NextLength(length)) {
|
||||
Reset();
|
||||
for (int i = 0; i < length; i++) {
|
||||
Add(Key(i, buffer));
|
||||
}
|
||||
Build();
|
||||
|
||||
ASSERT_LE(FilterSize(), static_cast<size_t>((length * 10 / 8) + 40))
|
||||
<< length;
|
||||
|
||||
// All added keys must match
|
||||
for (int i = 0; i < length; i++) {
|
||||
ASSERT_TRUE(Matches(Key(i, buffer)))
|
||||
<< "Length " << length << "; key " << i;
|
||||
}
|
||||
|
||||
// Check false positive rate
|
||||
double rate = FalsePositiveRate();
|
||||
if (kVerbose >= 1) {
|
||||
fprintf(stderr, "False positives: %5.2f%% @ length = %6d ; bytes = %6d\n",
|
||||
rate*100.0, length, static_cast<int>(FilterSize()));
|
||||
}
|
||||
ASSERT_LE(rate, 0.02); // Must not be over 2%
|
||||
if (rate > 0.0125) mediocre_filters++; // Allowed, but not too often
|
||||
else good_filters++;
|
||||
}
|
||||
if (kVerbose >= 1) {
|
||||
fprintf(stderr, "Filters: %d good, %d mediocre\n",
|
||||
good_filters, mediocre_filters);
|
||||
}
|
||||
ASSERT_LE(mediocre_filters, good_filters/5);
|
||||
}
|
||||
|
||||
// Different bits-per-byte
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return leveldb::test::RunAllTests();
|
||||
}
|
||||
405
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/cache.cc
generated
vendored
Normal file
405
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/cache.cc
generated
vendored
Normal file
@@ -0,0 +1,405 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "leveldb/cache.h"
|
||||
#include "port/port.h"
|
||||
#include "util/hash.h"
|
||||
#include "util/mutexlock.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
Cache::~Cache() {
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// LRU cache implementation
|
||||
//
|
||||
// Cache entries have an "in_cache" boolean indicating whether the cache has a
|
||||
// reference on the entry. The only ways that this can become false without the
|
||||
// entry being passed to its "deleter" are via Erase(), via Insert() when
|
||||
// an element with a duplicate key is inserted, or on destruction of the cache.
|
||||
//
|
||||
// The cache keeps two linked lists of items in the cache. All items in the
|
||||
// cache are in one list or the other, and never both. Items still referenced
|
||||
// by clients but erased from the cache are in neither list. The lists are:
|
||||
// - in-use: contains the items currently referenced by clients, in no
|
||||
// particular order. (This list is used for invariant checking. If we
|
||||
// removed the check, elements that would otherwise be on this list could be
|
||||
// left as disconnected singleton lists.)
|
||||
// - LRU: contains the items not currently referenced by clients, in LRU order
|
||||
// Elements are moved between these lists by the Ref() and Unref() methods,
|
||||
// when they detect an element in the cache acquiring or losing its only
|
||||
// external reference.
|
||||
|
||||
// An entry is a variable length heap-allocated structure. Entries
|
||||
// are kept in a circular doubly linked list ordered by access time.
|
||||
struct LRUHandle {
|
||||
void* value;
|
||||
void (*deleter)(const Slice&, void* value);
|
||||
LRUHandle* next_hash;
|
||||
LRUHandle* next;
|
||||
LRUHandle* prev;
|
||||
size_t charge; // TODO(opt): Only allow uint32_t?
|
||||
size_t key_length;
|
||||
bool in_cache; // Whether entry is in the cache.
|
||||
uint32_t refs; // References, including cache reference, if present.
|
||||
uint32_t hash; // Hash of key(); used for fast sharding and comparisons
|
||||
char key_data[1]; // Beginning of key
|
||||
|
||||
Slice key() const {
|
||||
// For cheaper lookups, we allow a temporary Handle object
|
||||
// to store a pointer to a key in "value".
|
||||
if (next == this) {
|
||||
return *(reinterpret_cast<Slice*>(value));
|
||||
} else {
|
||||
return Slice(key_data, key_length);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// We provide our own simple hash table since it removes a whole bunch
|
||||
// of porting hacks and is also faster than some of the built-in hash
|
||||
// table implementations in some of the compiler/runtime combinations
|
||||
// we have tested. E.g., readrandom speeds up by ~5% over the g++
|
||||
// 4.4.3's builtin hashtable.
|
||||
class HandleTable {
|
||||
public:
|
||||
HandleTable() : length_(0), elems_(0), list_(NULL) { Resize(); }
|
||||
~HandleTable() { delete[] list_; }
|
||||
|
||||
LRUHandle* Lookup(const Slice& key, uint32_t hash) {
|
||||
return *FindPointer(key, hash);
|
||||
}
|
||||
|
||||
LRUHandle* Insert(LRUHandle* h) {
|
||||
LRUHandle** ptr = FindPointer(h->key(), h->hash);
|
||||
LRUHandle* old = *ptr;
|
||||
h->next_hash = (old == NULL ? NULL : old->next_hash);
|
||||
*ptr = h;
|
||||
if (old == NULL) {
|
||||
++elems_;
|
||||
if (elems_ > length_) {
|
||||
// Since each cache entry is fairly large, we aim for a small
|
||||
// average linked list length (<= 1).
|
||||
Resize();
|
||||
}
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
LRUHandle* Remove(const Slice& key, uint32_t hash) {
|
||||
LRUHandle** ptr = FindPointer(key, hash);
|
||||
LRUHandle* result = *ptr;
|
||||
if (result != NULL) {
|
||||
*ptr = result->next_hash;
|
||||
--elems_;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
// The table consists of an array of buckets where each bucket is
|
||||
// a linked list of cache entries that hash into the bucket.
|
||||
uint32_t length_;
|
||||
uint32_t elems_;
|
||||
LRUHandle** list_;
|
||||
|
||||
// Return a pointer to slot that points to a cache entry that
|
||||
// matches key/hash. If there is no such cache entry, return a
|
||||
// pointer to the trailing slot in the corresponding linked list.
|
||||
LRUHandle** FindPointer(const Slice& key, uint32_t hash) {
|
||||
LRUHandle** ptr = &list_[hash & (length_ - 1)];
|
||||
while (*ptr != NULL &&
|
||||
((*ptr)->hash != hash || key != (*ptr)->key())) {
|
||||
ptr = &(*ptr)->next_hash;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void Resize() {
|
||||
uint32_t new_length = 4;
|
||||
while (new_length < elems_) {
|
||||
new_length *= 2;
|
||||
}
|
||||
LRUHandle** new_list = new LRUHandle*[new_length];
|
||||
memset(new_list, 0, sizeof(new_list[0]) * new_length);
|
||||
uint32_t count = 0;
|
||||
for (uint32_t i = 0; i < length_; i++) {
|
||||
LRUHandle* h = list_[i];
|
||||
while (h != NULL) {
|
||||
LRUHandle* next = h->next_hash;
|
||||
uint32_t hash = h->hash;
|
||||
LRUHandle** ptr = &new_list[hash & (new_length - 1)];
|
||||
h->next_hash = *ptr;
|
||||
*ptr = h;
|
||||
h = next;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
assert(elems_ == count);
|
||||
delete[] list_;
|
||||
list_ = new_list;
|
||||
length_ = new_length;
|
||||
}
|
||||
};
|
||||
|
||||
// A single shard of sharded cache.
|
||||
class LRUCache {
|
||||
public:
|
||||
LRUCache();
|
||||
~LRUCache();
|
||||
|
||||
// Separate from constructor so caller can easily make an array of LRUCache
|
||||
void SetCapacity(size_t capacity) { capacity_ = capacity; }
|
||||
|
||||
// Like Cache methods, but with an extra "hash" parameter.
|
||||
Cache::Handle* Insert(const Slice& key, uint32_t hash,
|
||||
void* value, size_t charge,
|
||||
void (*deleter)(const Slice& key, void* value));
|
||||
Cache::Handle* Lookup(const Slice& key, uint32_t hash);
|
||||
void Release(Cache::Handle* handle);
|
||||
void Erase(const Slice& key, uint32_t hash);
|
||||
void Prune();
|
||||
size_t TotalCharge() const {
|
||||
MutexLock l(&mutex_);
|
||||
return usage_;
|
||||
}
|
||||
|
||||
private:
|
||||
void LRU_Remove(LRUHandle* e);
|
||||
void LRU_Append(LRUHandle*list, LRUHandle* e);
|
||||
void Ref(LRUHandle* e);
|
||||
void Unref(LRUHandle* e);
|
||||
bool FinishErase(LRUHandle* e);
|
||||
|
||||
// Initialized before use.
|
||||
size_t capacity_;
|
||||
|
||||
// mutex_ protects the following state.
|
||||
mutable port::Mutex mutex_;
|
||||
size_t usage_;
|
||||
|
||||
// Dummy head of LRU list.
|
||||
// lru.prev is newest entry, lru.next is oldest entry.
|
||||
// Entries have refs==1 and in_cache==true.
|
||||
LRUHandle lru_;
|
||||
|
||||
// Dummy head of in-use list.
|
||||
// Entries are in use by clients, and have refs >= 2 and in_cache==true.
|
||||
LRUHandle in_use_;
|
||||
|
||||
HandleTable table_;
|
||||
};
|
||||
|
||||
LRUCache::LRUCache()
|
||||
: usage_(0) {
|
||||
// Make empty circular linked lists.
|
||||
lru_.next = &lru_;
|
||||
lru_.prev = &lru_;
|
||||
in_use_.next = &in_use_;
|
||||
in_use_.prev = &in_use_;
|
||||
}
|
||||
|
||||
LRUCache::~LRUCache() {
|
||||
assert(in_use_.next == &in_use_); // Error if caller has an unreleased handle
|
||||
for (LRUHandle* e = lru_.next; e != &lru_; ) {
|
||||
LRUHandle* next = e->next;
|
||||
assert(e->in_cache);
|
||||
e->in_cache = false;
|
||||
assert(e->refs == 1); // Invariant of lru_ list.
|
||||
Unref(e);
|
||||
e = next;
|
||||
}
|
||||
}
|
||||
|
||||
void LRUCache::Ref(LRUHandle* e) {
|
||||
if (e->refs == 1 && e->in_cache) { // If on lru_ list, move to in_use_ list.
|
||||
LRU_Remove(e);
|
||||
LRU_Append(&in_use_, e);
|
||||
}
|
||||
e->refs++;
|
||||
}
|
||||
|
||||
void LRUCache::Unref(LRUHandle* e) {
|
||||
assert(e->refs > 0);
|
||||
e->refs--;
|
||||
if (e->refs == 0) { // Deallocate.
|
||||
assert(!e->in_cache);
|
||||
(*e->deleter)(e->key(), e->value);
|
||||
free(e);
|
||||
} else if (e->in_cache && e->refs == 1) { // No longer in use; move to lru_ list.
|
||||
LRU_Remove(e);
|
||||
LRU_Append(&lru_, e);
|
||||
}
|
||||
}
|
||||
|
||||
void LRUCache::LRU_Remove(LRUHandle* e) {
|
||||
e->next->prev = e->prev;
|
||||
e->prev->next = e->next;
|
||||
}
|
||||
|
||||
void LRUCache::LRU_Append(LRUHandle* list, LRUHandle* e) {
|
||||
// Make "e" newest entry by inserting just before *list
|
||||
e->next = list;
|
||||
e->prev = list->prev;
|
||||
e->prev->next = e;
|
||||
e->next->prev = e;
|
||||
}
|
||||
|
||||
Cache::Handle* LRUCache::Lookup(const Slice& key, uint32_t hash) {
|
||||
MutexLock l(&mutex_);
|
||||
LRUHandle* e = table_.Lookup(key, hash);
|
||||
if (e != NULL) {
|
||||
Ref(e);
|
||||
}
|
||||
return reinterpret_cast<Cache::Handle*>(e);
|
||||
}
|
||||
|
||||
void LRUCache::Release(Cache::Handle* handle) {
|
||||
MutexLock l(&mutex_);
|
||||
Unref(reinterpret_cast<LRUHandle*>(handle));
|
||||
}
|
||||
|
||||
Cache::Handle* LRUCache::Insert(
|
||||
const Slice& key, uint32_t hash, void* value, size_t charge,
|
||||
void (*deleter)(const Slice& key, void* value)) {
|
||||
MutexLock l(&mutex_);
|
||||
|
||||
LRUHandle* e = reinterpret_cast<LRUHandle*>(
|
||||
malloc(sizeof(LRUHandle)-1 + key.size()));
|
||||
e->value = value;
|
||||
e->deleter = deleter;
|
||||
e->charge = charge;
|
||||
e->key_length = key.size();
|
||||
e->hash = hash;
|
||||
e->in_cache = false;
|
||||
e->refs = 1; // for the returned handle.
|
||||
memcpy(e->key_data, key.data(), key.size());
|
||||
|
||||
if (capacity_ > 0) {
|
||||
e->refs++; // for the cache's reference.
|
||||
e->in_cache = true;
|
||||
LRU_Append(&in_use_, e);
|
||||
usage_ += charge;
|
||||
FinishErase(table_.Insert(e));
|
||||
} // else don't cache. (Tests use capacity_==0 to turn off caching.)
|
||||
|
||||
while (usage_ > capacity_ && lru_.next != &lru_) {
|
||||
LRUHandle* old = lru_.next;
|
||||
assert(old->refs == 1);
|
||||
bool erased = FinishErase(table_.Remove(old->key(), old->hash));
|
||||
if (!erased) { // to avoid unused variable when compiled NDEBUG
|
||||
assert(erased);
|
||||
}
|
||||
}
|
||||
|
||||
return reinterpret_cast<Cache::Handle*>(e);
|
||||
}
|
||||
|
||||
// If e != NULL, finish removing *e from the cache; it has already been removed
|
||||
// from the hash table. Return whether e != NULL. Requires mutex_ held.
|
||||
bool LRUCache::FinishErase(LRUHandle* e) {
|
||||
if (e != NULL) {
|
||||
assert(e->in_cache);
|
||||
LRU_Remove(e);
|
||||
e->in_cache = false;
|
||||
usage_ -= e->charge;
|
||||
Unref(e);
|
||||
}
|
||||
return e != NULL;
|
||||
}
|
||||
|
||||
void LRUCache::Erase(const Slice& key, uint32_t hash) {
|
||||
MutexLock l(&mutex_);
|
||||
FinishErase(table_.Remove(key, hash));
|
||||
}
|
||||
|
||||
void LRUCache::Prune() {
|
||||
MutexLock l(&mutex_);
|
||||
while (lru_.next != &lru_) {
|
||||
LRUHandle* e = lru_.next;
|
||||
assert(e->refs == 1);
|
||||
bool erased = FinishErase(table_.Remove(e->key(), e->hash));
|
||||
if (!erased) { // to avoid unused variable when compiled NDEBUG
|
||||
assert(erased);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const int kNumShardBits = 4;
|
||||
static const int kNumShards = 1 << kNumShardBits;
|
||||
|
||||
class ShardedLRUCache : public Cache {
|
||||
private:
|
||||
LRUCache shard_[kNumShards];
|
||||
port::Mutex id_mutex_;
|
||||
uint64_t last_id_;
|
||||
|
||||
static inline uint32_t HashSlice(const Slice& s) {
|
||||
return Hash(s.data(), s.size(), 0);
|
||||
}
|
||||
|
||||
static uint32_t Shard(uint32_t hash) {
|
||||
return hash >> (32 - kNumShardBits);
|
||||
}
|
||||
|
||||
public:
|
||||
explicit ShardedLRUCache(size_t capacity)
|
||||
: last_id_(0) {
|
||||
const size_t per_shard = (capacity + (kNumShards - 1)) / kNumShards;
|
||||
for (int s = 0; s < kNumShards; s++) {
|
||||
shard_[s].SetCapacity(per_shard);
|
||||
}
|
||||
}
|
||||
virtual ~ShardedLRUCache() { }
|
||||
virtual Handle* Insert(const Slice& key, void* value, size_t charge,
|
||||
void (*deleter)(const Slice& key, void* value)) {
|
||||
const uint32_t hash = HashSlice(key);
|
||||
return shard_[Shard(hash)].Insert(key, hash, value, charge, deleter);
|
||||
}
|
||||
virtual Handle* Lookup(const Slice& key) {
|
||||
const uint32_t hash = HashSlice(key);
|
||||
return shard_[Shard(hash)].Lookup(key, hash);
|
||||
}
|
||||
virtual void Release(Handle* handle) {
|
||||
LRUHandle* h = reinterpret_cast<LRUHandle*>(handle);
|
||||
shard_[Shard(h->hash)].Release(handle);
|
||||
}
|
||||
virtual void Erase(const Slice& key) {
|
||||
const uint32_t hash = HashSlice(key);
|
||||
shard_[Shard(hash)].Erase(key, hash);
|
||||
}
|
||||
virtual void* Value(Handle* handle) {
|
||||
return reinterpret_cast<LRUHandle*>(handle)->value;
|
||||
}
|
||||
virtual uint64_t NewId() {
|
||||
MutexLock l(&id_mutex_);
|
||||
return ++(last_id_);
|
||||
}
|
||||
virtual void Prune() {
|
||||
for (int s = 0; s < kNumShards; s++) {
|
||||
shard_[s].Prune();
|
||||
}
|
||||
}
|
||||
virtual size_t TotalCharge() const {
|
||||
size_t total = 0;
|
||||
for (int s = 0; s < kNumShards; s++) {
|
||||
total += shard_[s].TotalCharge();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
Cache* NewLRUCache(size_t capacity) {
|
||||
return new ShardedLRUCache(capacity);
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
226
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/cache_test.cc
generated
vendored
Normal file
226
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/cache_test.cc
generated
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "leveldb/cache.h"
|
||||
|
||||
#include <vector>
|
||||
#include "util/coding.h"
|
||||
#include "util/testharness.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
// Conversions between numeric keys/values and the types expected by Cache.
|
||||
static std::string EncodeKey(int k) {
|
||||
std::string result;
|
||||
PutFixed32(&result, k);
|
||||
return result;
|
||||
}
|
||||
static int DecodeKey(const Slice& k) {
|
||||
assert(k.size() == 4);
|
||||
return DecodeFixed32(k.data());
|
||||
}
|
||||
static void* EncodeValue(uintptr_t v) { return reinterpret_cast<void*>(v); }
|
||||
static int DecodeValue(void* v) { return reinterpret_cast<uintptr_t>(v); }
|
||||
|
||||
class CacheTest {
|
||||
public:
|
||||
static CacheTest* current_;
|
||||
|
||||
static void Deleter(const Slice& key, void* v) {
|
||||
current_->deleted_keys_.push_back(DecodeKey(key));
|
||||
current_->deleted_values_.push_back(DecodeValue(v));
|
||||
}
|
||||
|
||||
static const int kCacheSize = 1000;
|
||||
std::vector<int> deleted_keys_;
|
||||
std::vector<int> deleted_values_;
|
||||
Cache* cache_;
|
||||
|
||||
CacheTest() : cache_(NewLRUCache(kCacheSize)) {
|
||||
current_ = this;
|
||||
}
|
||||
|
||||
~CacheTest() {
|
||||
delete cache_;
|
||||
}
|
||||
|
||||
int Lookup(int key) {
|
||||
Cache::Handle* handle = cache_->Lookup(EncodeKey(key));
|
||||
const int r = (handle == NULL) ? -1 : DecodeValue(cache_->Value(handle));
|
||||
if (handle != NULL) {
|
||||
cache_->Release(handle);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void Insert(int key, int value, int charge = 1) {
|
||||
cache_->Release(cache_->Insert(EncodeKey(key), EncodeValue(value), charge,
|
||||
&CacheTest::Deleter));
|
||||
}
|
||||
|
||||
Cache::Handle* InsertAndReturnHandle(int key, int value, int charge = 1) {
|
||||
return cache_->Insert(EncodeKey(key), EncodeValue(value), charge,
|
||||
&CacheTest::Deleter);
|
||||
}
|
||||
|
||||
void Erase(int key) {
|
||||
cache_->Erase(EncodeKey(key));
|
||||
}
|
||||
};
|
||||
CacheTest* CacheTest::current_;
|
||||
|
||||
TEST(CacheTest, HitAndMiss) {
|
||||
ASSERT_EQ(-1, Lookup(100));
|
||||
|
||||
Insert(100, 101);
|
||||
ASSERT_EQ(101, Lookup(100));
|
||||
ASSERT_EQ(-1, Lookup(200));
|
||||
ASSERT_EQ(-1, Lookup(300));
|
||||
|
||||
Insert(200, 201);
|
||||
ASSERT_EQ(101, Lookup(100));
|
||||
ASSERT_EQ(201, Lookup(200));
|
||||
ASSERT_EQ(-1, Lookup(300));
|
||||
|
||||
Insert(100, 102);
|
||||
ASSERT_EQ(102, Lookup(100));
|
||||
ASSERT_EQ(201, Lookup(200));
|
||||
ASSERT_EQ(-1, Lookup(300));
|
||||
|
||||
ASSERT_EQ(1, deleted_keys_.size());
|
||||
ASSERT_EQ(100, deleted_keys_[0]);
|
||||
ASSERT_EQ(101, deleted_values_[0]);
|
||||
}
|
||||
|
||||
TEST(CacheTest, Erase) {
|
||||
Erase(200);
|
||||
ASSERT_EQ(0, deleted_keys_.size());
|
||||
|
||||
Insert(100, 101);
|
||||
Insert(200, 201);
|
||||
Erase(100);
|
||||
ASSERT_EQ(-1, Lookup(100));
|
||||
ASSERT_EQ(201, Lookup(200));
|
||||
ASSERT_EQ(1, deleted_keys_.size());
|
||||
ASSERT_EQ(100, deleted_keys_[0]);
|
||||
ASSERT_EQ(101, deleted_values_[0]);
|
||||
|
||||
Erase(100);
|
||||
ASSERT_EQ(-1, Lookup(100));
|
||||
ASSERT_EQ(201, Lookup(200));
|
||||
ASSERT_EQ(1, deleted_keys_.size());
|
||||
}
|
||||
|
||||
TEST(CacheTest, EntriesArePinned) {
|
||||
Insert(100, 101);
|
||||
Cache::Handle* h1 = cache_->Lookup(EncodeKey(100));
|
||||
ASSERT_EQ(101, DecodeValue(cache_->Value(h1)));
|
||||
|
||||
Insert(100, 102);
|
||||
Cache::Handle* h2 = cache_->Lookup(EncodeKey(100));
|
||||
ASSERT_EQ(102, DecodeValue(cache_->Value(h2)));
|
||||
ASSERT_EQ(0, deleted_keys_.size());
|
||||
|
||||
cache_->Release(h1);
|
||||
ASSERT_EQ(1, deleted_keys_.size());
|
||||
ASSERT_EQ(100, deleted_keys_[0]);
|
||||
ASSERT_EQ(101, deleted_values_[0]);
|
||||
|
||||
Erase(100);
|
||||
ASSERT_EQ(-1, Lookup(100));
|
||||
ASSERT_EQ(1, deleted_keys_.size());
|
||||
|
||||
cache_->Release(h2);
|
||||
ASSERT_EQ(2, deleted_keys_.size());
|
||||
ASSERT_EQ(100, deleted_keys_[1]);
|
||||
ASSERT_EQ(102, deleted_values_[1]);
|
||||
}
|
||||
|
||||
TEST(CacheTest, EvictionPolicy) {
|
||||
Insert(100, 101);
|
||||
Insert(200, 201);
|
||||
Insert(300, 301);
|
||||
Cache::Handle* h = cache_->Lookup(EncodeKey(300));
|
||||
|
||||
// Frequently used entry must be kept around,
|
||||
// as must things that are still in use.
|
||||
for (int i = 0; i < kCacheSize + 100; i++) {
|
||||
Insert(1000+i, 2000+i);
|
||||
ASSERT_EQ(2000+i, Lookup(1000+i));
|
||||
ASSERT_EQ(101, Lookup(100));
|
||||
}
|
||||
ASSERT_EQ(101, Lookup(100));
|
||||
ASSERT_EQ(-1, Lookup(200));
|
||||
ASSERT_EQ(301, Lookup(300));
|
||||
cache_->Release(h);
|
||||
}
|
||||
|
||||
TEST(CacheTest, UseExceedsCacheSize) {
|
||||
// Overfill the cache, keeping handles on all inserted entries.
|
||||
std::vector<Cache::Handle*> h;
|
||||
for (int i = 0; i < kCacheSize + 100; i++) {
|
||||
h.push_back(InsertAndReturnHandle(1000+i, 2000+i));
|
||||
}
|
||||
|
||||
// Check that all the entries can be found in the cache.
|
||||
for (int i = 0; i < h.size(); i++) {
|
||||
ASSERT_EQ(2000+i, Lookup(1000+i));
|
||||
}
|
||||
|
||||
for (int i = 0; i < h.size(); i++) {
|
||||
cache_->Release(h[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CacheTest, HeavyEntries) {
|
||||
// Add a bunch of light and heavy entries and then count the combined
|
||||
// size of items still in the cache, which must be approximately the
|
||||
// same as the total capacity.
|
||||
const int kLight = 1;
|
||||
const int kHeavy = 10;
|
||||
int added = 0;
|
||||
int index = 0;
|
||||
while (added < 2*kCacheSize) {
|
||||
const int weight = (index & 1) ? kLight : kHeavy;
|
||||
Insert(index, 1000+index, weight);
|
||||
added += weight;
|
||||
index++;
|
||||
}
|
||||
|
||||
int cached_weight = 0;
|
||||
for (int i = 0; i < index; i++) {
|
||||
const int weight = (i & 1 ? kLight : kHeavy);
|
||||
int r = Lookup(i);
|
||||
if (r >= 0) {
|
||||
cached_weight += weight;
|
||||
ASSERT_EQ(1000+i, r);
|
||||
}
|
||||
}
|
||||
ASSERT_LE(cached_weight, kCacheSize + kCacheSize/10);
|
||||
}
|
||||
|
||||
TEST(CacheTest, NewId) {
|
||||
uint64_t a = cache_->NewId();
|
||||
uint64_t b = cache_->NewId();
|
||||
ASSERT_NE(a, b);
|
||||
}
|
||||
|
||||
TEST(CacheTest, Prune) {
|
||||
Insert(1, 100);
|
||||
Insert(2, 200);
|
||||
|
||||
Cache::Handle* handle = cache_->Lookup(EncodeKey(1));
|
||||
ASSERT_TRUE(handle);
|
||||
cache_->Prune();
|
||||
cache_->Release(handle);
|
||||
|
||||
ASSERT_EQ(100, Lookup(1));
|
||||
ASSERT_EQ(-1, Lookup(2));
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return leveldb::test::RunAllTests();
|
||||
}
|
||||
194
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/coding.cc
generated
vendored
Normal file
194
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/coding.cc
generated
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "util/coding.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
void EncodeFixed32(char* buf, uint32_t value) {
|
||||
if (port::kLittleEndian) {
|
||||
memcpy(buf, &value, sizeof(value));
|
||||
} else {
|
||||
buf[0] = value & 0xff;
|
||||
buf[1] = (value >> 8) & 0xff;
|
||||
buf[2] = (value >> 16) & 0xff;
|
||||
buf[3] = (value >> 24) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
void EncodeFixed64(char* buf, uint64_t value) {
|
||||
if (port::kLittleEndian) {
|
||||
memcpy(buf, &value, sizeof(value));
|
||||
} else {
|
||||
buf[0] = value & 0xff;
|
||||
buf[1] = (value >> 8) & 0xff;
|
||||
buf[2] = (value >> 16) & 0xff;
|
||||
buf[3] = (value >> 24) & 0xff;
|
||||
buf[4] = (value >> 32) & 0xff;
|
||||
buf[5] = (value >> 40) & 0xff;
|
||||
buf[6] = (value >> 48) & 0xff;
|
||||
buf[7] = (value >> 56) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
void PutFixed32(std::string* dst, uint32_t value) {
|
||||
char buf[sizeof(value)];
|
||||
EncodeFixed32(buf, value);
|
||||
dst->append(buf, sizeof(buf));
|
||||
}
|
||||
|
||||
void PutFixed64(std::string* dst, uint64_t value) {
|
||||
char buf[sizeof(value)];
|
||||
EncodeFixed64(buf, value);
|
||||
dst->append(buf, sizeof(buf));
|
||||
}
|
||||
|
||||
char* EncodeVarint32(char* dst, uint32_t v) {
|
||||
// Operate on characters as unsigneds
|
||||
unsigned char* ptr = reinterpret_cast<unsigned char*>(dst);
|
||||
static const int B = 128;
|
||||
if (v < (1<<7)) {
|
||||
*(ptr++) = v;
|
||||
} else if (v < (1<<14)) {
|
||||
*(ptr++) = v | B;
|
||||
*(ptr++) = v>>7;
|
||||
} else if (v < (1<<21)) {
|
||||
*(ptr++) = v | B;
|
||||
*(ptr++) = (v>>7) | B;
|
||||
*(ptr++) = v>>14;
|
||||
} else if (v < (1<<28)) {
|
||||
*(ptr++) = v | B;
|
||||
*(ptr++) = (v>>7) | B;
|
||||
*(ptr++) = (v>>14) | B;
|
||||
*(ptr++) = v>>21;
|
||||
} else {
|
||||
*(ptr++) = v | B;
|
||||
*(ptr++) = (v>>7) | B;
|
||||
*(ptr++) = (v>>14) | B;
|
||||
*(ptr++) = (v>>21) | B;
|
||||
*(ptr++) = v>>28;
|
||||
}
|
||||
return reinterpret_cast<char*>(ptr);
|
||||
}
|
||||
|
||||
void PutVarint32(std::string* dst, uint32_t v) {
|
||||
char buf[5];
|
||||
char* ptr = EncodeVarint32(buf, v);
|
||||
dst->append(buf, ptr - buf);
|
||||
}
|
||||
|
||||
char* EncodeVarint64(char* dst, uint64_t v) {
|
||||
static const int B = 128;
|
||||
unsigned char* ptr = reinterpret_cast<unsigned char*>(dst);
|
||||
while (v >= B) {
|
||||
*(ptr++) = (v & (B-1)) | B;
|
||||
v >>= 7;
|
||||
}
|
||||
*(ptr++) = static_cast<unsigned char>(v);
|
||||
return reinterpret_cast<char*>(ptr);
|
||||
}
|
||||
|
||||
void PutVarint64(std::string* dst, uint64_t v) {
|
||||
char buf[10];
|
||||
char* ptr = EncodeVarint64(buf, v);
|
||||
dst->append(buf, ptr - buf);
|
||||
}
|
||||
|
||||
void PutLengthPrefixedSlice(std::string* dst, const Slice& value) {
|
||||
PutVarint32(dst, value.size());
|
||||
dst->append(value.data(), value.size());
|
||||
}
|
||||
|
||||
int VarintLength(uint64_t v) {
|
||||
int len = 1;
|
||||
while (v >= 128) {
|
||||
v >>= 7;
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
const char* GetVarint32PtrFallback(const char* p,
|
||||
const char* limit,
|
||||
uint32_t* value) {
|
||||
uint32_t result = 0;
|
||||
for (uint32_t shift = 0; shift <= 28 && p < limit; shift += 7) {
|
||||
uint32_t byte = *(reinterpret_cast<const unsigned char*>(p));
|
||||
p++;
|
||||
if (byte & 128) {
|
||||
// More bytes are present
|
||||
result |= ((byte & 127) << shift);
|
||||
} else {
|
||||
result |= (byte << shift);
|
||||
*value = result;
|
||||
return reinterpret_cast<const char*>(p);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool GetVarint32(Slice* input, uint32_t* value) {
|
||||
const char* p = input->data();
|
||||
const char* limit = p + input->size();
|
||||
const char* q = GetVarint32Ptr(p, limit, value);
|
||||
if (q == NULL) {
|
||||
return false;
|
||||
} else {
|
||||
*input = Slice(q, limit - q);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const char* GetVarint64Ptr(const char* p, const char* limit, uint64_t* value) {
|
||||
uint64_t result = 0;
|
||||
for (uint32_t shift = 0; shift <= 63 && p < limit; shift += 7) {
|
||||
uint64_t byte = *(reinterpret_cast<const unsigned char*>(p));
|
||||
p++;
|
||||
if (byte & 128) {
|
||||
// More bytes are present
|
||||
result |= ((byte & 127) << shift);
|
||||
} else {
|
||||
result |= (byte << shift);
|
||||
*value = result;
|
||||
return reinterpret_cast<const char*>(p);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool GetVarint64(Slice* input, uint64_t* value) {
|
||||
const char* p = input->data();
|
||||
const char* limit = p + input->size();
|
||||
const char* q = GetVarint64Ptr(p, limit, value);
|
||||
if (q == NULL) {
|
||||
return false;
|
||||
} else {
|
||||
*input = Slice(q, limit - q);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const char* GetLengthPrefixedSlice(const char* p, const char* limit,
|
||||
Slice* result) {
|
||||
uint32_t len;
|
||||
p = GetVarint32Ptr(p, limit, &len);
|
||||
if (p == NULL) return NULL;
|
||||
if (p + len > limit) return NULL;
|
||||
*result = Slice(p, len);
|
||||
return p + len;
|
||||
}
|
||||
|
||||
bool GetLengthPrefixedSlice(Slice* input, Slice* result) {
|
||||
uint32_t len;
|
||||
if (GetVarint32(input, &len) &&
|
||||
input->size() >= len) {
|
||||
*result = Slice(input->data(), len);
|
||||
input->remove_prefix(len);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
104
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/coding.h
generated
vendored
Normal file
104
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/coding.h
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
//
|
||||
// Endian-neutral encoding:
|
||||
// * Fixed-length numbers are encoded with least-significant byte first
|
||||
// * In addition we support variable length "varint" encoding
|
||||
// * Strings are encoded prefixed by their length in varint format
|
||||
|
||||
#ifndef STORAGE_LEVELDB_UTIL_CODING_H_
|
||||
#define STORAGE_LEVELDB_UTIL_CODING_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include "leveldb/slice.h"
|
||||
#include "port/port.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
// Standard Put... routines append to a string
|
||||
extern void PutFixed32(std::string* dst, uint32_t value);
|
||||
extern void PutFixed64(std::string* dst, uint64_t value);
|
||||
extern void PutVarint32(std::string* dst, uint32_t value);
|
||||
extern void PutVarint64(std::string* dst, uint64_t value);
|
||||
extern void PutLengthPrefixedSlice(std::string* dst, const Slice& value);
|
||||
|
||||
// Standard Get... routines parse a value from the beginning of a Slice
|
||||
// and advance the slice past the parsed value.
|
||||
extern bool GetVarint32(Slice* input, uint32_t* value);
|
||||
extern bool GetVarint64(Slice* input, uint64_t* value);
|
||||
extern bool GetLengthPrefixedSlice(Slice* input, Slice* result);
|
||||
|
||||
// Pointer-based variants of GetVarint... These either store a value
|
||||
// in *v and return a pointer just past the parsed value, or return
|
||||
// NULL on error. These routines only look at bytes in the range
|
||||
// [p..limit-1]
|
||||
extern const char* GetVarint32Ptr(const char* p,const char* limit, uint32_t* v);
|
||||
extern const char* GetVarint64Ptr(const char* p,const char* limit, uint64_t* v);
|
||||
|
||||
// Returns the length of the varint32 or varint64 encoding of "v"
|
||||
extern int VarintLength(uint64_t v);
|
||||
|
||||
// Lower-level versions of Put... that write directly into a character buffer
|
||||
// REQUIRES: dst has enough space for the value being written
|
||||
extern void EncodeFixed32(char* dst, uint32_t value);
|
||||
extern void EncodeFixed64(char* dst, uint64_t value);
|
||||
|
||||
// Lower-level versions of Put... that write directly into a character buffer
|
||||
// and return a pointer just past the last byte written.
|
||||
// REQUIRES: dst has enough space for the value being written
|
||||
extern char* EncodeVarint32(char* dst, uint32_t value);
|
||||
extern char* EncodeVarint64(char* dst, uint64_t value);
|
||||
|
||||
// Lower-level versions of Get... that read directly from a character buffer
|
||||
// without any bounds checking.
|
||||
|
||||
inline uint32_t DecodeFixed32(const char* ptr) {
|
||||
if (port::kLittleEndian) {
|
||||
// Load the raw bytes
|
||||
uint32_t result;
|
||||
memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load
|
||||
return result;
|
||||
} else {
|
||||
return ((static_cast<uint32_t>(static_cast<unsigned char>(ptr[0])))
|
||||
| (static_cast<uint32_t>(static_cast<unsigned char>(ptr[1])) << 8)
|
||||
| (static_cast<uint32_t>(static_cast<unsigned char>(ptr[2])) << 16)
|
||||
| (static_cast<uint32_t>(static_cast<unsigned char>(ptr[3])) << 24));
|
||||
}
|
||||
}
|
||||
|
||||
inline uint64_t DecodeFixed64(const char* ptr) {
|
||||
if (port::kLittleEndian) {
|
||||
// Load the raw bytes
|
||||
uint64_t result;
|
||||
memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load
|
||||
return result;
|
||||
} else {
|
||||
uint64_t lo = DecodeFixed32(ptr);
|
||||
uint64_t hi = DecodeFixed32(ptr + 4);
|
||||
return (hi << 32) | lo;
|
||||
}
|
||||
}
|
||||
|
||||
// Internal routine for use by fallback path of GetVarint32Ptr
|
||||
extern const char* GetVarint32PtrFallback(const char* p,
|
||||
const char* limit,
|
||||
uint32_t* value);
|
||||
inline const char* GetVarint32Ptr(const char* p,
|
||||
const char* limit,
|
||||
uint32_t* value) {
|
||||
if (p < limit) {
|
||||
uint32_t result = *(reinterpret_cast<const unsigned char*>(p));
|
||||
if ((result & 128) == 0) {
|
||||
*value = result;
|
||||
return p + 1;
|
||||
}
|
||||
}
|
||||
return GetVarint32PtrFallback(p, limit, value);
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_UTIL_CODING_H_
|
||||
196
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/coding_test.cc
generated
vendored
Normal file
196
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/coding_test.cc
generated
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "util/coding.h"
|
||||
|
||||
#include "util/testharness.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
class Coding { };
|
||||
|
||||
TEST(Coding, Fixed32) {
|
||||
std::string s;
|
||||
for (uint32_t v = 0; v < 100000; v++) {
|
||||
PutFixed32(&s, v);
|
||||
}
|
||||
|
||||
const char* p = s.data();
|
||||
for (uint32_t v = 0; v < 100000; v++) {
|
||||
uint32_t actual = DecodeFixed32(p);
|
||||
ASSERT_EQ(v, actual);
|
||||
p += sizeof(uint32_t);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Coding, Fixed64) {
|
||||
std::string s;
|
||||
for (int power = 0; power <= 63; power++) {
|
||||
uint64_t v = static_cast<uint64_t>(1) << power;
|
||||
PutFixed64(&s, v - 1);
|
||||
PutFixed64(&s, v + 0);
|
||||
PutFixed64(&s, v + 1);
|
||||
}
|
||||
|
||||
const char* p = s.data();
|
||||
for (int power = 0; power <= 63; power++) {
|
||||
uint64_t v = static_cast<uint64_t>(1) << power;
|
||||
uint64_t actual;
|
||||
actual = DecodeFixed64(p);
|
||||
ASSERT_EQ(v-1, actual);
|
||||
p += sizeof(uint64_t);
|
||||
|
||||
actual = DecodeFixed64(p);
|
||||
ASSERT_EQ(v+0, actual);
|
||||
p += sizeof(uint64_t);
|
||||
|
||||
actual = DecodeFixed64(p);
|
||||
ASSERT_EQ(v+1, actual);
|
||||
p += sizeof(uint64_t);
|
||||
}
|
||||
}
|
||||
|
||||
// Test that encoding routines generate little-endian encodings
|
||||
TEST(Coding, EncodingOutput) {
|
||||
std::string dst;
|
||||
PutFixed32(&dst, 0x04030201);
|
||||
ASSERT_EQ(4, dst.size());
|
||||
ASSERT_EQ(0x01, static_cast<int>(dst[0]));
|
||||
ASSERT_EQ(0x02, static_cast<int>(dst[1]));
|
||||
ASSERT_EQ(0x03, static_cast<int>(dst[2]));
|
||||
ASSERT_EQ(0x04, static_cast<int>(dst[3]));
|
||||
|
||||
dst.clear();
|
||||
PutFixed64(&dst, 0x0807060504030201ull);
|
||||
ASSERT_EQ(8, dst.size());
|
||||
ASSERT_EQ(0x01, static_cast<int>(dst[0]));
|
||||
ASSERT_EQ(0x02, static_cast<int>(dst[1]));
|
||||
ASSERT_EQ(0x03, static_cast<int>(dst[2]));
|
||||
ASSERT_EQ(0x04, static_cast<int>(dst[3]));
|
||||
ASSERT_EQ(0x05, static_cast<int>(dst[4]));
|
||||
ASSERT_EQ(0x06, static_cast<int>(dst[5]));
|
||||
ASSERT_EQ(0x07, static_cast<int>(dst[6]));
|
||||
ASSERT_EQ(0x08, static_cast<int>(dst[7]));
|
||||
}
|
||||
|
||||
TEST(Coding, Varint32) {
|
||||
std::string s;
|
||||
for (uint32_t i = 0; i < (32 * 32); i++) {
|
||||
uint32_t v = (i / 32) << (i % 32);
|
||||
PutVarint32(&s, v);
|
||||
}
|
||||
|
||||
const char* p = s.data();
|
||||
const char* limit = p + s.size();
|
||||
for (uint32_t i = 0; i < (32 * 32); i++) {
|
||||
uint32_t expected = (i / 32) << (i % 32);
|
||||
uint32_t actual;
|
||||
const char* start = p;
|
||||
p = GetVarint32Ptr(p, limit, &actual);
|
||||
ASSERT_TRUE(p != NULL);
|
||||
ASSERT_EQ(expected, actual);
|
||||
ASSERT_EQ(VarintLength(actual), p - start);
|
||||
}
|
||||
ASSERT_EQ(p, s.data() + s.size());
|
||||
}
|
||||
|
||||
TEST(Coding, Varint64) {
|
||||
// Construct the list of values to check
|
||||
std::vector<uint64_t> values;
|
||||
// Some special values
|
||||
values.push_back(0);
|
||||
values.push_back(100);
|
||||
values.push_back(~static_cast<uint64_t>(0));
|
||||
values.push_back(~static_cast<uint64_t>(0) - 1);
|
||||
for (uint32_t k = 0; k < 64; k++) {
|
||||
// Test values near powers of two
|
||||
const uint64_t power = 1ull << k;
|
||||
values.push_back(power);
|
||||
values.push_back(power-1);
|
||||
values.push_back(power+1);
|
||||
}
|
||||
|
||||
std::string s;
|
||||
for (size_t i = 0; i < values.size(); i++) {
|
||||
PutVarint64(&s, values[i]);
|
||||
}
|
||||
|
||||
const char* p = s.data();
|
||||
const char* limit = p + s.size();
|
||||
for (size_t i = 0; i < values.size(); i++) {
|
||||
ASSERT_TRUE(p < limit);
|
||||
uint64_t actual;
|
||||
const char* start = p;
|
||||
p = GetVarint64Ptr(p, limit, &actual);
|
||||
ASSERT_TRUE(p != NULL);
|
||||
ASSERT_EQ(values[i], actual);
|
||||
ASSERT_EQ(VarintLength(actual), p - start);
|
||||
}
|
||||
ASSERT_EQ(p, limit);
|
||||
|
||||
}
|
||||
|
||||
TEST(Coding, Varint32Overflow) {
|
||||
uint32_t result;
|
||||
std::string input("\x81\x82\x83\x84\x85\x11");
|
||||
ASSERT_TRUE(GetVarint32Ptr(input.data(), input.data() + input.size(), &result)
|
||||
== NULL);
|
||||
}
|
||||
|
||||
TEST(Coding, Varint32Truncation) {
|
||||
uint32_t large_value = (1u << 31) + 100;
|
||||
std::string s;
|
||||
PutVarint32(&s, large_value);
|
||||
uint32_t result;
|
||||
for (size_t len = 0; len < s.size() - 1; len++) {
|
||||
ASSERT_TRUE(GetVarint32Ptr(s.data(), s.data() + len, &result) == NULL);
|
||||
}
|
||||
ASSERT_TRUE(GetVarint32Ptr(s.data(), s.data() + s.size(), &result) != NULL);
|
||||
ASSERT_EQ(large_value, result);
|
||||
}
|
||||
|
||||
TEST(Coding, Varint64Overflow) {
|
||||
uint64_t result;
|
||||
std::string input("\x81\x82\x83\x84\x85\x81\x82\x83\x84\x85\x11");
|
||||
ASSERT_TRUE(GetVarint64Ptr(input.data(), input.data() + input.size(), &result)
|
||||
== NULL);
|
||||
}
|
||||
|
||||
TEST(Coding, Varint64Truncation) {
|
||||
uint64_t large_value = (1ull << 63) + 100ull;
|
||||
std::string s;
|
||||
PutVarint64(&s, large_value);
|
||||
uint64_t result;
|
||||
for (size_t len = 0; len < s.size() - 1; len++) {
|
||||
ASSERT_TRUE(GetVarint64Ptr(s.data(), s.data() + len, &result) == NULL);
|
||||
}
|
||||
ASSERT_TRUE(GetVarint64Ptr(s.data(), s.data() + s.size(), &result) != NULL);
|
||||
ASSERT_EQ(large_value, result);
|
||||
}
|
||||
|
||||
TEST(Coding, Strings) {
|
||||
std::string s;
|
||||
PutLengthPrefixedSlice(&s, Slice(""));
|
||||
PutLengthPrefixedSlice(&s, Slice("foo"));
|
||||
PutLengthPrefixedSlice(&s, Slice("bar"));
|
||||
PutLengthPrefixedSlice(&s, Slice(std::string(200, 'x')));
|
||||
|
||||
Slice input(s);
|
||||
Slice v;
|
||||
ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v));
|
||||
ASSERT_EQ("", v.ToString());
|
||||
ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v));
|
||||
ASSERT_EQ("foo", v.ToString());
|
||||
ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v));
|
||||
ASSERT_EQ("bar", v.ToString());
|
||||
ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v));
|
||||
ASSERT_EQ(std::string(200, 'x'), v.ToString());
|
||||
ASSERT_EQ("", input.ToString());
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return leveldb::test::RunAllTests();
|
||||
}
|
||||
81
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/comparator.cc
generated
vendored
Normal file
81
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/comparator.cc
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdint.h>
|
||||
#include "leveldb/comparator.h"
|
||||
#include "leveldb/slice.h"
|
||||
#include "port/port.h"
|
||||
#include "util/logging.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
Comparator::~Comparator() { }
|
||||
|
||||
namespace {
|
||||
class BytewiseComparatorImpl : public Comparator {
|
||||
public:
|
||||
BytewiseComparatorImpl() { }
|
||||
|
||||
virtual const char* Name() const {
|
||||
return "leveldb.BytewiseComparator";
|
||||
}
|
||||
|
||||
virtual int Compare(const Slice& a, const Slice& b) const {
|
||||
return a.compare(b);
|
||||
}
|
||||
|
||||
virtual void FindShortestSeparator(
|
||||
std::string* start,
|
||||
const Slice& limit) const {
|
||||
// Find length of common prefix
|
||||
size_t min_length = std::min(start->size(), limit.size());
|
||||
size_t diff_index = 0;
|
||||
while ((diff_index < min_length) &&
|
||||
((*start)[diff_index] == limit[diff_index])) {
|
||||
diff_index++;
|
||||
}
|
||||
|
||||
if (diff_index >= min_length) {
|
||||
// Do not shorten if one string is a prefix of the other
|
||||
} else {
|
||||
uint8_t diff_byte = static_cast<uint8_t>((*start)[diff_index]);
|
||||
if (diff_byte < static_cast<uint8_t>(0xff) &&
|
||||
diff_byte + 1 < static_cast<uint8_t>(limit[diff_index])) {
|
||||
(*start)[diff_index]++;
|
||||
start->resize(diff_index + 1);
|
||||
assert(Compare(*start, limit) < 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void FindShortSuccessor(std::string* key) const {
|
||||
// Find first character that can be incremented
|
||||
size_t n = key->size();
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
const uint8_t byte = (*key)[i];
|
||||
if (byte != static_cast<uint8_t>(0xff)) {
|
||||
(*key)[i] = byte + 1;
|
||||
key->resize(i+1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// *key is a run of 0xffs. Leave it alone.
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
static port::OnceType once = LEVELDB_ONCE_INIT;
|
||||
static const Comparator* bytewise;
|
||||
|
||||
static void InitModule() {
|
||||
bytewise = new BytewiseComparatorImpl;
|
||||
}
|
||||
|
||||
const Comparator* BytewiseComparator() {
|
||||
port::InitOnce(&once, InitModule);
|
||||
return bytewise;
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
350
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/crc32c.cc
generated
vendored
Normal file
350
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/crc32c.cc
generated
vendored
Normal file
@@ -0,0 +1,350 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
//
|
||||
// A portable implementation of crc32c, optimized to handle
|
||||
// four bytes at a time.
|
||||
|
||||
#include "util/crc32c.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "port/port.h"
|
||||
#include "util/coding.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace crc32c {
|
||||
|
||||
static const uint32_t table0_[256] = {
|
||||
0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4,
|
||||
0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb,
|
||||
0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b,
|
||||
0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24,
|
||||
0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b,
|
||||
0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,
|
||||
0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54,
|
||||
0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b,
|
||||
0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a,
|
||||
0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35,
|
||||
0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5,
|
||||
0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,
|
||||
0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45,
|
||||
0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a,
|
||||
0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a,
|
||||
0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595,
|
||||
0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48,
|
||||
0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,
|
||||
0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687,
|
||||
0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198,
|
||||
0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927,
|
||||
0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38,
|
||||
0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8,
|
||||
0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,
|
||||
0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096,
|
||||
0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789,
|
||||
0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859,
|
||||
0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46,
|
||||
0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9,
|
||||
0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,
|
||||
0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36,
|
||||
0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829,
|
||||
0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c,
|
||||
0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93,
|
||||
0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043,
|
||||
0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,
|
||||
0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3,
|
||||
0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc,
|
||||
0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c,
|
||||
0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033,
|
||||
0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652,
|
||||
0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,
|
||||
0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d,
|
||||
0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982,
|
||||
0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d,
|
||||
0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622,
|
||||
0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2,
|
||||
0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,
|
||||
0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530,
|
||||
0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f,
|
||||
0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff,
|
||||
0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0,
|
||||
0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f,
|
||||
0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,
|
||||
0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90,
|
||||
0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f,
|
||||
0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee,
|
||||
0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1,
|
||||
0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321,
|
||||
0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,
|
||||
0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81,
|
||||
0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e,
|
||||
0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e,
|
||||
0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351
|
||||
};
|
||||
static const uint32_t table1_[256] = {
|
||||
0x00000000, 0x13a29877, 0x274530ee, 0x34e7a899,
|
||||
0x4e8a61dc, 0x5d28f9ab, 0x69cf5132, 0x7a6dc945,
|
||||
0x9d14c3b8, 0x8eb65bcf, 0xba51f356, 0xa9f36b21,
|
||||
0xd39ea264, 0xc03c3a13, 0xf4db928a, 0xe7790afd,
|
||||
0x3fc5f181, 0x2c6769f6, 0x1880c16f, 0x0b225918,
|
||||
0x714f905d, 0x62ed082a, 0x560aa0b3, 0x45a838c4,
|
||||
0xa2d13239, 0xb173aa4e, 0x859402d7, 0x96369aa0,
|
||||
0xec5b53e5, 0xfff9cb92, 0xcb1e630b, 0xd8bcfb7c,
|
||||
0x7f8be302, 0x6c297b75, 0x58ced3ec, 0x4b6c4b9b,
|
||||
0x310182de, 0x22a31aa9, 0x1644b230, 0x05e62a47,
|
||||
0xe29f20ba, 0xf13db8cd, 0xc5da1054, 0xd6788823,
|
||||
0xac154166, 0xbfb7d911, 0x8b507188, 0x98f2e9ff,
|
||||
0x404e1283, 0x53ec8af4, 0x670b226d, 0x74a9ba1a,
|
||||
0x0ec4735f, 0x1d66eb28, 0x298143b1, 0x3a23dbc6,
|
||||
0xdd5ad13b, 0xcef8494c, 0xfa1fe1d5, 0xe9bd79a2,
|
||||
0x93d0b0e7, 0x80722890, 0xb4958009, 0xa737187e,
|
||||
0xff17c604, 0xecb55e73, 0xd852f6ea, 0xcbf06e9d,
|
||||
0xb19da7d8, 0xa23f3faf, 0x96d89736, 0x857a0f41,
|
||||
0x620305bc, 0x71a19dcb, 0x45463552, 0x56e4ad25,
|
||||
0x2c896460, 0x3f2bfc17, 0x0bcc548e, 0x186eccf9,
|
||||
0xc0d23785, 0xd370aff2, 0xe797076b, 0xf4359f1c,
|
||||
0x8e585659, 0x9dface2e, 0xa91d66b7, 0xbabffec0,
|
||||
0x5dc6f43d, 0x4e646c4a, 0x7a83c4d3, 0x69215ca4,
|
||||
0x134c95e1, 0x00ee0d96, 0x3409a50f, 0x27ab3d78,
|
||||
0x809c2506, 0x933ebd71, 0xa7d915e8, 0xb47b8d9f,
|
||||
0xce1644da, 0xddb4dcad, 0xe9537434, 0xfaf1ec43,
|
||||
0x1d88e6be, 0x0e2a7ec9, 0x3acdd650, 0x296f4e27,
|
||||
0x53028762, 0x40a01f15, 0x7447b78c, 0x67e52ffb,
|
||||
0xbf59d487, 0xacfb4cf0, 0x981ce469, 0x8bbe7c1e,
|
||||
0xf1d3b55b, 0xe2712d2c, 0xd69685b5, 0xc5341dc2,
|
||||
0x224d173f, 0x31ef8f48, 0x050827d1, 0x16aabfa6,
|
||||
0x6cc776e3, 0x7f65ee94, 0x4b82460d, 0x5820de7a,
|
||||
0xfbc3faf9, 0xe861628e, 0xdc86ca17, 0xcf245260,
|
||||
0xb5499b25, 0xa6eb0352, 0x920cabcb, 0x81ae33bc,
|
||||
0x66d73941, 0x7575a136, 0x419209af, 0x523091d8,
|
||||
0x285d589d, 0x3bffc0ea, 0x0f186873, 0x1cbaf004,
|
||||
0xc4060b78, 0xd7a4930f, 0xe3433b96, 0xf0e1a3e1,
|
||||
0x8a8c6aa4, 0x992ef2d3, 0xadc95a4a, 0xbe6bc23d,
|
||||
0x5912c8c0, 0x4ab050b7, 0x7e57f82e, 0x6df56059,
|
||||
0x1798a91c, 0x043a316b, 0x30dd99f2, 0x237f0185,
|
||||
0x844819fb, 0x97ea818c, 0xa30d2915, 0xb0afb162,
|
||||
0xcac27827, 0xd960e050, 0xed8748c9, 0xfe25d0be,
|
||||
0x195cda43, 0x0afe4234, 0x3e19eaad, 0x2dbb72da,
|
||||
0x57d6bb9f, 0x447423e8, 0x70938b71, 0x63311306,
|
||||
0xbb8de87a, 0xa82f700d, 0x9cc8d894, 0x8f6a40e3,
|
||||
0xf50789a6, 0xe6a511d1, 0xd242b948, 0xc1e0213f,
|
||||
0x26992bc2, 0x353bb3b5, 0x01dc1b2c, 0x127e835b,
|
||||
0x68134a1e, 0x7bb1d269, 0x4f567af0, 0x5cf4e287,
|
||||
0x04d43cfd, 0x1776a48a, 0x23910c13, 0x30339464,
|
||||
0x4a5e5d21, 0x59fcc556, 0x6d1b6dcf, 0x7eb9f5b8,
|
||||
0x99c0ff45, 0x8a626732, 0xbe85cfab, 0xad2757dc,
|
||||
0xd74a9e99, 0xc4e806ee, 0xf00fae77, 0xe3ad3600,
|
||||
0x3b11cd7c, 0x28b3550b, 0x1c54fd92, 0x0ff665e5,
|
||||
0x759baca0, 0x663934d7, 0x52de9c4e, 0x417c0439,
|
||||
0xa6050ec4, 0xb5a796b3, 0x81403e2a, 0x92e2a65d,
|
||||
0xe88f6f18, 0xfb2df76f, 0xcfca5ff6, 0xdc68c781,
|
||||
0x7b5fdfff, 0x68fd4788, 0x5c1aef11, 0x4fb87766,
|
||||
0x35d5be23, 0x26772654, 0x12908ecd, 0x013216ba,
|
||||
0xe64b1c47, 0xf5e98430, 0xc10e2ca9, 0xd2acb4de,
|
||||
0xa8c17d9b, 0xbb63e5ec, 0x8f844d75, 0x9c26d502,
|
||||
0x449a2e7e, 0x5738b609, 0x63df1e90, 0x707d86e7,
|
||||
0x0a104fa2, 0x19b2d7d5, 0x2d557f4c, 0x3ef7e73b,
|
||||
0xd98eedc6, 0xca2c75b1, 0xfecbdd28, 0xed69455f,
|
||||
0x97048c1a, 0x84a6146d, 0xb041bcf4, 0xa3e32483
|
||||
};
|
||||
static const uint32_t table2_[256] = {
|
||||
0x00000000, 0xa541927e, 0x4f6f520d, 0xea2ec073,
|
||||
0x9edea41a, 0x3b9f3664, 0xd1b1f617, 0x74f06469,
|
||||
0x38513ec5, 0x9d10acbb, 0x773e6cc8, 0xd27ffeb6,
|
||||
0xa68f9adf, 0x03ce08a1, 0xe9e0c8d2, 0x4ca15aac,
|
||||
0x70a27d8a, 0xd5e3eff4, 0x3fcd2f87, 0x9a8cbdf9,
|
||||
0xee7cd990, 0x4b3d4bee, 0xa1138b9d, 0x045219e3,
|
||||
0x48f3434f, 0xedb2d131, 0x079c1142, 0xa2dd833c,
|
||||
0xd62de755, 0x736c752b, 0x9942b558, 0x3c032726,
|
||||
0xe144fb14, 0x4405696a, 0xae2ba919, 0x0b6a3b67,
|
||||
0x7f9a5f0e, 0xdadbcd70, 0x30f50d03, 0x95b49f7d,
|
||||
0xd915c5d1, 0x7c5457af, 0x967a97dc, 0x333b05a2,
|
||||
0x47cb61cb, 0xe28af3b5, 0x08a433c6, 0xade5a1b8,
|
||||
0x91e6869e, 0x34a714e0, 0xde89d493, 0x7bc846ed,
|
||||
0x0f382284, 0xaa79b0fa, 0x40577089, 0xe516e2f7,
|
||||
0xa9b7b85b, 0x0cf62a25, 0xe6d8ea56, 0x43997828,
|
||||
0x37691c41, 0x92288e3f, 0x78064e4c, 0xdd47dc32,
|
||||
0xc76580d9, 0x622412a7, 0x880ad2d4, 0x2d4b40aa,
|
||||
0x59bb24c3, 0xfcfab6bd, 0x16d476ce, 0xb395e4b0,
|
||||
0xff34be1c, 0x5a752c62, 0xb05bec11, 0x151a7e6f,
|
||||
0x61ea1a06, 0xc4ab8878, 0x2e85480b, 0x8bc4da75,
|
||||
0xb7c7fd53, 0x12866f2d, 0xf8a8af5e, 0x5de93d20,
|
||||
0x29195949, 0x8c58cb37, 0x66760b44, 0xc337993a,
|
||||
0x8f96c396, 0x2ad751e8, 0xc0f9919b, 0x65b803e5,
|
||||
0x1148678c, 0xb409f5f2, 0x5e273581, 0xfb66a7ff,
|
||||
0x26217bcd, 0x8360e9b3, 0x694e29c0, 0xcc0fbbbe,
|
||||
0xb8ffdfd7, 0x1dbe4da9, 0xf7908dda, 0x52d11fa4,
|
||||
0x1e704508, 0xbb31d776, 0x511f1705, 0xf45e857b,
|
||||
0x80aee112, 0x25ef736c, 0xcfc1b31f, 0x6a802161,
|
||||
0x56830647, 0xf3c29439, 0x19ec544a, 0xbcadc634,
|
||||
0xc85da25d, 0x6d1c3023, 0x8732f050, 0x2273622e,
|
||||
0x6ed23882, 0xcb93aafc, 0x21bd6a8f, 0x84fcf8f1,
|
||||
0xf00c9c98, 0x554d0ee6, 0xbf63ce95, 0x1a225ceb,
|
||||
0x8b277743, 0x2e66e53d, 0xc448254e, 0x6109b730,
|
||||
0x15f9d359, 0xb0b84127, 0x5a968154, 0xffd7132a,
|
||||
0xb3764986, 0x1637dbf8, 0xfc191b8b, 0x595889f5,
|
||||
0x2da8ed9c, 0x88e97fe2, 0x62c7bf91, 0xc7862def,
|
||||
0xfb850ac9, 0x5ec498b7, 0xb4ea58c4, 0x11abcaba,
|
||||
0x655baed3, 0xc01a3cad, 0x2a34fcde, 0x8f756ea0,
|
||||
0xc3d4340c, 0x6695a672, 0x8cbb6601, 0x29faf47f,
|
||||
0x5d0a9016, 0xf84b0268, 0x1265c21b, 0xb7245065,
|
||||
0x6a638c57, 0xcf221e29, 0x250cde5a, 0x804d4c24,
|
||||
0xf4bd284d, 0x51fcba33, 0xbbd27a40, 0x1e93e83e,
|
||||
0x5232b292, 0xf77320ec, 0x1d5de09f, 0xb81c72e1,
|
||||
0xccec1688, 0x69ad84f6, 0x83834485, 0x26c2d6fb,
|
||||
0x1ac1f1dd, 0xbf8063a3, 0x55aea3d0, 0xf0ef31ae,
|
||||
0x841f55c7, 0x215ec7b9, 0xcb7007ca, 0x6e3195b4,
|
||||
0x2290cf18, 0x87d15d66, 0x6dff9d15, 0xc8be0f6b,
|
||||
0xbc4e6b02, 0x190ff97c, 0xf321390f, 0x5660ab71,
|
||||
0x4c42f79a, 0xe90365e4, 0x032da597, 0xa66c37e9,
|
||||
0xd29c5380, 0x77ddc1fe, 0x9df3018d, 0x38b293f3,
|
||||
0x7413c95f, 0xd1525b21, 0x3b7c9b52, 0x9e3d092c,
|
||||
0xeacd6d45, 0x4f8cff3b, 0xa5a23f48, 0x00e3ad36,
|
||||
0x3ce08a10, 0x99a1186e, 0x738fd81d, 0xd6ce4a63,
|
||||
0xa23e2e0a, 0x077fbc74, 0xed517c07, 0x4810ee79,
|
||||
0x04b1b4d5, 0xa1f026ab, 0x4bdee6d8, 0xee9f74a6,
|
||||
0x9a6f10cf, 0x3f2e82b1, 0xd50042c2, 0x7041d0bc,
|
||||
0xad060c8e, 0x08479ef0, 0xe2695e83, 0x4728ccfd,
|
||||
0x33d8a894, 0x96993aea, 0x7cb7fa99, 0xd9f668e7,
|
||||
0x9557324b, 0x3016a035, 0xda386046, 0x7f79f238,
|
||||
0x0b899651, 0xaec8042f, 0x44e6c45c, 0xe1a75622,
|
||||
0xdda47104, 0x78e5e37a, 0x92cb2309, 0x378ab177,
|
||||
0x437ad51e, 0xe63b4760, 0x0c158713, 0xa954156d,
|
||||
0xe5f54fc1, 0x40b4ddbf, 0xaa9a1dcc, 0x0fdb8fb2,
|
||||
0x7b2bebdb, 0xde6a79a5, 0x3444b9d6, 0x91052ba8
|
||||
};
|
||||
static const uint32_t table3_[256] = {
|
||||
0x00000000, 0xdd45aab8, 0xbf672381, 0x62228939,
|
||||
0x7b2231f3, 0xa6679b4b, 0xc4451272, 0x1900b8ca,
|
||||
0xf64463e6, 0x2b01c95e, 0x49234067, 0x9466eadf,
|
||||
0x8d665215, 0x5023f8ad, 0x32017194, 0xef44db2c,
|
||||
0xe964b13d, 0x34211b85, 0x560392bc, 0x8b463804,
|
||||
0x924680ce, 0x4f032a76, 0x2d21a34f, 0xf06409f7,
|
||||
0x1f20d2db, 0xc2657863, 0xa047f15a, 0x7d025be2,
|
||||
0x6402e328, 0xb9474990, 0xdb65c0a9, 0x06206a11,
|
||||
0xd725148b, 0x0a60be33, 0x6842370a, 0xb5079db2,
|
||||
0xac072578, 0x71428fc0, 0x136006f9, 0xce25ac41,
|
||||
0x2161776d, 0xfc24ddd5, 0x9e0654ec, 0x4343fe54,
|
||||
0x5a43469e, 0x8706ec26, 0xe524651f, 0x3861cfa7,
|
||||
0x3e41a5b6, 0xe3040f0e, 0x81268637, 0x5c632c8f,
|
||||
0x45639445, 0x98263efd, 0xfa04b7c4, 0x27411d7c,
|
||||
0xc805c650, 0x15406ce8, 0x7762e5d1, 0xaa274f69,
|
||||
0xb327f7a3, 0x6e625d1b, 0x0c40d422, 0xd1057e9a,
|
||||
0xaba65fe7, 0x76e3f55f, 0x14c17c66, 0xc984d6de,
|
||||
0xd0846e14, 0x0dc1c4ac, 0x6fe34d95, 0xb2a6e72d,
|
||||
0x5de23c01, 0x80a796b9, 0xe2851f80, 0x3fc0b538,
|
||||
0x26c00df2, 0xfb85a74a, 0x99a72e73, 0x44e284cb,
|
||||
0x42c2eeda, 0x9f874462, 0xfda5cd5b, 0x20e067e3,
|
||||
0x39e0df29, 0xe4a57591, 0x8687fca8, 0x5bc25610,
|
||||
0xb4868d3c, 0x69c32784, 0x0be1aebd, 0xd6a40405,
|
||||
0xcfa4bccf, 0x12e11677, 0x70c39f4e, 0xad8635f6,
|
||||
0x7c834b6c, 0xa1c6e1d4, 0xc3e468ed, 0x1ea1c255,
|
||||
0x07a17a9f, 0xdae4d027, 0xb8c6591e, 0x6583f3a6,
|
||||
0x8ac7288a, 0x57828232, 0x35a00b0b, 0xe8e5a1b3,
|
||||
0xf1e51979, 0x2ca0b3c1, 0x4e823af8, 0x93c79040,
|
||||
0x95e7fa51, 0x48a250e9, 0x2a80d9d0, 0xf7c57368,
|
||||
0xeec5cba2, 0x3380611a, 0x51a2e823, 0x8ce7429b,
|
||||
0x63a399b7, 0xbee6330f, 0xdcc4ba36, 0x0181108e,
|
||||
0x1881a844, 0xc5c402fc, 0xa7e68bc5, 0x7aa3217d,
|
||||
0x52a0c93f, 0x8fe56387, 0xedc7eabe, 0x30824006,
|
||||
0x2982f8cc, 0xf4c75274, 0x96e5db4d, 0x4ba071f5,
|
||||
0xa4e4aad9, 0x79a10061, 0x1b838958, 0xc6c623e0,
|
||||
0xdfc69b2a, 0x02833192, 0x60a1b8ab, 0xbde41213,
|
||||
0xbbc47802, 0x6681d2ba, 0x04a35b83, 0xd9e6f13b,
|
||||
0xc0e649f1, 0x1da3e349, 0x7f816a70, 0xa2c4c0c8,
|
||||
0x4d801be4, 0x90c5b15c, 0xf2e73865, 0x2fa292dd,
|
||||
0x36a22a17, 0xebe780af, 0x89c50996, 0x5480a32e,
|
||||
0x8585ddb4, 0x58c0770c, 0x3ae2fe35, 0xe7a7548d,
|
||||
0xfea7ec47, 0x23e246ff, 0x41c0cfc6, 0x9c85657e,
|
||||
0x73c1be52, 0xae8414ea, 0xcca69dd3, 0x11e3376b,
|
||||
0x08e38fa1, 0xd5a62519, 0xb784ac20, 0x6ac10698,
|
||||
0x6ce16c89, 0xb1a4c631, 0xd3864f08, 0x0ec3e5b0,
|
||||
0x17c35d7a, 0xca86f7c2, 0xa8a47efb, 0x75e1d443,
|
||||
0x9aa50f6f, 0x47e0a5d7, 0x25c22cee, 0xf8878656,
|
||||
0xe1873e9c, 0x3cc29424, 0x5ee01d1d, 0x83a5b7a5,
|
||||
0xf90696d8, 0x24433c60, 0x4661b559, 0x9b241fe1,
|
||||
0x8224a72b, 0x5f610d93, 0x3d4384aa, 0xe0062e12,
|
||||
0x0f42f53e, 0xd2075f86, 0xb025d6bf, 0x6d607c07,
|
||||
0x7460c4cd, 0xa9256e75, 0xcb07e74c, 0x16424df4,
|
||||
0x106227e5, 0xcd278d5d, 0xaf050464, 0x7240aedc,
|
||||
0x6b401616, 0xb605bcae, 0xd4273597, 0x09629f2f,
|
||||
0xe6264403, 0x3b63eebb, 0x59416782, 0x8404cd3a,
|
||||
0x9d0475f0, 0x4041df48, 0x22635671, 0xff26fcc9,
|
||||
0x2e238253, 0xf36628eb, 0x9144a1d2, 0x4c010b6a,
|
||||
0x5501b3a0, 0x88441918, 0xea669021, 0x37233a99,
|
||||
0xd867e1b5, 0x05224b0d, 0x6700c234, 0xba45688c,
|
||||
0xa345d046, 0x7e007afe, 0x1c22f3c7, 0xc167597f,
|
||||
0xc747336e, 0x1a0299d6, 0x782010ef, 0xa565ba57,
|
||||
0xbc65029d, 0x6120a825, 0x0302211c, 0xde478ba4,
|
||||
0x31035088, 0xec46fa30, 0x8e647309, 0x5321d9b1,
|
||||
0x4a21617b, 0x9764cbc3, 0xf54642fa, 0x2803e842
|
||||
};
|
||||
|
||||
// Used to fetch a naturally-aligned 32-bit word in little endian byte-order
|
||||
static inline uint32_t LE_LOAD32(const uint8_t *p) {
|
||||
return DecodeFixed32(reinterpret_cast<const char*>(p));
|
||||
}
|
||||
|
||||
// Determine if the CPU running this program can accelerate the CRC32C
|
||||
// calculation.
|
||||
static bool CanAccelerateCRC32C() {
|
||||
// port::AcceleretedCRC32C returns zero when unable to accelerate.
|
||||
static const char kTestCRCBuffer[] = "TestCRCBuffer";
|
||||
static const char kBufSize = sizeof(kTestCRCBuffer) - 1;
|
||||
static const uint32_t kTestCRCValue = 0xdcbc59fa;
|
||||
|
||||
return port::AcceleratedCRC32C(0, kTestCRCBuffer, kBufSize) == kTestCRCValue;
|
||||
}
|
||||
|
||||
uint32_t Extend(uint32_t crc, const char* buf, size_t size) {
|
||||
static bool accelerate = CanAccelerateCRC32C();
|
||||
if (accelerate) {
|
||||
return port::AcceleratedCRC32C(crc, buf, size);
|
||||
}
|
||||
|
||||
const uint8_t *p = reinterpret_cast<const uint8_t *>(buf);
|
||||
const uint8_t *e = p + size;
|
||||
uint32_t l = crc ^ 0xffffffffu;
|
||||
|
||||
#define STEP1 do { \
|
||||
int c = (l & 0xff) ^ *p++; \
|
||||
l = table0_[c] ^ (l >> 8); \
|
||||
} while (0)
|
||||
#define STEP4 do { \
|
||||
uint32_t c = l ^ LE_LOAD32(p); \
|
||||
p += 4; \
|
||||
l = table3_[c & 0xff] ^ \
|
||||
table2_[(c >> 8) & 0xff] ^ \
|
||||
table1_[(c >> 16) & 0xff] ^ \
|
||||
table0_[c >> 24]; \
|
||||
} while (0)
|
||||
|
||||
// Point x at first 4-byte aligned byte in string. This might be
|
||||
// just past the end of the string.
|
||||
const uintptr_t pval = reinterpret_cast<uintptr_t>(p);
|
||||
const uint8_t* x = reinterpret_cast<const uint8_t*>(((pval + 3) >> 2) << 2);
|
||||
if (x <= e) {
|
||||
// Process bytes until finished or p is 4-byte aligned
|
||||
while (p != x) {
|
||||
STEP1;
|
||||
}
|
||||
}
|
||||
// Process bytes 16 at a time
|
||||
while ((e-p) >= 16) {
|
||||
STEP4; STEP4; STEP4; STEP4;
|
||||
}
|
||||
// Process bytes 4 at a time
|
||||
while ((e-p) >= 4) {
|
||||
STEP4;
|
||||
}
|
||||
// Process the last few bytes
|
||||
while (p != e) {
|
||||
STEP1;
|
||||
}
|
||||
#undef STEP4
|
||||
#undef STEP1
|
||||
return l ^ 0xffffffffu;
|
||||
}
|
||||
|
||||
} // namespace crc32c
|
||||
} // namespace leveldb
|
||||
45
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/crc32c.h
generated
vendored
Normal file
45
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/crc32c.h
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_UTIL_CRC32C_H_
|
||||
#define STORAGE_LEVELDB_UTIL_CRC32C_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace leveldb {
|
||||
namespace crc32c {
|
||||
|
||||
// Return the crc32c of concat(A, data[0,n-1]) where init_crc is the
|
||||
// crc32c of some string A. Extend() is often used to maintain the
|
||||
// crc32c of a stream of data.
|
||||
extern uint32_t Extend(uint32_t init_crc, const char* data, size_t n);
|
||||
|
||||
// Return the crc32c of data[0,n-1]
|
||||
inline uint32_t Value(const char* data, size_t n) {
|
||||
return Extend(0, data, n);
|
||||
}
|
||||
|
||||
static const uint32_t kMaskDelta = 0xa282ead8ul;
|
||||
|
||||
// Return a masked representation of crc.
|
||||
//
|
||||
// Motivation: it is problematic to compute the CRC of a string that
|
||||
// contains embedded CRCs. Therefore we recommend that CRCs stored
|
||||
// somewhere (e.g., in files) should be masked before being stored.
|
||||
inline uint32_t Mask(uint32_t crc) {
|
||||
// Rotate right by 15 bits and add a constant.
|
||||
return ((crc >> 15) | (crc << 17)) + kMaskDelta;
|
||||
}
|
||||
|
||||
// Return the crc whose masked representation is masked_crc.
|
||||
inline uint32_t Unmask(uint32_t masked_crc) {
|
||||
uint32_t rot = masked_crc - kMaskDelta;
|
||||
return ((rot >> 17) | (rot << 15));
|
||||
}
|
||||
|
||||
} // namespace crc32c
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_UTIL_CRC32C_H_
|
||||
72
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/crc32c_test.cc
generated
vendored
Normal file
72
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/crc32c_test.cc
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "util/crc32c.h"
|
||||
#include "util/testharness.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace crc32c {
|
||||
|
||||
class CRC { };
|
||||
|
||||
TEST(CRC, StandardResults) {
|
||||
// From rfc3720 section B.4.
|
||||
char buf[32];
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
ASSERT_EQ(0x8a9136aa, Value(buf, sizeof(buf)));
|
||||
|
||||
memset(buf, 0xff, sizeof(buf));
|
||||
ASSERT_EQ(0x62a8ab43, Value(buf, sizeof(buf)));
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
buf[i] = i;
|
||||
}
|
||||
ASSERT_EQ(0x46dd794e, Value(buf, sizeof(buf)));
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
buf[i] = 31 - i;
|
||||
}
|
||||
ASSERT_EQ(0x113fdb5c, Value(buf, sizeof(buf)));
|
||||
|
||||
unsigned char data[48] = {
|
||||
0x01, 0xc0, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x14, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x04, 0x00,
|
||||
0x00, 0x00, 0x00, 0x14,
|
||||
0x00, 0x00, 0x00, 0x18,
|
||||
0x28, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
ASSERT_EQ(0xd9963a56, Value(reinterpret_cast<char*>(data), sizeof(data)));
|
||||
}
|
||||
|
||||
TEST(CRC, Values) {
|
||||
ASSERT_NE(Value("a", 1), Value("foo", 3));
|
||||
}
|
||||
|
||||
TEST(CRC, Extend) {
|
||||
ASSERT_EQ(Value("hello world", 11),
|
||||
Extend(Value("hello ", 6), "world", 5));
|
||||
}
|
||||
|
||||
TEST(CRC, Mask) {
|
||||
uint32_t crc = Value("foo", 3);
|
||||
ASSERT_NE(crc, Mask(crc));
|
||||
ASSERT_NE(crc, Mask(Mask(crc)));
|
||||
ASSERT_EQ(crc, Unmask(Mask(crc)));
|
||||
ASSERT_EQ(crc, Unmask(Unmask(Mask(Mask(crc)))));
|
||||
}
|
||||
|
||||
} // namespace crc32c
|
||||
} // namespace leveldb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return leveldb::test::RunAllTests();
|
||||
}
|
||||
100
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/env.cc
generated
vendored
Normal file
100
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/env.cc
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "leveldb/env.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
Env::~Env() {
|
||||
}
|
||||
|
||||
Status Env::NewAppendableFile(const std::string& fname, WritableFile** result) {
|
||||
return Status::NotSupported("NewAppendableFile", fname);
|
||||
}
|
||||
|
||||
SequentialFile::~SequentialFile() {
|
||||
}
|
||||
|
||||
RandomAccessFile::~RandomAccessFile() {
|
||||
}
|
||||
|
||||
WritableFile::~WritableFile() {
|
||||
}
|
||||
|
||||
Logger::~Logger() {
|
||||
}
|
||||
|
||||
FileLock::~FileLock() {
|
||||
}
|
||||
|
||||
void Log(Logger* info_log, const char* format, ...) {
|
||||
if (info_log != NULL) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
info_log->Logv(format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
static Status DoWriteStringToFile(Env* env, const Slice& data,
|
||||
const std::string& fname,
|
||||
bool should_sync) {
|
||||
WritableFile* file;
|
||||
Status s = env->NewWritableFile(fname, &file);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
s = file->Append(data);
|
||||
if (s.ok() && should_sync) {
|
||||
s = file->Sync();
|
||||
}
|
||||
if (s.ok()) {
|
||||
s = file->Close();
|
||||
}
|
||||
delete file; // Will auto-close if we did not close above
|
||||
if (!s.ok()) {
|
||||
env->DeleteFile(fname);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
Status WriteStringToFile(Env* env, const Slice& data,
|
||||
const std::string& fname) {
|
||||
return DoWriteStringToFile(env, data, fname, false);
|
||||
}
|
||||
|
||||
Status WriteStringToFileSync(Env* env, const Slice& data,
|
||||
const std::string& fname) {
|
||||
return DoWriteStringToFile(env, data, fname, true);
|
||||
}
|
||||
|
||||
Status ReadFileToString(Env* env, const std::string& fname, std::string* data) {
|
||||
data->clear();
|
||||
SequentialFile* file;
|
||||
Status s = env->NewSequentialFile(fname, &file);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
static const int kBufferSize = 8192;
|
||||
char* space = new char[kBufferSize];
|
||||
while (true) {
|
||||
Slice fragment;
|
||||
s = file->Read(kBufferSize, &fragment, space);
|
||||
if (!s.ok()) {
|
||||
break;
|
||||
}
|
||||
data->append(fragment.data(), fragment.size());
|
||||
if (fragment.empty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete[] space;
|
||||
delete file;
|
||||
return s;
|
||||
}
|
||||
|
||||
EnvWrapper::~EnvWrapper() {
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
695
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/env_posix.cc
generated
vendored
Normal file
695
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/env_posix.cc
generated
vendored
Normal file
@@ -0,0 +1,695 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <deque>
|
||||
#include <limits>
|
||||
#include <set>
|
||||
#include "leveldb/env.h"
|
||||
#include "leveldb/slice.h"
|
||||
#include "port/port.h"
|
||||
#include "util/logging.h"
|
||||
#include "util/mutexlock.h"
|
||||
#include "util/posix_logger.h"
|
||||
#include "util/env_posix_test_helper.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
namespace {
|
||||
|
||||
static int open_read_only_file_limit = -1;
|
||||
static int mmap_limit = -1;
|
||||
|
||||
static Status IOError(const std::string& context, int err_number) {
|
||||
return Status::IOError(context, strerror(err_number));
|
||||
}
|
||||
|
||||
// Helper class to limit resource usage to avoid exhaustion.
|
||||
// Currently used to limit read-only file descriptors and mmap file usage
|
||||
// so that we do not end up running out of file descriptors, virtual memory,
|
||||
// or running into kernel performance problems for very large databases.
|
||||
class Limiter {
|
||||
public:
|
||||
// Limit maximum number of resources to |n|.
|
||||
Limiter(intptr_t n) {
|
||||
SetAllowed(n);
|
||||
}
|
||||
|
||||
// If another resource is available, acquire it and return true.
|
||||
// Else return false.
|
||||
bool Acquire() {
|
||||
if (GetAllowed() <= 0) {
|
||||
return false;
|
||||
}
|
||||
MutexLock l(&mu_);
|
||||
intptr_t x = GetAllowed();
|
||||
if (x <= 0) {
|
||||
return false;
|
||||
} else {
|
||||
SetAllowed(x - 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Release a resource acquired by a previous call to Acquire() that returned
|
||||
// true.
|
||||
void Release() {
|
||||
MutexLock l(&mu_);
|
||||
SetAllowed(GetAllowed() + 1);
|
||||
}
|
||||
|
||||
private:
|
||||
port::Mutex mu_;
|
||||
port::AtomicPointer allowed_;
|
||||
|
||||
intptr_t GetAllowed() const {
|
||||
return reinterpret_cast<intptr_t>(allowed_.Acquire_Load());
|
||||
}
|
||||
|
||||
// REQUIRES: mu_ must be held
|
||||
void SetAllowed(intptr_t v) {
|
||||
allowed_.Release_Store(reinterpret_cast<void*>(v));
|
||||
}
|
||||
|
||||
Limiter(const Limiter&);
|
||||
void operator=(const Limiter&);
|
||||
};
|
||||
|
||||
class PosixSequentialFile: public SequentialFile {
|
||||
private:
|
||||
std::string filename_;
|
||||
FILE* file_;
|
||||
|
||||
public:
|
||||
PosixSequentialFile(const std::string& fname, FILE* f)
|
||||
: filename_(fname), file_(f) { }
|
||||
virtual ~PosixSequentialFile() { fclose(file_); }
|
||||
|
||||
virtual Status Read(size_t n, Slice* result, char* scratch) {
|
||||
Status s;
|
||||
size_t r = fread_unlocked(scratch, 1, n, file_);
|
||||
*result = Slice(scratch, r);
|
||||
if (r < n) {
|
||||
if (feof(file_)) {
|
||||
// We leave status as ok if we hit the end of the file
|
||||
} else {
|
||||
// A partial read with an error: return a non-ok status
|
||||
s = IOError(filename_, errno);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
virtual Status Skip(uint64_t n) {
|
||||
if (fseek(file_, n, SEEK_CUR)) {
|
||||
return IOError(filename_, errno);
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
};
|
||||
|
||||
// pread() based random-access
|
||||
class PosixRandomAccessFile: public RandomAccessFile {
|
||||
private:
|
||||
std::string filename_;
|
||||
bool temporary_fd_; // If true, fd_ is -1 and we open on every read.
|
||||
int fd_;
|
||||
Limiter* limiter_;
|
||||
|
||||
public:
|
||||
PosixRandomAccessFile(const std::string& fname, int fd, Limiter* limiter)
|
||||
: filename_(fname), fd_(fd), limiter_(limiter) {
|
||||
temporary_fd_ = !limiter->Acquire();
|
||||
if (temporary_fd_) {
|
||||
// Open file on every access.
|
||||
close(fd_);
|
||||
fd_ = -1;
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~PosixRandomAccessFile() {
|
||||
if (!temporary_fd_) {
|
||||
close(fd_);
|
||||
limiter_->Release();
|
||||
}
|
||||
}
|
||||
|
||||
virtual Status Read(uint64_t offset, size_t n, Slice* result,
|
||||
char* scratch) const {
|
||||
int fd = fd_;
|
||||
if (temporary_fd_) {
|
||||
fd = open(filename_.c_str(), O_RDONLY);
|
||||
if (fd < 0) {
|
||||
return IOError(filename_, errno);
|
||||
}
|
||||
}
|
||||
|
||||
Status s;
|
||||
ssize_t r = pread(fd, scratch, n, static_cast<off_t>(offset));
|
||||
*result = Slice(scratch, (r < 0) ? 0 : r);
|
||||
if (r < 0) {
|
||||
// An error: return a non-ok status
|
||||
s = IOError(filename_, errno);
|
||||
}
|
||||
if (temporary_fd_) {
|
||||
// Close the temporary file descriptor opened earlier.
|
||||
close(fd);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
// mmap() based random-access
|
||||
class PosixMmapReadableFile: public RandomAccessFile {
|
||||
private:
|
||||
std::string filename_;
|
||||
void* mmapped_region_;
|
||||
size_t length_;
|
||||
Limiter* limiter_;
|
||||
|
||||
public:
|
||||
// base[0,length-1] contains the mmapped contents of the file.
|
||||
PosixMmapReadableFile(const std::string& fname, void* base, size_t length,
|
||||
Limiter* limiter)
|
||||
: filename_(fname), mmapped_region_(base), length_(length),
|
||||
limiter_(limiter) {
|
||||
}
|
||||
|
||||
virtual ~PosixMmapReadableFile() {
|
||||
munmap(mmapped_region_, length_);
|
||||
limiter_->Release();
|
||||
}
|
||||
|
||||
virtual Status Read(uint64_t offset, size_t n, Slice* result,
|
||||
char* scratch) const {
|
||||
Status s;
|
||||
if (offset + n > length_) {
|
||||
*result = Slice();
|
||||
s = IOError(filename_, EINVAL);
|
||||
} else {
|
||||
*result = Slice(reinterpret_cast<char*>(mmapped_region_) + offset, n);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
class PosixWritableFile : public WritableFile {
|
||||
private:
|
||||
std::string filename_;
|
||||
FILE* file_;
|
||||
|
||||
public:
|
||||
PosixWritableFile(const std::string& fname, FILE* f)
|
||||
: filename_(fname), file_(f) { }
|
||||
|
||||
~PosixWritableFile() {
|
||||
if (file_ != NULL) {
|
||||
// Ignoring any potential errors
|
||||
fclose(file_);
|
||||
}
|
||||
}
|
||||
|
||||
virtual Status Append(const Slice& data) {
|
||||
size_t r = fwrite_unlocked(data.data(), 1, data.size(), file_);
|
||||
if (r != data.size()) {
|
||||
return IOError(filename_, errno);
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
virtual Status Close() {
|
||||
Status result;
|
||||
if (fclose(file_) != 0) {
|
||||
result = IOError(filename_, errno);
|
||||
}
|
||||
file_ = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual Status Flush() {
|
||||
if (fflush_unlocked(file_) != 0) {
|
||||
return IOError(filename_, errno);
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status SyncDirIfManifest() {
|
||||
const char* f = filename_.c_str();
|
||||
const char* sep = strrchr(f, '/');
|
||||
Slice basename;
|
||||
std::string dir;
|
||||
if (sep == NULL) {
|
||||
dir = ".";
|
||||
basename = f;
|
||||
} else {
|
||||
dir = std::string(f, sep - f);
|
||||
basename = sep + 1;
|
||||
}
|
||||
Status s;
|
||||
if (basename.starts_with("MANIFEST")) {
|
||||
int fd = open(dir.c_str(), O_RDONLY);
|
||||
if (fd < 0) {
|
||||
s = IOError(dir, errno);
|
||||
} else {
|
||||
if (fsync(fd) < 0) {
|
||||
s = IOError(dir, errno);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
virtual Status Sync() {
|
||||
// Ensure new files referred to by the manifest are in the filesystem.
|
||||
Status s = SyncDirIfManifest();
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
if (fflush_unlocked(file_) != 0 ||
|
||||
fdatasync(fileno(file_)) != 0) {
|
||||
s = Status::IOError(filename_, strerror(errno));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
static int LockOrUnlock(int fd, bool lock) {
|
||||
errno = 0;
|
||||
struct flock f;
|
||||
memset(&f, 0, sizeof(f));
|
||||
f.l_type = (lock ? F_WRLCK : F_UNLCK);
|
||||
f.l_whence = SEEK_SET;
|
||||
f.l_start = 0;
|
||||
f.l_len = 0; // Lock/unlock entire file
|
||||
return fcntl(fd, F_SETLK, &f);
|
||||
}
|
||||
|
||||
class PosixFileLock : public FileLock {
|
||||
public:
|
||||
int fd_;
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
// Set of locked files. We keep a separate set instead of just
|
||||
// relying on fcntrl(F_SETLK) since fcntl(F_SETLK) does not provide
|
||||
// any protection against multiple uses from the same process.
|
||||
class PosixLockTable {
|
||||
private:
|
||||
port::Mutex mu_;
|
||||
std::set<std::string> locked_files_;
|
||||
public:
|
||||
bool Insert(const std::string& fname) {
|
||||
MutexLock l(&mu_);
|
||||
return locked_files_.insert(fname).second;
|
||||
}
|
||||
void Remove(const std::string& fname) {
|
||||
MutexLock l(&mu_);
|
||||
locked_files_.erase(fname);
|
||||
}
|
||||
};
|
||||
|
||||
class PosixEnv : public Env {
|
||||
public:
|
||||
PosixEnv();
|
||||
virtual ~PosixEnv() {
|
||||
char msg[] = "Destroying Env::Default()\n";
|
||||
fwrite(msg, 1, sizeof(msg), stderr);
|
||||
abort();
|
||||
}
|
||||
|
||||
virtual Status NewSequentialFile(const std::string& fname,
|
||||
SequentialFile** result) {
|
||||
FILE* f = fopen(fname.c_str(), "r");
|
||||
if (f == NULL) {
|
||||
*result = NULL;
|
||||
return IOError(fname, errno);
|
||||
} else {
|
||||
*result = new PosixSequentialFile(fname, f);
|
||||
return Status::OK();
|
||||
}
|
||||
}
|
||||
|
||||
virtual Status NewRandomAccessFile(const std::string& fname,
|
||||
RandomAccessFile** result) {
|
||||
*result = NULL;
|
||||
Status s;
|
||||
int fd = open(fname.c_str(), O_RDONLY);
|
||||
if (fd < 0) {
|
||||
s = IOError(fname, errno);
|
||||
} else if (mmap_limit_.Acquire()) {
|
||||
uint64_t size;
|
||||
s = GetFileSize(fname, &size);
|
||||
if (s.ok()) {
|
||||
void* base = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (base != MAP_FAILED) {
|
||||
*result = new PosixMmapReadableFile(fname, base, size, &mmap_limit_);
|
||||
} else {
|
||||
s = IOError(fname, errno);
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
if (!s.ok()) {
|
||||
mmap_limit_.Release();
|
||||
}
|
||||
} else {
|
||||
*result = new PosixRandomAccessFile(fname, fd, &fd_limit_);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
virtual Status NewWritableFile(const std::string& fname,
|
||||
WritableFile** result) {
|
||||
Status s;
|
||||
FILE* f = fopen(fname.c_str(), "w");
|
||||
if (f == NULL) {
|
||||
*result = NULL;
|
||||
s = IOError(fname, errno);
|
||||
} else {
|
||||
*result = new PosixWritableFile(fname, f);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
virtual Status NewAppendableFile(const std::string& fname,
|
||||
WritableFile** result) {
|
||||
Status s;
|
||||
FILE* f = fopen(fname.c_str(), "a");
|
||||
if (f == NULL) {
|
||||
*result = NULL;
|
||||
s = IOError(fname, errno);
|
||||
} else {
|
||||
*result = new PosixWritableFile(fname, f);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
virtual bool FileExists(const std::string& fname) {
|
||||
return access(fname.c_str(), F_OK) == 0;
|
||||
}
|
||||
|
||||
virtual Status GetChildren(const std::string& dir,
|
||||
std::vector<std::string>* result) {
|
||||
result->clear();
|
||||
DIR* d = opendir(dir.c_str());
|
||||
if (d == NULL) {
|
||||
return IOError(dir, errno);
|
||||
}
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(d)) != NULL) {
|
||||
result->push_back(entry->d_name);
|
||||
}
|
||||
closedir(d);
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
virtual Status DeleteFile(const std::string& fname) {
|
||||
Status result;
|
||||
if (unlink(fname.c_str()) != 0) {
|
||||
result = IOError(fname, errno);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual Status CreateDir(const std::string& name) {
|
||||
Status result;
|
||||
if (mkdir(name.c_str(), 0755) != 0) {
|
||||
result = IOError(name, errno);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual Status DeleteDir(const std::string& name) {
|
||||
Status result;
|
||||
if (rmdir(name.c_str()) != 0) {
|
||||
result = IOError(name, errno);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual Status GetFileSize(const std::string& fname, uint64_t* size) {
|
||||
Status s;
|
||||
struct stat sbuf;
|
||||
if (stat(fname.c_str(), &sbuf) != 0) {
|
||||
*size = 0;
|
||||
s = IOError(fname, errno);
|
||||
} else {
|
||||
*size = sbuf.st_size;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
virtual Status RenameFile(const std::string& src, const std::string& target) {
|
||||
Status result;
|
||||
if (rename(src.c_str(), target.c_str()) != 0) {
|
||||
result = IOError(src, errno);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual Status LockFile(const std::string& fname, FileLock** lock) {
|
||||
*lock = NULL;
|
||||
Status result;
|
||||
int fd = open(fname.c_str(), O_RDWR | O_CREAT, 0644);
|
||||
if (fd < 0) {
|
||||
result = IOError(fname, errno);
|
||||
} else if (!locks_.Insert(fname)) {
|
||||
close(fd);
|
||||
result = Status::IOError("lock " + fname, "already held by process");
|
||||
} else if (LockOrUnlock(fd, true) == -1) {
|
||||
result = IOError("lock " + fname, errno);
|
||||
close(fd);
|
||||
locks_.Remove(fname);
|
||||
} else {
|
||||
PosixFileLock* my_lock = new PosixFileLock;
|
||||
my_lock->fd_ = fd;
|
||||
my_lock->name_ = fname;
|
||||
*lock = my_lock;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual Status UnlockFile(FileLock* lock) {
|
||||
PosixFileLock* my_lock = reinterpret_cast<PosixFileLock*>(lock);
|
||||
Status result;
|
||||
if (LockOrUnlock(my_lock->fd_, false) == -1) {
|
||||
result = IOError("unlock", errno);
|
||||
}
|
||||
locks_.Remove(my_lock->name_);
|
||||
close(my_lock->fd_);
|
||||
delete my_lock;
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual void Schedule(void (*function)(void*), void* arg);
|
||||
|
||||
virtual void StartThread(void (*function)(void* arg), void* arg);
|
||||
|
||||
virtual Status GetTestDirectory(std::string* result) {
|
||||
const char* env = getenv("TEST_TMPDIR");
|
||||
if (env && env[0] != '\0') {
|
||||
*result = env;
|
||||
} else {
|
||||
char buf[100];
|
||||
snprintf(buf, sizeof(buf), "/tmp/leveldbtest-%d", int(geteuid()));
|
||||
*result = buf;
|
||||
}
|
||||
// Directory may already exist
|
||||
CreateDir(*result);
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
static uint64_t gettid() {
|
||||
pthread_t tid = pthread_self();
|
||||
uint64_t thread_id = 0;
|
||||
memcpy(&thread_id, &tid, std::min(sizeof(thread_id), sizeof(tid)));
|
||||
return thread_id;
|
||||
}
|
||||
|
||||
virtual Status NewLogger(const std::string& fname, Logger** result) {
|
||||
FILE* f = fopen(fname.c_str(), "w");
|
||||
if (f == NULL) {
|
||||
*result = NULL;
|
||||
return IOError(fname, errno);
|
||||
} else {
|
||||
*result = new PosixLogger(f, &PosixEnv::gettid);
|
||||
return Status::OK();
|
||||
}
|
||||
}
|
||||
|
||||
virtual uint64_t NowMicros() {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return static_cast<uint64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
|
||||
}
|
||||
|
||||
virtual void SleepForMicroseconds(int micros) {
|
||||
usleep(micros);
|
||||
}
|
||||
|
||||
private:
|
||||
void PthreadCall(const char* label, int result) {
|
||||
if (result != 0) {
|
||||
fprintf(stderr, "pthread %s: %s\n", label, strerror(result));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
// BGThread() is the body of the background thread
|
||||
void BGThread();
|
||||
static void* BGThreadWrapper(void* arg) {
|
||||
reinterpret_cast<PosixEnv*>(arg)->BGThread();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_t mu_;
|
||||
pthread_cond_t bgsignal_;
|
||||
pthread_t bgthread_;
|
||||
bool started_bgthread_;
|
||||
|
||||
// Entry per Schedule() call
|
||||
struct BGItem { void* arg; void (*function)(void*); };
|
||||
typedef std::deque<BGItem> BGQueue;
|
||||
BGQueue queue_;
|
||||
|
||||
PosixLockTable locks_;
|
||||
Limiter mmap_limit_;
|
||||
Limiter fd_limit_;
|
||||
};
|
||||
|
||||
// Return the maximum number of concurrent mmaps.
|
||||
static int MaxMmaps() {
|
||||
if (mmap_limit >= 0) {
|
||||
return mmap_limit;
|
||||
}
|
||||
// Up to 1000 mmaps for 64-bit binaries; none for smaller pointer sizes.
|
||||
mmap_limit = sizeof(void*) >= 8 ? 1000 : 0;
|
||||
return mmap_limit;
|
||||
}
|
||||
|
||||
// Return the maximum number of read-only files to keep open.
|
||||
static intptr_t MaxOpenFiles() {
|
||||
if (open_read_only_file_limit >= 0) {
|
||||
return open_read_only_file_limit;
|
||||
}
|
||||
struct rlimit rlim;
|
||||
if (getrlimit(RLIMIT_NOFILE, &rlim)) {
|
||||
// getrlimit failed, fallback to hard-coded default.
|
||||
open_read_only_file_limit = 50;
|
||||
} else if (rlim.rlim_cur == RLIM_INFINITY) {
|
||||
open_read_only_file_limit = std::numeric_limits<int>::max();
|
||||
} else {
|
||||
// Allow use of 20% of available file descriptors for read-only files.
|
||||
open_read_only_file_limit = rlim.rlim_cur / 5;
|
||||
}
|
||||
return open_read_only_file_limit;
|
||||
}
|
||||
|
||||
PosixEnv::PosixEnv()
|
||||
: started_bgthread_(false),
|
||||
mmap_limit_(MaxMmaps()),
|
||||
fd_limit_(MaxOpenFiles()) {
|
||||
PthreadCall("mutex_init", pthread_mutex_init(&mu_, NULL));
|
||||
PthreadCall("cvar_init", pthread_cond_init(&bgsignal_, NULL));
|
||||
}
|
||||
|
||||
void PosixEnv::Schedule(void (*function)(void*), void* arg) {
|
||||
PthreadCall("lock", pthread_mutex_lock(&mu_));
|
||||
|
||||
// Start background thread if necessary
|
||||
if (!started_bgthread_) {
|
||||
started_bgthread_ = true;
|
||||
PthreadCall(
|
||||
"create thread",
|
||||
pthread_create(&bgthread_, NULL, &PosixEnv::BGThreadWrapper, this));
|
||||
}
|
||||
|
||||
// If the queue is currently empty, the background thread may currently be
|
||||
// waiting.
|
||||
if (queue_.empty()) {
|
||||
PthreadCall("signal", pthread_cond_signal(&bgsignal_));
|
||||
}
|
||||
|
||||
// Add to priority queue
|
||||
queue_.push_back(BGItem());
|
||||
queue_.back().function = function;
|
||||
queue_.back().arg = arg;
|
||||
|
||||
PthreadCall("unlock", pthread_mutex_unlock(&mu_));
|
||||
}
|
||||
|
||||
void PosixEnv::BGThread() {
|
||||
while (true) {
|
||||
// Wait until there is an item that is ready to run
|
||||
PthreadCall("lock", pthread_mutex_lock(&mu_));
|
||||
while (queue_.empty()) {
|
||||
PthreadCall("wait", pthread_cond_wait(&bgsignal_, &mu_));
|
||||
}
|
||||
|
||||
void (*function)(void*) = queue_.front().function;
|
||||
void* arg = queue_.front().arg;
|
||||
queue_.pop_front();
|
||||
|
||||
PthreadCall("unlock", pthread_mutex_unlock(&mu_));
|
||||
(*function)(arg);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct StartThreadState {
|
||||
void (*user_function)(void*);
|
||||
void* arg;
|
||||
};
|
||||
}
|
||||
static void* StartThreadWrapper(void* arg) {
|
||||
StartThreadState* state = reinterpret_cast<StartThreadState*>(arg);
|
||||
state->user_function(state->arg);
|
||||
delete state;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void PosixEnv::StartThread(void (*function)(void* arg), void* arg) {
|
||||
pthread_t t;
|
||||
StartThreadState* state = new StartThreadState;
|
||||
state->user_function = function;
|
||||
state->arg = arg;
|
||||
PthreadCall("start thread",
|
||||
pthread_create(&t, NULL, &StartThreadWrapper, state));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
static pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||
static Env* default_env;
|
||||
static void InitDefaultEnv() { default_env = new PosixEnv; }
|
||||
|
||||
void EnvPosixTestHelper::SetReadOnlyFDLimit(int limit) {
|
||||
assert(default_env == NULL);
|
||||
open_read_only_file_limit = limit;
|
||||
}
|
||||
|
||||
void EnvPosixTestHelper::SetReadOnlyMMapLimit(int limit) {
|
||||
assert(default_env == NULL);
|
||||
mmap_limit = limit;
|
||||
}
|
||||
|
||||
Env* Env::Default() {
|
||||
pthread_once(&once, InitDefaultEnv);
|
||||
return default_env;
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
66
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/env_posix_test.cc
generated
vendored
Normal file
66
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/env_posix_test.cc
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "leveldb/env.h"
|
||||
|
||||
#include "port/port.h"
|
||||
#include "util/testharness.h"
|
||||
#include "util/env_posix_test_helper.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
static const int kDelayMicros = 100000;
|
||||
static const int kReadOnlyFileLimit = 4;
|
||||
static const int kMMapLimit = 4;
|
||||
|
||||
class EnvPosixTest {
|
||||
public:
|
||||
Env* env_;
|
||||
EnvPosixTest() : env_(Env::Default()) { }
|
||||
|
||||
static void SetFileLimits(int read_only_file_limit, int mmap_limit) {
|
||||
EnvPosixTestHelper::SetReadOnlyFDLimit(read_only_file_limit);
|
||||
EnvPosixTestHelper::SetReadOnlyMMapLimit(mmap_limit);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(EnvPosixTest, TestOpenOnRead) {
|
||||
// Write some test data to a single file that will be opened |n| times.
|
||||
std::string test_dir;
|
||||
ASSERT_OK(env_->GetTestDirectory(&test_dir));
|
||||
std::string test_file = test_dir + "/open_on_read.txt";
|
||||
|
||||
FILE* f = fopen(test_file.c_str(), "w");
|
||||
ASSERT_TRUE(f != NULL);
|
||||
const char kFileData[] = "abcdefghijklmnopqrstuvwxyz";
|
||||
fputs(kFileData, f);
|
||||
fclose(f);
|
||||
|
||||
// Open test file some number above the sum of the two limits to force
|
||||
// open-on-read behavior of POSIX Env leveldb::RandomAccessFile.
|
||||
const int kNumFiles = kReadOnlyFileLimit + kMMapLimit + 5;
|
||||
leveldb::RandomAccessFile* files[kNumFiles] = {0};
|
||||
for (int i = 0; i < kNumFiles; i++) {
|
||||
ASSERT_OK(env_->NewRandomAccessFile(test_file, &files[i]));
|
||||
}
|
||||
char scratch;
|
||||
Slice read_result;
|
||||
for (int i = 0; i < kNumFiles; i++) {
|
||||
ASSERT_OK(files[i]->Read(i, 1, &read_result, &scratch));
|
||||
ASSERT_EQ(kFileData[i], read_result[0]);
|
||||
}
|
||||
for (int i = 0; i < kNumFiles; i++) {
|
||||
delete files[i];
|
||||
}
|
||||
ASSERT_OK(env_->DeleteFile(test_file));
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// All tests currently run with the same read-only file limits.
|
||||
leveldb::EnvPosixTest::SetFileLimits(leveldb::kReadOnlyFileLimit,
|
||||
leveldb::kMMapLimit);
|
||||
return leveldb::test::RunAllTests();
|
||||
}
|
||||
28
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/env_posix_test_helper.h
generated
vendored
Normal file
28
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/env_posix_test_helper.h
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright 2017 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_
|
||||
#define STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
class EnvPosixTest;
|
||||
|
||||
// A helper for the POSIX Env to facilitate testing.
|
||||
class EnvPosixTestHelper {
|
||||
private:
|
||||
friend class EnvPosixTest;
|
||||
|
||||
// Set the maximum number of read-only files that will be opened.
|
||||
// Must be called before creating an Env.
|
||||
static void SetReadOnlyFDLimit(int limit);
|
||||
|
||||
// Set the maximum number of read-only files that will be mapped via mmap.
|
||||
// Must be called before creating an Env.
|
||||
static void SetReadOnlyMMapLimit(int limit);
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_
|
||||
106
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/env_test.cc
generated
vendored
Normal file
106
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/env_test.cc
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "leveldb/env.h"
|
||||
|
||||
#include "port/port.h"
|
||||
#include "util/testharness.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
static const int kDelayMicros = 100000;
|
||||
static const int kReadOnlyFileLimit = 4;
|
||||
static const int kMMapLimit = 4;
|
||||
|
||||
class EnvTest {
|
||||
private:
|
||||
port::Mutex mu_;
|
||||
std::string events_;
|
||||
|
||||
public:
|
||||
Env* env_;
|
||||
EnvTest() : env_(Env::Default()) { }
|
||||
};
|
||||
|
||||
static void SetBool(void* ptr) {
|
||||
reinterpret_cast<port::AtomicPointer*>(ptr)->NoBarrier_Store(ptr);
|
||||
}
|
||||
|
||||
TEST(EnvTest, RunImmediately) {
|
||||
port::AtomicPointer called (NULL);
|
||||
env_->Schedule(&SetBool, &called);
|
||||
env_->SleepForMicroseconds(kDelayMicros);
|
||||
ASSERT_TRUE(called.NoBarrier_Load() != NULL);
|
||||
}
|
||||
|
||||
TEST(EnvTest, RunMany) {
|
||||
port::AtomicPointer last_id (NULL);
|
||||
|
||||
struct CB {
|
||||
port::AtomicPointer* last_id_ptr; // Pointer to shared slot
|
||||
uintptr_t id; // Order# for the execution of this callback
|
||||
|
||||
CB(port::AtomicPointer* p, int i) : last_id_ptr(p), id(i) { }
|
||||
|
||||
static void Run(void* v) {
|
||||
CB* cb = reinterpret_cast<CB*>(v);
|
||||
void* cur = cb->last_id_ptr->NoBarrier_Load();
|
||||
ASSERT_EQ(cb->id-1, reinterpret_cast<uintptr_t>(cur));
|
||||
cb->last_id_ptr->Release_Store(reinterpret_cast<void*>(cb->id));
|
||||
}
|
||||
};
|
||||
|
||||
// Schedule in different order than start time
|
||||
CB cb1(&last_id, 1);
|
||||
CB cb2(&last_id, 2);
|
||||
CB cb3(&last_id, 3);
|
||||
CB cb4(&last_id, 4);
|
||||
env_->Schedule(&CB::Run, &cb1);
|
||||
env_->Schedule(&CB::Run, &cb2);
|
||||
env_->Schedule(&CB::Run, &cb3);
|
||||
env_->Schedule(&CB::Run, &cb4);
|
||||
|
||||
env_->SleepForMicroseconds(kDelayMicros);
|
||||
void* cur = last_id.Acquire_Load();
|
||||
ASSERT_EQ(4, reinterpret_cast<uintptr_t>(cur));
|
||||
}
|
||||
|
||||
struct State {
|
||||
port::Mutex mu;
|
||||
int val;
|
||||
int num_running;
|
||||
};
|
||||
|
||||
static void ThreadBody(void* arg) {
|
||||
State* s = reinterpret_cast<State*>(arg);
|
||||
s->mu.Lock();
|
||||
s->val += 1;
|
||||
s->num_running -= 1;
|
||||
s->mu.Unlock();
|
||||
}
|
||||
|
||||
TEST(EnvTest, StartThread) {
|
||||
State state;
|
||||
state.val = 0;
|
||||
state.num_running = 3;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
env_->StartThread(&ThreadBody, &state);
|
||||
}
|
||||
while (true) {
|
||||
state.mu.Lock();
|
||||
int num = state.num_running;
|
||||
state.mu.Unlock();
|
||||
if (num == 0) {
|
||||
break;
|
||||
}
|
||||
env_->SleepForMicroseconds(kDelayMicros);
|
||||
}
|
||||
ASSERT_EQ(state.val, 3);
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return leveldb::test::RunAllTests();
|
||||
}
|
||||
11
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/filter_policy.cc
generated
vendored
Normal file
11
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/filter_policy.cc
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2012 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "leveldb/filter_policy.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
FilterPolicy::~FilterPolicy() { }
|
||||
|
||||
} // namespace leveldb
|
||||
52
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/hash.cc
generated
vendored
Normal file
52
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/hash.cc
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include <string.h>
|
||||
#include "util/coding.h"
|
||||
#include "util/hash.h"
|
||||
|
||||
// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through
|
||||
// between switch labels. The real definition should be provided externally.
|
||||
// This one is a fallback version for unsupported compilers.
|
||||
#ifndef FALLTHROUGH_INTENDED
|
||||
#define FALLTHROUGH_INTENDED do { } while (0)
|
||||
#endif
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
uint32_t Hash(const char* data, size_t n, uint32_t seed) {
|
||||
// Similar to murmur hash
|
||||
const uint32_t m = 0xc6a4a793;
|
||||
const uint32_t r = 24;
|
||||
const char* limit = data + n;
|
||||
uint32_t h = seed ^ (n * m);
|
||||
|
||||
// Pick up four bytes at a time
|
||||
while (data + 4 <= limit) {
|
||||
uint32_t w = DecodeFixed32(data);
|
||||
data += 4;
|
||||
h += w;
|
||||
h *= m;
|
||||
h ^= (h >> 16);
|
||||
}
|
||||
|
||||
// Pick up remaining bytes
|
||||
switch (limit - data) {
|
||||
case 3:
|
||||
h += static_cast<unsigned char>(data[2]) << 16;
|
||||
FALLTHROUGH_INTENDED;
|
||||
case 2:
|
||||
h += static_cast<unsigned char>(data[1]) << 8;
|
||||
FALLTHROUGH_INTENDED;
|
||||
case 1:
|
||||
h += static_cast<unsigned char>(data[0]);
|
||||
h *= m;
|
||||
h ^= (h >> r);
|
||||
break;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
} // namespace leveldb
|
||||
19
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/hash.h
generated
vendored
Normal file
19
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/hash.h
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
//
|
||||
// Simple hash function used for internal data structures
|
||||
|
||||
#ifndef STORAGE_LEVELDB_UTIL_HASH_H_
|
||||
#define STORAGE_LEVELDB_UTIL_HASH_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
extern uint32_t Hash(const char* data, size_t n, uint32_t seed);
|
||||
|
||||
}
|
||||
|
||||
#endif // STORAGE_LEVELDB_UTIL_HASH_H_
|
||||
54
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/hash_test.cc
generated
vendored
Normal file
54
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/hash_test.cc
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "util/hash.h"
|
||||
#include "util/testharness.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
class HASH { };
|
||||
|
||||
TEST(HASH, SignedUnsignedIssue) {
|
||||
const unsigned char data1[1] = {0x62};
|
||||
const unsigned char data2[2] = {0xc3, 0x97};
|
||||
const unsigned char data3[3] = {0xe2, 0x99, 0xa5};
|
||||
const unsigned char data4[4] = {0xe1, 0x80, 0xb9, 0x32};
|
||||
const unsigned char data5[48] = {
|
||||
0x01, 0xc0, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x14, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x04, 0x00,
|
||||
0x00, 0x00, 0x00, 0x14,
|
||||
0x00, 0x00, 0x00, 0x18,
|
||||
0x28, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
ASSERT_EQ(Hash(0, 0, 0xbc9f1d34), 0xbc9f1d34);
|
||||
ASSERT_EQ(
|
||||
Hash(reinterpret_cast<const char*>(data1), sizeof(data1), 0xbc9f1d34),
|
||||
0xef1345c4);
|
||||
ASSERT_EQ(
|
||||
Hash(reinterpret_cast<const char*>(data2), sizeof(data2), 0xbc9f1d34),
|
||||
0x5b663814);
|
||||
ASSERT_EQ(
|
||||
Hash(reinterpret_cast<const char*>(data3), sizeof(data3), 0xbc9f1d34),
|
||||
0x323c078f);
|
||||
ASSERT_EQ(
|
||||
Hash(reinterpret_cast<const char*>(data4), sizeof(data4), 0xbc9f1d34),
|
||||
0xed21633a);
|
||||
ASSERT_EQ(
|
||||
Hash(reinterpret_cast<const char*>(data5), sizeof(data5), 0x12345678),
|
||||
0xf333dabb);
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return leveldb::test::RunAllTests();
|
||||
}
|
||||
139
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/histogram.cc
generated
vendored
Normal file
139
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/histogram.cc
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include "port/port.h"
|
||||
#include "util/histogram.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
const double Histogram::kBucketLimit[kNumBuckets] = {
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 20, 25, 30, 35, 40, 45,
|
||||
50, 60, 70, 80, 90, 100, 120, 140, 160, 180, 200, 250, 300, 350, 400, 450,
|
||||
500, 600, 700, 800, 900, 1000, 1200, 1400, 1600, 1800, 2000, 2500, 3000,
|
||||
3500, 4000, 4500, 5000, 6000, 7000, 8000, 9000, 10000, 12000, 14000,
|
||||
16000, 18000, 20000, 25000, 30000, 35000, 40000, 45000, 50000, 60000,
|
||||
70000, 80000, 90000, 100000, 120000, 140000, 160000, 180000, 200000,
|
||||
250000, 300000, 350000, 400000, 450000, 500000, 600000, 700000, 800000,
|
||||
900000, 1000000, 1200000, 1400000, 1600000, 1800000, 2000000, 2500000,
|
||||
3000000, 3500000, 4000000, 4500000, 5000000, 6000000, 7000000, 8000000,
|
||||
9000000, 10000000, 12000000, 14000000, 16000000, 18000000, 20000000,
|
||||
25000000, 30000000, 35000000, 40000000, 45000000, 50000000, 60000000,
|
||||
70000000, 80000000, 90000000, 100000000, 120000000, 140000000, 160000000,
|
||||
180000000, 200000000, 250000000, 300000000, 350000000, 400000000,
|
||||
450000000, 500000000, 600000000, 700000000, 800000000, 900000000,
|
||||
1000000000, 1200000000, 1400000000, 1600000000, 1800000000, 2000000000,
|
||||
2500000000.0, 3000000000.0, 3500000000.0, 4000000000.0, 4500000000.0,
|
||||
5000000000.0, 6000000000.0, 7000000000.0, 8000000000.0, 9000000000.0,
|
||||
1e200,
|
||||
};
|
||||
|
||||
void Histogram::Clear() {
|
||||
min_ = kBucketLimit[kNumBuckets-1];
|
||||
max_ = 0;
|
||||
num_ = 0;
|
||||
sum_ = 0;
|
||||
sum_squares_ = 0;
|
||||
for (int i = 0; i < kNumBuckets; i++) {
|
||||
buckets_[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Histogram::Add(double value) {
|
||||
// Linear search is fast enough for our usage in db_bench
|
||||
int b = 0;
|
||||
while (b < kNumBuckets - 1 && kBucketLimit[b] <= value) {
|
||||
b++;
|
||||
}
|
||||
buckets_[b] += 1.0;
|
||||
if (min_ > value) min_ = value;
|
||||
if (max_ < value) max_ = value;
|
||||
num_++;
|
||||
sum_ += value;
|
||||
sum_squares_ += (value * value);
|
||||
}
|
||||
|
||||
void Histogram::Merge(const Histogram& other) {
|
||||
if (other.min_ < min_) min_ = other.min_;
|
||||
if (other.max_ > max_) max_ = other.max_;
|
||||
num_ += other.num_;
|
||||
sum_ += other.sum_;
|
||||
sum_squares_ += other.sum_squares_;
|
||||
for (int b = 0; b < kNumBuckets; b++) {
|
||||
buckets_[b] += other.buckets_[b];
|
||||
}
|
||||
}
|
||||
|
||||
double Histogram::Median() const {
|
||||
return Percentile(50.0);
|
||||
}
|
||||
|
||||
double Histogram::Percentile(double p) const {
|
||||
double threshold = num_ * (p / 100.0);
|
||||
double sum = 0;
|
||||
for (int b = 0; b < kNumBuckets; b++) {
|
||||
sum += buckets_[b];
|
||||
if (sum >= threshold) {
|
||||
// Scale linearly within this bucket
|
||||
double left_point = (b == 0) ? 0 : kBucketLimit[b-1];
|
||||
double right_point = kBucketLimit[b];
|
||||
double left_sum = sum - buckets_[b];
|
||||
double right_sum = sum;
|
||||
double pos = (threshold - left_sum) / (right_sum - left_sum);
|
||||
double r = left_point + (right_point - left_point) * pos;
|
||||
if (r < min_) r = min_;
|
||||
if (r > max_) r = max_;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return max_;
|
||||
}
|
||||
|
||||
double Histogram::Average() const {
|
||||
if (num_ == 0.0) return 0;
|
||||
return sum_ / num_;
|
||||
}
|
||||
|
||||
double Histogram::StandardDeviation() const {
|
||||
if (num_ == 0.0) return 0;
|
||||
double variance = (sum_squares_ * num_ - sum_ * sum_) / (num_ * num_);
|
||||
return sqrt(variance);
|
||||
}
|
||||
|
||||
std::string Histogram::ToString() const {
|
||||
std::string r;
|
||||
char buf[200];
|
||||
snprintf(buf, sizeof(buf),
|
||||
"Count: %.0f Average: %.4f StdDev: %.2f\n",
|
||||
num_, Average(), StandardDeviation());
|
||||
r.append(buf);
|
||||
snprintf(buf, sizeof(buf),
|
||||
"Min: %.4f Median: %.4f Max: %.4f\n",
|
||||
(num_ == 0.0 ? 0.0 : min_), Median(), max_);
|
||||
r.append(buf);
|
||||
r.append("------------------------------------------------------\n");
|
||||
const double mult = 100.0 / num_;
|
||||
double sum = 0;
|
||||
for (int b = 0; b < kNumBuckets; b++) {
|
||||
if (buckets_[b] <= 0.0) continue;
|
||||
sum += buckets_[b];
|
||||
snprintf(buf, sizeof(buf),
|
||||
"[ %7.0f, %7.0f ) %7.0f %7.3f%% %7.3f%% ",
|
||||
((b == 0) ? 0.0 : kBucketLimit[b-1]), // left
|
||||
kBucketLimit[b], // right
|
||||
buckets_[b], // count
|
||||
mult * buckets_[b], // percentage
|
||||
mult * sum); // cumulative percentage
|
||||
r.append(buf);
|
||||
|
||||
// Add hash marks based on percentage; 20 marks for 100%.
|
||||
int marks = static_cast<int>(20*(buckets_[b] / num_) + 0.5);
|
||||
r.append(marks, '#');
|
||||
r.push_back('\n');
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
42
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/histogram.h
generated
vendored
Normal file
42
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/histogram.h
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_UTIL_HISTOGRAM_H_
|
||||
#define STORAGE_LEVELDB_UTIL_HISTOGRAM_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
class Histogram {
|
||||
public:
|
||||
Histogram() { }
|
||||
~Histogram() { }
|
||||
|
||||
void Clear();
|
||||
void Add(double value);
|
||||
void Merge(const Histogram& other);
|
||||
|
||||
std::string ToString() const;
|
||||
|
||||
private:
|
||||
double min_;
|
||||
double max_;
|
||||
double num_;
|
||||
double sum_;
|
||||
double sum_squares_;
|
||||
|
||||
enum { kNumBuckets = 154 };
|
||||
static const double kBucketLimit[kNumBuckets];
|
||||
double buckets_[kNumBuckets];
|
||||
|
||||
double Median() const;
|
||||
double Percentile(double p) const;
|
||||
double Average() const;
|
||||
double StandardDeviation() const;
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_UTIL_HISTOGRAM_H_
|
||||
72
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/logging.cc
generated
vendored
Normal file
72
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/logging.cc
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "util/logging.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "leveldb/env.h"
|
||||
#include "leveldb/slice.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
void AppendNumberTo(std::string* str, uint64_t num) {
|
||||
char buf[30];
|
||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long) num);
|
||||
str->append(buf);
|
||||
}
|
||||
|
||||
void AppendEscapedStringTo(std::string* str, const Slice& value) {
|
||||
for (size_t i = 0; i < value.size(); i++) {
|
||||
char c = value[i];
|
||||
if (c >= ' ' && c <= '~') {
|
||||
str->push_back(c);
|
||||
} else {
|
||||
char buf[10];
|
||||
snprintf(buf, sizeof(buf), "\\x%02x",
|
||||
static_cast<unsigned int>(c) & 0xff);
|
||||
str->append(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string NumberToString(uint64_t num) {
|
||||
std::string r;
|
||||
AppendNumberTo(&r, num);
|
||||
return r;
|
||||
}
|
||||
|
||||
std::string EscapeString(const Slice& value) {
|
||||
std::string r;
|
||||
AppendEscapedStringTo(&r, value);
|
||||
return r;
|
||||
}
|
||||
|
||||
bool ConsumeDecimalNumber(Slice* in, uint64_t* val) {
|
||||
uint64_t v = 0;
|
||||
int digits = 0;
|
||||
while (!in->empty()) {
|
||||
char c = (*in)[0];
|
||||
if (c >= '0' && c <= '9') {
|
||||
++digits;
|
||||
const int delta = (c - '0');
|
||||
static const uint64_t kMaxUint64 = ~static_cast<uint64_t>(0);
|
||||
if (v > kMaxUint64/10 ||
|
||||
(v == kMaxUint64/10 && delta > kMaxUint64%10)) {
|
||||
// Overflow
|
||||
return false;
|
||||
}
|
||||
v = (v * 10) + delta;
|
||||
in->remove_prefix(1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*val = v;
|
||||
return (digits > 0);
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
43
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/logging.h
generated
vendored
Normal file
43
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/logging.h
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
//
|
||||
// Must not be included from any .h files to avoid polluting the namespace
|
||||
// with macros.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_UTIL_LOGGING_H_
|
||||
#define STORAGE_LEVELDB_UTIL_LOGGING_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include "port/port.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
class Slice;
|
||||
class WritableFile;
|
||||
|
||||
// Append a human-readable printout of "num" to *str
|
||||
extern void AppendNumberTo(std::string* str, uint64_t num);
|
||||
|
||||
// Append a human-readable printout of "value" to *str.
|
||||
// Escapes any non-printable characters found in "value".
|
||||
extern void AppendEscapedStringTo(std::string* str, const Slice& value);
|
||||
|
||||
// Return a human-readable printout of "num"
|
||||
extern std::string NumberToString(uint64_t num);
|
||||
|
||||
// Return a human-readable version of "value".
|
||||
// Escapes any non-printable characters found in "value".
|
||||
extern std::string EscapeString(const Slice& value);
|
||||
|
||||
// Parse a human-readable number from "*in" into *value. On success,
|
||||
// advances "*in" past the consumed number and sets "*val" to the
|
||||
// numeric value. Otherwise, returns false and leaves *in in an
|
||||
// unspecified state.
|
||||
extern bool ConsumeDecimalNumber(Slice* in, uint64_t* val);
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_UTIL_LOGGING_H_
|
||||
41
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/mutexlock.h
generated
vendored
Normal file
41
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/mutexlock.h
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_
|
||||
#define STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_
|
||||
|
||||
#include "port/port.h"
|
||||
#include "port/thread_annotations.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
// Helper class that locks a mutex on construction and unlocks the mutex when
|
||||
// the destructor of the MutexLock object is invoked.
|
||||
//
|
||||
// Typical usage:
|
||||
//
|
||||
// void MyClass::MyMethod() {
|
||||
// MutexLock l(&mu_); // mu_ is an instance variable
|
||||
// ... some complex code, possibly with multiple return paths ...
|
||||
// }
|
||||
|
||||
class SCOPED_LOCKABLE MutexLock {
|
||||
public:
|
||||
explicit MutexLock(port::Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu)
|
||||
: mu_(mu) {
|
||||
this->mu_->Lock();
|
||||
}
|
||||
~MutexLock() UNLOCK_FUNCTION() { this->mu_->Unlock(); }
|
||||
|
||||
private:
|
||||
port::Mutex *const mu_;
|
||||
// No copying allowed
|
||||
MutexLock(const MutexLock&);
|
||||
void operator=(const MutexLock&);
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
|
||||
#endif // STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_
|
||||
30
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/options.cc
generated
vendored
Normal file
30
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/options.cc
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "leveldb/options.h"
|
||||
|
||||
#include "leveldb/comparator.h"
|
||||
#include "leveldb/env.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
Options::Options()
|
||||
: comparator(BytewiseComparator()),
|
||||
create_if_missing(false),
|
||||
error_if_exists(false),
|
||||
paranoid_checks(false),
|
||||
env(Env::Default()),
|
||||
info_log(NULL),
|
||||
write_buffer_size(4<<20),
|
||||
max_open_files(1000),
|
||||
block_cache(NULL),
|
||||
block_size(4096),
|
||||
block_restart_interval(16),
|
||||
max_file_size(2<<20),
|
||||
compression(kSnappyCompression),
|
||||
reuse_logs(false),
|
||||
filter_policy(NULL) {
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
98
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/posix_logger.h
generated
vendored
Normal file
98
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/posix_logger.h
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
//
|
||||
// Logger implementation that can be shared by all environments
|
||||
// where enough posix functionality is available.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_
|
||||
#define STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include "leveldb/env.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
class PosixLogger : public Logger {
|
||||
private:
|
||||
FILE* file_;
|
||||
uint64_t (*gettid_)(); // Return the thread id for the current thread
|
||||
public:
|
||||
PosixLogger(FILE* f, uint64_t (*gettid)()) : file_(f), gettid_(gettid) { }
|
||||
virtual ~PosixLogger() {
|
||||
fclose(file_);
|
||||
}
|
||||
virtual void Logv(const char* format, va_list ap) {
|
||||
const uint64_t thread_id = (*gettid_)();
|
||||
|
||||
// We try twice: the first time with a fixed-size stack allocated buffer,
|
||||
// and the second time with a much larger dynamically allocated buffer.
|
||||
char buffer[500];
|
||||
for (int iter = 0; iter < 2; iter++) {
|
||||
char* base;
|
||||
int bufsize;
|
||||
if (iter == 0) {
|
||||
bufsize = sizeof(buffer);
|
||||
base = buffer;
|
||||
} else {
|
||||
bufsize = 30000;
|
||||
base = new char[bufsize];
|
||||
}
|
||||
char* p = base;
|
||||
char* limit = base + bufsize;
|
||||
|
||||
struct timeval now_tv;
|
||||
gettimeofday(&now_tv, NULL);
|
||||
const time_t seconds = now_tv.tv_sec;
|
||||
struct tm t;
|
||||
localtime_r(&seconds, &t);
|
||||
p += snprintf(p, limit - p,
|
||||
"%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ",
|
||||
t.tm_year + 1900,
|
||||
t.tm_mon + 1,
|
||||
t.tm_mday,
|
||||
t.tm_hour,
|
||||
t.tm_min,
|
||||
t.tm_sec,
|
||||
static_cast<int>(now_tv.tv_usec),
|
||||
static_cast<long long unsigned int>(thread_id));
|
||||
|
||||
// Print the message
|
||||
if (p < limit) {
|
||||
va_list backup_ap;
|
||||
va_copy(backup_ap, ap);
|
||||
p += vsnprintf(p, limit - p, format, backup_ap);
|
||||
va_end(backup_ap);
|
||||
}
|
||||
|
||||
// Truncate to available space if necessary
|
||||
if (p >= limit) {
|
||||
if (iter == 0) {
|
||||
continue; // Try again with larger buffer
|
||||
} else {
|
||||
p = limit - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Add newline if necessary
|
||||
if (p == base || p[-1] != '\n') {
|
||||
*p++ = '\n';
|
||||
}
|
||||
|
||||
assert(p <= limit);
|
||||
fwrite(base, 1, p - base, file_);
|
||||
fflush(file_);
|
||||
if (base != buffer) {
|
||||
delete[] base;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_
|
||||
64
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/random.h
generated
vendored
Normal file
64
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/random.h
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_UTIL_RANDOM_H_
|
||||
#define STORAGE_LEVELDB_UTIL_RANDOM_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
// A very simple random number generator. Not especially good at
|
||||
// generating truly random bits, but good enough for our needs in this
|
||||
// package.
|
||||
class Random {
|
||||
private:
|
||||
uint32_t seed_;
|
||||
public:
|
||||
explicit Random(uint32_t s) : seed_(s & 0x7fffffffu) {
|
||||
// Avoid bad seeds.
|
||||
if (seed_ == 0 || seed_ == 2147483647L) {
|
||||
seed_ = 1;
|
||||
}
|
||||
}
|
||||
uint32_t Next() {
|
||||
static const uint32_t M = 2147483647L; // 2^31-1
|
||||
static const uint64_t A = 16807; // bits 14, 8, 7, 5, 2, 1, 0
|
||||
// We are computing
|
||||
// seed_ = (seed_ * A) % M, where M = 2^31-1
|
||||
//
|
||||
// seed_ must not be zero or M, or else all subsequent computed values
|
||||
// will be zero or M respectively. For all other values, seed_ will end
|
||||
// up cycling through every number in [1,M-1]
|
||||
uint64_t product = seed_ * A;
|
||||
|
||||
// Compute (product % M) using the fact that ((x << 31) % M) == x.
|
||||
seed_ = static_cast<uint32_t>((product >> 31) + (product & M));
|
||||
// The first reduction may overflow by 1 bit, so we may need to
|
||||
// repeat. mod == M is not possible; using > allows the faster
|
||||
// sign-bit-based test.
|
||||
if (seed_ > M) {
|
||||
seed_ -= M;
|
||||
}
|
||||
return seed_;
|
||||
}
|
||||
// Returns a uniformly distributed value in the range [0..n-1]
|
||||
// REQUIRES: n > 0
|
||||
uint32_t Uniform(int n) { return Next() % n; }
|
||||
|
||||
// Randomly returns true ~"1/n" of the time, and false otherwise.
|
||||
// REQUIRES: n > 0
|
||||
bool OneIn(int n) { return (Next() % n) == 0; }
|
||||
|
||||
// Skewed: pick "base" uniformly from range [0,max_log] and then
|
||||
// return "base" random bits. The effect is to pick a number in the
|
||||
// range [0,2^max_log-1] with exponential bias towards smaller numbers.
|
||||
uint32_t Skewed(int max_log) {
|
||||
return Uniform(1 << Uniform(max_log + 1));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_UTIL_RANDOM_H_
|
||||
75
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/status.cc
generated
vendored
Normal file
75
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/status.cc
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include <stdio.h>
|
||||
#include "port/port.h"
|
||||
#include "leveldb/status.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
const char* Status::CopyState(const char* state) {
|
||||
uint32_t size;
|
||||
memcpy(&size, state, sizeof(size));
|
||||
char* result = new char[size + 5];
|
||||
memcpy(result, state, size + 5);
|
||||
return result;
|
||||
}
|
||||
|
||||
Status::Status(Code code, const Slice& msg, const Slice& msg2) {
|
||||
assert(code != kOk);
|
||||
const uint32_t len1 = msg.size();
|
||||
const uint32_t len2 = msg2.size();
|
||||
const uint32_t size = len1 + (len2 ? (2 + len2) : 0);
|
||||
char* result = new char[size + 5];
|
||||
memcpy(result, &size, sizeof(size));
|
||||
result[4] = static_cast<char>(code);
|
||||
memcpy(result + 5, msg.data(), len1);
|
||||
if (len2) {
|
||||
result[5 + len1] = ':';
|
||||
result[6 + len1] = ' ';
|
||||
memcpy(result + 7 + len1, msg2.data(), len2);
|
||||
}
|
||||
state_ = result;
|
||||
}
|
||||
|
||||
std::string Status::ToString() const {
|
||||
if (state_ == NULL) {
|
||||
return "OK";
|
||||
} else {
|
||||
char tmp[30];
|
||||
const char* type;
|
||||
switch (code()) {
|
||||
case kOk:
|
||||
type = "OK";
|
||||
break;
|
||||
case kNotFound:
|
||||
type = "NotFound: ";
|
||||
break;
|
||||
case kCorruption:
|
||||
type = "Corruption: ";
|
||||
break;
|
||||
case kNotSupported:
|
||||
type = "Not implemented: ";
|
||||
break;
|
||||
case kInvalidArgument:
|
||||
type = "Invalid argument: ";
|
||||
break;
|
||||
case kIOError:
|
||||
type = "IO error: ";
|
||||
break;
|
||||
default:
|
||||
snprintf(tmp, sizeof(tmp), "Unknown code(%d): ",
|
||||
static_cast<int>(code()));
|
||||
type = tmp;
|
||||
break;
|
||||
}
|
||||
std::string result(type);
|
||||
uint32_t length;
|
||||
memcpy(&length, state_, sizeof(length));
|
||||
result.append(state_ + 5, length);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
77
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/testharness.cc
generated
vendored
Normal file
77
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/testharness.cc
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "util/testharness.h"
|
||||
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace leveldb {
|
||||
namespace test {
|
||||
|
||||
namespace {
|
||||
struct Test {
|
||||
const char* base;
|
||||
const char* name;
|
||||
void (*func)();
|
||||
};
|
||||
std::vector<Test>* tests;
|
||||
}
|
||||
|
||||
bool RegisterTest(const char* base, const char* name, void (*func)()) {
|
||||
if (tests == NULL) {
|
||||
tests = new std::vector<Test>;
|
||||
}
|
||||
Test t;
|
||||
t.base = base;
|
||||
t.name = name;
|
||||
t.func = func;
|
||||
tests->push_back(t);
|
||||
return true;
|
||||
}
|
||||
|
||||
int RunAllTests() {
|
||||
const char* matcher = getenv("LEVELDB_TESTS");
|
||||
|
||||
int num = 0;
|
||||
if (tests != NULL) {
|
||||
for (size_t i = 0; i < tests->size(); i++) {
|
||||
const Test& t = (*tests)[i];
|
||||
if (matcher != NULL) {
|
||||
std::string name = t.base;
|
||||
name.push_back('.');
|
||||
name.append(t.name);
|
||||
if (strstr(name.c_str(), matcher) == NULL) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "==== Test %s.%s\n", t.base, t.name);
|
||||
(*t.func)();
|
||||
++num;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "==== PASSED %d tests\n", num);
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string TmpDir() {
|
||||
std::string dir;
|
||||
Status s = Env::Default()->GetTestDirectory(&dir);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
return dir;
|
||||
}
|
||||
|
||||
int RandomSeed() {
|
||||
const char* env = getenv("TEST_RANDOM_SEED");
|
||||
int result = (env != NULL ? atoi(env) : 301);
|
||||
if (result <= 0) {
|
||||
result = 301;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace leveldb
|
||||
138
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/testharness.h
generated
vendored
Normal file
138
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/testharness.h
generated
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_UTIL_TESTHARNESS_H_
|
||||
#define STORAGE_LEVELDB_UTIL_TESTHARNESS_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sstream>
|
||||
#include "leveldb/env.h"
|
||||
#include "leveldb/slice.h"
|
||||
#include "util/random.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace test {
|
||||
|
||||
// Run some of the tests registered by the TEST() macro. If the
|
||||
// environment variable "LEVELDB_TESTS" is not set, runs all tests.
|
||||
// Otherwise, runs only the tests whose name contains the value of
|
||||
// "LEVELDB_TESTS" as a substring. E.g., suppose the tests are:
|
||||
// TEST(Foo, Hello) { ... }
|
||||
// TEST(Foo, World) { ... }
|
||||
// LEVELDB_TESTS=Hello will run the first test
|
||||
// LEVELDB_TESTS=o will run both tests
|
||||
// LEVELDB_TESTS=Junk will run no tests
|
||||
//
|
||||
// Returns 0 if all tests pass.
|
||||
// Dies or returns a non-zero value if some test fails.
|
||||
extern int RunAllTests();
|
||||
|
||||
// Return the directory to use for temporary storage.
|
||||
extern std::string TmpDir();
|
||||
|
||||
// Return a randomization seed for this run. Typically returns the
|
||||
// same number on repeated invocations of this binary, but automated
|
||||
// runs may be able to vary the seed.
|
||||
extern int RandomSeed();
|
||||
|
||||
// An instance of Tester is allocated to hold temporary state during
|
||||
// the execution of an assertion.
|
||||
class Tester {
|
||||
private:
|
||||
bool ok_;
|
||||
const char* fname_;
|
||||
int line_;
|
||||
std::stringstream ss_;
|
||||
|
||||
public:
|
||||
Tester(const char* f, int l)
|
||||
: ok_(true), fname_(f), line_(l) {
|
||||
}
|
||||
|
||||
~Tester() {
|
||||
if (!ok_) {
|
||||
fprintf(stderr, "%s:%d:%s\n", fname_, line_, ss_.str().c_str());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Tester& Is(bool b, const char* msg) {
|
||||
if (!b) {
|
||||
ss_ << " Assertion failure " << msg;
|
||||
ok_ = false;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Tester& IsOk(const Status& s) {
|
||||
if (!s.ok()) {
|
||||
ss_ << " " << s.ToString();
|
||||
ok_ = false;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
#define BINARY_OP(name,op) \
|
||||
template <class X, class Y> \
|
||||
Tester& name(const X& x, const Y& y) { \
|
||||
if (! (x op y)) { \
|
||||
ss_ << " failed: " << x << (" " #op " ") << y; \
|
||||
ok_ = false; \
|
||||
} \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
BINARY_OP(IsEq, ==)
|
||||
BINARY_OP(IsNe, !=)
|
||||
BINARY_OP(IsGe, >=)
|
||||
BINARY_OP(IsGt, >)
|
||||
BINARY_OP(IsLe, <=)
|
||||
BINARY_OP(IsLt, <)
|
||||
#undef BINARY_OP
|
||||
|
||||
// Attach the specified value to the error message if an error has occurred
|
||||
template <class V>
|
||||
Tester& operator<<(const V& value) {
|
||||
if (!ok_) {
|
||||
ss_ << " " << value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#define ASSERT_TRUE(c) ::leveldb::test::Tester(__FILE__, __LINE__).Is((c), #c)
|
||||
#define ASSERT_OK(s) ::leveldb::test::Tester(__FILE__, __LINE__).IsOk((s))
|
||||
#define ASSERT_EQ(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsEq((a),(b))
|
||||
#define ASSERT_NE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsNe((a),(b))
|
||||
#define ASSERT_GE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsGe((a),(b))
|
||||
#define ASSERT_GT(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsGt((a),(b))
|
||||
#define ASSERT_LE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsLe((a),(b))
|
||||
#define ASSERT_LT(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsLt((a),(b))
|
||||
|
||||
#define TCONCAT(a,b) TCONCAT1(a,b)
|
||||
#define TCONCAT1(a,b) a##b
|
||||
|
||||
#define TEST(base,name) \
|
||||
class TCONCAT(_Test_,name) : public base { \
|
||||
public: \
|
||||
void _Run(); \
|
||||
static void _RunIt() { \
|
||||
TCONCAT(_Test_,name) t; \
|
||||
t._Run(); \
|
||||
} \
|
||||
}; \
|
||||
bool TCONCAT(_Test_ignored_,name) = \
|
||||
::leveldb::test::RegisterTest(#base, #name, &TCONCAT(_Test_,name)::_RunIt); \
|
||||
void TCONCAT(_Test_,name)::_Run()
|
||||
|
||||
// Register the specified test. Typically not used directly, but
|
||||
// invoked via the macro expansion of TEST.
|
||||
extern bool RegisterTest(const char* base, const char* name, void (*func)());
|
||||
|
||||
|
||||
} // namespace test
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_UTIL_TESTHARNESS_H_
|
||||
51
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/testutil.cc
generated
vendored
Normal file
51
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/testutil.cc
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "util/testutil.h"
|
||||
|
||||
#include "util/random.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace test {
|
||||
|
||||
Slice RandomString(Random* rnd, int len, std::string* dst) {
|
||||
dst->resize(len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
(*dst)[i] = static_cast<char>(' ' + rnd->Uniform(95)); // ' ' .. '~'
|
||||
}
|
||||
return Slice(*dst);
|
||||
}
|
||||
|
||||
std::string RandomKey(Random* rnd, int len) {
|
||||
// Make sure to generate a wide variety of characters so we
|
||||
// test the boundary conditions for short-key optimizations.
|
||||
static const char kTestChars[] = {
|
||||
'\0', '\1', 'a', 'b', 'c', 'd', 'e', '\xfd', '\xfe', '\xff'
|
||||
};
|
||||
std::string result;
|
||||
for (int i = 0; i < len; i++) {
|
||||
result += kTestChars[rnd->Uniform(sizeof(kTestChars))];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
extern Slice CompressibleString(Random* rnd, double compressed_fraction,
|
||||
size_t len, std::string* dst) {
|
||||
int raw = static_cast<int>(len * compressed_fraction);
|
||||
if (raw < 1) raw = 1;
|
||||
std::string raw_data;
|
||||
RandomString(rnd, raw, &raw_data);
|
||||
|
||||
// Duplicate the random data until we have filled "len" bytes
|
||||
dst->clear();
|
||||
while (dst->size() < len) {
|
||||
dst->append(raw_data);
|
||||
}
|
||||
dst->resize(len);
|
||||
return Slice(*dst);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace leveldb
|
||||
63
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/testutil.h
generated
vendored
Normal file
63
node_modules/classic-level/deps/leveldb/leveldb-1.20/util/testutil.h
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_UTIL_TESTUTIL_H_
|
||||
#define STORAGE_LEVELDB_UTIL_TESTUTIL_H_
|
||||
|
||||
#include "leveldb/env.h"
|
||||
#include "leveldb/slice.h"
|
||||
#include "util/random.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace test {
|
||||
|
||||
// Store in *dst a random string of length "len" and return a Slice that
|
||||
// references the generated data.
|
||||
extern Slice RandomString(Random* rnd, int len, std::string* dst);
|
||||
|
||||
// Return a random key with the specified length that may contain interesting
|
||||
// characters (e.g. \x00, \xff, etc.).
|
||||
extern std::string RandomKey(Random* rnd, int len);
|
||||
|
||||
// Store in *dst a string of length "len" that will compress to
|
||||
// "N*compressed_fraction" bytes and return a Slice that references
|
||||
// the generated data.
|
||||
extern Slice CompressibleString(Random* rnd, double compressed_fraction,
|
||||
size_t len, std::string* dst);
|
||||
|
||||
// A wrapper that allows injection of errors.
|
||||
class ErrorEnv : public EnvWrapper {
|
||||
public:
|
||||
bool writable_file_error_;
|
||||
int num_writable_file_errors_;
|
||||
|
||||
ErrorEnv() : EnvWrapper(Env::Default()),
|
||||
writable_file_error_(false),
|
||||
num_writable_file_errors_(0) { }
|
||||
|
||||
virtual Status NewWritableFile(const std::string& fname,
|
||||
WritableFile** result) {
|
||||
if (writable_file_error_) {
|
||||
++num_writable_file_errors_;
|
||||
*result = NULL;
|
||||
return Status::IOError(fname, "fake error");
|
||||
}
|
||||
return target()->NewWritableFile(fname, result);
|
||||
}
|
||||
|
||||
virtual Status NewAppendableFile(const std::string& fname,
|
||||
WritableFile** result) {
|
||||
if (writable_file_error_) {
|
||||
++num_writable_file_errors_;
|
||||
*result = NULL;
|
||||
return Status::IOError(fname, "fake error");
|
||||
}
|
||||
return target()->NewAppendableFile(fname, result);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_UTIL_TESTUTIL_H_
|
||||
Reference in New Issue
Block a user