Add loadable dump format to vitastor-kv (dump)

antietcd
Vitaliy Filippov 2024-03-02 15:27:29 +03:00
parent 9dc4d5fd7b
commit 231d4b15fc
3 changed files with 83 additions and 15 deletions

View File

@ -118,8 +118,9 @@ void kv_cli_t::run(const json11::Json::object & cfg)
finished = true; finished = true;
} }
}); });
interactive = true; interactive = isatty(0);
printf("> "); if (interactive)
printf("> ");
} }
catch (std::exception & e) catch (std::exception & e)
{ {
@ -236,7 +237,7 @@ void kv_cli_t::handle_cmd(const std::string & cmd, std::function<void()> cb)
if (res < 0) if (res < 0)
fprintf(stderr, "Error opening index: %s (code %d)\n", strerror(-res), res); fprintf(stderr, "Error opening index: %s (code %d)\n", strerror(-res), res);
else else
printf("Index opened. Current size: %lu bytes\n", db->get_size()); fprintf(interactive ? stdout : stderr, "Index opened. Current size: %lu bytes\n", db->get_size());
cb(); cb();
}); });
} }
@ -272,15 +273,15 @@ void kv_cli_t::handle_cmd(const std::string & cmd, std::function<void()> cb)
} }
else if (opname == "get" || opname == "set" || opname == "del") else if (opname == "get" || opname == "set" || opname == "del")
{ {
std::string key = scan_escaped(cmd, pos);
if (opname == "get" || opname == "del") if (opname == "get" || opname == "del")
{ {
if (pos == std::string::npos) if (key == "")
{ {
fprintf(stderr, "Usage: %s <key>\n", opname.c_str()); fprintf(stderr, "Usage: %s <key>\n", opname.c_str());
cb(); cb();
return; return;
} }
auto key = trim(cmd.substr(pos+1));
if (opname == "get") if (opname == "get")
{ {
db->get(key, [this, cb](int res, const std::string & value) db->get(key, [this, cb](int res, const std::string & value)
@ -302,34 +303,33 @@ void kv_cli_t::handle_cmd(const std::string & cmd, std::function<void()> cb)
if (res < 0) if (res < 0)
fprintf(stderr, "Error: %s (code %d)\n", strerror(-res), res); fprintf(stderr, "Error: %s (code %d)\n", strerror(-res), res);
else else
printf("OK\n"); fprintf(interactive ? stdout : stderr, "OK\n");
cb(); cb();
}); });
} }
} }
else else
{ {
auto pos2 = cmd.find_first_of(" \t", pos+1); if (key == "" || pos >= cmd.size())
if (pos2 == std::string::npos)
{ {
fprintf(stderr, "Usage: set <key> <value>\n"); fprintf(stderr, "Usage: set <key> <value>\n");
cb(); cb();
return; return;
} }
auto key = trim(cmd.substr(pos+1, pos2-pos-1)); auto value = trim(cmd.substr(pos));
auto value = trim(cmd.substr(pos2+1));
db->set(key, value, [this, cb](int res) db->set(key, value, [this, cb](int res)
{ {
if (res < 0) if (res < 0)
fprintf(stderr, "Error: %s (code %d)\n", strerror(-res), res); fprintf(stderr, "Error: %s (code %d)\n", strerror(-res), res);
else else
printf("OK\n"); fprintf(interactive ? stdout : stderr, "OK\n");
cb(); cb();
}); });
} }
} }
else if (opname == "list") else if (opname == "list" || opname == "dump")
{ {
bool dump = opname == "dump";
std::string start, end; std::string start, end;
if (pos != std::string::npos) if (pos != std::string::npos)
{ {
@ -358,7 +358,10 @@ void kv_cli_t::handle_cmd(const std::string & cmd, std::function<void()> cb)
} }
else else
{ {
printf("%s = %s\n", key.c_str(), value.c_str()); if (dump)
printf("set %s %s\n", auto_addslashes(key).c_str(), value.c_str());
else
printf("%s = %s\n", key.c_str(), value.c_str());
db->list_next(handle, NULL); db->list_next(handle, NULL);
} }
}); });
@ -367,7 +370,7 @@ void kv_cli_t::handle_cmd(const std::string & cmd, std::function<void()> cb)
{ {
db->close([=]() db->close([=]()
{ {
printf("Index closed\n"); fprintf(interactive ? stdout : stderr, "Index closed\n");
cb(); cb();
}); });
} }
@ -382,7 +385,8 @@ void kv_cli_t::handle_cmd(const std::string & cmd, std::function<void()> cb)
stderr, "Unknown operation: %s. Supported operations:\n" stderr, "Unknown operation: %s. Supported operations:\n"
"open <pool_id> <inode_id> [block_size]\n" "open <pool_id> <inode_id> [block_size]\n"
"config <property> <value>\n" "config <property> <value>\n"
"get <key>\nset <key> <value>\ndel <key>\nlist [<start> [end]]\n" "get <key>\nset <key> <value>\ndel <key>\n"
"list [<start> [end]]\ndump [<start> [end]]\n"
"close\nquit\n", opname.c_str() "close\nquit\n", opname.c_str()
); );
cb(); cb();

View File

@ -348,3 +348,65 @@ std::vector<std::string> explode(const std::string & sep, const std::string & va
} }
return res; return res;
} }
// extract possibly double-quoted part of string with escape characters
std::string scan_escaped(const std::string & cmd, size_t & pos)
{
std::string key;
auto pos2 = cmd.find_first_not_of(" \t\r\n", pos);
if (pos2 == std::string::npos)
{
pos = cmd.size();
return "";
}
pos = pos2;
if (cmd[pos] != '"')
{
pos2 = cmd.find_first_of(" \t\r\n", pos);
pos2 = pos2 == std::string::npos ? cmd.size() : pos2;
key = cmd.substr(pos, pos2-pos);
pos2 = cmd.find_first_not_of(" \t\r\n", pos2);
pos = pos2 == std::string::npos ? cmd.size() : pos2;
return key;
}
pos++;
while (pos < cmd.size())
{
auto pos2 = cmd.find_first_of("\\\"", pos);
pos2 = pos2 == std::string::npos ? cmd.size() : pos2;
if (pos2 > pos)
key += cmd.substr(pos, pos2-pos);
pos = pos2;
if (pos >= cmd.size())
break;
if (cmd[pos] == '"')
{
pos++;
break;
}
if (cmd[pos] == '\\')
{
if (pos < cmd.size()-1)
key += cmd[++pos];
pos++;
}
}
return key;
}
std::string auto_addslashes(const std::string & str)
{
auto pos = str.find_first_of("\\\"");
if (pos == std::string::npos)
return str;
std::string res = "\""+str.substr(0, pos)+"\\"+str[pos];
while (pos < str.size()-1)
{
auto pos2 = str.find_first_of("\\\"", pos+1);
if (pos2 == std::string::npos)
return res + str.substr(pos+1) + "\"";
res += str.substr(pos, pos2-pos)+"\\"+str[pos2];
pos = pos2;
}
return res+"\"";
}

View File

@ -22,3 +22,5 @@ std::string str_repeat(const std::string & str, int times);
size_t utf8_length(const std::string & s); size_t utf8_length(const std::string & s);
size_t utf8_length(const char *s); size_t utf8_length(const char *s);
std::vector<std::string> explode(const std::string & sep, const std::string & value, bool trim); std::vector<std::string> explode(const std::string & sep, const std::string & value, bool trim);
std::string scan_escaped(const std::string & cmd, size_t & pos);
std::string auto_addslashes(const std::string & str);