Files
blackcoin-more/src/dbwrapper.h
Braydon Fuller de05c9ecbb db: add options to configure block index database
There was a previous assumption that blockindex would be quite small. With addressindex
and spentindex enabled the blockindex is much larger and the amount of cache allocated for
it should also increase. Furthermore, enabling compression should decrease the amount of
disk space required and less data to write/read. The default leveldb max_open_files is set to
1000, for the blockindex the default is set to 1000 with compression. The 64 value that is
current is kept for the utxo database and does not enable compression. Two additional options
are added here to be able to configure the values for leveldb and the block index:

- `-dbmaxopenfiles` A number of files for leveldb to keep open
- `-dbcompression` Boolean 0 or 1 to enable snappy leveldb compression
2016-07-14 13:56:17 -04:00

283 lines
8.1 KiB
C++

// Copyright (c) 2012-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_DBWRAPPER_H
#define BITCOIN_DBWRAPPER_H
#include "clientversion.h"
#include "serialize.h"
#include "streams.h"
#include "util.h"
#include "utilstrencodings.h"
#include "version.h"
#include <boost/filesystem/path.hpp>
#include <leveldb/db.h>
#include <leveldb/write_batch.h>
class dbwrapper_error : public std::runtime_error
{
public:
dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
};
void HandleError(const leveldb::Status& status) throw(dbwrapper_error);
/** Batch of changes queued to be written to a CDBWrapper */
class CDBBatch
{
friend class CDBWrapper;
private:
leveldb::WriteBatch batch;
const std::vector<unsigned char> *obfuscate_key;
public:
/**
* @param[in] obfuscate_key If passed, XOR data with this key.
*/
CDBBatch(const std::vector<unsigned char> *obfuscate_key) : obfuscate_key(obfuscate_key) { };
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;
ssValue.Xor(*obfuscate_key);
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 CDBIterator
{
private:
leveldb::Iterator *piter;
const std::vector<unsigned char> *obfuscate_key;
public:
/**
* @param[in] piterIn The original leveldb iterator.
* @param[in] obfuscate_key If passed, XOR data with this key.
*/
CDBIterator(leveldb::Iterator *piterIn, const std::vector<unsigned char>* obfuscate_key) :
piter(piterIn), obfuscate_key(obfuscate_key) { };
~CDBIterator();
bool Valid();
void SeekToFirst();
template<typename K> void Seek(const K& key) {
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(ssKey.GetSerializeSize(key));
ssKey << key;
leveldb::Slice slKey(&ssKey[0], ssKey.size());
piter->Seek(slKey);
}
void Next();
template<typename K> bool GetKey(K& key) {
leveldb::Slice slKey = piter->key();
try {
CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION);
ssKey >> key;
} catch (const std::exception&) {
return false;
}
return true;
}
unsigned int GetKeySize() {
return piter->key().size();
}
template<typename V> bool GetValue(V& value) {
leveldb::Slice slValue = piter->value();
try {
CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION);
ssValue.Xor(*obfuscate_key);
ssValue >> value;
} catch (const std::exception&) {
return false;
}
return true;
}
unsigned int GetValueSize() {
return piter->value().size();
}
};
class CDBWrapper
{
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;
//! a key used for optional XOR-obfuscation of the database
std::vector<unsigned char> obfuscate_key;
//! the key under which the obfuscation key is stored
static const std::string OBFUSCATE_KEY_KEY;
//! the length of the obfuscate key in number of bytes
static const unsigned int OBFUSCATE_KEY_NUM_BYTES;
std::vector<unsigned char> CreateObfuscateKey() const;
public:
/**
* @param[in] path Location in the filesystem where leveldb data will be stored.
* @param[in] nCacheSize Configures various leveldb cache settings.
* @param[in] fMemory If true, use leveldb's memory environment.
* @param[in] fWipe If true, remove all existing data.
* @param[in] obfuscate If true, store data obfuscated via simple XOR. If false, XOR
* with a zero'd byte array.
* @param[in] compression Enable snappy compression for the database
* @param[in] maxOpenFiles The maximum number of open files for the database
*/
CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool obfuscate = false, bool compression = false, int maxOpenFiles = 64);
~CDBWrapper();
template <typename K, typename V>
bool Read(const K& key, V& value) const throw(dbwrapper_error)
{
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;
LogPrintf("LevelDB read failure: %s\n", status.ToString());
HandleError(status);
}
try {
CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION);
ssValue.Xor(obfuscate_key);
ssValue >> value;
} catch (const std::exception&) {
return false;
}
return true;
}
template <typename K, typename V>
bool Write(const K& key, const V& value, bool fSync = false) throw(dbwrapper_error)
{
CDBBatch batch(&obfuscate_key);
batch.Write(key, value);
return WriteBatch(batch, fSync);
}
template <typename K>
bool Exists(const K& key) const throw(dbwrapper_error)
{
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;
LogPrintf("LevelDB read failure: %s\n", status.ToString());
HandleError(status);
}
return true;
}
template <typename K>
bool Erase(const K& key, bool fSync = false) throw(dbwrapper_error)
{
CDBBatch batch(&obfuscate_key);
batch.Erase(key);
return WriteBatch(batch, fSync);
}
bool WriteBatch(CDBBatch& batch, bool fSync = false) throw(dbwrapper_error);
// not available for LevelDB; provide for compatibility with BDB
bool Flush()
{
return true;
}
bool Sync() throw(dbwrapper_error)
{
CDBBatch batch(&obfuscate_key);
return WriteBatch(batch, true);
}
CDBIterator *NewIterator()
{
return new CDBIterator(pdb->NewIterator(iteroptions), &obfuscate_key);
}
/**
* Return true if the database managed by this class contains no entries.
*/
bool IsEmpty();
/**
* Accessor for obfuscate_key.
*/
const std::vector<unsigned char>& GetObfuscateKey() const;
/**
* Return the obfuscate_key as a hex-formatted string.
*/
std::string GetObfuscateKeyHex() const;
};
#endif // BITCOIN_DBWRAPPER_H