Skip to content

Commit e9568c9

Browse files
committed
Add SqliteKeyValue.cpp.
GitOrigin-RevId: d0490b00c3342db191a29e7780d3292e3b593896
1 parent a2d725f commit e9568c9

File tree

4 files changed

+157
-120
lines changed

4 files changed

+157
-120
lines changed

tddb/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ set(TDDB_SOURCE
1010

1111
td/db/SqliteDb.cpp
1212
td/db/SqliteStatement.cpp
13+
td/db/SqliteKeyValue.cpp
1314
td/db/SqliteKeyValueAsync.cpp
1415

1516
td/db/detail/RawSqliteDb.cpp

tddb/td/db/SqliteKeyValue.cpp

+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
//
2+
// Copyright Aliaksei Levin ([email protected]), Arseny Smirnov ([email protected]) 2014-2018
3+
//
4+
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5+
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6+
//
7+
#include "td/db/SqliteKeyValue.h"
8+
9+
#include "td/utils/ScopeGuard.h"
10+
11+
namespace td {
12+
13+
Result<bool> SqliteKeyValue::init(string path) {
14+
path_ = std::move(path);
15+
bool is_created = false;
16+
SqliteDb db;
17+
TRY_STATUS(db.init(path, &is_created));
18+
TRY_STATUS(db.exec("PRAGMA encoding=\"UTF-8\""));
19+
TRY_STATUS(db.exec("PRAGMA synchronous=NORMAL"));
20+
TRY_STATUS(db.exec("PRAGMA journal_mode=WAL"));
21+
TRY_STATUS(db.exec("PRAGMA temp_store=MEMORY"));
22+
TRY_STATUS(init_with_connection(std::move(db), "KV"));
23+
return is_created;
24+
}
25+
26+
Status SqliteKeyValue::init_with_connection(SqliteDb connection, string table_name) {
27+
db_ = std::move(connection);
28+
table_name_ = std::move(table_name);
29+
TRY_STATUS(init(db_, table_name_));
30+
31+
TRY_RESULT(set_stmt, db_.get_statement(PSLICE() << "REPLACE INTO " << table_name_ << " (k, v) VALUES (?1, ?2)"));
32+
set_stmt_ = std::move(set_stmt);
33+
TRY_RESULT(get_stmt, db_.get_statement(PSLICE() << "SELECT v FROM " << table_name_ << " WHERE k = ?1"));
34+
get_stmt_ = std::move(get_stmt);
35+
TRY_RESULT(erase_stmt, db_.get_statement(PSLICE() << "DELETE FROM " << table_name_ << " WHERE k = ?1"));
36+
erase_stmt_ = std::move(erase_stmt);
37+
TRY_RESULT(get_all_stmt, db_.get_statement(PSLICE() << "SELECT k, v FROM " << table_name_ << ""));
38+
39+
TRY_RESULT(erase_by_prefix_stmt,
40+
db_.get_statement(PSLICE() << "DELETE FROM " << table_name_ << " WHERE ?1 <= k AND k < ?2"));
41+
erase_by_prefix_stmt_ = std::move(erase_by_prefix_stmt);
42+
43+
TRY_RESULT(erase_by_prefix_rare_stmt,
44+
db_.get_statement(PSLICE() << "DELETE FROM " << table_name_ << " WHERE ?1 <= k"));
45+
erase_by_prefix_rare_stmt_ = std::move(erase_by_prefix_rare_stmt);
46+
47+
TRY_RESULT(get_by_prefix_stmt,
48+
db_.get_statement(PSLICE() << "SELECT k, v FROM " << table_name_ << " WHERE ?1 <= k AND k < ?2"));
49+
get_by_prefix_stmt_ = std::move(get_by_prefix_stmt);
50+
51+
TRY_RESULT(get_by_prefix_rare_stmt,
52+
db_.get_statement(PSLICE() << "SELECT k, v FROM " << table_name_ << " WHERE ?1 <= k"));
53+
get_by_prefix_rare_stmt_ = std::move(get_by_prefix_rare_stmt);
54+
55+
get_all_stmt_ = std::move(get_all_stmt);
56+
return Status::OK();
57+
}
58+
59+
void SqliteKeyValue::close_and_destroy() {
60+
drop(db_, table_name_).ensure();
61+
auto path = std::move(path_);
62+
clear();
63+
if (!path.empty()) {
64+
destroy(path).ignore();
65+
}
66+
}
67+
68+
SqliteKeyValue::SeqNo SqliteKeyValue::set(Slice key, Slice value) {
69+
set_stmt_.bind_blob(1, key).ensure();
70+
set_stmt_.bind_blob(2, value).ensure();
71+
set_stmt_.step().ensure();
72+
set_stmt_.reset();
73+
return 0;
74+
}
75+
76+
string SqliteKeyValue::get(Slice key) {
77+
SCOPE_EXIT {
78+
get_stmt_.reset();
79+
};
80+
get_stmt_.bind_blob(1, key).ensure();
81+
get_stmt_.step().ensure();
82+
if (!get_stmt_.has_row()) {
83+
return "";
84+
}
85+
auto data = get_stmt_.view_blob(0).str();
86+
get_stmt_.step().ignore();
87+
return data;
88+
}
89+
90+
SqliteKeyValue::SeqNo SqliteKeyValue::erase(Slice key) {
91+
erase_stmt_.bind_blob(1, key).ensure();
92+
erase_stmt_.step().ensure();
93+
erase_stmt_.reset();
94+
return 0;
95+
}
96+
97+
void SqliteKeyValue::erase_by_prefix(Slice prefix) {
98+
auto next = next_prefix(prefix);
99+
if (next.empty()) {
100+
SCOPE_EXIT {
101+
erase_by_prefix_rare_stmt_.reset();
102+
};
103+
erase_by_prefix_rare_stmt_.bind_blob(1, prefix).ensure();
104+
erase_by_prefix_rare_stmt_.step().ensure();
105+
} else {
106+
SCOPE_EXIT {
107+
erase_by_prefix_stmt_.reset();
108+
};
109+
erase_by_prefix_stmt_.bind_blob(1, prefix).ensure();
110+
erase_by_prefix_stmt_.bind_blob(2, next).ensure();
111+
erase_by_prefix_stmt_.step().ensure();
112+
}
113+
}
114+
115+
string SqliteKeyValue::next_prefix(Slice prefix) {
116+
string next = prefix.str();
117+
size_t pos = next.size();
118+
while (pos) {
119+
pos--;
120+
auto value = static_cast<uint8>(next[pos]);
121+
value++;
122+
next[pos] = static_cast<char>(value);
123+
if (value != 0) {
124+
return next;
125+
}
126+
}
127+
return string{};
128+
}
129+
130+
} // namespace td

tddb/td/db/SqliteKeyValue.h

+25-120
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#include "td/db/SqliteStatement.h"
1111

1212
#include "td/utils/logging.h"
13-
#include "td/utils/ScopeGuard.h"
1413
#include "td/utils/Slice.h"
1514
#include "td/utils/Status.h"
1615

@@ -20,106 +19,43 @@ namespace td {
2019

2120
class SqliteKeyValue {
2221
public:
23-
static Status drop(SqliteDb &connection, Slice kv_name) TD_WARN_UNUSED_RESULT {
24-
return connection.exec(PSLICE() << "DROP TABLE IF EXISTS " << kv_name);
22+
static Status drop(SqliteDb &connection, Slice table_name) TD_WARN_UNUSED_RESULT {
23+
return connection.exec(PSLICE() << "DROP TABLE IF EXISTS " << table_name);
2524
}
2625

27-
static Status init(SqliteDb &connection, Slice kv_name) TD_WARN_UNUSED_RESULT {
28-
return connection.exec(PSLICE() << "CREATE TABLE IF NOT EXISTS " << kv_name << " (k BLOB PRIMARY KEY, v BLOB)");
26+
static Status init(SqliteDb &connection, Slice table_name) TD_WARN_UNUSED_RESULT {
27+
return connection.exec(PSLICE() << "CREATE TABLE IF NOT EXISTS " << table_name << " (k BLOB PRIMARY KEY, v BLOB)");
2928
}
3029

3130
using SeqNo = uint64;
32-
Result<bool> init(string name) TD_WARN_UNUSED_RESULT {
33-
name_ = std::move(name);
34-
bool is_created = false;
35-
SqliteDb db;
36-
TRY_STATUS(db.init(name, &is_created));
37-
TRY_STATUS(db.exec("PRAGMA encoding=\"UTF-8\""));
38-
TRY_STATUS(db.exec("PRAGMA synchronous=NORMAL"));
39-
TRY_STATUS(db.exec("PRAGMA journal_mode=WAL"));
40-
TRY_STATUS(db.exec("PRAGMA temp_store=MEMORY"));
41-
TRY_STATUS(init_with_connection(std::move(db), "KV"));
42-
return is_created;
43-
}
4431

45-
Status init_with_connection(SqliteDb connection, string kv_name) TD_WARN_UNUSED_RESULT {
46-
db_ = std::move(connection);
47-
kv_name_ = std::move(kv_name);
48-
TRY_STATUS(init(db_, kv_name_));
49-
50-
TRY_RESULT(set_stmt, db_.get_statement(PSLICE() << "REPLACE INTO " << kv_name_ << " (k, v) VALUES (?1, ?2)"));
51-
set_stmt_ = std::move(set_stmt);
52-
TRY_RESULT(get_stmt, db_.get_statement(PSLICE() << "SELECT v FROM " << kv_name_ << " WHERE k = ?1"));
53-
get_stmt_ = std::move(get_stmt);
54-
TRY_RESULT(erase_stmt, db_.get_statement(PSLICE() << "DELETE FROM " << kv_name_ << " WHERE k = ?1"));
55-
erase_stmt_ = std::move(erase_stmt);
56-
TRY_RESULT(get_all_stmt, db_.get_statement(PSLICE() << "SELECT k, v FROM " << kv_name_ << ""));
57-
58-
TRY_RESULT(erase_by_prefix_stmt,
59-
db_.get_statement(PSLICE() << "DELETE FROM " << kv_name_ << " WHERE ?1 <= k AND k < ?2"));
60-
erase_by_prefix_stmt_ = std::move(erase_by_prefix_stmt);
61-
62-
TRY_RESULT(erase_by_prefix_rare_stmt,
63-
db_.get_statement(PSLICE() << "DELETE FROM " << kv_name_ << " WHERE ?1 <= k"));
64-
erase_by_prefix_rare_stmt_ = std::move(erase_by_prefix_rare_stmt);
65-
66-
TRY_RESULT(get_by_prefix_stmt,
67-
db_.get_statement(PSLICE() << "SELECT k, v FROM " << kv_name_ << " WHERE ?1 <= k AND k < ?2"));
68-
get_by_prefix_stmt_ = std::move(get_by_prefix_stmt);
69-
70-
TRY_RESULT(get_by_prefix_rare_stmt,
71-
db_.get_statement(PSLICE() << "SELECT k, v FROM " << kv_name_ << " WHERE ?1 <= k"));
72-
get_by_prefix_rare_stmt_ = std::move(get_by_prefix_rare_stmt);
73-
74-
get_all_stmt_ = std::move(get_all_stmt);
75-
return Status::OK();
32+
bool empty() const {
33+
return db_.empty();
7634
}
7735

36+
Result<bool> init(string path) TD_WARN_UNUSED_RESULT;
37+
38+
Status init_with_connection(SqliteDb connection, string table_name) TD_WARN_UNUSED_RESULT;
39+
7840
Result<bool> try_regenerate_index() TD_WARN_UNUSED_RESULT {
7941
return false;
8042
}
43+
8144
void close() {
8245
clear();
8346
}
84-
static Status destroy(Slice name) TD_WARN_UNUSED_RESULT {
85-
return SqliteDb::destroy(name);
86-
}
87-
void close_and_destroy() {
88-
drop(db_, kv_name_).ensure();
89-
auto name = std::move(name_);
90-
clear();
91-
if (!name.empty()) {
92-
SqliteDb::destroy(name).ignore();
93-
}
94-
}
9547

96-
SeqNo set(Slice key, Slice value) {
97-
set_stmt_.bind_blob(1, key).ensure();
98-
set_stmt_.bind_blob(2, value).ensure();
99-
set_stmt_.step().ensure();
100-
set_stmt_.reset();
101-
return 0;
48+
static Status destroy(Slice path) TD_WARN_UNUSED_RESULT {
49+
return SqliteDb::destroy(path);
10250
}
10351

104-
SeqNo erase(Slice key) {
105-
erase_stmt_.bind_blob(1, key).ensure();
106-
erase_stmt_.step().ensure();
107-
erase_stmt_.reset();
108-
return 0;
109-
}
110-
string get(Slice key) {
111-
SCOPE_EXIT {
112-
get_stmt_.reset();
113-
};
114-
get_stmt_.bind_blob(1, key).ensure();
115-
get_stmt_.step().ensure();
116-
if (!get_stmt_.has_row()) {
117-
return "";
118-
}
119-
auto data = get_stmt_.view_blob(0).str();
120-
get_stmt_.step().ignore();
121-
return data;
122-
}
52+
void close_and_destroy();
53+
54+
SeqNo set(Slice key, Slice value);
55+
56+
string get(Slice key);
57+
58+
SeqNo erase(Slice key);
12359

12460
Status begin_transaction() TD_WARN_UNUSED_RESULT {
12561
return db_.begin_transaction();
@@ -128,23 +64,7 @@ class SqliteKeyValue {
12864
return db_.commit_transaction();
12965
}
13066

131-
void erase_by_prefix(Slice prefix) {
132-
auto next = next_prefix(prefix);
133-
if (next.empty()) {
134-
SCOPE_EXIT {
135-
erase_by_prefix_rare_stmt_.reset();
136-
};
137-
erase_by_prefix_rare_stmt_.bind_blob(1, prefix).ensure();
138-
erase_by_prefix_rare_stmt_.step().ensure();
139-
} else {
140-
SCOPE_EXIT {
141-
erase_by_prefix_stmt_.reset();
142-
};
143-
erase_by_prefix_stmt_.bind_blob(1, prefix).ensure();
144-
erase_by_prefix_stmt_.bind_blob(2, next).ensure();
145-
erase_by_prefix_stmt_.step().ensure();
146-
}
147-
};
67+
void erase_by_prefix(Slice prefix);
14868

14969
std::unordered_map<string, string> get_all() {
15070
std::unordered_map<string, string> res;
@@ -160,6 +80,7 @@ class SqliteKeyValue {
16080
}
16181
get_by_range(prefix, next, callback);
16282
}
83+
16384
template <class CallbackT>
16485
void get_by_range(Slice from, Slice till, CallbackT &&callback) {
16586
SqliteStatement *stmt = nullptr;
@@ -183,16 +104,13 @@ class SqliteKeyValue {
183104
}
184105
}
185106

186-
bool empty() const {
187-
return db_.empty();
188-
}
189107
void clear() {
190108
*this = SqliteKeyValue();
191109
}
192110

193111
private:
194-
string name_; // deprecated
195-
string kv_name_;
112+
string path_;
113+
string table_name_;
196114
SqliteDb db_;
197115
SqliteStatement get_stmt_;
198116
SqliteStatement set_stmt_;
@@ -203,20 +121,7 @@ class SqliteKeyValue {
203121
SqliteStatement get_by_prefix_stmt_;
204122
SqliteStatement get_by_prefix_rare_stmt_;
205123

206-
string next_prefix(Slice prefix) {
207-
string next = prefix.str();
208-
size_t pos = next.size();
209-
while (pos) {
210-
pos--;
211-
auto value = static_cast<uint8>(next[pos]);
212-
value++;
213-
next[pos] = static_cast<char>(value);
214-
if (value != 0) {
215-
return next;
216-
}
217-
}
218-
return string{};
219-
}
124+
string next_prefix(Slice prefix);
220125
};
221126

222127
} // namespace td

tdutils/td/utils/ScopeGuard.h

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <utility>
1515

1616
namespace td {
17+
1718
class Guard {
1819
public:
1920
Guard() = default;

0 commit comments

Comments
 (0)