From baef7d0131209fcc81c4519bb627ab79adbaf053 Mon Sep 17 00:00:00 2001 From: Robert Pang Date: Tue, 17 Jul 2018 17:53:01 -0700 Subject: [PATCH] #377: Move unique index duplicate-value check to index tablet. Summary: Move duplicate-value check to unique index tablet to fix issue where no error is raised when inserting duplicate values in unique index of a primary key column. To do so, the index info is replicated in tablet metadata and primary key info is added to index metadata. Test Plan: TestIndex.testUniquePrimaryKeyIndex Reviewers: mihnea Reviewed By: mihnea Subscribers: bogdan, yql, bharat Differential Revision: https://phabricator.dev.yugabyte.com/D5144 --- .../src/test/java/org/yb/cql/TestIndex.java | 34 ++++- .../java/org/yb/cql/TestReturnsClause.java | 6 +- src/yb/common/common.proto | 4 + src/yb/common/index.cc | 40 +++++- src/yb/common/index.h | 14 ++ src/yb/docdb/doc_operation-test.cc | 3 +- src/yb/docdb/doc_operation.cc | 73 +++++----- src/yb/docdb/doc_operation.h | 5 + src/yb/master/async_rpc_tasks.cc | 3 + src/yb/master/catalog_manager.cc | 125 +++++++++++------- src/yb/master/catalog_manager.h | 23 +++- src/yb/master/master.proto | 5 +- src/yb/master/sys_catalog.cc | 1 + src/yb/tablet/metadata.proto | 3 + src/yb/tablet/tablet-harness.h | 1 + src/yb/tablet/tablet.cc | 32 +++-- src/yb/tablet/tablet.h | 3 + src/yb/tablet/tablet_bootstrap-test.cc | 1 + src/yb/tablet/tablet_metadata.cc | 19 ++- src/yb/tablet/tablet_metadata.h | 32 ++++- src/yb/tools/yb-bulk_load.cc | 2 +- src/yb/tserver/mini_tablet_server.cc | 2 +- src/yb/tserver/remote_bootstrap_client.cc | 4 + src/yb/tserver/tablet_server-test.cc | 2 +- src/yb/tserver/tablet_service.cc | 4 +- src/yb/tserver/ts_tablet_manager-test.cc | 3 +- src/yb/tserver/ts_tablet_manager.cc | 2 + src/yb/tserver/ts_tablet_manager.h | 1 + src/yb/tserver/tserver_admin.proto | 3 + 29 files changed, 326 insertions(+), 124 deletions(-) diff --git a/java/yb-cql/src/test/java/org/yb/cql/TestIndex.java b/java/yb-cql/src/test/java/org/yb/cql/TestIndex.java index 487a4b6e3177..ba11691add5e 100644 --- a/java/yb-cql/src/test/java/org/yb/cql/TestIndex.java +++ b/java/yb-cql/src/test/java/org/yb/cql/TestIndex.java @@ -642,8 +642,8 @@ private void assertInvalidUniqueIndexDML(String query, String indexName) { fail("InvalidQueryException not thrown for " + query); } catch (InvalidQueryException e) { assertTrue(e.getMessage().startsWith( - String.format("SQL error: Execution Error. Duplicate value disallowed by unique index " + - "%s.%s", DEFAULT_TEST_KEYSPACE, indexName))); + String.format("SQL error: Execution Error. Duplicate value disallowed by unique index %s", + indexName))); } } @@ -690,6 +690,36 @@ public void testUniqueIndex() throws Exception { session.execute("update test_unique set v1 = 7, v2 = 'e', v3 = 5 where k = 7;"); } + @Test + public void testUniquePrimaryKeyIndex() throws Exception { + // Test unique index on a primary key column. + session.execute("create table test_unique_pk (h1 int, h2 int, r int, v int, " + + "primary key ((h1, h2), r)) with transactions = {'enabled' : true};"); + session.execute("create unique index test_unique_pk_by_h2 on test_unique_pk (h2);"); + session.execute("create unique index test_unique_pk_by_r on test_unique_pk (r);"); + + session.execute("insert into test_unique_pk (h1, h2, r, v) values (1, 1, 1, 1);"); + + // Test inserting duplicate h2 and r values. + assertInvalidUniqueIndexDML( + "insert into test_unique_pk (h1, h2, r, v) values (1, 1, 2, 2);", "test_unique_pk_by_h2"); + assertInvalidUniqueIndexDML( + "insert into test_unique_pk (h1, h2, r, v) values (1, 2, 1, 2);", "test_unique_pk_by_r"); + + // Restart the cluster + miniCluster.restart(); + setUpCqlClient(); + + // Test inserting duplicate h2 and r values again. + assertInvalidUniqueIndexDML( + "insert into test_unique_pk (h1, h2, r, v) values (1, 1, 2, 2);", "test_unique_pk_by_h2"); + assertInvalidUniqueIndexDML( + "insert into test_unique_pk (h1, h2, r, v) values (1, 2, 1, 2);", "test_unique_pk_by_r"); + + // Test inserting non-duplicate h2 and r value. + session.execute("insert into test_unique_pk (h1, h2, r, v) values (1, 2, 2, 2);"); + } + @Test public void testConditionalDML() throws Exception { // Create test 2 test tables. One with normal secondary index and one with an additional unique diff --git a/java/yb-cql/src/test/java/org/yb/cql/TestReturnsClause.java b/java/yb-cql/src/test/java/org/yb/cql/TestReturnsClause.java index b24dac320503..74e33f79d0ff 100644 --- a/java/yb-cql/src/test/java/org/yb/cql/TestReturnsClause.java +++ b/java/yb-cql/src/test/java/org/yb/cql/TestReturnsClause.java @@ -181,8 +181,7 @@ public void testReturnsStatusWithIndex() throws Exception { checkReturnStatus("INSERT INTO test_rs_trans(h, r, v1, v2) VALUES (2, 2, 2, 'c')", columns, false /* applied */, - "Duplicate value disallowed by unique index " + - DEFAULT_TEST_KEYSPACE + ".test_rs_idx", + "Duplicate value disallowed by unique index test_rs_idx", "NULL", "NULL", "NULL", "NULL"); // Ensure main table write did not get applied due to the index failure. @@ -243,8 +242,7 @@ public void testReturnsStatusWithIndex() throws Exception { checkReturnStatus("INSERT INTO test_rs_trans_pk(h, r, v1, v2) VALUES (2, 1, 2, 'c')", columns, false /* applied */, - "Duplicate value disallowed by unique index " + - DEFAULT_TEST_KEYSPACE + ".test_rs_pk_idx", + "Duplicate value disallowed by unique index test_rs_pk_idx", "NULL", "NULL", "NULL", "NULL"); // Ensure main table write did not get applied due to the index failure. diff --git a/src/yb/common/common.proto b/src/yb/common/common.proto index 8deab5d67607..4fe21e0c8139 100644 --- a/src/yb/common/common.proto +++ b/src/yb/common/common.proto @@ -216,6 +216,7 @@ message SchemaPB { // columns to the index table columns. message IndexInfoPB { optional bytes table_id = 1; // Index table id. + optional bytes indexed_table_id = 8; // Indexed table id. optional uint32 version = 2; // Index table's schema version. optional bool is_local = 3 [ default = false ]; // Whether the index is a local index optional bool is_unique = 7 [ default = false ]; // Whether the index is a unique index @@ -228,6 +229,9 @@ message IndexInfoPB { repeated IndexColumnPB columns = 4; // Indexed and covering columns. optional uint32 hash_column_count = 5; // Number of hash columns in the index. optional uint32 range_column_count = 6; // Number of range columns in the index. + + repeated uint32 indexed_hash_column_ids = 9; // Hash column ids in the indexed table. + repeated uint32 indexed_range_column_ids = 10; // Range column ids in the indexed table. } message HostPortPB { diff --git a/src/yb/common/index.cc b/src/yb/common/index.cc index 6bd5f143ccf9..c7469680558e 100644 --- a/src/yb/common/index.cc +++ b/src/yb/common/index.cc @@ -18,7 +18,10 @@ #include "yb/common/common.pb.h" using std::vector; +using std::unordered_map; +using google::protobuf::RepeatedField; using google::protobuf::RepeatedPtrField; +using google::protobuf::uint32; namespace yb { @@ -44,16 +47,28 @@ vector IndexColumnFromPB( return cols; } +vector ColumnIdsFromPB(const RepeatedField& ids) { + vector column_ids; + column_ids.reserve(ids.size()); + for (const auto& id : ids) { + column_ids.emplace_back(id); + } + return column_ids; +} + } // namespace IndexInfo::IndexInfo(const IndexInfoPB& pb) : table_id_(pb.table_id()), + indexed_table_id_(pb.indexed_table_id()), schema_version_(pb.version()), is_local_(pb.is_local()), is_unique_(pb.is_unique()), columns_(IndexColumnFromPB(pb.columns())), hash_column_count_(pb.hash_column_count()), - range_column_count_(pb.range_column_count()) { + range_column_count_(pb.range_column_count()), + indexed_hash_column_ids_(ColumnIdsFromPB(pb.indexed_hash_column_ids())), + indexed_range_column_ids_(ColumnIdsFromPB(pb.indexed_range_column_ids())) { for (const IndexInfo::IndexColumn &index_col : columns_) { covered_column_ids_.insert(index_col.indexed_column_id); } @@ -61,6 +76,7 @@ IndexInfo::IndexInfo(const IndexInfoPB& pb) void IndexInfo::ToPB(IndexInfoPB* pb) const { pb->set_table_id(table_id_); + pb->set_indexed_table_id(indexed_table_id_); pb->set_version(schema_version_); pb->set_is_local(is_local_); pb->set_is_unique(is_unique_); @@ -69,6 +85,28 @@ void IndexInfo::ToPB(IndexInfoPB* pb) const { } pb->set_hash_column_count(hash_column_count_); pb->set_range_column_count(range_column_count_); + for (const auto id : indexed_hash_column_ids_) { + pb->add_indexed_hash_column_ids(id); + } + for (const auto id : indexed_range_column_ids_) { + pb->add_indexed_range_column_ids(id); + } +} + +vector IndexInfo::index_key_column_ids() const { + unordered_map map; + for (const auto column : columns_) { + map[column.indexed_column_id] = column.column_id; + } + vector ids; + ids.reserve(indexed_hash_column_ids_.size() + indexed_range_column_ids_.size()); + for (const auto id : indexed_hash_column_ids_) { + ids.push_back(map[id]); + } + for (const auto id : indexed_range_column_ids_) { + ids.push_back(map[id]); + } + return ids; } bool IndexInfo::PrimaryKeyColumnsOnly(const Schema& indexed_schema) const { diff --git a/src/yb/common/index.h b/src/yb/common/index.h index 50d917b44ea7..d68a17ac27fd 100644 --- a/src/yb/common/index.h +++ b/src/yb/common/index.h @@ -46,6 +46,7 @@ class IndexInfo { void ToPB(IndexInfoPB* pb) const; const TableId& table_id() const { return table_id_; } + const TableId& indexed_table_id() const { return indexed_table_id_; } uint32_t schema_version() const { return schema_version_; } bool is_local() const { return is_local_; } bool is_unique() const { return is_unique_; } @@ -56,6 +57,16 @@ class IndexInfo { size_t range_column_count() const { return range_column_count_; } size_t key_column_count() const { return hash_column_count_ + range_column_count_; } + const std::vector& indexed_hash_column_ids() const { + return indexed_hash_column_ids_; + } + const std::vector& indexed_range_column_ids() const { + return indexed_range_column_ids_; + } + + // Return column ids that are primary key columns of the indexed table. + std::vector index_key_column_ids() const; + // Index primary key columns of the indexed table only? bool PrimaryKeyColumnsOnly(const Schema& indexed_schema) const; @@ -64,12 +75,15 @@ class IndexInfo { private: const TableId table_id_; // Index table id. + const TableId indexed_table_id_; // Indexed table id. const uint32_t schema_version_ = 0; // Index table's schema version. const bool is_local_ = false; // Whether this is a local index. const bool is_unique_ = false; // Whether this is a unique index. const std::vector columns_; // Index columns. const size_t hash_column_count_ = 0; // Number of hash columns in the index. const size_t range_column_count_ = 0; // Number of range columns in the index. + const std::vector indexed_hash_column_ids_; // Hash column ids in the indexed table. + const std::vector indexed_range_column_ids_; // Range column ids in the indexed table. // Column ids covered by the index (include indexed columns). std::unordered_set covered_column_ids_; diff --git a/src/yb/docdb/doc_operation-test.cc b/src/yb/docdb/doc_operation-test.cc index 05ced706bae8..87b49251eee3 100644 --- a/src/yb/docdb/doc_operation-test.cc +++ b/src/yb/docdb/doc_operation-test.cc @@ -96,7 +96,8 @@ class DocOperationTest : public DocDBTestBase { void WriteQL(QLWriteRequestPB* ql_writereq_pb, const Schema& schema, QLResponsePB* ql_writeresp_pb, const HybridTime& hybrid_time = HybridTime::kMax) { - QLWriteOperation ql_write_op(schema, IndexMap(), kNonTransactionalOperationContext); + QLWriteOperation ql_write_op(schema, IndexMap(), nullptr /* unique_index_key_schema */, + kNonTransactionalOperationContext); ASSERT_OK(ql_write_op.Init(ql_writereq_pb, ql_writeresp_pb)); auto doc_write_batch = MakeDocWriteBatch(); ASSERT_OK(ql_write_op.Apply( diff --git a/src/yb/docdb/doc_operation.cc b/src/yb/docdb/doc_operation.cc index c4a4c944717f..23f3e12485ae 100644 --- a/src/yb/docdb/doc_operation.cc +++ b/src/yb/docdb/doc_operation.cc @@ -1962,6 +1962,41 @@ Status QLWriteOperation::PopulateStatusRow(const DocOperationApplyData& data, return Status::OK(); } +// Check if a duplicate value is inserted into a unique index. +Result QLWriteOperation::DuplicateUniqueIndexValue(const DocOperationApplyData& data) { + // If it is not an insert or it is not a unique index, this is not a duplicate insert. + if (request_.type() != QLWriteRequestPB::QL_STMT_INSERT || unique_index_key_schema_ == nullptr) { + return false; + } + + // Set up the iterator to read the current primary key associated with the index key. + DocQLScanSpec spec(*unique_index_key_schema_, *pk_doc_key_, request_.query_id()); + DocRowwiseIterator iterator(*unique_index_key_schema_, schema_, txn_op_context_, + data.doc_write_batch->doc_db(), data.deadline, data.read_time); + RETURN_NOT_OK(iterator.Init(spec)); + + // It is a duplicate value if the index key exist already and the associated indexed primary key + // is not the same. + if (!iterator.HasNext()) { + return false; + } + QLTableRow table_row; + RETURN_NOT_OK(iterator.NextRow(&table_row)); + std::unordered_set key_column_ids(unique_index_key_schema_->column_ids().begin(), + unique_index_key_schema_->column_ids().end()); + for (const auto& column_value : request_.column_values()) { + ColumnId column_id(column_value.column_id()); + if (key_column_ids.count(column_id) > 0) { + auto value = table_row.GetValue(column_id); + if (value && *value != column_value.expr().value()) { + return true; + } + } + } + + return false; +} + Status QLWriteOperation::ApplyForJsonOperators(const QLColumnValuePB& column_value, const DocOperationApplyData& data, const DocPath& sub_path, const MonoDelta& ttl, @@ -2161,6 +2196,12 @@ Status QLWriteOperation::Apply(const DocOperationApplyData& data) { } } + if (VERIFY_RESULT(DuplicateUniqueIndexValue(data))) { + response_->set_applied(false); + response_->set_status(QLResponsePB::YQL_STATUS_OK); + return Status::OK(); + } + const MonoDelta ttl = request_.has_ttl() ? MonoDelta::FromMilliseconds(request_.ttl()) : Value::kMaxTtl; const UserTimeMicros user_timestamp = request_.has_user_timestamp_usec() ? @@ -2405,29 +2446,6 @@ QLExpressionPB* NewKeyColumn(QLWriteRequestPB* request, const IndexInfo& index, : request->add_range_column_values()); } -// Set primary-key condition, i.e. "h1 = xx AND h2 = xx AND r1 = xx AND r2 = xx ...", and add the -// referenced columns. -void SetPrimaryKeyCondition(const IndexInfo* index, - const Schema& indexed_schema, - const QLTableRow& new_row, - QLWriteRequestPB* index_request, - QLConditionPB* condition) { - condition->set_op(QL_OP_AND); - for (size_t i = 0; i < index->columns().size(); i++) { - const IndexInfo::IndexColumn& index_column = index->column(i); - if (indexed_schema.is_key_column(index_column.indexed_column_id)) { - auto result = new_row.GetValue(index_column.indexed_column_id); - if (result) { - QLConditionPB* column_condition = condition->add_operands()->mutable_condition(); - column_condition->set_op(QL_OP_EQUAL); - column_condition->add_operands()->set_column_id(index_column.column_id); - *column_condition->add_operands()->mutable_value() = *result; - index_request->mutable_column_refs()->add_ids(index_column.column_id); - } - } - } -} - } // namespace QLWriteRequestPB* QLWriteOperation::NewIndexRequest(const IndexInfo* index, @@ -2436,15 +2454,6 @@ QLWriteRequestPB* QLWriteOperation::NewIndexRequest(const IndexInfo* index, index_requests_.emplace_back(index, QLWriteRequestPB()); QLWriteRequestPB* request = &index_requests_.back().second; request->set_type(type); - // For insert statement with unique index, add an "IF NOT EXISTS OR (primary key of the indexed - // table is the same)" condition to detect duplicate values. - if (type == QLWriteRequestPB::QL_STMT_INSERT && index->is_unique()) { - auto* condition = request->mutable_if_expr()->mutable_condition(); - condition->set_op(QL_OP_OR); - condition->add_operands()->mutable_condition()->set_op(QL_OP_NOT_EXISTS); - SetPrimaryKeyCondition(index, schema_, new_row, request, - condition->add_operands()->mutable_condition()); - } return request; } diff --git a/src/yb/docdb/doc_operation.h b/src/yb/docdb/doc_operation.h index c902c35f9f66..725c768189fe 100644 --- a/src/yb/docdb/doc_operation.h +++ b/src/yb/docdb/doc_operation.h @@ -180,9 +180,11 @@ class QLWriteOperation : public DocOperation, public DocExprExecutor { public: QLWriteOperation(const Schema& schema, const IndexMap& index_map, + const Schema* unique_index_key_schema, const TransactionOperationContextOpt& txn_op_context) : schema_(schema), index_map_(index_map), + unique_index_key_schema_(unique_index_key_schema), txn_op_context_(txn_op_context) {} @@ -252,6 +254,8 @@ class QLWriteOperation : public DocOperation, public DocExprExecutor { const QLTableRow& table_row, std::unique_ptr* rowblock); + Result DuplicateUniqueIndexValue(const DocOperationApplyData& data); + CHECKED_STATUS DeleteRow(const DocPath& row_path, DocWriteBatch* doc_write_batch); bool IsRowDeleted(const QLTableRow& current_row, const QLTableRow& new_row) const; @@ -264,6 +268,7 @@ class QLWriteOperation : public DocOperation, public DocExprExecutor { const Schema& schema_; const IndexMap& index_map_; + const Schema* unique_index_key_schema_ = nullptr; // Doc key and doc path for hashed key (i.e. without range columns). Present when there is a // static column being written. diff --git a/src/yb/master/async_rpc_tasks.cc b/src/yb/master/async_rpc_tasks.cc index fb6f3e5f5e57..d334ac2f94b2 100644 --- a/src/yb/master/async_rpc_tasks.cc +++ b/src/yb/master/async_rpc_tasks.cc @@ -375,6 +375,9 @@ AsyncCreateReplica::AsyncCreateReplica(Master *master, req_.mutable_schema()->CopyFrom(table_lock->data().pb.schema()); req_.mutable_partition_schema()->CopyFrom(table_lock->data().pb.partition_schema()); req_.mutable_config()->CopyFrom(tablet_pb.committed_consensus_state().config()); + if (table_lock->data().pb.has_index_info()) { + req_.mutable_index_info()->CopyFrom(table_lock->data().pb.index_info()); + } } void AsyncCreateReplica::HandleResponse(int attempt) { diff --git a/src/yb/master/catalog_manager.cc b/src/yb/master/catalog_manager.cc index 567f80d87e02..c6087f7f4833 100644 --- a/src/yb/master/catalog_manager.cc +++ b/src/yb/master/catalog_manager.cc @@ -1125,7 +1125,7 @@ Status CatalogManager::PrepareSystemTable(const TableName& table_name, req.set_table_type(TableType::YQL_TABLE_TYPE); RETURN_NOT_OK(CreateTableInMemory(req, schema, partition_schema, false, namespace_id, - partitions, &tablets, nullptr, &table)); + partitions, nullptr, &tablets, nullptr, &table)); LOG(INFO) << "Inserted new table info into CatalogManager maps: " << namespace_name << "." << table_name; @@ -1381,59 +1381,48 @@ Status CatalogManager::ValidateTableReplicationInfo(const ReplicationInfoPB& rep return Status::OK(); } -namespace { - -CHECKED_STATUS AddIndexColumn( - const Schema& indexed_schema, - const Schema& index_schema, - const size_t index_col_idx, - google::protobuf::RepeatedPtrField* cols) { - - const auto& col_name = index_schema.column(index_col_idx).name(); - const auto indexed_col_idx = indexed_schema.find_column(col_name); - if (PREDICT_FALSE(indexed_col_idx == Schema::kColumnNotFound)) { - return STATUS(NotFound, "The indexed table column does not exist", col_name); +Status CatalogManager::CreateIndexInfo(const TableId& indexed_table_id, + const Schema& indexed_schema, + const Schema& index_schema, + const bool is_local, + const bool is_unique, + IndexInfoPB* index_info) { + // index_info's table_id is set in CreateTableInfo() after the table id is generated. + index_info->set_indexed_table_id(indexed_table_id); + index_info->set_version(0); + index_info->set_is_local(is_local); + index_info->set_is_unique(is_unique); + for (size_t i = 0; i < index_schema.num_columns(); i++) { + const auto& col_name = index_schema.column(i).name(); + const auto indexed_col_idx = indexed_schema.find_column(col_name); + if (PREDICT_FALSE(indexed_col_idx == Schema::kColumnNotFound)) { + return STATUS(NotFound, "The indexed table column does not exist", col_name); + } + auto* col = index_info->add_columns(); + col->set_column_id(index_schema.column_id(i)); + col->set_indexed_column_id(indexed_schema.column_id(indexed_col_idx)); } - auto* col = cols->Add(); - col->set_column_id(index_schema.column_id(index_col_idx)); - col->set_indexed_column_id(indexed_schema.column_id(indexed_col_idx)); - return Status::OK(); -} - -} // namespace + index_info->set_hash_column_count(index_schema.num_hash_key_columns()); + index_info->set_range_column_count(index_schema.num_range_key_columns()); -Status CatalogManager::AddIndexInfoToTable(const TableId& indexed_table_id, - const TableId& index_table_id, - const Schema& index_schema, - const bool is_local, - const bool is_unique) { - // Lookup the indexed table and verify if it exists. - TRACE("Looking up indexed table"); - scoped_refptr indexed_table = GetTableInfo(indexed_table_id); - if (indexed_table == nullptr) { - return STATUS(NotFound, "The indexed table does not exist"); + for (size_t i = 0; i < indexed_schema.num_hash_key_columns(); i++) { + index_info->add_indexed_hash_column_ids(indexed_schema.column_id(i)); } - - Schema indexed_schema; - RETURN_NOT_OK(indexed_table->GetSchema(&indexed_schema)); - - // Populate index info. - IndexInfoPB index_info; - index_info.set_table_id(index_table_id); - index_info.set_version(0); - index_info.set_is_local(is_local); - index_info.set_is_unique(is_unique); - for (size_t i = 0; i < index_schema.num_columns(); i++) { - RETURN_NOT_OK(AddIndexColumn(indexed_schema, index_schema, i, index_info.mutable_columns())); + for (size_t i = indexed_schema.num_hash_key_columns(); i < indexed_schema.num_key_columns(); + i++) { + index_info->add_indexed_range_column_ids(indexed_schema.column_id(i)); } - index_info.set_hash_column_count(index_schema.num_hash_key_columns()); - index_info.set_range_column_count(index_schema.num_range_key_columns()); + return Status::OK(); +} + +Status CatalogManager::AddIndexInfoToTable(const scoped_refptr& indexed_table, + const IndexInfoPB& index_info) { TRACE("Locking indexed table"); auto l = indexed_table->LockForWrite(); // Add index info to indexed table and increment schema version. - l->mutable_data()->pb.add_indexes()->Swap(&index_info); + l->mutable_data()->pb.add_indexes()->CopyFrom(index_info); l->mutable_data()->pb.set_version(l->mutable_data()->pb.version() + 1); l->mutable_data()->set_state(SysTablesEntryPB::ALTERING, Substitute("Alter table version=$0 ts=$1", @@ -1486,8 +1475,9 @@ Status CatalogManager::CreateCopartitionedTable(const CreateTableRequestPB req, return SetupError(resp->mutable_error(), MasterErrorPB::TABLE_ALREADY_PRESENT, s); } + // TODO: pass index_info for copartitioned index. RETURN_NOT_OK(CreateTableInMemory(req, schema, partition_schema, true, namespace_id, - partitions, nullptr, resp, &this_table_info)); + partitions, nullptr, nullptr, resp, &this_table_info)); TRACE("Inserted new table info into CatalogManager maps"); @@ -1665,6 +1655,26 @@ Status CatalogManager::CreateTable(const CreateTableRequestPB* orig_req, return SetupError(resp->mutable_error(), MasterErrorPB::INVALID_SCHEMA, s); } + // For index table, populate the index info. + scoped_refptr indexed_table; + Schema indexed_schema; + IndexInfoPB index_info; + if (req.has_indexed_table_id()) { + TRACE("Looking up indexed table"); + indexed_table = GetTableInfo(req.indexed_table_id()); + if (indexed_table == nullptr) { + return STATUS(NotFound, "The indexed table does not exist"); + } + RETURN_NOT_OK(indexed_table->GetSchema(&indexed_schema)); + + RETURN_NOT_OK(CreateIndexInfo(req.indexed_table_id(), + indexed_schema, + schema, + req.is_local_index(), + req.is_unique_index(), + &index_info)); + } + TSDescriptorVector all_ts_descs; master_->ts_manager()->GetAllLiveDescriptors(&all_ts_descs); s = CheckValidReplicationInfo(replication_info, all_ts_descs, partitions, resp); @@ -1687,7 +1697,7 @@ Status CatalogManager::CreateTable(const CreateTableRequestPB* orig_req, } RETURN_NOT_OK(CreateTableInMemory(req, schema, partition_schema, false, namespace_id, - partitions, &tablets, resp, &table)); + partitions, &index_info, &tablets, resp, &table)); } TRACE("Inserted new table and tablet info into CatalogManager maps"); @@ -1725,8 +1735,7 @@ Status CatalogManager::CreateTable(const CreateTableRequestPB* orig_req, // For index table, insert index info in the indexed table. if (req.has_indexed_table_id()) { - s = AddIndexInfoToTable(req.indexed_table_id(), table->id(), schema, req.is_local_index(), - req.is_unique_index()); + s = AddIndexInfoToTable(indexed_table, index_info); if (PREDICT_FALSE(!s.ok())) { return AbortTableCreation(table.get(), tablets, s.CloneAndPrepend( @@ -1844,6 +1853,7 @@ Status CatalogManager::CreateTableInMemory(const CreateTableRequestPB& req, const bool is_copartitioned, const NamespaceId& namespace_id, const std::vector& partitions, + IndexInfoPB* index_info, std::vector* tablets, CreateTableResponsePB* resp, scoped_refptr* table) { @@ -1853,7 +1863,7 @@ Status CatalogManager::CreateTableInMemory(const CreateTableRequestPB& req, } // Add the new table in "preparing" state. - table->reset(CreateTableInfo(req, schema, partition_schema, namespace_id)); + table->reset(CreateTableInfo(req, schema, partition_schema, namespace_id, index_info)); table_ids_map_[(*table)->id()] = *table; table_names_map_[{namespace_id, req.name()}] = *table; @@ -1917,7 +1927,8 @@ Status CatalogManager::IsCreateTableDone(const IsCreateTableDoneRequestPB* req, TableInfo *CatalogManager::CreateTableInfo(const CreateTableRequestPB& req, const Schema& schema, const PartitionSchema& partition_schema, - const NamespaceId& namespace_id) { + const NamespaceId& namespace_id, + IndexInfoPB* index_info) { DCHECK(schema.has_column_ids()); TableInfo* table = new TableInfo(GenerateId()); table->mutable_metadata()->StartMutation(); @@ -1938,6 +1949,8 @@ TableInfo *CatalogManager::CreateTableInfo(const CreateTableRequestPB& req, metadata->set_indexed_table_id(req.indexed_table_id()); metadata->set_is_local_index(req.is_local_index()); metadata->set_is_unique_index(req.is_unique_index()); + index_info->set_table_id(table->id()); + metadata->mutable_index_info()->CopyFrom(*index_info); } return table; } @@ -5775,6 +5788,16 @@ const std::string TableInfo::indexed_table_id() const { return l->data().pb.has_indexed_table_id() ? l->data().pb.indexed_table_id() : ""; } +bool TableInfo::is_local_index() const { + auto l = LockForRead(); + return l->data().pb.is_local_index(); +} + +bool TableInfo::is_unique_index() const { + auto l = LockForRead(); + return l->data().pb.is_unique_index(); +} + TableType TableInfo::GetTableType() const { auto l = LockForRead(); return l->data().pb.table_type(); diff --git a/src/yb/master/catalog_manager.h b/src/yb/master/catalog_manager.h index c20bfba65c9f..88cd329e6088 100644 --- a/src/yb/master/catalog_manager.h +++ b/src/yb/master/catalog_manager.h @@ -357,6 +357,10 @@ class TableInfo : public RefCountedThreadSafe, // Return the indexed table id if the table is an index table. Otherwise, return an empty string. const std::string indexed_table_id() const; + // For index table + bool is_local_index() const; + bool is_unique_index() const; + // Return the table type of the table. TableType GetTableType() const; @@ -1180,6 +1184,7 @@ class CatalogManager : public tserver::TabletPeerLookupIf { const bool is_copartitioned, const NamespaceId& namespace_id, const vector& partitions, + IndexInfoPB* index_info, vector* tablets, CreateTableResponsePB* resp, scoped_refptr* table); @@ -1214,7 +1219,8 @@ class CatalogManager : public tserver::TabletPeerLookupIf { TableInfo* CreateTableInfo(const CreateTableRequestPB& req, const Schema& schema, const PartitionSchema& partition_schema, - const NamespaceId& namespace_id); + const NamespaceId& namespace_id, + IndexInfoPB* index_info); // Helper for creating the initial TabletInfo state. // Leaves the tablet "write locked" with the new info in the @@ -1222,12 +1228,17 @@ class CatalogManager : public tserver::TabletPeerLookupIf { TabletInfo *CreateTabletInfo(TableInfo* table, const PartitionPB& partition); + // Create index info. + CHECKED_STATUS CreateIndexInfo(const TableId& indexed_table_id, + const Schema& indexed_schema, + const Schema& index_schema, + const bool is_local, + const bool is_unique, + IndexInfoPB* index_info); + // Add index info to the indexed table. - CHECKED_STATUS AddIndexInfoToTable(const TableId& indexed_table_id, - const TableId& index_table_id, - const Schema& index_schema, - bool is_local, - bool is_unique); + CHECKED_STATUS AddIndexInfoToTable(const scoped_refptr& indexed_table, + const IndexInfoPB& index_info); // Delete index info from the indexed table. CHECKED_STATUS DeleteIndexInfoFromTable(const TableId& indexed_table_id, diff --git a/src/yb/master/master.proto b/src/yb/master/master.proto index b7b6f3db74e7..733cf7ac9961 100644 --- a/src/yb/master/master.proto +++ b/src/yb/master/master.proto @@ -328,10 +328,13 @@ message SysTablesEntryPB { // Secondary indexes of the table. repeated IndexInfoPB indexes = 12; - // For index table: + // For index table: [to be deprecated and replaced by "index_info"] optional bytes indexed_table_id = 13; // Indexed table id of this index. optional bool is_local_index = 14 [ default = false ]; // Whether this is a local index. optional bool is_unique_index = 15 [ default = false ]; // Whether this is a unique index. + + // For index table: information about this index. + optional IndexInfoPB index_info = 22; } // The data part of a SysRowEntry in the sys.catalog table for a namespace. diff --git a/src/yb/master/sys_catalog.cc b/src/yb/master/sys_catalog.cc index 7c48e73a1560..6d3bf06d0413 100644 --- a/src/yb/master/sys_catalog.cc +++ b/src/yb/master/sys_catalog.cc @@ -266,6 +266,7 @@ Status SysCatalogTable::CreateNew(FsManager *fs_manager) { TableType::YQL_TABLE_TYPE, schema, partition_schema, partitions[0], + boost::none /* index_info */, tablet::TABLET_DATA_READY, &metadata)); diff --git a/src/yb/tablet/metadata.proto b/src/yb/tablet/metadata.proto index 5674ecc3fce3..e2ed46cd1d30 100644 --- a/src/yb/tablet/metadata.proto +++ b/src/yb/tablet/metadata.proto @@ -135,6 +135,9 @@ message TabletSuperBlockPB { // Secondary indexes of the table. repeated IndexInfoPB indexes = 21; + + // For index table: information about this index. + optional IndexInfoPB index_info = 22; } message FilePB { diff --git a/src/yb/tablet/tablet-harness.h b/src/yb/tablet/tablet-harness.h index 1866431a29e7..b57c2f350d2e 100644 --- a/src/yb/tablet/tablet-harness.h +++ b/src/yb/tablet/tablet-harness.h @@ -118,6 +118,7 @@ class TabletHarness { schema_, partition.first, partition.second, + boost::none /* index_info */, TABLET_DATA_READY, &metadata)); if (options_.enable_metrics) { diff --git a/src/yb/tablet/tablet.cc b/src/yb/tablet/tablet.cc index 7dedda2c38a0..2eb6d7cda830 100644 --- a/src/yb/tablet/tablet.cc +++ b/src/yb/tablet/tablet.cc @@ -369,6 +369,14 @@ Tablet::Tablet( metadata_cache_.emplace(client_future_.get()); } + // If this is a unique index tablet, set up the index primary key schema. + if (metadata_->is_unique_index()) { + unique_index_key_schema_.emplace(); + const auto ids = metadata_->index_key_column_ids(); + CHECK_OK(metadata_->schema().CreateProjectionByIdsIgnoreMissing(ids, + &*unique_index_key_schema_)); + } + // TODO(dtxn) Create coordinator only for status tablets if (transaction_coordinator_context) { transaction_coordinator_ = std::make_unique( @@ -856,6 +864,8 @@ Status Tablet::KeyValueBatchFromQLWriteBatch(const WriteOperationData& data) { } else { auto write_op = std::make_unique(metadata_->schema(), metadata_->index_map(), + unique_index_key_schema_ ? + &*unique_index_key_schema_ : nullptr, *txn_op_ctx); RETURN_NOT_OK(write_op->Init(req, resp)); doc_ops.emplace_back(std::move(write_op)); @@ -870,9 +880,16 @@ Status Tablet::KeyValueBatchFromQLWriteBatch(const WriteOperationData& data) { for (size_t i = 0; i < doc_ops.size(); i++) { QLWriteOperation* ql_write_op = down_cast(doc_ops[i].get()); - // If the QL write op returns a rowblock, move the op to the transaction state to return the - // rows data as a sidecar after the transaction completes. - if (ql_write_op->rowblock() != nullptr) { + if (metadata_->is_unique_index() && + ql_write_op->request().type() == QLWriteRequestPB::QL_STMT_INSERT && + ql_write_op->response()->has_applied() && !ql_write_op->response()->applied()) { + // If this is an insert into a unique index and it fails to apply, report duplicate value err. + ql_write_op->response()->set_status(QLResponsePB::YQL_STATUS_USAGE_ERROR); + ql_write_op->response()->set_error_message( + Format("Duplicate value disallowed by unique index $0", metadata_->table_name())); + } else if (ql_write_op->rowblock() != nullptr) { + // If the QL write op returns a rowblock, move the op to the transaction state to return the + // rows data as a sidecar after the transaction completes. doc_ops[i].release(); data.operation_state->ql_write_ops()->emplace_back(unique_ptr(ql_write_op)); } @@ -933,7 +950,6 @@ Status Tablet::UpdateQLIndexes(docdb::DocOperations* doc_ops) { // Check the responses of the index write ops. auto* response = write_op->response(); for (const auto& pair : index_ops) { - const IndexInfo* index_info = pair.first; shared_ptr index_op = pair.second; auto* index_response = index_op->mutable_response(); @@ -942,14 +958,6 @@ Status Tablet::UpdateQLIndexes(docdb::DocOperations* doc_ops) { response->set_error_message(std::move(index_response->error_message())); break; } - - // For unique index, return error if the update failed due to duplicate values. - if (index_info->is_unique() && index_response->has_applied() && !index_response->applied()) { - response->set_status(QLResponsePB::YQL_STATUS_USAGE_ERROR); - response->set_error_message(Format("Duplicate value disallowed by unique index $0", - index_op->table()->name().ToString())); - break; - } } if (txn) { diff --git a/src/yb/tablet/tablet.h b/src/yb/tablet/tablet.h index 007afd54657d..102b29d2ff69 100644 --- a/src/yb/tablet/tablet.h +++ b/src/yb/tablet/tablet.h @@ -644,6 +644,9 @@ class Tablet : public AbstractTablet, public TransactionIntentApplier { boost::optional transaction_manager_; boost::optional metadata_cache_; + // Created only if it is a unique index tablet. + boost::optional unique_index_key_schema_; + std::atomic last_committed_write_index_{0}; // Remembers he HybridTime of the oldest write that is still not scheduled to diff --git a/src/yb/tablet/tablet_bootstrap-test.cc b/src/yb/tablet/tablet_bootstrap-test.cc index 672b27e954d5..2461ded6a8a9 100644 --- a/src/yb/tablet/tablet_bootstrap-test.cc +++ b/src/yb/tablet/tablet_bootstrap-test.cc @@ -98,6 +98,7 @@ class BootstrapTest : public LogTestBase { schema, partition.first, partition.second, + boost::none /* index_info */, TABLET_DATA_READY, meta)); return (*meta)->Flush(); diff --git a/src/yb/tablet/tablet_metadata.cc b/src/yb/tablet/tablet_metadata.cc index 5a683dc47788..156c560b57ac 100644 --- a/src/yb/tablet/tablet_metadata.cc +++ b/src/yb/tablet/tablet_metadata.cc @@ -95,6 +95,7 @@ Status TabletMetadata::CreateNew(FsManager* fs_manager, const Schema& schema, const PartitionSchema& partition_schema, const Partition& partition, + const boost::optional& index_info, const TabletDataState& initial_tablet_data_state, scoped_refptr* metadata, const string& data_root_dir, @@ -140,6 +141,7 @@ Status TabletMetadata::CreateNew(FsManager* fs_manager, schema, partition_schema, partition, + index_info, initial_tablet_data_state)); RETURN_NOT_OK(ret->Flush()); metadata->swap(ret); @@ -163,6 +165,7 @@ Status TabletMetadata::LoadOrCreate(FsManager* fs_manager, const Schema& schema, const PartitionSchema& partition_schema, const Partition& partition, + const boost::optional& index_info, const TabletDataState& initial_tablet_data_state, scoped_refptr* metadata) { Status s = Load(fs_manager, tablet_id, metadata); @@ -175,7 +178,7 @@ Status TabletMetadata::LoadOrCreate(FsManager* fs_manager, return Status::OK(); } else if (s.IsNotFound()) { return CreateNew(fs_manager, table_id, tablet_id, table_name, table_type, - schema, partition_schema, partition, + schema, partition_schema, partition, index_info, initial_tablet_data_state, metadata); } else { return s; @@ -273,6 +276,7 @@ TabletMetadata::TabletMetadata(FsManager* fs_manager, const Schema& schema, PartitionSchema partition_schema, Partition partition, + const boost::optional& index_info, const TabletDataState& tablet_data_state) : state_(kNotWrittenYet), table_id_(std::move(table_id)), @@ -284,6 +288,7 @@ TabletMetadata::TabletMetadata(FsManager* fs_manager, schema_version_(0), table_name_(std::move(table_name)), table_type_(table_type), + index_info_(index_info), rocksdb_dir_(rocksdb_dir), wal_dir_(wal_dir), partition_schema_(std::move(partition_schema)), @@ -339,6 +344,9 @@ Status TabletMetadata::LoadFromSuperBlock(const TabletSuperBlockPB& superblock) table_name_ = superblock.table_name(); table_type_ = superblock.table_type(); index_map_.FromPB(superblock.indexes()); + if (superblock.has_index_info()) { + index_info_.emplace(superblock.index_info()); + } rocksdb_dir_ = superblock.rocksdb_dir(); wal_dir_ = superblock.wal_dir(); @@ -539,6 +547,9 @@ Status TabletMetadata::ToSuperBlockUnlocked(TabletSuperBlockPB* super_block) con pb.set_table_name(table_name_); pb.set_table_type(table_type_); index_map_.ToPB(pb.mutable_indexes()); + if (index_info_) { + index_info_->ToPB(pb.mutable_index_info()); + } pb.set_rocksdb_dir(rocksdb_dir_); pb.set_wal_dir(wal_dir_); @@ -599,12 +610,6 @@ string TabletMetadata::table_name() const { return table_name_; } -TableType TabletMetadata::table_type() const { - std::lock_guard l(data_lock_); - DCHECK_NE(state_, kNotLoadedYet); - return table_type_; -} - uint32_t TabletMetadata::schema_version() const { std::lock_guard l(data_lock_); DCHECK_NE(state_, kNotLoadedYet); diff --git a/src/yb/tablet/tablet_metadata.h b/src/yb/tablet/tablet_metadata.h index 3ea2b7672be0..846eb82fab61 100644 --- a/src/yb/tablet/tablet_metadata.h +++ b/src/yb/tablet/tablet_metadata.h @@ -88,6 +88,7 @@ class TabletMetadata : public RefCountedThreadSafe { const Schema& schema, const PartitionSchema& partition_schema, const Partition& partition, + const boost::optional& index_info, const TabletDataState& initial_tablet_data_state, scoped_refptr* metadata, const std::string& data_root_dir = std::string(), @@ -111,6 +112,7 @@ class TabletMetadata : public RefCountedThreadSafe { const Schema& schema, const PartitionSchema& partition_schema, const Partition& partition, + const boost::optional& index_info, const TabletDataState& initial_tablet_data_state, scoped_refptr* metadata); @@ -124,14 +126,38 @@ class TabletMetadata : public RefCountedThreadSafe { return partition_; } - std::string table_id() const { + const std::string& table_id() const { DCHECK_NE(state_, kNotLoadedYet); return table_id_; } std::string table_name() const; - TableType table_type() const; + TableType table_type() const { + DCHECK_NE(state_, kNotLoadedYet); + return table_type_; + } + + const std::string& indexed_tablet_id() const { + DCHECK_NE(state_, kNotLoadedYet); + static const std::string kEmptyString = ""; + return index_info_ ? index_info_->indexed_table_id() : kEmptyString; + } + + bool is_local_index() const { + DCHECK_NE(state_, kNotLoadedYet); + return index_info_ && index_info_->is_local(); + } + + bool is_unique_index() const { + DCHECK_NE(state_, kNotLoadedYet); + return index_info_ && index_info_->is_unique(); + } + + std::vector index_key_column_ids() const { + DCHECK_NE(state_, kNotLoadedYet); + return index_info_ ? index_info_->index_key_column_ids() : std::vector(); + } std::string rocksdb_dir() const { return rocksdb_dir_; } @@ -268,6 +294,7 @@ class TabletMetadata : public RefCountedThreadSafe { const Schema& schema, PartitionSchema partition_schema, Partition partition, + const boost::optional& index_info, const TabletDataState& tablet_data_state); // Constructor for loading an existing tablet. @@ -334,6 +361,7 @@ class TabletMetadata : public RefCountedThreadSafe { uint32_t schema_version_; std::string table_name_; TableType table_type_; + boost::optional index_info_; // The directory where the RocksDB data for this tablet is stored. std::string rocksdb_dir_; diff --git a/src/yb/tools/yb-bulk_load.cc b/src/yb/tools/yb-bulk_load.cc index 1d9304445b85..8fdd79acdd3d 100644 --- a/src/yb/tools/yb-bulk_load.cc +++ b/src/yb/tools/yb-bulk_load.cc @@ -287,7 +287,7 @@ Status BulkLoadTask::InsertRow(const string &row, // Comment from PritamD: Don't need cross shard transaction support in bulk load, but I guess // once we have secondary indexes we probably might need to ensure bulk load builds the indexes // as well. - docdb::QLWriteOperation op(schema, index_map, boost::none); + docdb::QLWriteOperation op(schema, index_map, nullptr /* unique_index_key_schema */, boost::none); RETURN_NOT_OK(op.Init(&req, &resp)); RETURN_NOT_OK(op.Apply({ doc_write_batch, diff --git a/src/yb/tserver/mini_tablet_server.cc b/src/yb/tserver/mini_tablet_server.cc index 535a6e9015be..7fc231b60f1f 100644 --- a/src/yb/tserver/mini_tablet_server.cc +++ b/src/yb/tserver/mini_tablet_server.cc @@ -234,7 +234,7 @@ Status MiniTabletServer::AddTestTablet(const std::string& table_id, pair partition = tablet::CreateDefaultPartition(schema_with_ids); return server_->tablet_manager()->CreateNewTablet(table_id, tablet_id, partition.second, table_id, - table_type, schema_with_ids, partition.first, config, nullptr); + table_type, schema_with_ids, partition.first, boost::none /* index_info */, config, nullptr); } void MiniTabletServer::FailHeartbeats() { diff --git a/src/yb/tserver/remote_bootstrap_client.cc b/src/yb/tserver/remote_bootstrap_client.cc index 9fc46e6160e0..dc77b7015ab7 100644 --- a/src/yb/tserver/remote_bootstrap_client.cc +++ b/src/yb/tserver/remote_bootstrap_client.cc @@ -316,6 +316,10 @@ Status RemoteBootstrapClient::Start(const string& bootstrap_peer_uuid, schema, partition_schema, partition, + superblock_->has_index_info() ? + boost::optional( + superblock_->index_info()) : + boost::none, tablet::TABLET_DATA_COPYING, &meta_, data_root_dir, diff --git a/src/yb/tserver/tablet_server-test.cc b/src/yb/tserver/tablet_server-test.cc index 05e3abaae644..058edcfbc2c5 100644 --- a/src/yb/tserver/tablet_server-test.cc +++ b/src/yb/tserver/tablet_server-test.cc @@ -798,7 +798,7 @@ TEST_F(TabletServerTest, TestWriteOutOfBounds) { Partition partition; ASSERT_OK( mini_server_->server()->tablet_manager()->CreateNewTablet("TestWriteOutOfBoundsTable", tabletId, - partition, tabletId, YQL_TABLE_TYPE, schema, partition_schema, + partition, tabletId, YQL_TABLE_TYPE, schema, partition_schema, boost::none /* index_info */, mini_server_->CreateLocalConfig(), nullptr)); ASSERT_OK(WaitForTabletRunning(tabletId)); diff --git a/src/yb/tserver/tablet_service.cc b/src/yb/tserver/tablet_service.cc index 52e8eaab24d4..3d13314ee8e3 100644 --- a/src/yb/tserver/tablet_service.cc +++ b/src/yb/tserver/tablet_service.cc @@ -602,7 +602,9 @@ void TabletServiceAdminImpl::CreateTablet(const CreateTabletRequestPB* req, VLOG(1) << "Full request: " << req->DebugString(); s = server_->tablet_manager()->CreateNewTablet(req->table_id(), req->tablet_id(), partition, - req->table_name(), req->table_type(), schema, partition_schema, req->config(), nullptr); + req->table_name(), req->table_type(), schema, partition_schema, + req->has_index_info() ? boost::optional(req->index_info()) : boost::none, + req->config(), nullptr); if (PREDICT_FALSE(!s.ok())) { TabletServerErrorPB::Code code; if (s.IsAlreadyPresent()) { diff --git a/src/yb/tserver/ts_tablet_manager-test.cc b/src/yb/tserver/ts_tablet_manager-test.cc index df5e881167f8..08f9a345d455 100644 --- a/src/yb/tserver/ts_tablet_manager-test.cc +++ b/src/yb/tserver/ts_tablet_manager-test.cc @@ -108,7 +108,8 @@ class TsTabletManagerTest : public YBTest { std::shared_ptr tablet_peer; RETURN_NOT_OK( tablet_manager_->CreateNewTablet(tablet_id, tablet_id, partition.second, tablet_id, - TableType::DEFAULT_TABLE_TYPE, full_schema, partition.first, config_, &tablet_peer)); + TableType::DEFAULT_TABLE_TYPE, full_schema, partition.first, boost::none /* index_info */, + config_, &tablet_peer)); if (out_tablet_peer) { (*out_tablet_peer) = tablet_peer; } diff --git a/src/yb/tserver/ts_tablet_manager.cc b/src/yb/tserver/ts_tablet_manager.cc index cbb72d970a26..c3ab2625219f 100644 --- a/src/yb/tserver/ts_tablet_manager.cc +++ b/src/yb/tserver/ts_tablet_manager.cc @@ -484,6 +484,7 @@ Status TSTabletManager::CreateNewTablet( TableType table_type, const Schema &schema, const PartitionSchema &partition_schema, + const boost::optional& index_info, RaftConfigPB config, TabletPeerPtr *tablet_peer) { CHECK_EQ(state(), MANAGER_RUNNING); @@ -529,6 +530,7 @@ Status TSTabletManager::CreateNewTablet( schema, partition_schema, partition, + index_info, TABLET_DATA_READY, &meta, data_root_dir, diff --git a/src/yb/tserver/ts_tablet_manager.h b/src/yb/tserver/ts_tablet_manager.h index 0b9268c713d6..c52c32dfb500 100644 --- a/src/yb/tserver/ts_tablet_manager.h +++ b/src/yb/tserver/ts_tablet_manager.h @@ -165,6 +165,7 @@ class TSTabletManager : public tserver::TabletPeerLookupIf { TableType table_type, const Schema &schema, const PartitionSchema &partition_schema, + const boost::optional& index_info, consensus::RaftConfigPB config, std::shared_ptr *tablet_peer); diff --git a/src/yb/tserver/tserver_admin.proto b/src/yb/tserver/tserver_admin.proto index 965a2b19b2ca..424bb54c69cc 100644 --- a/src/yb/tserver/tserver_admin.proto +++ b/src/yb/tserver/tserver_admin.proto @@ -98,6 +98,9 @@ message CreateTabletRequestPB { // Initial consensus configuration for the tablet. required consensus.RaftConfigPB config = 7; + + // For index table: information about this index. + optional IndexInfoPB index_info = 12; } message CreateTabletResponsePB {