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