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