LCOV - code coverage report
Current view: top level - src - leveldbwrapper.h (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 44 51 86.3 %
Date: 2015-10-12 22:39:14 Functions: 26 30 86.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11