Skip to content

Commit dd66e04

Browse files
Expose leveldb functionality (#746)
Expose leveldb iterator and write batch functionality. Resolves: OLPEDGE-1589 Signed-off-by: Mykhailo Kuchma <[email protected]>
1 parent fa91594 commit dd66e04

File tree

2 files changed

+90
-37
lines changed

2 files changed

+90
-37
lines changed

olp-cpp-sdk-core/src/cache/DiskCache.cpp

Lines changed: 69 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,27 @@ void RemoveOtherDB(const std::string& data_path,
132132
}
133133
}
134134

135+
client::ApiError GetApiError(const leveldb::Status& status) {
136+
client::ErrorCode code = client::ErrorCode::Unknown;
137+
if (status.IsNotFound()) {
138+
code = client::ErrorCode::NotFound;
139+
}
140+
if (status.IsInvalidArgument()) {
141+
code = client::ErrorCode::InvalidArgument;
142+
}
143+
if (status.IsCorruption() || status.IsIOError()) {
144+
code = client::ErrorCode::InternalFailure;
145+
}
146+
if (status.IsNotSupportedError()) {
147+
code = client::ErrorCode::BadRequest;
148+
}
149+
return client::ApiError(code, status.ToString());
150+
}
151+
135152
} // anonymous namespace
136153

137154
DiskCache::DiskCache() = default;
155+
138156
DiskCache::~DiskCache() { Close(); }
139157

140158
void DiskCache::LevelDBLogger::Logv(const char* format, va_list ap) {
@@ -210,35 +228,21 @@ OpenResult DiskCache::Open(const std::string& data_path,
210228
}
211229

212230
if (!status.ok()) {
213-
SetOpenError(status);
231+
error_ = GetApiError(status);
232+
OLP_SDK_LOG_ERROR(kLogTag,
233+
"Open: failed, error=" << error_.GetError().GetMessage());
214234
return OpenResult::Fail;
235+
} else {
236+
error_ = NoError{};
215237
}
216238

217239
database_.reset(db);
218240
return OpenResult::Success;
219241
}
220242

