@@ -8069,37 +8069,71 @@ int ha_rocksdb::open(const char *const name, int mode, uint test_if_locked,
80698069 uint n_keys = table->s->keys + (has_hidden_pk(*table) ? 1 : 0);
80708070
80718071 if (m_tbl_def->m_key_count != n_keys) {
8072+ const char *alter_op;
8073+ if (m_tbl_def->m_key_count > n_keys)
8074+ alter_op = "ALTER TABLE ... ADD INDEX";
8075+ else
8076+ alter_op = "ALTER TABLE ... DROP INDEX";
8077+
80728078 LogPluginErrMsg(ERROR_LEVEL, 0,
8073- "Table '%s' definition mismatch between MyRocks "
8074- "(m_key_count=%d) and data dictionary (n_keys=%d)",
8079+ "Table '%s' definition differs between MyRocks "
8080+ "(m_key_count=%d) and the data dictionary (n_keys=%d). "
8081+ "This was likely caused by a crash during '%s'.",
80758082 m_tbl_def->full_tablename().c_str(), m_tbl_def->m_key_count,
8076- n_keys);
8083+ n_keys, alter_op );
80778084
80788085 for (uint i = 0; i < table->s->keys; i++) {
80798086 const char *key_name;
80808087 assert((*table).key_info != nullptr);
80818088 assert((*table).key_info[i].name != nullptr);
80828089 key_name = (*table).key_info[i].name;
80838090
8084- LogPluginErrMsg(
8085- ERROR_LEVEL, 0,
8086- "ha_rocksdb::open TABLE table_name=%s i=%d/%d key_name=%s",
8087- table->s->table_name.str, i, table->s->keys, key_name);
8091+ LogPluginErrMsg(INFORMATION_LEVEL, 0,
8092+ "TABLE table_name=%s i=%d/%d key_name=%s",
8093+ table->s->table_name.str, i, table->s->keys, key_name);
80888094 }
80898095
80908096 uint pk = table->s->primary_key;
80918097 LogPluginErrMsg(
8092- ERROR_LEVEL , 0, "ha_rocksdb::open TABLE PK key_name=%s",
8098+ INFORMATION_LEVEL , 0, "TABLE PK key_name=%s",
80938099 pk == MAX_INDEXES ? HIDDEN_PK_NAME : (*table).key_info[pk].name);
80948100
80958101 for (uint i = 0; i < m_tbl_def->m_key_count; i++) {
80968102 const char *rdb_name = m_tbl_def->m_key_descr_arr[i]->m_name.c_str();
8097- LogPluginErrMsg(
8098- ERROR_LEVEL, 0,
8099- "ha_rocksdb::open KEY_descr_arr table_name=%s i=%d/%d key_name=%s",
8100- m_tbl_def->full_tablename().c_str(), i, m_tbl_def->m_key_count,
8101- rdb_name);
8103+ LogPluginErrMsg(INFORMATION_LEVEL, 0,
8104+ "KEY_descr_arr table_name=%s i=%d/%d key_name=%s",
8105+ m_tbl_def->full_tablename().c_str(), i,
8106+ m_tbl_def->m_key_count, rdb_name);
81028107 }
8108+
8109+ #if defined(ROCKSDB_INCLUDE_VALIDATE_TABLES) && ROCKSDB_INCLUDE_VALIDATE_TABLES
8110+ if (m_tbl_def->m_key_count > n_keys && rocksdb_validate_tables > 0) {
8111+ if (rocksdb_validate_tables == 1) {
8112+ LogPluginErrMsg(
8113+ ERROR_LEVEL, 0,
8114+ "Start the server with \"rocksdb_validate_tables=2\" to attempt to "
8115+ "fix the problem.");
8116+ } else {
8117+ const std::string tbl_name = m_tbl_def->full_tablename();
8118+ LogPluginErrMsg(INFORMATION_LEVEL, 0,
8119+ "Starting reconstruction of the corrupted table %s.",
8120+ m_tbl_def->full_tablename().c_str());
8121+
8122+ if (rebuild_table_def_from_table(table) != HA_EXIT_SUCCESS) {
8123+ LogPluginErrMsg(ERROR_LEVEL, 0,
8124+ "Failed to rebuild table definition for table '%s'",
8125+ tbl_name.c_str());
8126+ my_error(ER_KEY_CREATE_DURING_ALTER, MYF(0));
8127+ return HA_EXIT_FAILURE;
8128+ }
8129+
8130+ LogPluginErrMsg(
8131+ INFORMATION_LEVEL, 0,
8132+ "Reconstruction of the corrupted table %s has finished.",
8133+ m_tbl_def->full_tablename().c_str());
8134+ }
8135+ }
8136+ #endif
81038137 }
81048138
81058139 // close() above has already called free_key_buffers(). No need to do it here.
@@ -8685,8 +8719,6 @@ std::unordered_map<std::string, uint> ha_rocksdb::get_old_key_positions(
86858719 const TABLE &old_table_arg, const Rdb_tbl_def &old_tbl_def_arg) const {
86868720 DBUG_ENTER_FUNC();
86878721
8688- std::shared_ptr<Rdb_key_def> *const old_key_descr =
8689- old_tbl_def_arg.m_key_descr_arr;
86908722 std::unordered_map<std::string, uint> old_key_pos;
86918723 std::unordered_map<std::string, uint> new_key_pos;
86928724 uint i;
@@ -8697,7 +8729,7 @@ std::unordered_map<std::string, uint> ha_rocksdb::get_old_key_positions(
86978729
86988730 for (i = 0; i < old_tbl_def_arg.m_key_count; i++) {
86998731 if (is_hidden_pk(i, old_table_arg, old_tbl_def_arg)) {
8700- old_key_pos[old_key_descr[i]->m_name ] = i;
8732+ old_key_pos[HIDDEN_PK_NAME ] = i;
87018733 continue;
87028734 }
87038735
@@ -8710,6 +8742,9 @@ std::unordered_map<std::string, uint> ha_rocksdb::get_old_key_positions(
87108742 CREATE TABLE t1 (a INT, b INT, KEY ka(a)) ENGINE=RocksDB;
87118743 ALTER TABLE t1 DROP INDEX ka, ADD INDEX ka(b), ALGORITHM=INPLACE;
87128744 */
8745+ if (i >= old_table_arg.s->keys) {
8746+ continue;
8747+ }
87138748 const KEY *const old_key = &old_table_arg.key_info[i];
87148749 const auto &it = new_key_pos.find(old_key->name);
87158750 if (it == new_key_pos.end()) {
@@ -13019,6 +13054,40 @@ int ha_rocksdb::delete_table(Rdb_tbl_def *const tbl) {
1301913054 DBUG_RETURN(HA_EXIT_SUCCESS);
1302013055}
1302113056
13057+ // A simplified version of ha_rocksdb::delete_table
13058+ // that leaves the table's data intact
13059+ int ha_rocksdb::delete_table_def(Rdb_tbl_def *const tbl) {
13060+ DBUG_ENTER_FUNC();
13061+
13062+ assert(tbl != nullptr);
13063+ assert(m_tbl_def == nullptr || m_tbl_def == tbl);
13064+ uint table_default_cf_id = tbl->m_key_descr_arr[0]->get_gl_index_id().cf_id;
13065+ auto local_dict_manager =
13066+ dict_manager.get_dict_manager_selector_non_const(table_default_cf_id);
13067+ const std::unique_ptr<rocksdb::WriteBatch> wb = local_dict_manager->begin();
13068+ rocksdb::WriteBatch *const batch = wb.get();
13069+
13070+ {
13071+ /*
13072+ Remove the table entry in data dictionary (this will also remove it from
13073+ the persistent data dictionary).
13074+ */
13075+ ddl_manager.remove(tbl, batch, table_default_cf_id, true);
13076+
13077+ int err = local_dict_manager->commit(batch);
13078+ if (err) {
13079+ DBUG_RETURN(err);
13080+ }
13081+ }
13082+
13083+ // avoid dangling pointer
13084+ m_tbl_def = nullptr;
13085+ m_iterator = nullptr;
13086+ m_pk_iterator = nullptr;
13087+ inited = NONE;
13088+ DBUG_RETURN(HA_EXIT_SUCCESS);
13089+ }
13090+
1302213091/*
1302313092 Note: the following function is called when the table is not open. That is,
1302413093 this->table==nullptr, pk_key_descr==nullptr, etc.
@@ -14402,6 +14471,84 @@ bool ha_rocksdb::prepare_inplace_alter_table(
1440214471 DBUG_RETURN(HA_EXIT_SUCCESS);
1440314472}
1440414473
14474+ // Reconstructs a corrupted m_tbl_def (Rdb_tbl_def) by removing the
14475+ // partially added index left after an incomplete "ALTER ... ADD INDEX".
14476+ // Derived from ha_rocksdb::prepare_inplace_alter_table.
14477+ bool ha_rocksdb::rebuild_table_def_from_table(TABLE *altered_table) {
14478+ DBUG_ENTER_FUNC();
14479+ assert(altered_table != nullptr);
14480+
14481+ Rdb_tbl_def *new_tdef = nullptr;
14482+ std::shared_ptr<Rdb_key_def> *new_key_descr = nullptr;
14483+ uint new_n_keys =
14484+ altered_table->s->keys + (has_hidden_pk(*altered_table) ? 1 : 0);
14485+ const std::string tbl_name = m_tbl_def->full_tablename();
14486+
14487+ try {
14488+ new_key_descr = new std::shared_ptr<Rdb_key_def>[new_n_keys];
14489+ new_tdef = new Rdb_tbl_def(tbl_name);
14490+ } catch (const std::bad_alloc &) {
14491+ my_error(ER_OUTOFMEMORY, MYF(0));
14492+ DBUG_RETURN(HA_EXIT_FAILURE);
14493+ }
14494+
14495+ new_tdef->m_key_descr_arr = new_key_descr;
14496+ new_tdef->m_key_count = new_n_keys;
14497+ new_tdef->m_pk_index = altered_table->s->primary_key;
14498+ new_tdef->m_auto_incr_val =
14499+ m_tbl_def->m_auto_incr_val.load(std::memory_order_relaxed);
14500+ new_tdef->m_hidden_pk_val =
14501+ m_tbl_def->m_hidden_pk_val.load(std::memory_order_relaxed);
14502+
14503+ if (create_key_defs(*altered_table, *new_tdef,
14504+ "" /* actual_user_table_name */, false /* is_dd_tbl */,
14505+ table, m_tbl_def)) {
14506+ goto error;
14507+ }
14508+
14509+ // delete old table_def but keep data
14510+ if (delete_table_def(m_tbl_def) != HA_EXIT_SUCCESS) {
14511+ LogPluginErrMsg(ERROR_LEVEL, 0, "Failure when trying to drop table %s",
14512+ tbl_name.c_str());
14513+ goto error;
14514+ }
14515+
14516+ {
14517+ auto local_dict_manager =
14518+ dict_manager.get_dict_manager_selector_non_const(false);
14519+ const std::unique_ptr<rocksdb::WriteBatch> wb = local_dict_manager->begin();
14520+ rocksdb::WriteBatch *const batch = wb.get();
14521+
14522+ std::lock_guard<Rdb_dict_manager> dm_lock(*local_dict_manager);
14523+
14524+ int err = ddl_manager.put_and_write(new_tdef, batch);
14525+ if (err != HA_EXIT_SUCCESS) goto error;
14526+
14527+ err = local_dict_manager->commit(batch);
14528+ if (err != HA_EXIT_SUCCESS) goto error;
14529+ }
14530+
14531+ m_tbl_def = new_tdef;
14532+ m_key_descr_arr = m_tbl_def->m_key_descr_arr;
14533+ m_pk_descr = m_key_descr_arr[pk_index(*altered_table, *m_tbl_def)];
14534+
14535+ DBUG_RETURN(HA_EXIT_SUCCESS);
14536+
14537+ error:
14538+ if (new_tdef) {
14539+ if (new_tdef->m_key_descr_arr) {
14540+ delete[] new_tdef->m_key_descr_arr;
14541+ new_tdef->m_key_descr_arr = nullptr;
14542+ }
14543+ delete new_tdef;
14544+ } else if (new_key_descr) {
14545+ delete[] new_key_descr;
14546+ }
14547+
14548+ my_error(ER_KEY_CREATE_DURING_ALTER, MYF(0));
14549+ DBUG_RETURN(HA_EXIT_FAILURE);
14550+ }
14551+
1440514552/**
1440614553 Alter the table structure in-place with operations specified using
1440714554 HA_ALTER_FLAGS and Alter_inplace_info. The level of concurrency allowed
0 commit comments