mirror of
https://github.com/dashpay/dash.git
synced 2024-12-30 22:35:51 +01:00
d004d7279f
This was a leftover from the times in which peers.dat depended in BDB. Other functions in db.cpp still depend on BerkelyDB, to be able to compile without BDB this (small) functionality needs to be moved to another file.
309 lines
8.1 KiB
C++
309 lines
8.1 KiB
C++
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
// Copyright (c) 2009-2013 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_DB_H
|
|
#define BITCOIN_DB_H
|
|
|
|
#include "serialize.h"
|
|
#include "sync.h"
|
|
#include "version.h"
|
|
|
|
#include <map>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <boost/filesystem/path.hpp>
|
|
#include <db_cxx.h>
|
|
|
|
class CAddrMan;
|
|
struct CBlockLocator;
|
|
class CDiskBlockIndex;
|
|
class COutPoint;
|
|
|
|
extern unsigned int nWalletDBUpdated;
|
|
|
|
void ThreadFlushWalletDB(const std::string& strWalletFile);
|
|
|
|
|
|
class CDBEnv
|
|
{
|
|
private:
|
|
bool fDbEnvInit;
|
|
bool fMockDb;
|
|
boost::filesystem::path path;
|
|
|
|
void EnvShutdown();
|
|
|
|
public:
|
|
mutable CCriticalSection cs_db;
|
|
DbEnv dbenv;
|
|
std::map<std::string, int> mapFileUseCount;
|
|
std::map<std::string, Db*> mapDb;
|
|
|
|
CDBEnv();
|
|
~CDBEnv();
|
|
void MakeMock();
|
|
bool IsMock() { return fMockDb; }
|
|
|
|
/*
|
|
* Verify that database file strFile is OK. If it is not,
|
|
* call the callback to try to recover.
|
|
* This must be called BEFORE strFile is opened.
|
|
* Returns true if strFile is OK.
|
|
*/
|
|
enum VerifyResult { VERIFY_OK, RECOVER_OK, RECOVER_FAIL };
|
|
VerifyResult Verify(std::string strFile, bool (*recoverFunc)(CDBEnv& dbenv, std::string strFile));
|
|
/*
|
|
* Salvage data from a file that Verify says is bad.
|
|
* fAggressive sets the DB_AGGRESSIVE flag (see berkeley DB->verify() method documentation).
|
|
* Appends binary key/value pairs to vResult, returns true if successful.
|
|
* NOTE: reads the entire database into memory, so cannot be used
|
|
* for huge databases.
|
|
*/
|
|
typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;
|
|
bool Salvage(std::string strFile, bool fAggressive, std::vector<KeyValPair>& vResult);
|
|
|
|
bool Open(const boost::filesystem::path &path);
|
|
void Close();
|
|
void Flush(bool fShutdown);
|
|
void CheckpointLSN(std::string strFile);
|
|
|
|
void CloseDb(const std::string& strFile);
|
|
bool RemoveDb(const std::string& strFile);
|
|
|
|
DbTxn *TxnBegin(int flags=DB_TXN_WRITE_NOSYNC)
|
|
{
|
|
DbTxn* ptxn = NULL;
|
|
int ret = dbenv.txn_begin(NULL, &ptxn, flags);
|
|
if (!ptxn || ret != 0)
|
|
return NULL;
|
|
return ptxn;
|
|
}
|
|
};
|
|
|
|
extern CDBEnv bitdb;
|
|
|
|
|
|
/** RAII class that provides access to a Berkeley database */
|
|
class CDB
|
|
{
|
|
protected:
|
|
Db* pdb;
|
|
std::string strFile;
|
|
DbTxn *activeTxn;
|
|
bool fReadOnly;
|
|
|
|
explicit CDB(const char* pszFile, const char* pszMode="r+");
|
|
~CDB() { Close(); }
|
|
public:
|
|
void Flush();
|
|
void Close();
|
|
private:
|
|
CDB(const CDB&);
|
|
void operator=(const CDB&);
|
|
|
|
protected:
|
|
template<typename K, typename T>
|
|
bool Read(const K& key, T& value)
|
|
{
|
|
if (!pdb)
|
|
return false;
|
|
|
|
// Key
|
|
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
|
ssKey.reserve(1000);
|
|
ssKey << key;
|
|
Dbt datKey(&ssKey[0], ssKey.size());
|
|
|
|
// Read
|
|
Dbt datValue;
|
|
datValue.set_flags(DB_DBT_MALLOC);
|
|
int ret = pdb->get(activeTxn, &datKey, &datValue, 0);
|
|
memset(datKey.get_data(), 0, datKey.get_size());
|
|
if (datValue.get_data() == NULL)
|
|
return false;
|
|
|
|
// Unserialize value
|
|
try {
|
|
CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
|
|
ssValue >> value;
|
|
}
|
|
catch (std::exception &e) {
|
|
return false;
|
|
}
|
|
|
|
// Clear and free memory
|
|
memset(datValue.get_data(), 0, datValue.get_size());
|
|
free(datValue.get_data());
|
|
return (ret == 0);
|
|
}
|
|
|
|
template<typename K, typename T>
|
|
bool Write(const K& key, const T& value, bool fOverwrite=true)
|
|
{
|
|
if (!pdb)
|
|
return false;
|
|
if (fReadOnly)
|
|
assert(!"Write called on database in read-only mode");
|
|
|
|
// Key
|
|
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
|
ssKey.reserve(1000);
|
|
ssKey << key;
|
|
Dbt datKey(&ssKey[0], ssKey.size());
|
|
|
|
// Value
|
|
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
|
|
ssValue.reserve(10000);
|
|
ssValue << value;
|
|
Dbt datValue(&ssValue[0], ssValue.size());
|
|
|
|
// Write
|
|
int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
|
|
|
|
// Clear memory in case it was a private key
|
|
memset(datKey.get_data(), 0, datKey.get_size());
|
|
memset(datValue.get_data(), 0, datValue.get_size());
|
|
return (ret == 0);
|
|
}
|
|
|
|
template<typename K>
|
|
bool Erase(const K& key)
|
|
{
|
|
if (!pdb)
|
|
return false;
|
|
if (fReadOnly)
|
|
assert(!"Erase called on database in read-only mode");
|
|
|
|
// Key
|
|
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
|
ssKey.reserve(1000);
|
|
ssKey << key;
|
|
Dbt datKey(&ssKey[0], ssKey.size());
|
|
|
|
// Erase
|
|
int ret = pdb->del(activeTxn, &datKey, 0);
|
|
|
|
// Clear memory
|
|
memset(datKey.get_data(), 0, datKey.get_size());
|
|
return (ret == 0 || ret == DB_NOTFOUND);
|
|
}
|
|
|
|
template<typename K>
|
|
bool Exists(const K& key)
|
|
{
|
|
if (!pdb)
|
|
return false;
|
|
|
|
// Key
|
|
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
|
ssKey.reserve(1000);
|
|
ssKey << key;
|
|
Dbt datKey(&ssKey[0], ssKey.size());
|
|
|
|
// Exists
|
|
int ret = pdb->exists(activeTxn, &datKey, 0);
|
|
|
|
// Clear memory
|
|
memset(datKey.get_data(), 0, datKey.get_size());
|
|
return (ret == 0);
|
|
}
|
|
|
|
Dbc* GetCursor()
|
|
{
|
|
if (!pdb)
|
|
return NULL;
|
|
Dbc* pcursor = NULL;
|
|
int ret = pdb->cursor(NULL, &pcursor, 0);
|
|
if (ret != 0)
|
|
return NULL;
|
|
return pcursor;
|
|
}
|
|
|
|
int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags=DB_NEXT)
|
|
{
|
|
// Read at cursor
|
|
Dbt datKey;
|
|
if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
|
|
{
|
|
datKey.set_data(&ssKey[0]);
|
|
datKey.set_size(ssKey.size());
|
|
}
|
|
Dbt datValue;
|
|
if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
|
|
{
|
|
datValue.set_data(&ssValue[0]);
|
|
datValue.set_size(ssValue.size());
|
|
}
|
|
datKey.set_flags(DB_DBT_MALLOC);
|
|
datValue.set_flags(DB_DBT_MALLOC);
|
|
int ret = pcursor->get(&datKey, &datValue, fFlags);
|
|
if (ret != 0)
|
|
return ret;
|
|
else if (datKey.get_data() == NULL || datValue.get_data() == NULL)
|
|
return 99999;
|
|
|
|
// Convert to streams
|
|
ssKey.SetType(SER_DISK);
|
|
ssKey.clear();
|
|
ssKey.write((char*)datKey.get_data(), datKey.get_size());
|
|
ssValue.SetType(SER_DISK);
|
|
ssValue.clear();
|
|
ssValue.write((char*)datValue.get_data(), datValue.get_size());
|
|
|
|
// Clear and free memory
|
|
memset(datKey.get_data(), 0, datKey.get_size());
|
|
memset(datValue.get_data(), 0, datValue.get_size());
|
|
free(datKey.get_data());
|
|
free(datValue.get_data());
|
|
return 0;
|
|
}
|
|
|
|
public:
|
|
bool TxnBegin()
|
|
{
|
|
if (!pdb || activeTxn)
|
|
return false;
|
|
DbTxn* ptxn = bitdb.TxnBegin();
|
|
if (!ptxn)
|
|
return false;
|
|
activeTxn = ptxn;
|
|
return true;
|
|
}
|
|
|
|
bool TxnCommit()
|
|
{
|
|
if (!pdb || !activeTxn)
|
|
return false;
|
|
int ret = activeTxn->commit(0);
|
|
activeTxn = NULL;
|
|
return (ret == 0);
|
|
}
|
|
|
|
bool TxnAbort()
|
|
{
|
|
if (!pdb || !activeTxn)
|
|
return false;
|
|
int ret = activeTxn->abort();
|
|
activeTxn = NULL;
|
|
return (ret == 0);
|
|
}
|
|
|
|
bool ReadVersion(int& nVersion)
|
|
{
|
|
nVersion = 0;
|
|
return Read(std::string("version"), nVersion);
|
|
}
|
|
|
|
bool WriteVersion(int nVersion)
|
|
{
|
|
return Write(std::string("version"), nVersion);
|
|
}
|
|
|
|
bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL);
|
|
};
|
|
|
|
#endif // BITCOIN_DB_H
|