Browse Source
Database-independent glue for supporting LevelDB databases. Based on code from earlier commits by Mike Hearn in his leveldb branch.miguelfreitas
Pieter Wuille
12 years ago
7 changed files with 212 additions and 5 deletions
@ -0,0 +1,58 @@ |
|||||||
|
// Copyright (c) 2012 The Bitcoin developers
|
||||||
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include "leveldb.h" |
||||||
|
#include "util.h" |
||||||
|
|
||||||
|
#include <leveldb/env.h> |
||||||
|
#include <leveldb/cache.h> |
||||||
|
#include <leveldb/filter_policy.h> |
||||||
|
|
||||||
|
#include <boost/filesystem.hpp> |
||||||
|
|
||||||
|
static leveldb::Options GetOptions() { |
||||||
|
leveldb::Options options; |
||||||
|
int nCacheSizeMB = GetArg("-dbcache", 25); |
||||||
|
options.block_cache = leveldb::NewLRUCache(nCacheSizeMB * 1048576); |
||||||
|
options.filter_policy = leveldb::NewBloomFilterPolicy(10); |
||||||
|
options.compression = leveldb::kNoCompression; |
||||||
|
return options; |
||||||
|
} |
||||||
|
|
||||||
|
CLevelDB::CLevelDB(const boost::filesystem::path &path) { |
||||||
|
penv = NULL; |
||||||
|
readoptions.verify_checksums = true; |
||||||
|
iteroptions.verify_checksums = true; |
||||||
|
iteroptions.fill_cache = false; |
||||||
|
syncoptions.sync = true; |
||||||
|
options = GetOptions(); |
||||||
|
options.create_if_missing = true; |
||||||
|
boost::filesystem::create_directory(path); |
||||||
|
printf("Opening LevelDB in %s\n", path.string().c_str()); |
||||||
|
leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb); |
||||||
|
if (!status.ok()) |
||||||
|
throw std::runtime_error(strprintf("CLevelDB(): error opening database environment %s", status.ToString().c_str())); |
||||||
|
printf("Opened LevelDB successfully\n"); |
||||||
|
} |
||||||
|
|
||||||
|
CLevelDB::~CLevelDB() { |
||||||
|
delete pdb; |
||||||
|
pdb = NULL; |
||||||
|
delete options.filter_policy; |
||||||
|
options.filter_policy = NULL; |
||||||
|
delete options.block_cache; |
||||||
|
options.block_cache = NULL; |
||||||
|
delete penv; |
||||||
|
options.env = NULL; |
||||||
|
} |
||||||
|
|
||||||
|
bool CLevelDB::WriteBatch(CLevelDBBatch &batch, bool fSync) { |
||||||
|
leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch); |
||||||
|
if (!status.ok()) { |
||||||
|
printf("LevelDB write failure: %s\n", status.ToString().c_str()); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
@ -0,0 +1,144 @@ |
|||||||
|
// Copyright (c) 2012 The Bitcoin developers
|
||||||
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
#ifndef BITCOIN_LEVELDB_H |
||||||
|
#define BITCOIN_LEVELDB_H |
||||||
|
|
||||||
|
#include "serialize.h" |
||||||
|
|
||||||
|
#include <leveldb/db.h> |
||||||
|
#include <leveldb/write_batch.h> |
||||||
|
|
||||||
|
#include <boost/filesystem/path.hpp> |
||||||
|
|
||||||
|
// Batch of changes queued to be written to a CLevelDB
|
||||||
|
class CLevelDBBatch |
||||||
|
{ |
||||||
|
friend class CLevelDB; |
||||||
|
|
||||||
|
private: |
||||||
|
leveldb::WriteBatch batch; |
||||||
|
|
||||||
|
public: |
||||||
|
template<typename K, typename V> void Write(const K& key, const V& value) { |
||||||
|
CDataStream ssKey(SER_DISK, CLIENT_VERSION); |
||||||
|
ssKey.reserve(ssKey.GetSerializeSize(key)); |
||||||
|
ssKey << key; |
||||||
|
leveldb::Slice slKey(&ssKey[0], ssKey.size()); |
||||||
|
|
||||||
|
CDataStream ssValue(SER_DISK, CLIENT_VERSION); |
||||||
|
ssValue.reserve(ssValue.GetSerializeSize(value)); |
||||||
|
ssValue << value; |
||||||
|
leveldb::Slice slValue(&ssValue[0], ssValue.size()); |
||||||
|
|
||||||
|
batch.Put(slKey, slValue); |
||||||
|
} |
||||||
|
|
||||||
|
template<typename K> void Erase(const K& key) { |
||||||
|
CDataStream ssKey(SER_DISK, CLIENT_VERSION); |
||||||
|
ssKey.reserve(ssKey.GetSerializeSize(key)); |
||||||
|
ssKey << key; |
||||||
|
leveldb::Slice slKey(&ssKey[0], ssKey.size()); |
||||||
|
|
||||||
|
batch.Delete(slKey); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
class CLevelDB |
||||||
|
{ |
||||||
|
private: |
||||||
|
// custom environment this database is using (may be NULL in case of default environment)
|
||||||
|
leveldb::Env *penv; |
||||||
|
|
||||||
|
// database options used
|
||||||
|
leveldb::Options options; |
||||||
|
|
||||||
|
// options used when reading from the database
|
||||||
|
leveldb::ReadOptions readoptions; |
||||||
|
|
||||||
|
// options used when iterating over values of the database
|
||||||
|
leveldb::ReadOptions iteroptions; |
||||||
|
|
||||||
|
// options used when writing to the database
|
||||||
|
leveldb::WriteOptions writeoptions; |
||||||
|
|
||||||
|
// options used when sync writing to the database
|
||||||
|
leveldb::WriteOptions syncoptions; |
||||||
|
|
||||||
|
// the database itself
|
||||||
|
leveldb::DB *pdb; |
||||||
|
|
||||||
|
public: |
||||||
|
CLevelDB(const boost::filesystem::path &path); |
||||||
|
~CLevelDB(); |
||||||
|
|
||||||
|
template<typename K, typename V> bool Read(const K& key, V& value) { |
||||||
|
CDataStream ssKey(SER_DISK, CLIENT_VERSION); |
||||||
|
ssKey.reserve(ssKey.GetSerializeSize(key)); |
||||||
|
ssKey << key; |
||||||
|
leveldb::Slice slKey(&ssKey[0], ssKey.size()); |
||||||
|
|
||||||
|
std::string strValue; |
||||||
|
leveldb::Status status = pdb->Get(readoptions, slKey, &strValue); |
||||||
|
if (!status.ok()) { |
||||||
|
if (status.IsNotFound()) |
||||||
|
return false; |
||||||
|
printf("LevelDB read failure: %s\n", status.ToString().c_str()); |
||||||
|
} |
||||||
|
try { |
||||||
|
CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION); |
||||||
|
ssValue >> value; |
||||||
|
} catch(std::exception &e) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
template<typename K, typename V> bool Write(const K& key, const V& value, bool fSync = false) { |
||||||
|
CLevelDBBatch batch; |
||||||
|
batch.Write(key, value); |
||||||
|
return WriteBatch(batch, fSync); |
||||||
|
} |
||||||
|
|
||||||
|
template<typename K> bool Exists(const K& key) { |
||||||
|
CDataStream ssKey(SER_DISK, CLIENT_VERSION); |
||||||
|
ssKey.reserve(ssKey.GetSerializeSize(key)); |
||||||
|
ssKey << key; |
||||||
|
leveldb::Slice slKey(&ssKey[0], ssKey.size()); |
||||||
|
|
||||||
|
std::string strValue; |
||||||
|
leveldb::Status status = pdb->Get(readoptions, slKey, &strValue); |
||||||
|
if (!status.ok()) { |
||||||
|
if (status.IsNotFound()) |
||||||
|
return false; |
||||||
|
printf("LevelDB read failure: %s\n", status.ToString().c_str()); |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
template<typename K> bool Erase(const K& key, bool fSync = false) { |
||||||
|
CLevelDBBatch batch; |
||||||
|
batch.Erase(key); |
||||||
|
return WriteBatch(batch, fSync); |
||||||
|
} |
||||||
|
|
||||||
|
bool WriteBatch(CLevelDBBatch &batch, bool fSync = false); |
||||||
|
|
||||||
|
// not available for LevelDB; provide for compatibility with BDB
|
||||||
|
bool Flush() { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
bool Sync() { |
||||||
|
CLevelDBBatch batch; |
||||||
|
return WriteBatch(batch, true); |
||||||
|
} |
||||||
|
|
||||||
|
// not exactly clean encapsulation, but it's easiest for now
|
||||||
|
leveldb::Iterator *NewIterator() { |
||||||
|
return pdb->NewIterator(iteroptions); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
#endif // BITCOIN_LEVELDB_H
|
||||||
|
|
Loading…
Reference in new issue