Ethereum  PoC-8
The C++ Implementation of Ethereum
LevelDB.cpp
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-ethereum is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  cpp-ethereum is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #include "LevelDB.h"
19 #include "Assertions.h"
20 
21 namespace dev
22 {
23 namespace db
24 {
25 namespace
26 {
27 inline leveldb::Slice toLDBSlice(Slice _slice)
28 {
29  return leveldb::Slice(_slice.data(), _slice.size());
30 }
31 
32 DatabaseStatus toDatabaseStatus(leveldb::Status const& _status)
33 {
34  if (_status.ok())
35  return DatabaseStatus::Ok;
36  else if (_status.IsIOError())
38  else if (_status.IsCorruption())
40  else if (_status.IsNotFound())
42  else
44 }
45 
46 void checkStatus(leveldb::Status const& _status, boost::filesystem::path const& _path = {})
47 {
48  if (_status.ok())
49  return;
50 
51  DatabaseError ex;
52  ex << errinfo_dbStatusCode(toDatabaseStatus(_status))
53  << errinfo_dbStatusString(_status.ToString());
54  if (!_path.empty())
55  ex << errinfo_path(_path.string());
56 
57  BOOST_THROW_EXCEPTION(ex);
58 }
59 
60 class LevelDBWriteBatch : public WriteBatchFace
61 {
62 public:
63  void insert(Slice _key, Slice _value) override;
64  void kill(Slice _key) override;
65 
66  leveldb::WriteBatch const& writeBatch() const { return m_writeBatch; }
67  leveldb::WriteBatch& writeBatch() { return m_writeBatch; }
68 
69 private:
70  leveldb::WriteBatch m_writeBatch;
71 };
72 
73 void LevelDBWriteBatch::insert(Slice _key, Slice _value)
74 {
75  m_writeBatch.Put(toLDBSlice(_key), toLDBSlice(_value));
76 }
77 
78 void LevelDBWriteBatch::kill(Slice _key)
79 {
80  m_writeBatch.Delete(toLDBSlice(_key));
81 }
82 
83 } // namespace
84 
85 leveldb::ReadOptions LevelDB::defaultReadOptions()
86 {
87  return leveldb::ReadOptions();
88 }
89 
90 leveldb::WriteOptions LevelDB::defaultWriteOptions()
91 {
92  return leveldb::WriteOptions();
93 }
94 
95 leveldb::Options LevelDB::defaultDBOptions()
96 {
97  leveldb::Options options;
98  options.create_if_missing = true;
99  options.max_open_files = 256;
100  return options;
101 }
102 
103 LevelDB::LevelDB(boost::filesystem::path const& _path, leveldb::ReadOptions _readOptions,
104  leveldb::WriteOptions _writeOptions, leveldb::Options _dbOptions)
105  : m_db(nullptr), m_readOptions(std::move(_readOptions)), m_writeOptions(std::move(_writeOptions))
106 {
107  auto db = static_cast<leveldb::DB*>(nullptr);
108  auto const status = leveldb::DB::Open(_dbOptions, _path.string(), &db);
109  checkStatus(status, _path);
110 
111  assert(db);
112  m_db.reset(db);
113 }
114 
115 std::string LevelDB::lookup(Slice _key) const
116 {
117  leveldb::Slice const key(_key.data(), _key.size());
118  std::string value;
119  auto const status = m_db->Get(m_readOptions, key, &value);
120  if (status.IsNotFound())
121  return std::string();
122 
123  checkStatus(status);
124  return value;
125 }
126 
127 bool LevelDB::exists(Slice _key) const
128 {
129  std::string value;
130  leveldb::Slice const key(_key.data(), _key.size());
131  auto const status = m_db->Get(m_readOptions, key, &value);
132  if (status.IsNotFound())
133  return false;
134 
135  checkStatus(status);
136  return true;
137 }
138 
139 void LevelDB::insert(Slice _key, Slice _value)
140 {
141  leveldb::Slice const key(_key.data(), _key.size());
142  leveldb::Slice const value(_value.data(), _value.size());
143  auto const status = m_db->Put(m_writeOptions, key, value);
144  checkStatus(status);
145 }
146 
148 {
149  leveldb::Slice const key(_key.data(), _key.size());
150  auto const status = m_db->Delete(m_writeOptions, key);
151  checkStatus(status);
152 }
153 
154 std::unique_ptr<WriteBatchFace> LevelDB::createWriteBatch() const
155 {
156  return std::unique_ptr<WriteBatchFace>(new LevelDBWriteBatch());
157 }
158 
159 void LevelDB::commit(std::unique_ptr<WriteBatchFace> _batch)
160 {
161  if (!_batch)
162  {
163  BOOST_THROW_EXCEPTION(DatabaseError() << errinfo_comment("Cannot commit null batch"));
164  }
165  auto* batchPtr = dynamic_cast<LevelDBWriteBatch*>(_batch.get());
166  if (!batchPtr)
167  {
168  BOOST_THROW_EXCEPTION(
169  DatabaseError() << errinfo_comment("Invalid batch type passed to LevelDB::commit"));
170  }
171  auto const status = m_db->Write(m_writeOptions, &batchPtr->writeBatch());
172  checkStatus(status);
173 }
174 
175 void LevelDB::forEach(std::function<bool(Slice, Slice)> _f) const
176 {
177  std::unique_ptr<leveldb::Iterator> itr(m_db->NewIterator(m_readOptions));
178  if (itr == nullptr)
179  {
180  BOOST_THROW_EXCEPTION(DatabaseError() << errinfo_comment("null iterator"));
181  }
182  auto keepIterating = true;
183  for (itr->SeekToFirst(); keepIterating && itr->Valid(); itr->Next())
184  {
185  auto const dbKey = itr->key();
186  auto const dbValue = itr->value();
187  Slice const key(dbKey.data(), dbKey.size());
188  Slice const value(dbValue.data(), dbValue.size());
189  keepIterating = _f(key, value);
190  }
191 }
192 
193 } // namespace db
194 } // namespace dev
dev::vector_ref
Definition: vector_ref.h:22
dev::db::errinfo_dbStatusCode
boost::error_info< struct tag_dbStatusCode, DatabaseStatus > errinfo_dbStatusCode
Definition: db.h:86
dev::db::LevelDB::defaultDBOptions
static leveldb::Options defaultDBOptions()
Definition: LevelDB.cpp:95
dev::db::LevelDB::insert
void insert(Slice _key, Slice _value) override
Definition: LevelDB.cpp:139
dev::db::errinfo_dbStatusString
boost::error_info< struct tag_dbStatusString, std::string > errinfo_dbStatusString
Definition: db.h:87
dev::db::LevelDB::LevelDB
LevelDB(boost::filesystem::path const &_path, leveldb::ReadOptions _readOptions=defaultReadOptions(), leveldb::WriteOptions _writeOptions=defaultWriteOptions(), leveldb::Options _dbOptions=defaultDBOptions())
Definition: LevelDB.cpp:103
dev::db::DatabaseStatus::Unknown
@ Unknown
dev::db::LevelDB::exists
bool exists(Slice _key) const override
Definition: LevelDB.cpp:127
dev::db::DatabaseStatus::Corruption
@ Corruption
LevelDB.h
dev::errinfo_path
boost::error_info< struct tag_path, std::string > errinfo_path
Definition: Exceptions.h:96
dev::db::DatabaseStatus::Ok
@ Ok
dev::db::LevelDB::defaultReadOptions
static leveldb::ReadOptions defaultReadOptions()
Definition: LevelDB.cpp:85
dev::db::LevelDB::kill
void kill(Slice _key) override
Definition: LevelDB.cpp:147
dev::db::DatabaseStatus::NotFound
@ NotFound
dev::db::LevelDB::commit
void commit(std::unique_ptr< WriteBatchFace > _batch) override
Definition: LevelDB.cpp:159
dev::db::LevelDB::lookup
std::string lookup(Slice _key) const override
Definition: LevelDB.cpp:115
dev::db::DatabaseStatus::IOError
@ IOError
dev::vector_ref::data
_T * data() const
Definition: vector_ref.h:49
dev::vector_ref::size
size_t size() const
Definition: vector_ref.h:53
dev::db::LevelDB::createWriteBatch
std::unique_ptr< WriteBatchFace > createWriteBatch() const override
Definition: LevelDB.cpp:154
dev::db::DatabaseStatus
DatabaseStatus
Definition: db.h:76
Assertions.h
std
Definition: FixedHash.h:393
dev
Definition: Address.cpp:21
dev::db::LevelDB::forEach
void forEach(std::function< bool(Slice, Slice)> _f) const override
Definition: LevelDB.cpp:175
dev::db::LevelDB::defaultWriteOptions
static leveldb::WriteOptions defaultWriteOptions()
Definition: LevelDB.cpp:90
dev::errinfo_comment
boost::error_info< struct tag_comment, std::string > errinfo_comment
Definition: Assertions.h:69
dev::db::Slice
vector_ref< char const > Slice
Definition: dbfwd.h:26