8f0c9950ff186088c5be2e6563a90f1d6faf429c
[novacoin.git] / src / txdb-leveldb.h
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.
5
6 #ifndef BITCOIN_LEVELDB_H
7 #define BITCOIN_LEVELDB_H
8
9 #include "serialize.h"
10
11 #include <map>
12 #include <string>
13 #include <vector>
14
15 #include <leveldb/db.h>
16 #include <leveldb/write_batch.h>
17
18 class CBigNum;
19 class CDiskBlockIndex;
20 class COutPoint;
21 class CTxIndex;
22 class CTransaction;
23 class uint256;
24 class CDiskTxPos;
25
26 // Class that provides access to a LevelDB. Note that this class is frequently
27 // instantiated on the stack and then destroyed again, so instantiation has to
28 // be very cheap. Unfortunately that means, a CTxDB instance is actually just a
29 // wrapper around some global state.
30 //
31 // A LevelDB is a key/value store that is optimized for fast usage on hard
32 // disks. It prefers long read/writes to seeks and is based on a series of
33 // sorted key/value mapping files that are stacked on top of each other, with
34 // newer files overriding older files. A background thread compacts them
35 // together when too many files stack up.
36 //
37 // Learn more: http://code.google.com/p/leveldb/
38 class CTxDB
39 {
40 public:
41     CTxDB(const char* pszMode="r+");
42     ~CTxDB() {
43         // Note that this is not the same as Close() because it deletes only
44         // data scoped to this TxDB object.
45         delete activeBatch;
46     }
47
48     // Destroys the underlying shared global state accessed by this TxDB.
49     void Close();
50
51 private:
52     leveldb::DB *pdb;  // Points to the global instance.
53
54     // A batch stores up writes and deletes for atomic application. When this
55     // field is non-NULL, writes/deletes go there instead of directly to disk.
56     leveldb::WriteBatch *activeBatch;
57     leveldb::Options options;
58     bool fReadOnly;
59     int nVersion;
60
61 protected:
62     // Returns true and sets (value,false) if activeBatch contains the given key
63     // or leaves value alone and sets deleted = true if activeBatch contains a
64     // delete for it.
65     bool ScanBatch(const CDataStream &key, std::string *value, bool *deleted) const;
66
67     template<typename K, typename T>
68     bool Read(const K& key, T& value)
69     {
70         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
71         ssKey.reserve(1000);
72         ssKey << key;
73         std::string strValue;
74
75         bool readFromDb = true;
76         if (activeBatch) {
77             // First we must search for it in the currently pending set of
78             // changes to the db. If not found in the batch, go on to read disk.
79             bool deleted = false;
80             readFromDb = ScanBatch(ssKey, &strValue, &deleted) == false;
81             if (deleted) {
82                 return false;
83             }
84         }
85         if (readFromDb) {
86             leveldb::Status status = pdb->Get(leveldb::ReadOptions(),
87                                               ssKey.str(), &strValue);
88             if (!status.ok()) {
89                 if (status.IsNotFound())
90                     return false;
91                 // Some unexpected error.
92                 printf("LevelDB read failure: %s\n", status.ToString().c_str());
93                 return false;
94             }
95         }
96         // Unserialize value
97         try {
98             CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(),
99                                 SER_DISK, CLIENT_VERSION);
100             ssValue >> value;
101         }
102         catch (const std::exception&) {
103             return false;
104         }
105         return true;
106     }
107
108     template<typename K, typename T>
109     bool Write(const K& key, const T& value)
110     {
111         if (fReadOnly)
112             assert(!"Write called on database in read-only mode");
113
114         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
115         ssKey.reserve(1000);
116         ssKey << key;
117         CDataStream ssValue(SER_DISK, CLIENT_VERSION);
118         ssValue.reserve(10000);
119         ssValue << value;
120
121         if (activeBatch) {
122             activeBatch->Put(ssKey.str(), ssValue.str());
123             return true;
124         }
125         leveldb::Status status = pdb->Put(leveldb::WriteOptions(), ssKey.str(), ssValue.str());
126         if (!status.ok()) {
127             printf("LevelDB write failure: %s\n", status.ToString().c_str());
128             return false;
129         }
130         return true;
131     }
132
133     template<typename K>
134     bool Erase(const K& key)
135     {
136         if (!pdb)
137             return false;
138         if (fReadOnly)
139             assert(!"Erase called on database in read-only mode");
140
141         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
142         ssKey.reserve(1000);
143         ssKey << key;
144         if (activeBatch) {
145             activeBatch->Delete(ssKey.str());
146             return true;
147         }
148         leveldb::Status status = pdb->Delete(leveldb::WriteOptions(), ssKey.str());
149         return (status.ok() || status.IsNotFound());
150     }
151
152     template<typename K>
153     bool Exists(const K& key)
154     {
155         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
156         ssKey.reserve(1000);
157         ssKey << key;
158         std::string unused;
159
160         if (activeBatch) {
161             bool deleted;
162             if (ScanBatch(ssKey, &unused, &deleted) && !deleted) {
163                 return true;
164             }
165         }
166
167
168         leveldb::Status status = pdb->Get(leveldb::ReadOptions(), ssKey.str(), &unused);
169         return status.IsNotFound() == false;
170     }
171
172
173 public:
174     bool TxnBegin();
175     bool TxnCommit();
176     bool TxnAbort()
177     {
178         delete activeBatch;
179         activeBatch = NULL;
180         return true;
181     }
182
183     bool ReadVersion(int& nVersion)
184     {
185         nVersion = 0;
186         return Read(std::string("version"), nVersion);
187     }
188
189     bool WriteVersion(int nVersion)
190     {
191         return Write(std::string("version"), nVersion);
192     }
193
194     bool ReadTxIndex(uint256 hash, CTxIndex& txindex);
195     bool UpdateTxIndex(uint256 hash, const CTxIndex& txindex);
196     bool AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight);
197     bool EraseTxIndex(const CTransaction& tx);
198     bool ContainsTx(uint256 hash);
199     bool ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex);
200     bool ReadDiskTx(uint256 hash, CTransaction& tx);
201     bool ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex);
202     bool ReadDiskTx(COutPoint outpoint, CTransaction& tx);
203     bool WriteBlockIndex(const CDiskBlockIndex& blockindex);
204     bool ReadHashBestChain(uint256& hashBestChain);
205     bool WriteHashBestChain(uint256 hashBestChain);
206     bool ReadBestInvalidTrust(CBigNum& bnBestInvalidTrust);
207     bool WriteBestInvalidTrust(CBigNum bnBestInvalidTrust);
208     bool ReadSyncCheckpoint(uint256& hashCheckpoint);
209     bool WriteSyncCheckpoint(uint256 hashCheckpoint);
210     bool ReadCheckpointPubKey(std::string& strPubKey);
211     bool WriteCheckpointPubKey(const std::string& strPubKey);
212     bool ReadModifierUpgradeTime(unsigned int& nUpgradeTime);
213     bool WriteModifierUpgradeTime(const unsigned int& nUpgradeTime);
214     bool LoadBlockIndex();
215 };
216
217
218 #endif // BITCOIN_DB_H