From 0b0c2afbceb9957c6682f216118d0d52af78a96f Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Fri, 27 Dec 2024 01:16:26 +0300 Subject: [PATCH] Implement "deleted" flag --- docs/usage/cli.en.md | 1 + docs/usage/cli.ru.md | 1 + mon/etcd_schema.js | 1 + src/client/etcd_state_client.cpp | 5 ++ src/client/etcd_state_client.h | 1 + src/cmd/cli.cpp | 5 +- src/cmd/cli_ls.cpp | 3 +- src/cmd/cli_modify.cpp | 9 +++ src/cmd/cli_rm.cpp | 115 ++++++++++++++++--------------- 9 files changed, 81 insertions(+), 60 deletions(-) diff --git a/docs/usage/cli.en.md b/docs/usage/cli.en.md index d7f216f9..17da64fb 100644 --- a/docs/usage/cli.en.md +++ b/docs/usage/cli.en.md @@ -146,6 +146,7 @@ Rename, resize image or change its readonly status. Images with children can't b If the new size is smaller than the old size, extra data will be purged. You should resize file system in the image, if present, before shrinking it. +* `--deleted 1|0` - Set/clear 'deleted image' flag (set automatically during unfinished deletes). * `-f|--force` - Proceed with shrinking or setting readwrite flag even if the image has children. * `--down-ok` - Proceed with shrinking even if some data will be left on unavailable OSDs. diff --git a/docs/usage/cli.ru.md b/docs/usage/cli.ru.md index b1e70e2b..1dab8b89 100644 --- a/docs/usage/cli.ru.md +++ b/docs/usage/cli.ru.md @@ -149,6 +149,7 @@ vitastor-cli snap-create [-p|--pool ] @ Если новый размер меньше старого, "лишние" данные будут удалены, поэтому перед уменьшением образа сначала уменьшите файловую систему в нём. +* `--deleted 1|0` - Установить/снять флаг "образ удалён" (устанавливается при незавершённом удалении). * `-f|--force` - Разрешить уменьшение или перевод в чтение-запись образа, у которого есть клоны. * `--down-ok` - Разрешить уменьшение, даже если часть данных останется неудалённой на недоступных OSD. diff --git a/mon/etcd_schema.js b/mon/etcd_schema.js index 3d55a3f9..6213ad1e 100644 --- a/mon/etcd_schema.js +++ b/mon/etcd_schema.js @@ -216,6 +216,7 @@ const etcd_tree = { parent_pool?: , parent_id?: , readonly?: boolean, + deleted?: boolean, } } }, */ diff --git a/src/client/etcd_state_client.cpp b/src/client/etcd_state_client.cpp index 9f89f33c..92b2143f 100644 --- a/src/client/etcd_state_client.cpp +++ b/src/client/etcd_state_client.cpp @@ -1217,6 +1217,7 @@ void etcd_state_client_t::parse_state(const etcd_kv_t & kv) .size = value["size"].uint64_value(), .parent_id = parent_inode_num, .readonly = value["readonly"].bool_value(), + .deleted = value["deleted"].bool_value(), .meta = value["meta"], .mod_revision = kv.mod_revision, }); @@ -1305,6 +1306,10 @@ json11::Json::object etcd_state_client_t::serialize_inode_cfg(inode_config_t *cf { new_cfg["readonly"] = true; } + if (cfg->deleted) + { + new_cfg["deleted"] = true; + } if (cfg->meta.is_object()) { new_cfg["meta"] = cfg->meta; diff --git a/src/client/etcd_state_client.h b/src/client/etcd_state_client.h index 646a7cf1..46cadeed 100644 --- a/src/client/etcd_state_client.h +++ b/src/client/etcd_state_client.h @@ -72,6 +72,7 @@ struct inode_config_t uint64_t size = 0; inode_t parent_id = 0; bool readonly = false; + bool deleted = false; // Arbitrary metadata json11::Json meta; // Change revision of the metadata in etcd diff --git a/src/cmd/cli.cpp b/src/cmd/cli.cpp index 9b5a88f0..439726d6 100644 --- a/src/cmd/cli.cpp +++ b/src/cmd/cli.cpp @@ -51,8 +51,9 @@ static const char* help_text = " Rename, resize image or change its readonly status. Images with children can't be made read-write.\n" " If the new size is smaller than the old size, extra data will be purged.\n" " You should resize file system in the image, if present, before shrinking it.\n" - " -f|--force Proceed with shrinking or setting readwrite flag even if the image has children.\n" - " --down-ok Proceed with shrinking even if some data will be left on unavailable OSDs.\n" + " --deleted 1|0 Set/clear 'deleted image' flag (set automatically during unfinished deletes).\n" + " -f|--force Proceed with shrinking or setting readwrite flag even if the image has children.\n" + " --down-ok Proceed with shrinking even if some data will be left on unavailable OSDs.\n" "\n" "vitastor-cli dd [iimg= | if=] [oimg= | of=] [bs=1M]\n" " [count=N] [seek/oseek=N] [skip/iseek=M] [iodepth=N] [status=progress]\n" diff --git a/src/cmd/cli_ls.cpp b/src/cmd/cli_ls.cpp index e8d16b9d..bab15856 100644 --- a/src/cmd/cli_ls.cpp +++ b/src/cmd/cli_ls.cpp @@ -371,7 +371,8 @@ resume_1: kv.second["delete_q"] = format_q(kv.second["delete_queue"].number_value()); } kv.second["size_fmt"] = format_size(kv.second["size"].uint64_value()); - kv.second["ro"] = kv.second["readonly"].bool_value() ? "RO" : "-"; + kv.second["ro"] = kv.second["deleted"].bool_value() ? "DEL" : + (kv.second["readonly"].bool_value() ? "RO" : "-"); } result.text = print_table(to_list(), cols, parent->color); state = 100; diff --git a/src/cmd/cli_modify.cpp b/src/cmd/cli_modify.cpp index eed8aa4f..8a946834 100644 --- a/src/cmd/cli_modify.cpp +++ b/src/cmd/cli_modify.cpp @@ -4,6 +4,7 @@ #include "cli.h" #include "cluster_client.h" #include "str_util.h" +#include "json_util.h" // Rename, resize image (and purge extra data on shrink) or change its readonly status struct image_changer_t @@ -15,6 +16,7 @@ struct image_changer_t uint64_t new_size = 0; bool force_size = false, inc_size = false; bool set_readonly = false, set_readwrite = false, force = false; + bool set_deleted = false, new_deleted = false; bool down_ok = false; // interval between fsyncs int fsync_interval = 128; @@ -82,6 +84,7 @@ struct image_changer_t } if ((!set_readwrite || !cfg.readonly) && (!set_readonly || cfg.readonly) && + (!set_deleted || cfg.deleted == new_deleted) && (!new_size && !force_size || cfg.size == new_size || cfg.size >= new_size && inc_size) && (new_name == "" || new_name == image_name)) { @@ -141,6 +144,10 @@ resume_1: return; } } + if (set_deleted) + { + cfg.deleted = new_deleted; + } if (new_name != "") { cfg.name = new_name; @@ -251,6 +258,8 @@ std::function cli_tool_t::start_modify(json11::Json cfg) changer->force = cfg["force"].bool_value(); changer->set_readonly = cfg["readonly"].bool_value(); changer->set_readwrite = cfg["readwrite"].bool_value(); + changer->set_deleted = !cfg["deleted"].is_null(); + changer->new_deleted = json_is_true(cfg["deleted"]); changer->fsync_interval = cfg["fsync_interval"].uint64_value(); if (!changer->fsync_interval) changer->fsync_interval = 128; diff --git a/src/cmd/cli_rm.cpp b/src/cmd/cli_rm.cpp index 1da1f279..18b86b45 100644 --- a/src/cmd/cli_rm.cpp +++ b/src/cmd/cli_rm.cpp @@ -95,6 +95,10 @@ struct snap_remover_t goto resume_7; else if (state == 8) goto resume_8; + else if (state == 9) + goto resume_9; + else if (state == 10) + goto resume_10; else if (state == 100) goto resume_100; assert(!state); @@ -129,23 +133,9 @@ resume_1: continue; rebased_images.push_back(parent->cli->st_cli.inode_config.at(merge_children[current_child]).name); start_merge_child(merge_children[current_child], merge_children[current_child]); - if (state == 100) - return; resume_2: - while (!cb(result)) - { - state = 2; + while (!wait_result(2)) return; - } - cb = NULL; - if (result.err) - { - result.data = my_result(result.data); - state = 100; - return; - } - else if (parent->progress) - printf("%s\n", result.text.c_str()); parent->change_parent(merge_children[current_child], new_parent, &result); state = 3; resume_3: @@ -164,42 +154,19 @@ resume_3: if (inverse_child != 0) { start_merge_child(inverse_child, inverse_parent); - if (state == 100) - return; resume_4: - while (!cb(result)) - { - state = 4; + while (!wait_result(4)) return; - } - cb = NULL; - if (result.err) - { - result.data = my_result(result.data); - state = 100; + // Mark child as deleted + start_mark_deleted(inverse_child); +resume_9: + while (!wait_result(9)) return; - } - else if (parent->progress) - printf("%s\n", result.text.c_str()); // Delete "inverse" child data start_delete_source(inverse_child); - if (state == 100) - return; resume_5: - while (!cb(result)) - { - state = 5; + while (!wait_result(5)) return; - } - cb = NULL; - if (result.err) - { - result.data = my_result(result.data); - state = 100; - return; - } - else if (parent->progress) - printf("%s\n", result.text.c_str()); // Delete "inverse" child metadata, rename parent over it, // and also change parent links of the previous "inverse" child rename_inverse_parent(); @@ -221,22 +188,15 @@ resume_6: deleted_images.push_back(parent_it->second.name); deleted_ids.push_back(chain_list[current_child]); } + // Mark child as deleted + start_mark_deleted(chain_list[current_child]); +resume_10: + while (!wait_result(10)) + return; start_delete_source(chain_list[current_child]); resume_7: - while (!cb(result)) - { - state = 7; + while (!wait_result(7)) return; - } - cb = NULL; - if (result.err) - { - result.data = my_result(result.data); - state = 100; - return; - } - else if (parent->progress) - printf("%s\n", result.text.c_str()); delete_inode_config(chain_list[current_child]); if (state == 100) return; @@ -256,6 +216,26 @@ resume_100: return; } + bool wait_result(int base_state) + { + if (state == 100 || !cb) + return true; + while (!cb(result)) + { + state = base_state; + return false; + } + cb = NULL; + if (result.err) + { + result.data = my_result(result.data); + state = 100; + } + else if (parent->progress) + printf("%s\n", result.text.c_str()); + return true; + } + json11::Json my_result(json11::Json src) { auto obj = src.object_items(); @@ -667,6 +647,27 @@ resume_100: }); } + void start_mark_deleted(inode_t inode) + { + auto ino_it = parent->cli->st_cli.inode_config.find(inode); + if (ino_it == parent->cli->st_cli.inode_config.end()) + { + char buf[1024]; + snprintf(buf, 1024, "Inode 0x%jx disappeared", inode); + result = (cli_result_t){ .err = EIO, .text = std::string(buf) }; + state = 100; + return; + } + if (ino_it->second.deleted) + { + return; + } + cb = parent->start_modify(json11::Json::object { + { "image", ino_it->second.name }, + { "deleted", true }, + }); + } + void start_delete_source(inode_t inode) { auto source = parent->cli->st_cli.inode_config.find(inode);