1 // Copyright (c) 2009-2012 The Bitcoin Developers.
2 // Authored by Google, Inc.
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 #ifndef BITCOIN_LEVELDB_H
7 #define BITCOIN_LEVELDB_H
15 #include <leveldb/db.h>
16 #include <leveldb/write_batch.h>
18 // Class that provides access to a LevelDB. Note that this class is frequently
19 // instantiated on the stack and then destroyed again, so instantiation has to
20 // be very cheap. Unfortunately that means, a CTxDB instance is actually just a
21 // wrapper around some global state.
23 // A LevelDB is a key/value store that is optimized for fast usage on hard
24 // disks. It prefers long read/writes to seeks and is based on a series of
25 // sorted key/value mapping files that are stacked on top of each other, with
26 // newer files overriding older files. A background thread compacts them
27 // together when too many files stack up.
29 // Learn more: http://code.google.com/p/leveldb/
33 CTxDB(const char* pszMode="r+");
35 // Note that this is not the same as Close() because it deletes only
36 // data scoped to this TxDB object.
40 // Destroys the underlying shared global state accessed by this TxDB.
44 leveldb::DB *pdb; // Points to the global instance.
45 // A batch stores up writes and deletes for atomic application. When this
46 // field is non-NULL, writes/deletes go there instead of directly to disk.
47 leveldb::WriteBatch *activeBatch;
48 leveldb::Options options;
52 // Returns true and sets (value,false) if activeBatch contains the given key
53 // or leaves value alone and sets deleted = true if activeBatch contains a
55 bool ScanBatch(const CDataStream &key, std::string *value, bool *deleted) const;
57 template<typename K, typename T>
58 bool Read(const K& key, T& value)
60 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
65 bool readFromDb = true;
67 // First we must search for it in the currently pending set of
68 // changes to the db. If not found in the batch, go on to read disk.
70 readFromDb = ScanBatch(ssKey, &strValue, &deleted) == false;
76 leveldb::Status status = pdb->Get(leveldb::ReadOptions(),
77 ssKey.str(), &strValue);
79 if (status.IsNotFound())
81 // Some unexpected error.
82 printf("LevelDB read failure: %s\n", status.ToString().c_str());
88 CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(),
89 SER_DISK, CLIENT_VERSION);
92 catch (std::exception &e) {
98 template<typename K, typename T>
99 bool Write(const K& key, const T& value)
102 assert(!"Write called on database in read-only mode");
104 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
107 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
108 ssValue.reserve(10000);
112 activeBatch->Put(ssKey.str(), ssValue.str());
115 leveldb::Status status = pdb->Put(leveldb::WriteOptions(), ssKey.str(), ssValue.str());
117 printf("LevelDB write failure: %s\n", status.ToString().c_str());
124 bool Erase(const K& key)
129 assert(!"Erase called on database in read-only mode");
131 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
135 activeBatch->Delete(ssKey.str());
138 leveldb::Status status = pdb->Delete(leveldb::WriteOptions(), ssKey.str());
139 return (status.ok() || status.IsNotFound());
143 bool Exists(const K& key)
145 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
152 if (ScanBatch(ssKey, &unused, &deleted) && !deleted) {
158 leveldb::Status status = pdb->Get(leveldb::ReadOptions(), ssKey.str(), &unused);
159 return status.IsNotFound() == false;
173 bool ReadVersion(int& nVersion)
176 return Read(std::string("version"), nVersion);
179 bool WriteVersion(int nVersion)
181 return Write(std::string("version"), nVersion);
184 bool ReadTxIndex(uint256 hash, CTxIndex& txindex);
185 bool UpdateTxIndex(uint256 hash, const CTxIndex& txindex);
186 bool AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight);
187 bool EraseTxIndex(const CTransaction& tx);
188 bool ContainsTx(uint256 hash);
189 bool ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex);
190 bool ReadDiskTx(uint256 hash, CTransaction& tx);
191 bool ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex);
192 bool ReadDiskTx(COutPoint outpoint, CTransaction& tx);
193 bool WriteBlockIndex(const CDiskBlockIndex& blockindex);
194 bool ReadHashBestChain(uint256& hashBestChain);
195 bool WriteHashBestChain(uint256 hashBestChain);
196 bool ReadBestInvalidTrust(CBigNum& bnBestInvalidTrust);
197 bool WriteBestInvalidTrust(CBigNum bnBestInvalidTrust);
198 bool ReadSyncCheckpoint(uint256& hashCheckpoint);
199 bool WriteSyncCheckpoint(uint256 hashCheckpoint);
200 bool ReadCheckpointPubKey(std::string& strPubKey);
201 bool WriteCheckpointPubKey(const std::string& strPubKey);
202 bool LoadBlockIndex();
204 bool LoadBlockIndexGuts();
207 // Called from the initialization code. Checks to see if there is an old
208 // blkindex.dat file. If so, deletes it and begins re-importing the block
209 // chain, which will create the new database.
210 enum LevelDBMigrationResult {
212 INSUFFICIENT_DISK_SPACE,
217 typedef boost::signals2::signal<void (double progress)> LevelDBMigrationProgress;
219 LevelDBMigrationResult MaybeMigrateToLevelDB(LevelDBMigrationProgress &progress);
221 #endif // BITCOIN_DB_H