* Author: Igor Fedotov, ifedotov@suse.com
*/
#include <iostream>
+#include <vector>
#include "common/ceph_argparse.h"
#include "common/debug.h"
#include "common/errno.h"
#include "common/ceph_json.h"
#include "common/admin_socket.h"
+#include "include/denc.h"
#include "global/global_init.h"
#include "os/bluestore/Allocator.h"
using namespace std;
void usage(const string &name) {
- cerr << "Usage: " << name << " <log_to_replay> <raw_duplicate|free_dump|try_alloc count want alloc_unit|replay_alloc alloc_list_file>" << std::endl;
+ cerr << "Usage: " << name << " <log_to_replay> <raw_duplicate|free_dump|try_alloc count want alloc_unit|replay_alloc alloc_list_file|export_binary out_file>" << std::endl;
}
void usage_replay_alloc(const string &name) {
cerr << "Allocation request format (space separated, optional parameters are 0 if not given): want unit [max] [hint]" << std::endl;
}
+struct binary_alloc_map_t {
+ std::vector<std::pair<uint64_t, uint64_t>> free_extents;
+
+ DENC(binary_alloc_map_t, v, p) {
+ DENC_START(1, 1, p);
+ denc(v.free_extents, p);
+ DENC_FINISH(p);
+ }
+};
+WRITE_CLASS_DENC(binary_alloc_map_t)
+
int replay_and_check_for_duplicate(char* fname)
{
unique_ptr<Allocator> alloc;
return 0;
}
-/*
-* This replays allocator dump (in JSON) reported by
- "ceph daemon <osd> bluestore allocator dump <name>"
- command and applies custom method to it
-*/
-int replay_free_dump_and_apply(char* fname,
- std::function<int (Allocator*, const string& aname)> fn)
+int replay_free_dump_and_apply_raw(
+ char* fname,
+ std::function<void (
+ std::string_view,
+ int64_t,
+ int64_t,
+ std::string_view)> create,
+ std::function<void (uint64_t, uint64_t)> add_ext)
{
string alloc_type;
string alloc_name;
ceph_assert(o);
decode_json_obj(alloc_unit, o);
- o = p.find_obj("extents");
- ceph_assert(o);
- ceph_assert(o->is_array());
+ int fd = -1;
+ o = p.find_obj("extents_file");
+ if (o) {
+ string filename = o->get_data_val().str;
+ fd = open(filename.c_str(), O_RDONLY);
+ if (fd < 0) {
+ std::cerr << "error: unable to open extents file: " << filename
+ << ", " << cpp_strerror(-errno)
+ << std::endl;
+ return -1;
+ }
+ } else {
+ o = p.find_obj("extents");
+ ceph_assert(o);
+ ceph_assert(o->is_array());
+ }
std::cout << "parsing completed!" << std::endl;
- unique_ptr<Allocator> alloc;
- alloc.reset(Allocator::create(g_ceph_context, alloc_type,
- capacity, alloc_unit, 0, 0, alloc_name));
-
- auto it = o->find_first();
- while (!it.end()) {
- auto *item_obj = *it;
- uint64_t offset = 0;
- uint64_t length = 0;
- string offset_str, length_str;
-
- bool b = JSONDecoder::decode_json("offset", offset_str, item_obj);
- ceph_assert(b);
- b = JSONDecoder::decode_json("length", length_str, item_obj);
- ceph_assert(b);
-
- char* p;
- offset = strtol(offset_str.c_str(), &p, 16);
- length = strtol(length_str.c_str(), &p, 16);
-
- // intentionally skip/trim entries that are above the capacity,
- // just to be able to "shrink" allocator by editing that field
- if (offset < capacity) {
- if (offset + length > capacity) {
- length = offset + length - capacity;
+ create(alloc_type, capacity, alloc_unit, alloc_name);
+ int r = 0;
+ if (fd < 0) {
+ auto it = o->find_first();
+ while (!it.end()) {
+ auto *item_obj = *it;
+ uint64_t offset = 0;
+ uint64_t length = 0;
+ string offset_str, length_str;
+
+ bool b = JSONDecoder::decode_json("offset", offset_str, item_obj);
+ ceph_assert(b);
+ b = JSONDecoder::decode_json("length", length_str, item_obj);
+ ceph_assert(b);
+
+ char* p;
+ offset = strtol(offset_str.c_str(), &p, 16);
+ length = strtol(length_str.c_str(), &p, 16);
+
+ // intentionally skip/trim entries that are above the capacity,
+ // just to be able to "shrink" allocator by editing that field
+ if (offset < capacity) {
+ if (offset + length > capacity) {
+ length = offset + length - capacity;
+ }
+ add_ext(offset, length);
}
- alloc->init_add_free(offset, length);
+ ++it;
}
-
- ++it;
+ } else {
+ bufferlist bl;
+ char buf[4096];
+ do {
+ r = read(fd, buf, sizeof(buf));
+ if (r > 0) {
+ bl.append(buf, r);
+ }
+ } while(r > 0);
+ if (r < 0) {
+ std::cerr << "error: error reading from extents file: "
+ << cpp_strerror(-errno)
+ << std::endl;
+ } else {
+ auto p = bl.cbegin();
+ binary_alloc_map_t amap;
+ try {
+ decode(amap, p);
+ for (auto p : amap.free_extents) {
+ add_ext(p.first, p.second);
+ }
+ } catch (ceph::buffer::error& e) {
+ std::cerr << __func__ << " unable to decode extents "
+ << ": " << e.what()
+ << std::endl;
+ r = -1;
+ }
+ }
+ close(fd);
}
+ return r;
+}
- int r = fn(alloc.get(), alloc_name);
+/*
+* This replays allocator dump (in JSON) reported by
+ "ceph daemon <osd> bluestore allocator dump <name>"
+ command and applies custom method to it
+*/
+int replay_free_dump_and_apply(char* fname,
+ std::function<int (Allocator*, const string& aname)> fn)
+{
+ unique_ptr<Allocator> alloc;
+ auto create_fn = [&](std::string_view alloc_type,
+ int64_t capacity,
+ int64_t alloc_unit,
+ std::string_view alloc_name) {
+ alloc.reset(
+ Allocator::create(
+ g_ceph_context, alloc_type, capacity, alloc_unit, 0, 0, alloc_name));
+ };
+ auto add_fn = [&](uint64_t offset,
+ uint64_t len) {
+ alloc->init_add_free(offset, len);
+ };
+ int r = replay_free_dump_and_apply_raw(
+ fname,
+ create_fn,
+ add_fn);
+ if (r == 0) {
+ r = fn(alloc.get(), alloc->get_name());
+ }
return r;
}
}
}
+int export_as_binary(char* fname, char* target_fname)
+{
+ int fd = creat(target_fname, 0);
+ if (fd < 0) {
+ std::cerr << "error: unable to open target file: " << target_fname
+ << ", " << cpp_strerror(-errno)
+ << std::endl;
+ return -1;
+ }
+
+ binary_alloc_map_t amap;
+ auto dummy_create_fn =
+ [&](std::string_view alloc_type,
+ int64_t capacity,
+ int64_t alloc_unit,
+ std::string_view alloc_name) {
+ };
+ auto add_fn = [&](uint64_t offset,
+ uint64_t len) {
+ amap.free_extents.emplace_back(offset, len);
+ };
+ int r = replay_free_dump_and_apply_raw(
+ fname,
+ dummy_create_fn,
+ add_fn);
+ if (r == 0) {
+ bufferlist out;
+ ceph::encode(amap, out);
+ auto w = write(fd, out.c_str(), out.length());
+ if (w < 1) {
+ std::cerr << "error: unable to open target file: " << target_fname
+ << ", " << cpp_strerror(-errno)
+ << std::endl;
+ }
+ }
+ close(fd);
+ return r;
+}
+
int main(int argc, char **argv)
{
vector<const char*> args;
}
return 0;
});
+ } else if (strcmp(argv[2], "export_binary") == 0) {
+ return export_as_binary(argv[1], argv[3]);
}
}