diff --git a/src/cli.cpp b/src/cli.cpp index 1c9196786..49fca28ed 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -95,25 +95,13 @@ void cli_tool_t::change_parent(inode_t cur, inode_t new_parent) fprintf(stderr, "Inode 0x%lx disappeared\n", cur); exit(1); } - inode_config_t *cur_cfg = &cur_cfg_it->second; - std::string cur_name = cur_cfg->name; + inode_config_t new_cfg = cur_cfg_it->second; + std::string cur_name = new_cfg.name; std::string cur_cfg_key = base64_encode(cli->st_cli.etcd_prefix+ "/config/inode/"+std::to_string(INODE_POOL(cur))+ "/"+std::to_string(INODE_NO_POOL(cur))); - json11::Json::object cur_cfg_json = json11::Json::object { - { "name", cur_cfg->name }, - { "size", cur_cfg->size }, - }; - if (new_parent) - { - if (INODE_POOL(cur) != INODE_POOL(new_parent)) - cur_cfg_json["parent_pool"] = (uint64_t)INODE_POOL(new_parent); - cur_cfg_json["parent_id"] = (uint64_t)INODE_NO_POOL(new_parent); - } - if (cur_cfg->readonly) - { - cur_cfg_json["readonly"] = true; - } + new_cfg.parent_id = new_parent; + json11::Json::object cur_cfg_json = cli->st_cli.serialize_inode_cfg(&new_cfg); waiting++; cli->st_cli.etcd_txn(json11::Json::object { { "compare", json11::Json::array { @@ -121,7 +109,7 @@ void cli_tool_t::change_parent(inode_t cur, inode_t new_parent) { "target", "MOD" }, { "key", cur_cfg_key }, { "result", "LESS" }, - { "mod_revision", cur_cfg->mod_revision+1 }, + { "mod_revision", new_cfg.mod_revision+1 }, }, } }, { "success", json11::Json::array { diff --git a/src/cli_snap_rm.cpp b/src/cli_snap_rm.cpp index 14c0e3f11..8de5c0122 100644 --- a/src/cli_snap_rm.cpp +++ b/src/cli_snap_rm.cpp @@ -138,7 +138,8 @@ resume_5: return; } cb = NULL; - // Delete "inverse" child metadata and rename parent over it + // Delete "inverse" child metadata, rename parent over it, + // and also change parent links of the previous "inverse" child rename_inverse_parent(); state = 6; resume_6: @@ -345,47 +346,76 @@ resume_9: "/config/inode/"+std::to_string(INODE_POOL(inverse_parent))+ "/"+std::to_string(INODE_NO_POOL(inverse_parent)) ); - json11::Json::object new_cfg = json11::Json::object { - { "name", child_cfg->name }, - { "size", child_cfg->size }, + // Fill new configuration + inode_config_t new_cfg = *child_cfg; + new_cfg.num = target_cfg->num; + new_cfg.parent_id = new_parent; + json11::Json::array cmp = json11::Json::array { + json11::Json::object { + { "target", "MOD" }, + { "key", child_cfg_key }, + { "result", "LESS" }, + { "mod_revision", child_cfg->mod_revision+1 }, + }, + json11::Json::object { + { "target", "MOD" }, + { "key", target_cfg_key }, + { "result", "LESS" }, + { "mod_revision", target_cfg->mod_revision+1 }, + }, }; - if (new_parent) + json11::Json::array txn = json11::Json::array { + json11::Json::object { + { "request_delete_range", json11::Json::object { + { "key", child_cfg_key }, + } }, + }, + json11::Json::object { + { "request_put", json11::Json::object { + { "key", target_cfg_key }, + { "value", base64_encode(json11::Json(parent->cli->st_cli.serialize_inode_cfg(&new_cfg)).dump()) }, + } }, + }, + json11::Json::object { + { "request_put", json11::Json::object { + { "key", base64_encode(parent->cli->st_cli.etcd_prefix+"/index/image/"+child_cfg->name) }, + { "value", base64_encode(json11::Json({ + { "id", INODE_NO_POOL(inverse_parent) }, + { "pool_id", (uint64_t)INODE_POOL(inverse_parent) }, + }).dump()) }, + } }, + }, + }; + // Reparent children of inverse_child + for (auto & cp: parent->cli->st_cli.inode_config) { - if (INODE_POOL(inverse_parent) != INODE_POOL(new_parent)) - new_cfg["parent_pool"] = (uint64_t)INODE_POOL(new_parent); - new_cfg["parent_id"] = (uint64_t)INODE_NO_POOL(new_parent); - } - if (child_cfg->readonly) - { - new_cfg["readonly"] = true; + if (cp.second.parent_id == child_cfg->num) + { + auto cp_cfg = cp.second; + cp_cfg.parent_id = inverse_parent; + auto cp_key = base64_encode( + parent->cli->st_cli.etcd_prefix+ + "/config/inode/"+std::to_string(INODE_POOL(cp.second.num))+ + "/"+std::to_string(INODE_NO_POOL(cp.second.num)) + ); + cmp.push_back(json11::Json::object { + { "target", "MOD" }, + { "key", cp_key }, + { "result", "LESS" }, + { "mod_revision", cp.second.mod_revision+1 }, + }); + txn.push_back(json11::Json::object { + { "request_put", json11::Json::object { + { "key", cp_key }, + { "value", base64_encode(json11::Json(parent->cli->st_cli.serialize_inode_cfg(&cp_cfg)).dump()) }, + } }, + }); + } } parent->waiting++; parent->cli->st_cli.etcd_txn(json11::Json::object { - { "compare", json11::Json::array { - json11::Json::object { - { "target", "MOD" }, - { "key", child_cfg_key }, - { "result", "LESS" }, - { "mod_revision", child_cfg->mod_revision+1 }, - }, - json11::Json::object { - { "target", "MOD" }, - { "key", target_cfg_key }, - { "result", "LESS" }, - { "mod_revision", target_cfg->mod_revision+1 }, - }, - } }, - { "success", json11::Json::array { - json11::Json::object { - { "request_delete_range", json11::Json::object { - { "key", child_cfg_key }, - } }, - { "request_put", json11::Json::object { - { "key", target_cfg_key }, - { "value", base64_encode(json11::Json(new_cfg).dump()) }, - } } - }, - } }, + { "compare", cmp }, + { "success", txn }, }, ETCD_SLOW_TIMEOUT, [this, target_name, child_name](std::string err, json11::Json res) { parent->waiting--; @@ -396,7 +426,10 @@ resume_9: } if (!res["succeeded"].bool_value()) { - fprintf(stderr, "Layer %s or %s configuration was modified during renaming\n", target_name.c_str(), child_name.c_str()); + fprintf( + stderr, "Parent (%s), child (%s), or one of its children" + " configuration was modified during rename\n", target_name.c_str(), child_name.c_str() + ); exit(1); } printf("Layer %s renamed to %s\n", target_name.c_str(), child_name.c_str()); @@ -414,9 +447,11 @@ resume_9: } inode_config_t *cur_cfg = &cur_cfg_it->second; std::string cur_name = cur_cfg->name; - std::string cur_cfg_key = base64_encode(parent->cli->st_cli.etcd_prefix+ + std::string cur_cfg_key = base64_encode( + parent->cli->st_cli.etcd_prefix+ "/config/inode/"+std::to_string(INODE_POOL(cur))+ - "/"+std::to_string(INODE_NO_POOL(cur))); + "/"+std::to_string(INODE_NO_POOL(cur)) + ); parent->waiting++; parent->cli->st_cli.etcd_txn(json11::Json::object { { "compare", json11::Json::array { @@ -432,6 +467,9 @@ resume_9: { "request_delete_range", json11::Json::object { { "key", cur_cfg_key }, } }, + { "request_delete_range", json11::Json::object { + { "key", base64_encode(parent->cli->st_cli.etcd_prefix+"/index/image/"+cur_name) }, + } }, }, } }, }, ETCD_SLOW_TIMEOUT, [this, cur_name](std::string err, json11::Json res) diff --git a/src/etcd_state_client.cpp b/src/etcd_state_client.cpp index 1dfa54400..12f6eddad 100644 --- a/src/etcd_state_client.cpp +++ b/src/etcd_state_client.cpp @@ -765,3 +765,22 @@ void etcd_state_client_t::close_watch(inode_watch_t* watch) } delete watch; } + +json11::Json::object & etcd_state_client_t::serialize_inode_cfg(inode_config_t *cfg) +{ + json11::Json::object new_cfg = json11::Json::object { + { "name", cfg->name }, + { "size", cfg->size }, + }; + if (cfg->parent_id) + { + if (INODE_POOL(cfg->num) != INODE_POOL(cfg->parent_id)) + new_cfg["parent_pool"] = (uint64_t)INODE_POOL(cfg->parent_id); + new_cfg["parent_id"] = (uint64_t)INODE_NO_POOL(cfg->parent_id); + } + if (cfg->readonly) + { + new_cfg["readonly"] = true; + } + return new_cfg; +} diff --git a/src/etcd_state_client.h b/src/etcd_state_client.h index c74250c32..daf3137fd 100644 --- a/src/etcd_state_client.h +++ b/src/etcd_state_client.h @@ -99,6 +99,7 @@ public: std::function on_change_pg_history_hook; std::function on_change_osd_state_hook; + json11::Json::object & serialize_inode_cfg(inode_config_t *cfg); etcd_kv_t parse_etcd_kv(const json11::Json & kv_json); void etcd_call(std::string api, json11::Json payload, int timeout, std::function callback); void etcd_txn(json11::Json txn, int timeout, std::function callback);