aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlevlam <levlam@telegram.org>2018-07-22 02:56:40 +0300
committerlevlam <levlam@telegram.org>2018-07-22 02:56:40 +0300
commite9568c9a8ef1176629d500e35c4e4c69b0b84e32 (patch)
treeeca1c09769d0feb64d9301438bc4264d5a5a5aae
parenta2d725f484c1d312807d62f992895be26226b36b (diff)
Add SqliteKeyValue.cpp.
GitOrigin-RevId: d0490b00c3342db191a29e7780d3292e3b593896
-rw-r--r--tddb/CMakeLists.txt1
-rw-r--r--tddb/td/db/SqliteKeyValue.cpp130
-rw-r--r--tddb/td/db/SqliteKeyValue.h145
-rw-r--r--tdutils/td/utils/ScopeGuard.h1
4 files changed, 157 insertions, 120 deletions
diff --git a/tddb/CMakeLists.txt b/tddb/CMakeLists.txt
index 531dcc5c0..50e17120f 100644
--- a/tddb/CMakeLists.txt
+++ b/tddb/CMakeLists.txt
@@ -10,6 +10,7 @@ set(TDDB_SOURCE
td/db/SqliteDb.cpp
td/db/SqliteStatement.cpp
+ td/db/SqliteKeyValue.cpp
td/db/SqliteKeyValueAsync.cpp
td/db/detail/RawSqliteDb.cpp
diff --git a/tddb/td/db/SqliteKeyValue.cpp b/tddb/td/db/SqliteKeyValue.cpp
new file mode 100644
index 000000000..34e0c4e5e
--- /dev/null
+++ b/tddb/td/db/SqliteKeyValue.cpp
@@ -0,0 +1,130 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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)
+//
+#include "td/db/SqliteKeyValue.h"
+
+#include "td/utils/ScopeGuard.h"
+
+namespace td {
+
+Result<bool> SqliteKeyValue::init(string path) {
+ path_ = std::move(path);
+ bool is_created = false;
+ SqliteDb db;
+ TRY_STATUS(db.init(path, &is_created));
+ TRY_STATUS(db.exec("PRAGMA encoding=\"UTF-8\""));
+ TRY_STATUS(db.exec("PRAGMA synchronous=NORMAL"));
+ TRY_STATUS(db.exec("PRAGMA journal_mode=WAL"));
+ TRY_STATUS(db.exec("PRAGMA temp_store=MEMORY"));
+ TRY_STATUS(init_with_connection(std::move(db), "KV"));
+ return is_created;
+}
+
+Status SqliteKeyValue::init_with_connection(SqliteDb connection, string table_name) {
+ db_ = std::move(connection);
+ table_name_ = std::move(table_name);
+ TRY_STATUS(init(db_, table_name_));
+
+ TRY_RESULT(set_stmt, db_.get_statement(PSLICE() << "REPLACE INTO " << table_name_ << " (k, v) VALUES (?1, ?2)"));
+ set_stmt_ = std::move(set_stmt);
+ TRY_RESULT(get_stmt, db_.get_statement(PSLICE() << "SELECT v FROM " << table_name_ << " WHERE k = ?1"));
+ get_stmt_ = std::move(get_stmt);
+ TRY_RESULT(erase_stmt, db_.get_statement(PSLICE() << "DELETE FROM " << table_name_ << " WHERE k = ?1"));
+ erase_stmt_ = std::move(erase_stmt);
+ TRY_RESULT(get_all_stmt, db_.get_statement(PSLICE() << "SELECT k, v FROM " << table_name_ << ""));
+
+ TRY_RESULT(erase_by_prefix_stmt,
+ db_.get_statement(PSLICE() << "DELETE FROM " << table_name_ << " WHERE ?1 <= k AND k < ?2"));
+ erase_by_prefix_stmt_ = std::move(erase_by_prefix_stmt);
+
+ TRY_RESULT(erase_by_prefix_rare_stmt,
+ db_.get_statement(PSLICE() << "DELETE FROM " << table_name_ << " WHERE ?1 <= k"));
+ erase_by_prefix_rare_stmt_ = std::move(erase_by_prefix_rare_stmt);
+
+ TRY_RESULT(get_by_prefix_stmt,
+ db_.get_statement(PSLICE() << "SELECT k, v FROM " << table_name_ << " WHERE ?1 <= k AND k < ?2"));
+ get_by_prefix_stmt_ = std::move(get_by_prefix_stmt);
+
+ TRY_RESULT(get_by_prefix_rare_stmt,
+ db_.get_statement(PSLICE() << "SELECT k, v FROM " << table_name_ << " WHERE ?1 <= k"));
+ get_by_prefix_rare_stmt_ = std::move(get_by_prefix_rare_stmt);
+
+ get_all_stmt_ = std::move(get_all_stmt);
+ return Status::OK();
+}
+
+void SqliteKeyValue::close_and_destroy() {
+ drop(db_, table_name_).ensure();
+ auto path = std::move(path_);
+ clear();
+ if (!path.empty()) {
+ destroy(path).ignore();
+ }
+}
+
+SqliteKeyValue::SeqNo SqliteKeyValue::set(Slice key, Slice value) {
+ set_stmt_.bind_blob(1, key).ensure();
+ set_stmt_.bind_blob(2, value).ensure();
+ set_stmt_.step().ensure();
+ set_stmt_.reset();
+ return 0;
+}
+
+string SqliteKeyValue::get(Slice key) {
+ SCOPE_EXIT {
+ get_stmt_.reset();
+ };
+ get_stmt_.bind_blob(1, key).ensure();
+ get_stmt_.step().ensure();
+ if (!get_stmt_.has_row()) {
+ return "";
+ }
+ auto data = get_stmt_.view_blob(0).str();
+ get_stmt_.step().ignore();
+ return data;
+}
+
+SqliteKeyValue::SeqNo SqliteKeyValue::erase(Slice key) {
+ erase_stmt_.bind_blob(1, key).ensure();
+ erase_stmt_.step().ensure();
+ erase_stmt_.reset();
+ return 0;
+}
+
+void SqliteKeyValue::erase_by_prefix(Slice prefix) {
+ auto next = next_prefix(prefix);
+ if (next.empty()) {
+ SCOPE_EXIT {
+ erase_by_prefix_rare_stmt_.reset();
+ };
+ erase_by_prefix_rare_stmt_.bind_blob(1, prefix).ensure();
+ erase_by_prefix_rare_stmt_.step().ensure();
+ } else {
+ SCOPE_EXIT {
+ erase_by_prefix_stmt_.reset();
+ };
+ erase_by_prefix_stmt_.bind_blob(1, prefix).ensure();
+ erase_by_prefix_stmt_.bind_blob(2, next).ensure();
+ erase_by_prefix_stmt_.step().ensure();
+ }
+}
+
+string SqliteKeyValue::next_prefix(Slice prefix) {
+ string next = prefix.str();
+ size_t pos = next.size();
+ while (pos) {
+ pos--;
+ auto value = static_cast<uint8>(next[pos]);
+ value++;
+ next[pos] = static_cast<char>(value);
+ if (value != 0) {
+ return next;
+ }
+ }
+ return string{};
+}
+
+} // namespace td
diff --git a/tddb/td/db/SqliteKeyValue.h b/tddb/td/db/SqliteKeyValue.h
index f4221f36c..31ac9a53d 100644
--- a/tddb/td/db/SqliteKeyValue.h
+++ b/tddb/td/db/SqliteKeyValue.h
@@ -10,7 +10,6 @@
#include "td/db/SqliteStatement.h"
#include "td/utils/logging.h"
-#include "td/utils/ScopeGuard.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h"
@@ -20,106 +19,43 @@ namespace td {
class SqliteKeyValue {
public:
- static Status drop(SqliteDb &connection, Slice kv_name) TD_WARN_UNUSED_RESULT {
- return connection.exec(PSLICE() << "DROP TABLE IF EXISTS " << kv_name);
+ static Status drop(SqliteDb &connection, Slice table_name) TD_WARN_UNUSED_RESULT {
+ return connection.exec(PSLICE() << "DROP TABLE IF EXISTS " << table_name);
}
- static Status init(SqliteDb &connection, Slice kv_name) TD_WARN_UNUSED_RESULT {
- return connection.exec(PSLICE() << "CREATE TABLE IF NOT EXISTS " << kv_name << " (k BLOB PRIMARY KEY, v BLOB)");
+ static Status init(SqliteDb &connection, Slice table_name) TD_WARN_UNUSED_RESULT {
+ return connection.exec(PSLICE() << "CREATE TABLE IF NOT EXISTS " << table_name << " (k BLOB PRIMARY KEY, v BLOB)");
}
using SeqNo = uint64;
- Result<bool> init(string name) TD_WARN_UNUSED_RESULT {
- name_ = std::move(name);
- bool is_created = false;
- SqliteDb db;
- TRY_STATUS(db.init(name, &is_created));
- TRY_STATUS(db.exec("PRAGMA encoding=\"UTF-8\""));
- TRY_STATUS(db.exec("PRAGMA synchronous=NORMAL"));
- TRY_STATUS(db.exec("PRAGMA journal_mode=WAL"));
- TRY_STATUS(db.exec("PRAGMA temp_store=MEMORY"));
- TRY_STATUS(init_with_connection(std::move(db), "KV"));
- return is_created;
- }
- Status init_with_connection(SqliteDb connection, string kv_name) TD_WARN_UNUSED_RESULT {
- db_ = std::move(connection);
- kv_name_ = std::move(kv_name);
- TRY_STATUS(init(db_, kv_name_));
-
- TRY_RESULT(set_stmt, db_.get_statement(PSLICE() << "REPLACE INTO " << kv_name_ << " (k, v) VALUES (?1, ?2)"));
- set_stmt_ = std::move(set_stmt);
- TRY_RESULT(get_stmt, db_.get_statement(PSLICE() << "SELECT v FROM " << kv_name_ << " WHERE k = ?1"));
- get_stmt_ = std::move(get_stmt);
- TRY_RESULT(erase_stmt, db_.get_statement(PSLICE() << "DELETE FROM " << kv_name_ << " WHERE k = ?1"));
- erase_stmt_ = std::move(erase_stmt);
- TRY_RESULT(get_all_stmt, db_.get_statement(PSLICE() << "SELECT k, v FROM " << kv_name_ << ""));
-
- TRY_RESULT(erase_by_prefix_stmt,
- db_.get_statement(PSLICE() << "DELETE FROM " << kv_name_ << " WHERE ?1 <= k AND k < ?2"));
- erase_by_prefix_stmt_ = std::move(erase_by_prefix_stmt);
-
- TRY_RESULT(erase_by_prefix_rare_stmt,
- db_.get_statement(PSLICE() << "DELETE FROM " << kv_name_ << " WHERE ?1 <= k"));
- erase_by_prefix_rare_stmt_ = std::move(erase_by_prefix_rare_stmt);
-
- TRY_RESULT(get_by_prefix_stmt,
- db_.get_statement(PSLICE() << "SELECT k, v FROM " << kv_name_ << " WHERE ?1 <= k AND k < ?2"));
- get_by_prefix_stmt_ = std::move(get_by_prefix_stmt);
-
- TRY_RESULT(get_by_prefix_rare_stmt,
- db_.get_statement(PSLICE() << "SELECT k, v FROM " << kv_name_ << " WHERE ?1 <= k"));
- get_by_prefix_rare_stmt_ = std::move(get_by_prefix_rare_stmt);
-
- get_all_stmt_ = std::move(get_all_stmt);
- return Status::OK();
+ bool empty() const {
+ return db_.empty();
}
+ Result<bool> init(string path) TD_WARN_UNUSED_RESULT;
+
+ Status init_with_connection(SqliteDb connection, string table_name) TD_WARN_UNUSED_RESULT;
+
Result<bool> try_regenerate_index() TD_WARN_UNUSED_RESULT {
return false;
}
+
void close() {
clear();
}
- static Status destroy(Slice name) TD_WARN_UNUSED_RESULT {
- return SqliteDb::destroy(name);
- }
- void close_and_destroy() {
- drop(db_, kv_name_).ensure();
- auto name = std::move(name_);
- clear();
- if (!name.empty()) {
- SqliteDb::destroy(name).ignore();
- }
- }
- SeqNo set(Slice key, Slice value) {
- set_stmt_.bind_blob(1, key).ensure();
- set_stmt_.bind_blob(2, value).ensure();
- set_stmt_.step().ensure();
- set_stmt_.reset();
- return 0;
+ static Status destroy(Slice path) TD_WARN_UNUSED_RESULT {
+ return SqliteDb::destroy(path);
}
- SeqNo erase(Slice key) {
- erase_stmt_.bind_blob(1, key).ensure();
- erase_stmt_.step().ensure();
- erase_stmt_.reset();
- return 0;
- }
- string get(Slice key) {
- SCOPE_EXIT {
- get_stmt_.reset();
- };
- get_stmt_.bind_blob(1, key).ensure();
- get_stmt_.step().ensure();
- if (!get_stmt_.has_row()) {
- return "";
- }
- auto data = get_stmt_.view_blob(0).str();
- get_stmt_.step().ignore();
- return data;
- }
+ void close_and_destroy();
+
+ SeqNo set(Slice key, Slice value);
+
+ string get(Slice key);
+
+ SeqNo erase(Slice key);
Status begin_transaction() TD_WARN_UNUSED_RESULT {
return db_.begin_transaction();
@@ -128,23 +64,7 @@ class SqliteKeyValue {
return db_.commit_transaction();
}
- void erase_by_prefix(Slice prefix) {
- auto next = next_prefix(prefix);
- if (next.empty()) {
- SCOPE_EXIT {
- erase_by_prefix_rare_stmt_.reset();
- };
- erase_by_prefix_rare_stmt_.bind_blob(1, prefix).ensure();
- erase_by_prefix_rare_stmt_.step().ensure();
- } else {
- SCOPE_EXIT {
- erase_by_prefix_stmt_.reset();
- };
- erase_by_prefix_stmt_.bind_blob(1, prefix).ensure();
- erase_by_prefix_stmt_.bind_blob(2, next).ensure();
- erase_by_prefix_stmt_.step().ensure();
- }
- };
+ void erase_by_prefix(Slice prefix);
std::unordered_map<string, string> get_all() {
std::unordered_map<string, string> res;
@@ -160,6 +80,7 @@ class SqliteKeyValue {
}
get_by_range(prefix, next, callback);
}
+
template <class CallbackT>
void get_by_range(Slice from, Slice till, CallbackT &&callback) {
SqliteStatement *stmt = nullptr;
@@ -183,16 +104,13 @@ class SqliteKeyValue {
}
}
- bool empty() const {
- return db_.empty();
- }
void clear() {
*this = SqliteKeyValue();
}
private:
- string name_; // deprecated
- string kv_name_;
+ string path_;
+ string table_name_;
SqliteDb db_;
SqliteStatement get_stmt_;
SqliteStatement set_stmt_;
@@ -203,20 +121,7 @@ class SqliteKeyValue {
SqliteStatement get_by_prefix_stmt_;
SqliteStatement get_by_prefix_rare_stmt_;
- string next_prefix(Slice prefix) {
- string next = prefix.str();
- size_t pos = next.size();
- while (pos) {
- pos--;
- auto value = static_cast<uint8>(next[pos]);
- value++;
- next[pos] = static_cast<char>(value);
- if (value != 0) {
- return next;
- }
- }
- return string{};
- }
+ string next_prefix(Slice prefix);
};
} // namespace td
diff --git a/tdutils/td/utils/ScopeGuard.h b/tdutils/td/utils/ScopeGuard.h
index a914ce357..b31198aa5 100644
--- a/tdutils/td/utils/ScopeGuard.h
+++ b/tdutils/td/utils/ScopeGuard.h
@@ -14,6 +14,7 @@
#include <utility>
namespace td {
+
class Guard {
public:
Guard() = default;