From 5f2eadce0920ec8feb264b4d5d42fb7514d98cb0 Mon Sep 17 00:00:00 2001 From: Piotr Sarna Date: Mon, 11 May 2020 13:11:38 +0200 Subject: [PATCH] alternator: wait for schema agreement after table creation In order to be sure that all nodes acknowledged that a table was created, the CreateTable request will now only return after seeing that schema agreement was reached. Rationale: alternator users check if the table was created by issuing a DescribeTable request, and assume that the table was correctly created if it returns nonempty results. However, our current implementation of DescribeTable returns local results, which is not enough to judge if all the other nodes acknowledge the new table. CQL drivers are reported to always wait for schema agreement after issuing DDL-changing requests, so there should be no harm in waiting a little longer for alternator's CreateTable as well. Fixes #6361 Tests: alternator(local) --- alternator/executor.cc | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/alternator/executor.cc b/alternator/executor.cc index 80023d2b66..2c5f433c8d 100644 --- a/alternator/executor.cc +++ b/alternator/executor.cc @@ -710,6 +710,17 @@ future executor::list_tags_of_resource(client_sta return make_ready_future(make_jsonable(std::move(ret))); } +static future<> wait_for_schema_agreement(db::timeout_clock::time_point deadline) { + return do_until([deadline] { + if (db::timeout_clock::now() > deadline) { + throw std::runtime_error("Unable to reach schema agreement"); + } + return service::get_local_migration_manager().have_schema_agreement(); + }, [] { + return seastar::sleep(500ms); + }); +} + future executor::create_table(client_state& client_state, tracing::trace_state_ptr trace_state, service_permit permit, rjson::value request) { _stats.api_operations.create_table++; elogger.trace("Creating table {}", request); @@ -907,7 +918,9 @@ future executor::create_table(client_state& clien if (rjson::find(table_info, "Tags")) { f = add_tags(_proxy, schema, table_info); } - return f.then([table_info = std::move(table_info), schema] () mutable { + return f.then([] { + return wait_for_schema_agreement(db::timeout_clock::now() + 10s); + }).then([table_info = std::move(table_info), schema] () mutable { rjson::value status = rjson::empty_object(); supplement_table_info(table_info, *schema); rjson::set(status, "TableDescription", std::move(table_info));