You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

dbwrapper.h 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. // Copyright (c) 2012-2015 The Bitcoin Core developers
  2. // Distributed under the MIT software license, see the accompanying
  3. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  4. #ifndef BITCOIN_DBWRAPPER_H
  5. #define BITCOIN_DBWRAPPER_H
  6. #include "clientversion.h"
  7. #include "serialize.h"
  8. #include "streams.h"
  9. #include "util.h"
  10. #include "utilstrencodings.h"
  11. #include "version.h"
  12. #include <boost/filesystem/path.hpp>
  13. #include <leveldb/db.h>
  14. #include <leveldb/write_batch.h>
  15. class dbwrapper_error : public std::runtime_error
  16. {
  17. public:
  18. dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
  19. };
  20. void HandleError(const leveldb::Status& status) throw(dbwrapper_error);
  21. /** Batch of changes queued to be written to a CDBWrapper */
  22. class CDBBatch
  23. {
  24. friend class CDBWrapper;
  25. private:
  26. leveldb::WriteBatch batch;
  27. const std::vector<unsigned char> *obfuscate_key;
  28. public:
  29. /**
  30. * @param[in] obfuscate_key If passed, XOR data with this key.
  31. */
  32. CDBBatch(const std::vector<unsigned char> *obfuscate_key) : obfuscate_key(obfuscate_key) { };
  33. template <typename K, typename V>
  34. void Write(const K& key, const V& value)
  35. {
  36. CDataStream ssKey(SER_DISK, CLIENT_VERSION);
  37. ssKey.reserve(ssKey.GetSerializeSize(key));
  38. ssKey << key;
  39. leveldb::Slice slKey(&ssKey[0], ssKey.size());
  40. CDataStream ssValue(SER_DISK, CLIENT_VERSION);
  41. ssValue.reserve(ssValue.GetSerializeSize(value));
  42. ssValue << value;
  43. ssValue.Xor(*obfuscate_key);
  44. leveldb::Slice slValue(&ssValue[0], ssValue.size());
  45. batch.Put(slKey, slValue);
  46. }
  47. template <typename K>
  48. void Erase(const K& key)
  49. {
  50. CDataStream ssKey(SER_DISK, CLIENT_VERSION);
  51. ssKey.reserve(ssKey.GetSerializeSize(key));
  52. ssKey << key;
  53. leveldb::Slice slKey(&ssKey[0], ssKey.size());
  54. batch.Delete(slKey);
  55. }
  56. };
  57. class CDBIterator
  58. {
  59. private:
  60. leveldb::Iterator *piter;
  61. const std::vector<unsigned char> *obfuscate_key;
  62. public:
  63. /**
  64. * @param[in] piterIn The original leveldb iterator.
  65. * @param[in] obfuscate_key If passed, XOR data with this key.
  66. */
  67. CDBIterator(leveldb::Iterator *piterIn, const std::vector<unsigned char>* obfuscate_key) :
  68. piter(piterIn), obfuscate_key(obfuscate_key) { };
  69. ~CDBIterator();
  70. bool Valid();
  71. void SeekToFirst();
  72. template<typename K> void Seek(const K& key) {
  73. CDataStream ssKey(SER_DISK, CLIENT_VERSION);
  74. ssKey.reserve(ssKey.GetSerializeSize(key));
  75. ssKey << key;
  76. leveldb::Slice slKey(&ssKey[0], ssKey.size());
  77. piter->Seek(slKey);
  78. }
  79. void Next();
  80. template<typename K> bool GetKey(K& key) {
  81. leveldb::Slice slKey = piter->key();
  82. try {
  83. CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION);
  84. ssKey >> key;
  85. } catch (const std::exception&) {
  86. return false;
  87. }
  88. return true;
  89. }
  90. unsigned int GetKeySize() {
  91. return piter->key().size();
  92. }
  93. template<typename V> bool GetValue(V& value) {
  94. leveldb::Slice slValue = piter->value();
  95. try {
  96. CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION);
  97. ssValue.Xor(*obfuscate_key);
  98. ssValue >> value;
  99. } catch (const std::exception&) {
  100. return false;
  101. }
  102. return true;
  103. }
  104. unsigned int GetValueSize() {
  105. return piter->value().size();
  106. }
  107. };
  108. class CDBWrapper
  109. {
  110. private:
  111. //! custom environment this database is using (may be NULL in case of default environment)
  112. leveldb::Env* penv;
  113. //! database options used
  114. leveldb::Options options;
  115. //! options used when reading from the database
  116. leveldb::ReadOptions readoptions;
  117. //! options used when iterating over values of the database
  118. leveldb::ReadOptions iteroptions;
  119. //! options used when writing to the database
  120. leveldb::WriteOptions writeoptions;
  121. //! options used when sync writing to the database
  122. leveldb::WriteOptions syncoptions;
  123. //! the database itself
  124. leveldb::DB* pdb;
  125. //! a key used for optional XOR-obfuscation of the database
  126. std::vector<unsigned char> obfuscate_key;
  127. //! the key under which the obfuscation key is stored
  128. static const std::string OBFUSCATE_KEY_KEY;
  129. //! the length of the obfuscate key in number of bytes
  130. static const unsigned int OBFUSCATE_KEY_NUM_BYTES;
  131. std::vector<unsigned char> CreateObfuscateKey() const;
  132. public:
  133. /**
  134. * @param[in] path Location in the filesystem where leveldb data will be stored.
  135. * @param[in] nCacheSize Configures various leveldb cache settings.
  136. * @param[in] fMemory If true, use leveldb's memory environment.
  137. * @param[in] fWipe If true, remove all existing data.
  138. * @param[in] obfuscate If true, store data obfuscated via simple XOR. If false, XOR
  139. * with a zero'd byte array.
  140. */
  141. CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool obfuscate = false);
  142. ~CDBWrapper();
  143. template <typename K, typename V>
  144. bool Read(const K& key, V& value) const throw(dbwrapper_error)
  145. {
  146. CDataStream ssKey(SER_DISK, CLIENT_VERSION);
  147. ssKey.reserve(ssKey.GetSerializeSize(key));
  148. ssKey << key;
  149. leveldb::Slice slKey(&ssKey[0], ssKey.size());
  150. std::string strValue;
  151. leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
  152. if (!status.ok()) {
  153. if (status.IsNotFound())
  154. return false;
  155. LogPrintf("LevelDB read failure: %s\n", status.ToString());
  156. HandleError(status);
  157. }
  158. try {
  159. CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION);
  160. ssValue.Xor(obfuscate_key);
  161. ssValue >> value;
  162. } catch (const std::exception&) {
  163. return false;
  164. }
  165. return true;
  166. }
  167. template <typename K, typename V>
  168. bool Write(const K& key, const V& value, bool fSync = false) throw(dbwrapper_error)
  169. {
  170. CDBBatch batch(&obfuscate_key);
  171. batch.Write(key, value);
  172. return WriteBatch(batch, fSync);
  173. }
  174. template <typename K>
  175. bool Exists(const K& key) const throw(dbwrapper_error)
  176. {
  177. CDataStream ssKey(SER_DISK, CLIENT_VERSION);
  178. ssKey.reserve(ssKey.GetSerializeSize(key));
  179. ssKey << key;
  180. leveldb::Slice slKey(&ssKey[0], ssKey.size());
  181. std::string strValue;
  182. leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
  183. if (!status.ok()) {
  184. if (status.IsNotFound())
  185. return false;
  186. LogPrintf("LevelDB read failure: %s\n", status.ToString());
  187. HandleError(status);
  188. }
  189. return true;
  190. }
  191. template <typename K>
  192. bool Erase(const K& key, bool fSync = false) throw(dbwrapper_error)
  193. {
  194. CDBBatch batch(&obfuscate_key);
  195. batch.Erase(key);
  196. return WriteBatch(batch, fSync);
  197. }
  198. bool WriteBatch(CDBBatch& batch, bool fSync = false) throw(dbwrapper_error);
  199. // not available for LevelDB; provide for compatibility with BDB
  200. bool Flush()
  201. {
  202. return true;
  203. }
  204. bool Sync() throw(dbwrapper_error)
  205. {
  206. CDBBatch batch(&obfuscate_key);
  207. return WriteBatch(batch, true);
  208. }
  209. CDBIterator *NewIterator()
  210. {
  211. return new CDBIterator(pdb->NewIterator(iteroptions), &obfuscate_key);
  212. }
  213. /**
  214. * Return true if the database managed by this class contains no entries.
  215. */
  216. bool IsEmpty();
  217. /**
  218. * Accessor for obfuscate_key.
  219. */
  220. const std::vector<unsigned char>& GetObfuscateKey() const;
  221. /**
  222. * Return the obfuscate_key as a hex-formatted string.
  223. */
  224. std::string GetObfuscateKeyHex() const;
  225. };
  226. #endif // BITCOIN_DBWRAPPER_H