Implement alloc-osd (allocate a new OSD number) command
parent
66fe1a469b
commit
d3903f039c
|
@ -153,7 +153,7 @@ target_link_libraries(vitastor-nbd
|
||||||
|
|
||||||
# vitastor-cli
|
# vitastor-cli
|
||||||
add_executable(vitastor-cli
|
add_executable(vitastor-cli
|
||||||
cli.cpp cli_ls.cpp cli_create.cpp cli_modify.cpp cli_flatten.cpp cli_merge.cpp cli_rm.cpp cli_snap_rm.cpp
|
cli.cpp cli_alloc_osd.cpp cli_ls.cpp cli_create.cpp cli_modify.cpp cli_flatten.cpp cli_merge.cpp cli_rm.cpp cli_snap_rm.cpp
|
||||||
)
|
)
|
||||||
target_link_libraries(vitastor-cli
|
target_link_libraries(vitastor-cli
|
||||||
vitastor_client
|
vitastor_client
|
||||||
|
|
10
src/cli.cpp
10
src/cli.cpp
|
@ -130,6 +130,9 @@ void cli_tool_t::help()
|
||||||
" <to> must be a child of <from> and <target> may be one of the layers between\n"
|
" <to> must be a child of <from> and <target> may be one of the layers between\n"
|
||||||
" <from> and <to>, including <from> and <to>.\n"
|
" <from> and <to>, including <from> and <to>.\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
"%s alloc-osd\n"
|
||||||
|
" Allocate a new OSD number and reserve it by creating empty /osd/stats/<n> key.\n"
|
||||||
|
"\n"
|
||||||
"GLOBAL OPTIONS:\n"
|
"GLOBAL OPTIONS:\n"
|
||||||
" --etcd_address <etcd_address>\n"
|
" --etcd_address <etcd_address>\n"
|
||||||
" --iodepth N Send N operations in parallel to each OSD when possible (default 32)\n"
|
" --iodepth N Send N operations in parallel to each OSD when possible (default 32)\n"
|
||||||
|
@ -139,7 +142,7 @@ void cli_tool_t::help()
|
||||||
" --no-color Disable colored output\n"
|
" --no-color Disable colored output\n"
|
||||||
" --json JSON output\n"
|
" --json JSON output\n"
|
||||||
,
|
,
|
||||||
exe_name, exe_name, exe_name, exe_name, exe_name, exe_name, exe_name, exe_name, exe_name
|
exe_name, exe_name, exe_name, exe_name, exe_name, exe_name, exe_name, exe_name, exe_name, exe_name
|
||||||
);
|
);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
@ -268,6 +271,11 @@ void cli_tool_t::run(json11::Json cfg)
|
||||||
// Remove multiple snapshots and rebase their children
|
// Remove multiple snapshots and rebase their children
|
||||||
action_cb = start_snap_rm(cfg);
|
action_cb = start_snap_rm(cfg);
|
||||||
}
|
}
|
||||||
|
else if (cmd[0] == "alloc-osd")
|
||||||
|
{
|
||||||
|
// Allocate a new OSD number
|
||||||
|
action_cb = start_alloc_osd(cfg);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr, "unknown command: %s\n", cmd[0].string_value().c_str());
|
fprintf(stderr, "unknown command: %s\n", cmd[0].string_value().c_str());
|
||||||
|
|
|
@ -50,11 +50,12 @@ public:
|
||||||
friend struct snap_flattener_t;
|
friend struct snap_flattener_t;
|
||||||
friend struct snap_remover_t;
|
friend struct snap_remover_t;
|
||||||
|
|
||||||
std::function<bool(void)> start_ls(json11::Json cfg);
|
std::function<bool(void)> start_ls(json11::Json);
|
||||||
std::function<bool(void)> start_create(json11::Json cfg);
|
std::function<bool(void)> start_create(json11::Json);
|
||||||
std::function<bool(void)> start_modify(json11::Json cfg);
|
std::function<bool(void)> start_modify(json11::Json);
|
||||||
std::function<bool(void)> start_rm(json11::Json);
|
std::function<bool(void)> start_rm(json11::Json);
|
||||||
std::function<bool(void)> start_merge(json11::Json);
|
std::function<bool(void)> start_merge(json11::Json);
|
||||||
std::function<bool(void)> start_flatten(json11::Json);
|
std::function<bool(void)> start_flatten(json11::Json);
|
||||||
std::function<bool(void)> start_snap_rm(json11::Json);
|
std::function<bool(void)> start_snap_rm(json11::Json);
|
||||||
|
std::function<bool(void)> start_alloc_osd(json11::Json cfg, uint64_t *out = NULL);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
// Copyright (c) Vitaliy Filippov, 2019+
|
||||||
|
// License: VNPL-1.1 (see README.md for details)
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "cli.h"
|
||||||
|
#include "cluster_client.h"
|
||||||
|
#include "base64.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
// Safely allocate an OSD number
|
||||||
|
struct alloc_osd_t
|
||||||
|
{
|
||||||
|
cli_tool_t *parent;
|
||||||
|
|
||||||
|
json11::Json result;
|
||||||
|
uint64_t new_id = 1;
|
||||||
|
|
||||||
|
int state = 0;
|
||||||
|
|
||||||
|
bool is_done()
|
||||||
|
{
|
||||||
|
return state == 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
if (state == 1)
|
||||||
|
goto resume_1;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
etcd_txn(json11::Json::object {
|
||||||
|
{ "compare", json11::Json::array {
|
||||||
|
json11::Json::object {
|
||||||
|
{ "target", "VERSION" },
|
||||||
|
{ "version", 0 },
|
||||||
|
{ "key", base64_encode(
|
||||||
|
parent->cli->st_cli.etcd_prefix+"/osd/stats/"+std::to_string(new_id)
|
||||||
|
) },
|
||||||
|
},
|
||||||
|
} },
|
||||||
|
{ "success", json11::Json::array {
|
||||||
|
json11::Json::object {
|
||||||
|
{ "request_put", json11::Json::object {
|
||||||
|
{ "key", base64_encode(
|
||||||
|
parent->cli->st_cli.etcd_prefix+"/osd/stats/"+std::to_string(new_id)
|
||||||
|
) },
|
||||||
|
{ "value", base64_encode("{}") },
|
||||||
|
} },
|
||||||
|
},
|
||||||
|
} },
|
||||||
|
{ "failure", json11::Json::array {
|
||||||
|
json11::Json::object {
|
||||||
|
{ "request_range", json11::Json::object {
|
||||||
|
{ "key", base64_encode(parent->cli->st_cli.etcd_prefix+"/osd/stats/") },
|
||||||
|
{ "range_end", base64_encode(parent->cli->st_cli.etcd_prefix+"/osd/stats0") },
|
||||||
|
{ "keys_only", true },
|
||||||
|
} },
|
||||||
|
},
|
||||||
|
} },
|
||||||
|
});
|
||||||
|
resume_1:
|
||||||
|
state = 1;
|
||||||
|
if (parent->waiting > 0)
|
||||||
|
return;
|
||||||
|
if (!result["succeeded"].bool_value())
|
||||||
|
{
|
||||||
|
std::vector<osd_num_t> used;
|
||||||
|
for (auto kv: result["responses"][0]["response_range"]["kvs"].array_items())
|
||||||
|
{
|
||||||
|
std::string key = base64_decode(kv["key"].string_value());
|
||||||
|
osd_num_t cur_osd;
|
||||||
|
char null_byte = 0;
|
||||||
|
sscanf(key.c_str() + parent->cli->st_cli.etcd_prefix.length(), "/osd/stats/%lu%c", &cur_osd, &null_byte);
|
||||||
|
if (!cur_osd || null_byte != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Invalid key in etcd: %s\n", key.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
used.push_back(cur_osd);
|
||||||
|
}
|
||||||
|
std::sort(used.begin(), used.end());
|
||||||
|
if (used[used.size()-1] == used.size())
|
||||||
|
{
|
||||||
|
new_id = used.size()+1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int s = 0, e = used.size();
|
||||||
|
while (e > s+1)
|
||||||
|
{
|
||||||
|
int c = (s+e)/2;
|
||||||
|
if (used[c] == c+1)
|
||||||
|
s = c;
|
||||||
|
else
|
||||||
|
e = c;
|
||||||
|
}
|
||||||
|
new_id = used[e-1]+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
void etcd_txn(json11::Json txn)
|
||||||
|
{
|
||||||
|
parent->waiting++;
|
||||||
|
parent->cli->st_cli.etcd_txn(txn, ETCD_SLOW_TIMEOUT, [this](std::string err, json11::Json res)
|
||||||
|
{
|
||||||
|
parent->waiting--;
|
||||||
|
if (err != "")
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error reading from etcd: %s\n", err.c_str());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
this->result = res;
|
||||||
|
parent->ringloop->wakeup();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::function<bool(void)> cli_tool_t::start_alloc_osd(json11::Json cfg, uint64_t *out)
|
||||||
|
{
|
||||||
|
json11::Json::array cmd = cfg["command"].array_items();
|
||||||
|
auto alloc_osd = new alloc_osd_t();
|
||||||
|
alloc_osd->parent = this;
|
||||||
|
return [alloc_osd, &out]()
|
||||||
|
{
|
||||||
|
alloc_osd->loop();
|
||||||
|
if (alloc_osd->is_done())
|
||||||
|
{
|
||||||
|
if (out)
|
||||||
|
*out = alloc_osd->new_id;
|
||||||
|
else if (alloc_osd->new_id)
|
||||||
|
printf("%lu\n", alloc_osd->new_id);
|
||||||
|
delete alloc_osd;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue