-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Creating a table which looks like a secondary index breaks the secondary idnex creation mechanism #8620
Comments
edit: It's even worse when the fake table contains column names not found in the base table. It returns an ugly internal error with a backtrace. A new reproducer: CREATE KEYSPACE ks WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};
use ks;
CREATE TABLE t (id int primary key, v int);
CREATE TABLE t_v_idx_index (this_column_name_does_not_exist_in_t int primary key);
CREATE INDEX ON t(v);
DROP TABLE t_v_idx_index; And here's the ugly result: cassandra@cqlsh:ks> DROP TABLE t_v_idx_index;
ServerError: base_schema(): operation unsupported when initialized only for view reads. Missing column in the base table: this_column_name_does_not_exist_in_t Backtrace: 0x254d98e 0x254de30 0x254e1d8 0x1b33e72 0x1b33d16 0x2189e70 0x2189d14 0x2189b82 0x19ed931 0x12d30ce 0x18ff943 0x18f8b3c 0x18f7db3 0x24382d1
--------
seastar::continuation<seastar::internal::promise_base_with_type<void>, seastar::async<db::schema_tables::do_merge_schema(seastar::sharded<service::storage_proxy>&, std::vector<mutation, std::allocator<mutation> >, bool)::$_16>(seastar::thread_attributes, db::schema_tables::do_merge_schema(seastar::sharded<service::storage_proxy>&, std::vector<mutation, std::allocator<mutation> >, bool)::$_16&&)::{lambda()#2}, seastar::future<void>::then_impl_nrvo<{lambda()#2}, seastar::future>(db::schema_tables::do_merge_schema(seastar::sharded<service::storage_proxy>&, std::vector<mutation, std::allocator<mutation> >, bool)::$_16&&)::{lambda(seastar::internal::promise_base_with_type<void>&&, {lambda()#2}&, seastar::future_state<seastar::internal::monostate>&&)#1}, void>
--------
seastar::continuation<seastar::internal::promise_base_with_type<void>, seastar::future<void>::finally_body<seastar::async<db::schema_tables::do_merge_schema(seastar::sharded<service::storage_proxy>&, std::vector<mutation, std::allocator<mutation> >, bool)::$_16>(seastar::thread_attributes, db::schema_tables::do_merge_schema(seastar::sharded<service::storage_proxy>&, std::vector<mutation, std::allocator<mutation> >, bool)::$_16&&)::{lambda()#3}, false>, seastar::future<void>::then_wrapped_nrvo<seastar::future<void>, seastar::async<db::schema_tables::do_merge_schema(seastar::sharded<service::storage_proxy>&, std::vector<mutation, std::allocator<mutation> >, bool)::$_16>(seastar::thread_attributes, db::schema_tables::do_merge_schema(seastar::sharded<service::storage_proxy>&, std::vector<mutation, std::allocator<mutation> >, bool)::$_16&&)::{lambda()#3}>(seastar::async<db::schema_tables::do_merge_schema(seastar::sharded<service::storage_proxy>&, std::vector<mutation, std::allocator<mutation> >, bool)::$_16>(seastar::thread_attributes, db::schema_tables::do_merge_schema(seastar::sharded<service::storage_proxy>&, std::vector<mutation, std::allocator<mutation> >, bool)::$_16&&)::{lambda()#3}&&)::{lambda(seastar::internal::promise_base_with_type<void>&&, seastar::async<db::schema_tables::do_merge_schema(seastar::sharded<service::storage_proxy>&, std::vector<mutation, std::allocator<mutation> >, bool)::$_16>(seastar::thread_attributes, auto:1&&)::{lambda()#3}&, seastar::future_state<seastar::internal::monostate>&&)#1}, void>
--------
seastar::continuation<seastar::internal::promise_base_with_type<void>, db::schema_tables::merge_schema(seastar::sharded<service::storage_proxy>&, gms::feature_service&, std::vector<mutation, std::allocator<mutation> >)::$_11::operator()()::{lambda()#1}, seastar::future<void>::then_impl_nrvo<{lambda()#1}, seastar::future>({lambda()#1}&&)::{lambda(seastar::internal::promise_base_with_type<void>&&, {lambda()#1}&, seastar::future_state<seastar::internal::monostate>&&)#1}, void>
--------
seastar::continuation<seastar::internal::promise_base_with_type<void>, seastar::future<void>::finally_body<db::schema_tables::merge_schema(seastar::sharded<service::storage_proxy>&, gms::feature_service&, std::vector<mutation, std::allocator<mutation> >)::$_12, true>, seastar::future<void>::then_wrapped_nrvo<seastar::future<void>, seastar::future<void>::finally_body<db::schema_tables::merge_schema(seastar::sharded<service::storage_proxy>&, gms::feature_service&, std::vector<mutation, std::allocator<mutation> >)::$_12, true> >(seastar::future<void>::finally_body<db::schema_tables::merge_schema(seastar::sharded<service::storage_proxy>&, gms::feature_service&, std::vector<mutation, std::allocator<mutation> >)::$_12, true>&&)::{lambda(seastar::internal::promise_base_with_type<void>&&, seastar::future<void>::finally_body<db::schema_tables::merge_schema(seastar::sharded<service::storage_proxy>&, gms::feature_service&, std::vector<mutation, std::allocator<mutation> >)::$_12, true>&, seastar::future_state<seastar::internal::monostate>&&)#1}, void>
--------
seastar::continuation<seastar::internal::promise_base_with_type<seastar::shared_ptr<cql_transport::event::schema_change> >, cql3::statements::drop_table_statement::announce_migration(cql3::query_processor&) const::$_1, seastar::future<void>::then_wrapped_nrvo<seastar::shared_ptr<cql_transport::event::schema_change>, cql3::statements::drop_table_statement::announce_migration(cql3::query_processor&) const::$_1>(cql3::statements::drop_table_statement::announce_migration(cql3::query_processor&) const::$_1&&)::{lambda(seastar::internal::promise_base_with_type<seastar::shared_ptr<cql_transport::event::schema_change> >&&, cql3::statements::drop_table_statement::announce_migration(cql3::query_processor&) const::$_1&, seastar::future_state<seastar::internal::monostate>&&)#1}, void>
--------
seastar::continuation<seastar::internal::promise_base_with_type<seastar::shared_ptr<cql_transport::messages::result_message> >, cql3::statements::schema_altering_statement::execute0(cql3::query_processor&, service::query_state&, cql3::query_options const&) const::$_0, seastar::future<seastar::shared_ptr<cql_transport::event::schema_change> >::then_impl_nrvo<cql3::statements::schema_altering_statement::execute0(cql3::query_processor&, service::query_state&, cql3::query_options const&) const::$_0, seastar::future<seastar::shared_ptr<cql_transport::messages::result_message> > >(cql3::statements::schema_altering_statement::execute0(cql3::query_processor&, service::query_state&, cql3::query_options const&) const::$_0&&)::{lambda(seastar::internal::promise_base_with_type<seastar::shared_ptr<cql_transport::messages::result_message> >&&, cql3::statements::schema_altering_statement::execute0(cql3::query_processor&, service::query_state&, cql3::query_options const&) const::$_0&, seastar::future_state<seastar::shared_ptr<cql_transport::event::schema_change> >&&)#1}, seastar::shared_ptr<cql_transport::event::schema_change> >
--------
seastar::continuation<seastar::internal::promise_base_with_type<seastar::shared_ptr<cql_transport::messages::result_message> >, cql3::statements::schema_altering_statement::execute(cql3::query_processor&, service::query_state&, cql3::query_options const&) const::$_1, seastar::future<seastar::shared_ptr<cql_transport::messages::result_message> >::then_impl_nrvo<cql3::statements::schema_altering_statement::execute(cql3::query_processor&, service::query_state&, cql3::query_options const&) const::$_1, seastar::future<seastar::shared_ptr<cql_transport::messages::result_message> > >(cql3::statements::schema_altering_statement::execute(cql3::query_processor&, service::query_state&, cql3::query_options const&) const::$_1&&)::{lambda(seastar::internal::promise_base_with_type<seastar::shared_ptr<cql_transport::messages::result_message> >&&, cql3::statements::schema_altering_statement::execute(cql3::query_processor&, service::query_state&, cql3::query_options const&) const::$_1&, seastar::future_state<seastar::shared_ptr<cql_transport::messages::result_message> >&&)#1}, seastar::shared_ptr<cql_transport::messages::result_message> >
--------
seastar::continuation<seastar::internal::promise_base_with_type<seastar::shared_ptr<cql_transport::messages::result_message> >, cql3::query_processor::process_authorized_statement(seastar::shared_ptr<cql3::cql_statement>, service::query_state&, cql3::query_options const&)::$_4, seastar::future<seastar::shared_ptr<cql_transport::messages::result_message> >::then_impl_nrvo<cql3::query_processor::process_authorized_statement(seastar::shared_ptr<cql3::cql_statement>, service::query_state&, cql3::query_options const&)::$_4, seastar::future<seastar::shared_ptr<cql_transport::messages::result_message> > >(cql3::query_processor::process_authorized_statement(seastar::shared_ptr<cql3::cql_statement>, service::query_state&, cql3::query_options const&)::$_4&&)::{lambda(seastar::internal::promise_base_with_type<seastar::shared_ptr<cql_transport::messages::result_message> >&&, cql3::query_processor::process_authorized_statement(seastar::shared_ptr<cql3::cql_statement>, service::query_state&, cql3::query_options const&)::$_4&, seastar::future_state<seastar::shared_ptr<cql_transport::messages::result_message> >&&)#1}, seastar::shared_ptr<cql_transport::messages::result_message> >
--------
seastar::continuation<seastar::internal::promise_base_with_type<std::variant<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > >, unsigned int> >, cql_transport::process_query_internal(service::client_state&, seastar::sharded<cql3::query_processor>&, cql_transport::request_reader, unsigned short, unsigned char, cql_serialization_format, service_permit, tracing::trace_state_ptr, bool)::$_12, seastar::future<seastar::shared_ptr<cql_transport::messages::result_message> >::then_impl_nrvo<cql_transport::process_query_internal(service::client_state&, seastar::sharded<cql3::query_processor>&, cql_transport::request_reader, unsigned short, unsigned char, cql_serialization_format, service_permit, tracing::trace_state_ptr, bool)::$_12, seastar::future<std::variant<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > >, unsigned int> > >(cql_transport::process_query_internal(service::client_state&, seastar::sharded<cql3::query_processor>&, cql_transport::request_reader, unsigned short, unsigned char, cql_serialization_format, service_permit, tracing::trace_state_ptr, bool)::$_12&&)::{lambda(seastar::internal::promise_base_with_type<std::variant<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > >, unsigned int> >&&, cql_transport::process_query_internal(service::client_state&, seastar::sharded<cql3::query_processor>&, cql_transport::request_reader, unsigned short, unsigned char, cql_serialization_format, service_permit, tracing::trace_state_ptr, bool)::$_12&, seastar::future_state<seastar::shared_ptr<cql_transport::messages::result_message> >&&)#1}, seastar::shared_ptr<cql_transport::messages::result_message> >
--------
seastar::continuation<seastar::internal::promise_base_with_type<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > > >, cql_transport::cql_server::connection::process<seastar::future<std::variant<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > >, unsigned int> > (*)(service::client_state&, seastar::sharded<cql3::query_processor>&, cql_transport::request_reader, unsigned short, unsigned char, cql_serialization_format, service_permit, tracing::trace_state_ptr, bool)>(unsigned short, cql_transport::request_reader, service::client_state&, service_permit, tracing::trace_state_ptr, seastar::future<std::variant<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > >, unsigned int> > (*)(service::client_state&, seastar::sharded<cql3::query_processor>&, cql_transport::request_reader, unsigned short, unsigned char, cql_serialization_format, service_permit, tracing::trace_state_ptr, bool))::{lambda(std::variant<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > >, unsigned int>)#1}, seastar::future<std::variant<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > >, unsigned int> >::then_impl_nrvo<{lambda(std::variant<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > >, unsigned int>)#1}, seastar::future<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > > > >({lambda(std::variant<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > >, unsigned int>)#1}&&)::{lambda(seastar::internal::promise_base_with_type<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > > >&&, {lambda(std::variant<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > >, unsigned int>)#1}&, seastar::future_state<std::variant<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > >, unsigned int> >&&)#1}, std::variant<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > >, unsigned int> >
--------
seastar::continuation<seastar::internal::promise_base_with_type<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > > >, cql_transport::cql_server::connection::process_request_one(fragmented_temporary_buffer::istream, unsigned char, unsigned short, service::client_state&, cql_transport::cql_server::connection::tracing_request_type, service_permit)::$_3, seastar::future<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > > >::then_wrapped_nrvo<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > >, cql_transport::cql_server::connection::process_request_one(fragmented_temporary_buffer::istream, unsigned char, unsigned short, service::client_state&, cql_transport::cql_server::connection::tracing_request_type, service_permit)::$_3>(cql_transport::cql_server::connection::process_request_one(fragmented_temporary_buffer::istream, unsigned char, unsigned short, service::client_state&, cql_transport::cql_server::connection::tracing_request_type, service_permit)::$_3&&)::{lambda(seastar::internal::promise_base_with_type<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > > >&&, cql_transport::cql_server::connection::process_request_one(fragmented_temporary_buffer::istream, unsigned char, unsigned short, service::client_state&, cql_transport::cql_server::connection::tracing_request_type, service_permit)::$_3&, seastar::future_state<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > > >&&)#1}, seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<cql_transport::response> > > >
--------
seastar::continuation<seastar::internal::promise_base_with_type<void>, cql_transport::cql_server::connection::process_request()::$_4::operator()(seastar::future<std::optional<cql_transport::cql_binary_frame_v3> >&&) const::{lambda(seastar::semaphore_units<seastar::semaphore_default_exception_factory, std::chrono::_V2::steady_clock>)#1}::operator()(seastar::semaphore_units<seastar::semaphore_default_exception_factory, std::chrono::_V2::steady_clock>) const::{lambda(fragmented_temporary_buffer)#1}::operator()({lambda(seastar::semaphore_units<seastar::semaphore_default_exception_factory, std::chrono::_V2::steady_clock>)#1})::{lambda(seastar::future<seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<seastar::foreign_ptr> > > >)#1}, std::unique_ptr<cql_transport::response, std::default_delete<seastar::foreign_ptr> >::then_wrapped_nrvo<void, seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<seastar::foreign_ptr> > > >(seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<seastar::foreign_ptr> > >&&)::{lambda(seastar::internal::promise_base_with_type<void>&&, seastar::foreign_ptr<std::unique_ptr<cql_transport::response, std::default_delete<seastar::foreign_ptr> > >&, seastar::future_state<std::default_delete<seastar::foreign_ptr> >&&)#1}, std::default_delete<seastar::foreign_ptr> >
|
This commit adds a failing unit test for an issue with index creation after a table with malicious name is previously created as well. Refs scylladb#8620
I think we have two options now:
As I said I prefer option 2. Or is there any other option? |
Yes, option 2 is the way to go in my opinion. We already have this check in the code (because once the index tries to create its internal table, it fails), but the problem is that the operation is definitely not rolled back properly - the index creation process is left in a half-baked, undefined state. This issue can probably be fixed simply by adding an additional check if a table with conflicting name exists. Then we'll probably still be susceptible for rare races in case we check that there's no conflicting name, then yield, and then somebody else creates a table with the name we just checked, but that's just an example of a whole class of problems we currently have with concurrent schema changes. All of these will be void once we switch to Raft, so perhaps it's not worth going too far with the investigation. |
When an index is created without an explicit name, a default name is chosen. However, there was no check if a table with conflicting name already exists. The check is now in place and if any conflicts are found, a new index name is chosen instead. When an index is created *with* an explicit name and a conflicting regular table is found, index creation should simply fail. This series comes with a test. Fixes #8620 Tests: unit(release) Closes #8632 * github.com:scylladb/scylla: cql-pytest: add regression tests for index creation cql3: fail to create an index if there is a name conflict database: check for conflicting table names for indexes
It's important to backport this fix because we had a customer that without it experienced not only an annoying message but an assertion failure on reboot after we are left with an inconsistent case. |
When an index is created without an explicit name, a default name is chosen. However, there was no check if a table with conflicting name already exists. The check is now in place and if any conflicts are found, a new index name is chosen instead. When an index is created *with* an explicit name and a conflicting regular table is found, index creation should simply fail. This series comes with a test. Fixes #8620 Tests: unit(release) Closes #8632 * github.com:scylladb/scylla: cql-pytest: add regression tests for index creation cql3: fail to create an index if there is a name conflict database: check for conflicting table names for indexes (cherry picked from commit cee4c07)
Backported to next-4.5 (89fbcf9) |
When an index is created without an explicit name, a default name is chosen. However, there was no check if a table with conflicting name already exists. The check is now in place and if any conflicts are found, a new index name is chosen instead. When an index is created *with* an explicit name and a conflicting regular table is found, index creation should simply fail. This series comes with a test. Fixes #8620 Tests: unit(release) Closes #8632 * github.com:scylladb/scylla: cql-pytest: add regression tests for index creation cql3: fail to create an index if there is a name conflict database: check for conflicting table names for indexes (cherry picked from commit cee4c07)
Backported also to next-4.4 (cb3225f). Sadly, the backport to next-4.3 has a big problem - the patch applies, but the resulting code doesn't pass the test. It gives a strange "base_schema(): operation unsupported when initialized only for view reads" error. @eliransin any thoughts on this? It seems an area you fixed in the past, are there any patches in this area which we may not have backported to 4.3? |
When an index is created without an explicit name, a default name is chosen. However, there was no check if a table with conflicting name already exists. The check is now in place and if any conflicts are found, a new index name is chosen instead. When an index is created *with* an explicit name and a conflicting regular table is found, index creation should simply fail. This series comes with a test. Fixes #8620 Tests: unit(release) Closes #8632 * github.com:scylladb/scylla: cql-pytest: add regression tests for index creation cql3: fail to create an index if there is a name conflict database: check for conflicting table names for indexes (cherry picked from commit cee4c07)
I did the backport to next-4.3 again, and now it works. Maybe I did something wrong last time. The backport is: 2e7f618 |
When testing an unrelated change, I came across a way to ;eave the secondary index creation mechanism in Scylla in a broken state.
Reproducer:
The snippet exploits the fact that the internal table created for the secondary index is named after a pattern - in this case, an index on
t(v)
is going to be namedt_v_idx
, and its table is going to bet_v_idx_index
.Since we happened to create a regular table with an identical name, creating an index fails. The first minor bug is that the error message says
ServerError: Column family t3_v_idx_index exists
, which is not strictly true - such index does not exist, there just happens to be a table named identically. It gets worse:ServerError: Can't find a column family with UUID 1027b711-b18f-11eb-bcd4-ab78603bce8b
. The table was just created, so why can't we drop it?t_v_idx_index
table seems to not exist in the schema tables, so its removal was actually successful, even though it returned an error:This bug is not particularly dangerous, since it requires creating a maliciously named table, but it's nonetheless a bug. Also, a trivial workaround is to created a named index -
CREATE INDEX hello ON t(v)
works just fine.The text was updated successfully, but these errors were encountered: