]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/kvstore_tool.cc
import 14.2.4 nautilus point release
[ceph.git] / ceph / src / tools / kvstore_tool.cc
CommitLineData
11fdf7f2
TL
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "kvstore_tool.h"
5
6#include <iostream>
7
8#include "common/errno.h"
9#include "common/url_escape.h"
10#include "include/buffer.h"
11#include "kv/KeyValueDB.h"
12
494da23a
TL
13StoreTool::StoreTool(const string& type,
14 const string& path,
15 bool need_open_db,
16 bool need_stats)
11fdf7f2
TL
17 : store_path(path)
18{
494da23a
TL
19
20 if (need_stats) {
21 g_conf()->rocksdb_perf = true;
22 g_conf()->rocksdb_collect_compaction_stats = true;
23 }
24
11fdf7f2
TL
25 if (type == "bluestore-kv") {
26#ifdef WITH_BLUESTORE
27 if (load_bluestore(path, need_open_db) != 0)
28 exit(1);
29#else
30 cerr << "bluestore not compiled in" << std::endl;
31 exit(1);
32#endif
33 } else {
34 auto db_ptr = KeyValueDB::create(g_ceph_context, type, path);
35 if (need_open_db) {
36 if (int r = db_ptr->open(std::cerr); r < 0) {
37 cerr << "failed to open type " << type << " path " << path << ": "
38 << cpp_strerror(r) << std::endl;
39 exit(1);
40 }
41 db.reset(db_ptr);
42 }
43 }
44}
45
46int StoreTool::load_bluestore(const string& path, bool need_open_db)
47{
48 auto bluestore = new BlueStore(g_ceph_context, path);
49 KeyValueDB *db_ptr;
50 int r = bluestore->start_kv_only(&db_ptr, need_open_db);
51 if (r < 0) {
52 return -EINVAL;
53 }
54 db = decltype(db){db_ptr, Deleter(bluestore)};
55 return 0;
56}
57
58uint32_t StoreTool::traverse(const string& prefix,
59 const bool do_crc,
60 const bool do_value_dump,
61 ostream *out)
62{
63 KeyValueDB::WholeSpaceIterator iter = db->get_wholespace_iterator();
64
65 if (prefix.empty())
66 iter->seek_to_first();
67 else
68 iter->seek_to_first(prefix);
69
70 uint32_t crc = -1;
71
72 while (iter->valid()) {
73 pair<string,string> rk = iter->raw_key();
74 if (!prefix.empty() && (rk.first != prefix))
75 break;
76
77 if (out)
78 *out << url_escape(rk.first) << "\t" << url_escape(rk.second);
79 if (do_crc) {
80 bufferlist bl;
81 bl.append(rk.first);
82 bl.append(rk.second);
83 bl.append(iter->value());
84
85 crc = bl.crc32c(crc);
86 if (out) {
87 *out << "\t" << bl.crc32c(0);
88 }
89 }
90 if (out)
91 *out << std::endl;
92 if (out && do_value_dump) {
93 bufferptr bp = iter->value_as_ptr();
94 bufferlist value;
95 value.append(bp);
96 ostringstream os;
97 value.hexdump(os);
98 std::cout << os.str() << std::endl;
99 }
100 iter->next();
101 }
102
103 return crc;
104}
105
106void StoreTool::list(const string& prefix, const bool do_crc,
107 const bool do_value_dump)
108{
109 traverse(prefix, do_crc, do_value_dump,& std::cout);
110}
111
112bool StoreTool::exists(const string& prefix)
113{
114 ceph_assert(!prefix.empty());
115 KeyValueDB::WholeSpaceIterator iter = db->get_wholespace_iterator();
116 iter->seek_to_first(prefix);
117 return (iter->valid() && (iter->raw_key().first == prefix));
118}
119
120bool StoreTool::exists(const string& prefix, const string& key)
121{
122 ceph_assert(!prefix.empty());
123
124 if (key.empty()) {
125 return exists(prefix);
126 }
127 bool exists = false;
128 get(prefix, key, exists);
129 return exists;
130}
131
132bufferlist StoreTool::get(const string& prefix,
133 const string& key,
134 bool& exists)
135{
136 ceph_assert(!prefix.empty() && !key.empty());
137
138 map<string,bufferlist> result;
139 std::set<std::string> keys;
140 keys.insert(key);
141 db->get(prefix, keys, &result);
142
143 if (result.count(key) > 0) {
144 exists = true;
145 return result[key];
146 } else {
147 exists = false;
148 return bufferlist();
149 }
150}
151
152uint64_t StoreTool::get_size()
153{
154 map<string,uint64_t> extras;
155 uint64_t s = db->get_estimated_size(extras);
156 for (auto& [name, size] : extras) {
157 std::cout << name << " - " << size << std::endl;
158 }
159 std::cout << "total: " << s << std::endl;
160 return s;
161}
162
163bool StoreTool::set(const string &prefix, const string &key, bufferlist &val)
164{
165 ceph_assert(!prefix.empty());
166 ceph_assert(!key.empty());
167 ceph_assert(val.length() > 0);
168
169 KeyValueDB::Transaction tx = db->get_transaction();
170 tx->set(prefix, key, val);
171 int ret = db->submit_transaction_sync(tx);
172
173 return (ret == 0);
174}
175
176bool StoreTool::rm(const string& prefix, const string& key)
177{
178 ceph_assert(!prefix.empty());
179 ceph_assert(!key.empty());
180
181 KeyValueDB::Transaction tx = db->get_transaction();
182 tx->rmkey(prefix, key);
183 int ret = db->submit_transaction_sync(tx);
184
185 return (ret == 0);
186}
187
188bool StoreTool::rm_prefix(const string& prefix)
189{
190 ceph_assert(!prefix.empty());
191
192 KeyValueDB::Transaction tx = db->get_transaction();
193 tx->rmkeys_by_prefix(prefix);
194 int ret = db->submit_transaction_sync(tx);
195
196 return (ret == 0);
197}
198
199void StoreTool::print_summary(const uint64_t total_keys, const uint64_t total_size,
200 const uint64_t total_txs, const string& store_path,
201 const string& other_path, const int duration) const
202{
203 std::cout << "summary:" << std::endl;
204 std::cout << " copied " << total_keys << " keys" << std::endl;
205 std::cout << " used " << total_txs << " transactions" << std::endl;
206 std::cout << " total size " << byte_u_t(total_size) << std::endl;
207 std::cout << " from '" << store_path << "' to '" << other_path << "'"
208 << std::endl;
209 std::cout << " duration " << duration << " seconds" << std::endl;
210}
211
494da23a
TL
212int StoreTool::print_stats() const
213{
214 ostringstream ostr;
215 Formatter* f = Formatter::create("json-pretty", "json-pretty", "json-pretty");
216 int ret = -1;
217 if (g_conf()->rocksdb_perf) {
218 db->get_statistics(f);
219 ostr << "db_statistics ";
220 f->flush(ostr);
221 ret = 0;
222 } else {
223 ostr << "db_statistics not enabled";
224 f->flush(ostr);
225 }
226 std::cout << ostr.str() << std::endl;
227 delete f;
228 return ret;
229}
230
11fdf7f2
TL
231int StoreTool::copy_store_to(const string& type, const string& other_path,
232 const int num_keys_per_tx,
233 const string& other_type)
234{
235 if (num_keys_per_tx <= 0) {
236 std::cerr << "must specify a number of keys/tx > 0" << std::endl;
237 return -EINVAL;
238 }
239
240 // open or create a leveldb store at @p other_path
241 boost::scoped_ptr<KeyValueDB> other;
242 KeyValueDB *other_ptr = KeyValueDB::create(g_ceph_context,
243 other_type,
244 other_path);
245 if (int err = other_ptr->create_and_open(std::cerr); err < 0) {
246 return err;
247 }
248 other.reset(other_ptr);
249
250 KeyValueDB::WholeSpaceIterator it = db->get_wholespace_iterator();
251 it->seek_to_first();
252 uint64_t total_keys = 0;
253 uint64_t total_size = 0;
254 uint64_t total_txs = 0;
255
256 auto duration = [start=coarse_mono_clock::now()] {
257 const auto now = coarse_mono_clock::now();
258 auto seconds = std::chrono::duration<double>(now - start);
259 return seconds.count();
260 };
261
262 do {
263 int num_keys = 0;
264
265 KeyValueDB::Transaction tx = other->get_transaction();
266
267 while (it->valid() && num_keys < num_keys_per_tx) {
268 auto [prefix, key] = it->raw_key();
269 bufferlist v = it->value();
270 tx->set(prefix, key, v);
271
272 num_keys++;
273 total_size += v.length();
274
275 it->next();
276 }
277
278 total_txs++;
279 total_keys += num_keys;
280
281 if (num_keys > 0)
282 other->submit_transaction_sync(tx);
283
284 std::cout << "ts = " << duration() << "s, copied " << total_keys
285 << " keys so far (" << byte_u_t(total_size) << ")"
286 << std::endl;
287
288 } while (it->valid());
289
290 print_summary(total_keys, total_size, total_txs, store_path, other_path,
291 duration());
292
293 return 0;
294}
295
296void StoreTool::compact()
297{
298 db->compact();
299}
300
301void StoreTool::compact_prefix(const string& prefix)
302{
303 db->compact_prefix(prefix);
304}
305
306void StoreTool::compact_range(const string& prefix,
307 const string& start,
308 const string& end)
309{
310 db->compact_range(prefix, start, end);
311}
312
313int StoreTool::destructive_repair()
314{
315 return db->repair(std::cout);
316}