221-
void DiskCache::SetOpenError(const leveldb::Status& status) {
222-
client::ErrorCode code = client::ErrorCode::Unknown;
223-
if (status.IsNotFound()) {
224-
code = client::ErrorCode::NotFound;
225-
}
226-
if (status.IsInvalidArgument()) {
227-
code = client::ErrorCode::InvalidArgument;
228-
}
229-
if (status.IsCorruption() || status.IsIOError()) {
230-
code = client::ErrorCode::InternalFailure;
231-
}
232-
if (status.IsNotSupportedError()) {
233-
code = client::ErrorCode::BadRequest;
234-
}
235-
std::string error_message = status.ToString();
236-
OLP_SDK_LOG_ERROR(kLogTag, "Open: failed, error=" << error_message);
237-
error_ = client::ApiError(code, std::move(error_message));
238-
}
239-
240243
bool DiskCache::Put(const std::string& key, leveldb::Slice slice) {
241244
if (!database_) {
245+
OLP_SDK_LOG_ERROR(kLogTag, "Put: Database is uninitialized");
242246
return false;
243247
}
244248

@@ -257,22 +261,60 @@ bool DiskCache::Put(const std::string& key, leveldb::Slice slice) {
257261
}
258262

259263
boost::optional<std::string> DiskCache::Get(const std::string& key) {
264+
if (!database_) {
265+
OLP_SDK_LOG_ERROR(kLogTag, "Get: Database is uninitialized");
266+
return boost::none;
267+
}
268+
260269
std::string res;
261270
leveldb::ReadOptions options;
262271
options.verify_checksums = check_crc_;
263-
return database_ && database_->Get(options, ToLeveldbSlice(key), &res).ok()
272+
return database_->Get(options, ToLeveldbSlice(key), &res).ok()
264273
? boost::optional<std::string>(std::move(res))
265274
: boost::none;
266275
}
267276

268277
bool DiskCache::Remove(const std::string& key) {
269-
if (!database_ || !database_->Delete(leveldb::WriteOptions(), key).ok())
278+
if (!database_) {
279+
OLP_SDK_LOG_ERROR(kLogTag, "Remove: Database is uninitialized");
270280
return false;
271-
return true;
281+
}
282+
return database_->Delete(leveldb::WriteOptions(), key).ok();
283+
}
284+
285+
std::unique_ptr<leveldb::Iterator> DiskCache::NewIterator(
286+
leveldb::ReadOptions options) {
287+
if (!database_) {
288+
OLP_SDK_LOG_ERROR(kLogTag, "NewIterator: Database is uninitialized");
289+
return nullptr;
290+
}
291+
return std::unique_ptr<leveldb::Iterator>(database_->NewIterator(options));
292+
}
293+
294+
DiskCache::OperationOutcome DiskCache::ApplyBatch(
295+
std::unique_ptr<leveldb::WriteBatch> batch) {
296+
if (!database_) {
297+
OLP_SDK_LOG_ERROR(kLogTag, "ApplyBatch: Database is uninitialized");
298+
return client::ApiError(client::ErrorCode::PreconditionFailed,
299+
"Database is not initialized");
300+
}
301+
if (!batch) {
302+
OLP_SDK_LOG_ERROR(kLogTag, "ApplyBatch: failed, batch is null");
303+
return client::ApiError(client::ErrorCode::PreconditionFailed,
304+
"Batch can't be null");
305+
}
306+
const auto status = database_->Write(leveldb::WriteOptions(), batch.get());
307+
if (!status.ok()) {
308+
OLP_SDK_LOG_ERROR(kLogTag,
309+
"ApplyBatch: failed, status=" << status.ToString());
310+
return GetApiError(status);
311+
}
312+
return NoError{};
272313
}
273314

274315
bool DiskCache::RemoveKeysWithPrefix(const std::string& prefix) {
275316
if (!database_) {
317+
OLP_SDK_LOG_ERROR(kLogTag, "RemoveKeysWithPrefix: Database is uninitialized");
276318
return false;
277319
}
278320

@@ -281,8 +323,7 @@ bool DiskCache::RemoveKeysWithPrefix(const std::string& prefix) {
281323
leveldb::ReadOptions opts;
282324
opts.verify_checksums = check_crc_;
283325
opts.fill_cache = true;
284-
std::unique_ptr<leveldb::Iterator> iterator;
285-
iterator.reset(database_->NewIterator(opts));
326+
auto iterator = NewIterator(opts);
286327

287328
if (prefix.empty()) {
288329
for (iterator->SeekToFirst(); iterator->Valid(); iterator->Next()) {
@@ -296,13 +337,9 @@ bool DiskCache::RemoveKeysWithPrefix(const std::string& prefix) {
296337
}
297338
}
298339

299-
const auto status = database_->Write(leveldb::WriteOptions(), batch.get());
300-
if (!status.ok()) {
301-
OLP_SDK_LOG_ERROR(
302-
kLogTag, "RemoveKeysWithPrefix: failed, status=" << status.ToString());
303-
return false;
304-
}
305-
return true;
340+
auto result = ApplyBatch(std::move(batch));
341+
342+
return result.IsSuccessful();
306343
}
307344

308345
} // namespace cache

olp-cpp-sdk-core/src/cache/DiskCache.h

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,12 @@
2929
#include <vector>
3030

3131
#include <leveldb/env.h>
32+
#include <leveldb/iterator.h>
33+
#include <leveldb/options.h>
3234
#include <leveldb/write_batch.h>
3335
#include <olp/core/cache/CacheSettings.h>
3436
#include <olp/core/client/ApiError.h>
37+
#include <olp/core/client/ApiResponse.h>
3538

3639
namespace leveldb {
3740
class DB;
@@ -76,6 +79,12 @@ class DiskCache {
7679
public:
7780
static constexpr uint64_t kSizeMax = std::numeric_limits<uint64_t>::max();
7881

82+
/// No error type
83+
struct NoError {};
84+
85+
/// Operation result type
86+
using OperationOutcome = client::ApiResponse<NoError, client::ApiError>;
87+
7988
/// Logger that forwards leveldb log messages to our logging framework.
8089
class LevelDBLogger : public leveldb::Logger {
8190
void Logv(const char* format, va_list ap) override;
@@ -89,28 +98,35 @@ class DiskCache {
8998

9099
void Close();
91100
bool Clear();
92-
client::ApiError OpenError() const { return error_; }
101+
102+
OperationOutcome OpenError() const { return error_; }
93103

94104
bool Put(const std::string& key, leveldb::Slice slice);
95105

96106
boost::optional<std::string> Get(const std::string& key);
97107

98108
/// Remove single key/value from DB.
99109
bool Remove(const std::string& key);
110+
111+
/// Get a new leveldb cache iterator. Use options.fill_cache = false for bulk
112+
/// scans.
113+
std::unique_ptr<leveldb::Iterator> NewIterator(leveldb::ReadOptions options);
114+
115+
/// Allow batch writting so that we can delete and write multiple values at
116+
/// the same time.
117+
OperationOutcome ApplyBatch(std::unique_ptr<leveldb::WriteBatch> batch);
118+
100119
/// Empty prefix deleted everything from DB.
101120
bool RemoveKeysWithPrefix(const std::string& prefix);
102121

103-
private:
104-
void SetOpenError(const leveldb::Status& status);
105-
106122
private:
107123
std::string disk_cache_path_;
108124
std::unique_ptr<leveldb::DB> database_;
109125
std::unique_ptr<DiskCacheSizeLimitEnv> environment_;
110126
std::unique_ptr<LevelDBLogger> leveldb_logger_;
111127
uint64_t max_size_{kSizeMax};
112128
bool check_crc_{false};
113-
client::ApiError error_;
129+
OperationOutcome error_;
114130
};
115131

116132
} // namespace cache

0 commit comments

Comments
 (0)