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.

leveldbwrapper.h 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // Copyright (c) 2012-2013 The Bitcoin developers
  2. // Distributed under the MIT/X11 software license, see the accompanying
  3. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  4. #ifndef BITCOIN_LEVELDBWRAPPER_H
  5. #define BITCOIN_LEVELDBWRAPPER_H
  6. #include "serialize.h"
  7. #include "util.h"
  8. #include "version.h"
  9. #include <boost/filesystem/path.hpp>
  10. #include <leveldb/db.h>
  11. #include <leveldb/write_batch.h>
  12. class leveldb_error : public std::runtime_error
  13. {
  14. public:
  15. leveldb_error(const std::string &msg) : std::runtime_error(msg) {}
  16. };
  17. void HandleError(const leveldb::Status &status) throw(leveldb_error);
  18. // Batch of changes queued to be written to a CLevelDBWrapper
  19. class CLevelDBBatch
  20. {
  21. friend class CLevelDBWrapper;
  22. private:
  23. leveldb::WriteBatch batch;
  24. public:
  25. template<typename K, typename V> void Write(const K& key, const V& value) {
  26. CDataStream ssKey(SER_DISK, CLIENT_VERSION);
  27. ssKey.reserve(ssKey.GetSerializeSize(key));
  28. ssKey << key;
  29. leveldb::Slice slKey(&ssKey[0], ssKey.size());
  30. CDataStream ssValue(SER_DISK, CLIENT_VERSION);
  31. ssValue.reserve(ssValue.GetSerializeSize(value));
  32. ssValue << value;
  33. leveldb::Slice slValue(&ssValue[0], ssValue.size());
  34. batch.Put(slKey, slValue);
  35. }
  36. template<typename K> void Erase(const K& key) {
  37. CDataStream ssKey(SER_DISK, CLIENT_VERSION);
  38. ssKey.reserve(ssKey.GetSerializeSize(key));
  39. ssKey << key;
  40. leveldb::Slice slKey(&ssKey[0], ssKey.size());
  41. batch.Delete(slKey);
  42. }
  43. };
  44. class CLevelDBWrapper
  45. {
  46. private:
  47. // custom environment this database is using (may be NULL in case of default environment)
  48. leveldb::Env *penv;
  49. // database options used
  50. leveldb::Options options;
  51. // options used when reading from the database
  52. leveldb::ReadOptions readoptions;
  53. // options used when iterating over values of the database
  54. leveldb::ReadOptions iteroptions;
  55. // options used when writing to the database
  56. leveldb::WriteOptions writeoptions;
  57. // options used when sync writing to the database
  58. leveldb::WriteOptions syncoptions;
  59. // the database itself
  60. leveldb::DB *pdb;
  61. public:
  62. CLevelDBWrapper(const boost::filesystem::path &path, size_t nCacheSize, bool fMemory = false, bool fWipe = false);
  63. ~CLevelDBWrapper();
  64. template<typename K, typename V> bool Read(const K& key, V& value) throw(leveldb_error) {
  65. CDataStream ssKey(SER_DISK, CLIENT_VERSION);
  66. ssKey.reserve(ssKey.GetSerializeSize(key));
  67. ssKey << key;
  68. leveldb::Slice slKey(&ssKey[0], ssKey.size());
  69. std::string strValue;
  70. leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
  71. if (!status.ok()) {
  72. if (status.IsNotFound())
  73. return false;
  74. LogPrintf("LevelDB read failure: %s\n", status.ToString().c_str());
  75. HandleError(status);
  76. }
  77. try {
  78. CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION);
  79. ssValue >> value;
  80. } catch(std::exception &e) {
  81. return false;
  82. }
  83. return true;
  84. }
  85. template<typename K, typename V> bool Write(const K& key, const V& value, bool fSync = false) throw(leveldb_error) {
  86. CLevelDBBatch batch;
  87. batch.Write(key, value);
  88. return WriteBatch(batch, fSync);
  89. }
  90. template<typename K> bool Exists(const K& key) throw(leveldb_error) {
  91. CDataStream ssKey(SER_DISK, CLIENT_VERSION);
  92. ssKey.reserve(ssKey.GetSerializeSize(key));
  93. ssKey << key;
  94. leveldb::Slice slKey(&ssKey[0], ssKey.size());
  95. std::string strValue;
  96. leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
  97. if (!status.ok()) {
  98. if (status.IsNotFound())
  99. return false;
  100. LogPrintf("LevelDB read failure: %s\n", status.ToString().c_str());
  101. HandleError(status);
  102. }
  103. return true;
  104. }
  105. template<typename K> bool Erase(const K& key, bool fSync = false) throw(leveldb_error) {
  106. CLevelDBBatch batch;
  107. batch.Erase(key);
  108. return WriteBatch(batch, fSync);
  109. }
  110. bool WriteBatch(CLevelDBBatch &batch, bool fSync = false) throw(leveldb_error);
  111. // not available for LevelDB; provide for compatibility with BDB
  112. bool Flush() {
  113. return true;
  114. }
  115. bool Sync() throw(leveldb_error) {
  116. CLevelDBBatch batch;
  117. return WriteBatch(batch, true);
  118. }
  119. // not exactly clean encapsulation, but it's easiest for now
  120. leveldb::Iterator *NewIterator() {
  121. return pdb->NewIterator(iteroptions);
  122. }
  123. };
  124. #endif // BITCOIN_LEVELDBWRAPPER_H