2018-12-31 20:04:05 +01:00
|
|
|
//
|
2021-01-01 13:57:46 +01:00
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
|
2018-12-31 20:04:05 +01:00
|
|
|
//
|
|
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
//
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "td/db/SqliteDb.h"
|
|
|
|
#include "td/db/SqliteStatement.h"
|
|
|
|
|
|
|
|
#include "td/utils/logging.h"
|
|
|
|
#include "td/utils/Slice.h"
|
|
|
|
#include "td/utils/Status.h"
|
|
|
|
|
|
|
|
#include <unordered_map>
|
|
|
|
|
|
|
|
namespace td {
|
2018-05-24 23:37:43 +02:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
class SqliteKeyValue {
|
|
|
|
public:
|
2018-07-22 01:56:40 +02:00
|
|
|
static Status drop(SqliteDb &connection, Slice table_name) TD_WARN_UNUSED_RESULT {
|
2021-03-12 12:31:51 +01:00
|
|
|
return connection.exec(PSLICE() << "DROP TABLE IF EXISTS " << table_name);
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2018-07-22 01:56:40 +02:00
|
|
|
static Status init(SqliteDb &connection, Slice table_name) TD_WARN_UNUSED_RESULT {
|
2021-03-12 12:31:51 +01:00
|
|
|
return connection.exec(PSLICE() << "CREATE TABLE IF NOT EXISTS " << table_name << " (k BLOB PRIMARY KEY, v BLOB)");
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
using SeqNo = uint64;
|
|
|
|
|
2018-07-22 01:56:40 +02:00
|
|
|
bool empty() const {
|
2021-03-12 12:31:51 +01:00
|
|
|
return db_.empty();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2018-07-22 01:56:40 +02:00
|
|
|
Result<bool> init(string path) TD_WARN_UNUSED_RESULT;
|
|
|
|
|
|
|
|
Status init_with_connection(SqliteDb connection, string table_name) TD_WARN_UNUSED_RESULT;
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
Result<bool> try_regenerate_index() TD_WARN_UNUSED_RESULT {
|
|
|
|
return false;
|
|
|
|
}
|
2018-07-22 01:56:40 +02:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
void close() {
|
2018-08-06 16:22:22 +02:00
|
|
|
*this = SqliteKeyValue();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2018-08-06 16:22:22 +02:00
|
|
|
Status drop();
|
2018-07-22 01:56:40 +02:00
|
|
|
|
|
|
|
SeqNo set(Slice key, Slice value);
|
|
|
|
|
|
|
|
string get(Slice key);
|
|
|
|
|
|
|
|
SeqNo erase(Slice key);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2018-07-17 23:41:26 +02:00
|
|
|
Status begin_transaction() TD_WARN_UNUSED_RESULT {
|
2021-03-12 12:31:51 +01:00
|
|
|
return db_.begin_transaction();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
2018-07-17 23:41:26 +02:00
|
|
|
Status commit_transaction() TD_WARN_UNUSED_RESULT {
|
2021-03-12 12:31:51 +01:00
|
|
|
return db_.commit_transaction();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2018-07-22 01:56:40 +02:00
|
|
|
void erase_by_prefix(Slice prefix);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
std::unordered_map<string, string> get_all() {
|
|
|
|
std::unordered_map<string, string> res;
|
2019-05-01 16:15:54 +02:00
|
|
|
get_by_prefix("", [&](Slice key, Slice value) {
|
|
|
|
res.emplace(key.str(), value.str());
|
|
|
|
return true;
|
|
|
|
});
|
2018-12-31 20:04:05 +01:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class CallbackT>
|
|
|
|
void get_by_prefix(Slice prefix, CallbackT &&callback) {
|
|
|
|
string next;
|
|
|
|
if (!prefix.empty()) {
|
|
|
|
next = next_prefix(prefix);
|
|
|
|
}
|
|
|
|
get_by_range(prefix, next, callback);
|
|
|
|
}
|
2018-07-22 01:56:40 +02:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
template <class CallbackT>
|
|
|
|
void get_by_range(Slice from, Slice till, CallbackT &&callback) {
|
|
|
|
SqliteStatement *stmt = nullptr;
|
|
|
|
if (from.empty()) {
|
|
|
|
stmt = &get_all_stmt_;
|
|
|
|
} else {
|
|
|
|
if (till.empty()) {
|
|
|
|
stmt = &get_by_prefix_rare_stmt_;
|
|
|
|
stmt->bind_blob(1, till).ensure();
|
|
|
|
} else {
|
|
|
|
stmt = &get_by_prefix_stmt_;
|
|
|
|
stmt->bind_blob(1, from).ensure();
|
|
|
|
stmt->bind_blob(2, till).ensure();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
auto guard = stmt->guard();
|
|
|
|
stmt->step().ensure();
|
|
|
|
while (stmt->has_row()) {
|
2019-05-01 16:15:54 +02:00
|
|
|
if (!callback(stmt->view_blob(0), stmt->view_blob(1))) {
|
|
|
|
return;
|
|
|
|
}
|
2018-12-31 20:04:05 +01:00
|
|
|
stmt->step().ensure();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2018-07-22 01:56:40 +02:00
|
|
|
string path_;
|
2021-03-12 12:31:51 +01:00
|
|
|
string table_name_;
|
|
|
|
SqliteDb db_;
|
|
|
|
SqliteStatement get_stmt_;
|
|
|
|
SqliteStatement set_stmt_;
|
|
|
|
SqliteStatement erase_stmt_;
|
2018-12-31 20:04:05 +01:00
|
|
|
SqliteStatement get_all_stmt_;
|
2021-03-12 12:31:51 +01:00
|
|
|
SqliteStatement erase_by_prefix_stmt_;
|
|
|
|
SqliteStatement erase_by_prefix_rare_stmt_;
|
2018-12-31 20:04:05 +01:00
|
|
|
SqliteStatement get_by_prefix_stmt_;
|
|
|
|
SqliteStatement get_by_prefix_rare_stmt_;
|
|
|
|
|
2018-07-22 01:56:40 +02:00
|
|
|
string next_prefix(Slice prefix);
|
2018-12-31 20:04:05 +01:00
|
|
|
};
|
2018-05-24 23:37:43 +02:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
} // namespace td
|