| // Copyright 2015 Cloudera, Inc. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include <gflags/gflags.h> |
| #include <gtest/gtest.h> |
| #include <string> |
| #include <tr1/memory> |
| |
| #include "kudu/client/client-test-util.h" |
| #include "kudu/common/wire_protocol-test-util.h" |
| #include "kudu/integration-tests/external_mini_cluster-itest-base.h" |
| #include "kudu/util/metrics.h" |
| |
| using std::string; |
| using std::vector; |
| |
| METRIC_DECLARE_entity(server); |
| METRIC_DECLARE_histogram(handler_latency_kudu_tserver_TabletServerAdminService_CreateTablet); |
| |
| namespace kudu { |
| |
| const char* const kTableName = "test-table"; |
| |
| class CreateTableITest : public ExternalMiniClusterITestBase { |
| }; |
| |
| // Regression test for an issue seen when we fail to create a majority of the |
| // replicas in a tablet. Previously, we'd still consider the tablet "RUNNING" |
| // on the master and finish the table creation, even though that tablet would |
| // be stuck forever with its minority never able to elect a leader. |
| TEST_F(CreateTableITest, TestCreateWhenMajorityOfReplicasFailCreation) { |
| const int kNumReplicas = 3; |
| vector<string> ts_flags; |
| vector<string> master_flags; |
| master_flags.push_back("--tablet_creation_timeout_ms=1000"); |
| NO_FATALS(StartCluster(ts_flags, master_flags, kNumReplicas)); |
| |
| // Shut down 2/3 of the tablet servers. |
| cluster_->tablet_server(1)->Shutdown(); |
| cluster_->tablet_server(2)->Shutdown(); |
| |
| // Try to create a single-tablet table. |
| // This won't succeed because we can't create enough replicas to get |
| // a quorum. |
| gscoped_ptr<client::KuduTableCreator> table_creator(client_->NewTableCreator()); |
| client::KuduSchema client_schema(client::KuduSchemaFromSchema(GetSimpleTestSchema())); |
| ASSERT_OK(table_creator->table_name(kTableName) |
| .schema(&client_schema) |
| .num_replicas(3) |
| .wait(false) |
| .Create()); |
| |
| // Sleep until we've seen a couple retries on our live server. |
| int64_t num_create_attempts = 0; |
| while (num_create_attempts < 3) { |
| SleepFor(MonoDelta::FromMilliseconds(100)); |
| ASSERT_OK(cluster_->tablet_server(0)->GetInt64Metric( |
| &METRIC_ENTITY_server, |
| "kudu.tabletserver", |
| &METRIC_handler_latency_kudu_tserver_TabletServerAdminService_CreateTablet, |
| "total_count", |
| &num_create_attempts)); |
| LOG(INFO) << "Waiting for the master to retry creating the tablet 3 times... " |
| << num_create_attempts << " RPCs seen so far"; |
| |
| // The CreateTable operation should still be considered in progress, even though |
| // we'll be successful at creating a single replica. |
| bool in_progress = false; |
| ASSERT_OK(client_->IsCreateTableInProgress(kTableName, &in_progress)); |
| ASSERT_TRUE(in_progress); |
| } |
| |
| // Once we restart the servers, we should succeed at creating a healthy |
| // replicated tablet. |
| ASSERT_OK(cluster_->tablet_server(1)->Restart()); |
| ASSERT_OK(cluster_->tablet_server(2)->Restart()); |
| |
| // We should eventually finish the table creation we started earlier. |
| bool in_progress = false; |
| while (in_progress) { |
| LOG(INFO) << "Waiting for the master to successfully create the table..."; |
| ASSERT_OK(client_->IsCreateTableInProgress(kTableName, &in_progress)); |
| SleepFor(MonoDelta::FromMilliseconds(100)); |
| } |
| } |
| |
| } // namespace kudu |