Browse Source

LevelDB glue

Database-independent glue for supporting LevelDB databases.

Based on code from earlier commits by Mike Hearn in his leveldb
branch.
pull/145/head
Pieter Wuille 12 years ago
parent
commit
43b7905e98
  1. 1
      bitcoin-qt.pro
  2. 58
      src/leveldb.cpp
  3. 144
      src/leveldb.h
  4. 5
      src/makefile.linux-mingw
  5. 3
      src/makefile.mingw
  6. 3
      src/makefile.osx
  7. 3
      src/makefile.unix

1
bitcoin-qt.pro

@ -97,6 +97,7 @@ contains(USE_LEVELDB, -) {
DEFINES += USE_LEVELDB
INCLUDEPATH += src/leveldb/include src/leveldb/helpers
LIBS += $$PWD/src/leveldb/libleveldb.a $$PWD/src/leveldb/libmemenv.a
SOURCES += src/leveldb.cpp
!windows {
genleveldb.commands = cd $$PWD/src/leveldb ; $(MAKE) libleveldb.a libmemenv.a
} else {

58
src/leveldb.cpp

@ -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;
}

144
src/leveldb.h

@ -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

5
src/makefile.linux-mingw

@ -88,12 +88,13 @@ OBJS= \
all: bitcoind.exe
ifdef USE_LEVELDB
LIBS += $(CURDIR)/leveldb/libleveldb.lib $(CURDIR)/leveldb/libmemenv.a
LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
DEFS += -I"$(CURDIR)/leveldb/include" -DUSE_LEVELDB
DEFS += -I"$(CURDIR)/leveldb/helpers"
OBJS += obj/leveldb.o
leveldb/libleveldb.a:
@echo "Building LevelDB ..."; cd leveldb; TARGET_OS=OS_WINDOWS_CROSSCOMPILE CXXFLAGS="-I$(INCLUDEPATHS)" LDFLAGS="-L$(LIBPATHS)" make libleveldb.a libmemenv.a; cd ..
obj/db.o: leveldb/libleveldb.a
obj/leveldb.o: leveldb/libleveldb.a
endif
obj/build.h: FORCE

3
src/makefile.mingw

@ -94,9 +94,10 @@ ifdef USE_LEVELDB
LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
DEFS += $(addprefix -I,$(CURDIR)/leveldb/include) -DUSE_LEVELDB
DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers)
OBJS += obj/leveldb.o
leveldb/libleveldb.a:
cd leveldb; make libleveldb.a libmemenv.a; cd ..
obj/db.o: leveldb/libleveldb.lib
obj/leveldb.o: leveldb/libleveldb.lib
endif
obj/%.o: %.cpp $(HEADERS)

3
src/makefile.osx

@ -127,9 +127,10 @@ ifdef USE_LEVELDB
LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
DEFS += $(addprefix -I,$(CURDIR)/leveldb/include) -DUSE_LEVELDB
DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers)
OBJS += obj/leveldb.o
leveldb/libleveldb.a:
@echo "Building LevelDB ..."; cd leveldb; make libleveldb.a libmemenv.a; cd ..
obj/db.o: leveldb/libleveldb.a
obj/leveldb.o: leveldb/libleveldb.a
endif
# auto-generated dependencies:

3
src/makefile.unix

@ -143,9 +143,10 @@ ifdef USE_LEVELDB
LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
DEFS += $(addprefix -I,$(CURDIR)/leveldb/include) -DUSE_LEVELDB
DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers)
OBJS += obj/leveldb.o
leveldb/libleveldb.a:
@echo "Building LevelDB ..."; cd leveldb; make libleveldb.a libmemenv.a; cd ..;
obj/db.o: leveldb/libleveldb.a
obj/leveldb.o: leveldb/libleveldb.a
endif
# auto-generated dependencies:

Loading…
Cancel
Save