This is an automated email from the ASF dual-hosted git repository.
alexey pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kudu.git
The following commit(s) were added to refs/heads/master by this push:
new b2fae6d [catalog_manager] Status::AlreadyPresent for range duplicates
b2fae6d is described below
commit b2fae6d0aec813c9a82c4cd1cbb3e5d495d6e35a
Author: Alexey Serbin <[email protected]>
AuthorDate: Fri Oct 2 22:54:54 2020 -0700
[catalog_manager] Status::AlreadyPresent for range duplicates
With this patch, CatalogManager discriminates between overlapped
and exact duplicate key ranges when adding new partitions, returning
Status::AlreadyPresent() for exact range duplicates and
Status::InvalidArgument for otherwise overlapped ones. The number
of hash buckets is not taken into account when searching/reporting
about the exact duplicates in key range for partitions.
Before this patch, CatalogManager returned Status::InvalidArgument()
for exact duplicates and otherwise overlapped ranges as well.
This patch also updates the relevant tests, so the new behavior
has enough test coverage.
A follow-up patch will use the newly introduced finer status reporting.
To be more precise, TxnManager could send multiple requests to add the
same new tablet for the transaction status table while processing
concurrent BeginTransaction() requests. With that, it should be able
to tell between an error when the corresponding tablet is already
present and other types of errors.
Change-Id: I42c1b821f3bd6854c06682ae3c85a058665f1489
Reviewed-on: http://gerrit.cloudera.org:8080/16544
Tested-by: Kudu Jenkins
Reviewed-by: Andrew Wong <[email protected]>
---
.../org/apache/kudu/client/TestAlterTable.java | 18 +--
src/kudu/integration-tests/alter_table-test.cc | 125 ++++++++++++---------
.../integration-tests/txn_status_table-itest.cc | 2 +-
src/kudu/master/catalog_manager.cc | 105 +++++++++++------
4 files changed, 148 insertions(+), 102 deletions(-)
diff --git
a/java/kudu-client/src/test/java/org/apache/kudu/client/TestAlterTable.java
b/java/kudu-client/src/test/java/org/apache/kudu/client/TestAlterTable.java
index 6f05a25..5d88178 100644
--- a/java/kudu-client/src/test/java/org/apache/kudu/client/TestAlterTable.java
+++ b/java/kudu-client/src/test/java/org/apache/kudu/client/TestAlterTable.java
@@ -389,7 +389,7 @@ public class TestAlterTable {
insertRows(table, 0, 100);
assertEquals(100, countRowsInTable(table));
- // ADD [0, 100) <- illegal (duplicate)
+ // ADD [0, 100) <- already present (duplicate)
PartialRow lower = schema.newPartialRow();
PartialRow upper = schema.newPartialRow();
lower.addInt("c0", 0);
@@ -398,9 +398,9 @@ public class TestAlterTable {
client.alterTable(tableName, new
AlterTableOptions().addRangePartition(lower, upper));
fail();
} catch (KuduException e) {
- assertTrue(e.getStatus().isInvalidArgument());
+ assertTrue(e.getStatus().isAlreadyPresent());
assertTrue(e.getStatus().getMessage().contains(
- "New range partition conflicts with existing range partition"));
+ "range partition already exists"));
}
assertEquals(100, countRowsInTable(table));
@@ -413,7 +413,7 @@ public class TestAlterTable {
} catch (KuduException e) {
assertTrue(e.getStatus().isInvalidArgument());
assertTrue(e.getStatus().getMessage().contains(
- "New range partition conflicts with existing range partition"));
+ "new range partition conflicts with existing one"));
}
assertEquals(100, countRowsInTable(table));
@@ -426,7 +426,7 @@ public class TestAlterTable {
} catch (KuduException e) {
assertTrue(e.getStatus().isInvalidArgument());
assertTrue(e.getStatus().getMessage().contains(
- "New range partition conflicts with existing range partition"));
+ "new range partition conflicts with existing one"));
}
assertEquals(100, countRowsInTable(table));
@@ -445,7 +445,7 @@ public class TestAlterTable {
} catch (KuduException e) {
assertTrue(e.getStatus().isInvalidArgument());
assertTrue(e.getStatus().getMessage().contains(
- "New range partition conflicts with existing range partition"));
+ "new range partition conflicts with existing one"));
}
assertEquals(100, countRowsInTable(table));
@@ -458,7 +458,7 @@ public class TestAlterTable {
} catch (KuduException e) {
assertTrue(e.getStatus().isInvalidArgument());
assertTrue(e.getStatus().getMessage(),
e.getStatus().getMessage().contains(
- "No range partition found for drop range partition step"));
+ "no range partition to drop"));
}
assertEquals(100, countRowsInTable(table));
@@ -473,7 +473,7 @@ public class TestAlterTable {
} catch (KuduException e) {
assertTrue(e.getStatus().isInvalidArgument());
assertTrue(e.getStatus().getMessage().contains(
- "No range partition found for drop range partition step"));
+ "no range partition to drop"));
}
assertEquals(100, countRowsInTable(table));
assertFalse(client.tableExists("foo"));
@@ -507,7 +507,7 @@ public class TestAlterTable {
} catch (KuduException e) {
assertTrue(e.getStatus().isInvalidArgument());
assertTrue(e.getStatus().getMessage().contains(
- "No range partition found for drop range partition step"));
+ "no range partition to drop"));
}
assertEquals(100, countRowsInTable(table));
}
diff --git a/src/kudu/integration-tests/alter_table-test.cc
b/src/kudu/integration-tests/alter_table-test.cc
index d9b62d4..69dc64e 100644
--- a/src/kudu/integration-tests/alter_table-test.cc
+++ b/src/kudu/integration-tests/alter_table-test.cc
@@ -1417,7 +1417,7 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
ASSERT_OK(InsertRowsSequential(table_name, 0, 100));
ASSERT_EQ(100, CountTableRows(table.get()));
- // ADD [0, 100) <- illegal (duplicate)
+ // ADD [0, 100) <- already present (duplicate)
table_alterer.reset(client_->NewTableAlterer(table_name));
lower.reset(schema_.NewRow());
upper.reset(schema_.NewRow());
@@ -1425,8 +1425,8 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
ASSERT_OK(upper->SetInt32("c0", 100));
table_alterer->AddRangePartition(lower.release(), upper.release());
s = table_alterer->wait(false)->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "New range partition conflicts with
existing range partition");
+ ASSERT_TRUE(s.IsAlreadyPresent()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "range partition already exists");
ASSERT_EQ(100, CountTableRows(table.get()));
// ADD [50, 150) <- illegal (overlap)
@@ -1437,8 +1437,9 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
ASSERT_OK(upper->SetInt32("c0", 150));
table_alterer->AddRangePartition(lower.release(), upper.release());
s = table_alterer->wait(false)->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "New range partition conflicts with
existing range partition");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(),
+ "new range partition conflicts with existing one");
ASSERT_EQ(100, CountTableRows(table.get()));
// ADD (-50, 50] <- illegal (overlap)
@@ -1451,8 +1452,9 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
KuduTableCreator::EXCLUSIVE_BOUND,
KuduTableCreator::INCLUSIVE_BOUND);
s = table_alterer->wait(false)->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "New range partition conflicts with
existing range partition");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(
+ s.ToString(), "new range partition conflicts with existing one");
ASSERT_EQ(100, CountTableRows(table.get()));
// ADD [200, 300)
@@ -1469,8 +1471,9 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
ASSERT_OK(upper->SetInt32("c0", 150));
table_alterer->AddRangePartition(lower.release(), upper.release());
s = table_alterer->wait(false)->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "New range partition conflicts with
existing range partition");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(
+ s.ToString(), "new range partition conflicts with existing one");
ASSERT_FALSE(InsertRowsSequential(table_name, 200, 100).ok());
ASSERT_EQ(100, CountTableRows(table.get()));
@@ -1478,8 +1481,8 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
table_alterer.reset(client_->NewTableAlterer(table_name));
table_alterer->DropRangePartition(schema_.NewRow(), schema_.NewRow());
s = table_alterer->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "No range partition found for drop range
partition step");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "no range partition to drop");
ASSERT_EQ(100, CountTableRows(table.get()));
// DROP [50, 150)
@@ -1492,8 +1495,8 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
table_alterer->DropRangePartition(lower.release(), upper.release());
table_alterer->RenameTo("foo");
s = table_alterer->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "No range partition found for drop range
partition step");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "no range partition to drop");
ASSERT_EQ(100, CountTableRows(table.get()));
// DROP [-50, 50)
@@ -1504,8 +1507,8 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
ASSERT_OK(upper->SetInt32("c0", 50));
table_alterer->DropRangePartition(lower.release(), upper.release());
s = table_alterer->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "No range partition found for drop range
partition step");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "no range partition to drop");
ASSERT_EQ(100, CountTableRows(table.get()));
// DROP [0, 100)
@@ -1540,8 +1543,8 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
ASSERT_OK(upper->SetInt32("c0", 10));
table_alterer->DropRangePartition(lower.release(), upper.release());
s = table_alterer->wait(false)->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "No range partition found for drop range
partition step");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "no range partition to drop");
ASSERT_EQ(100, CountTableRows(table.get()));
// KUDU-1750 Regression cases:
@@ -1554,8 +1557,8 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
ASSERT_OK(upper->SetInt32("c0", 50));
table_alterer->DropRangePartition(lower.release(), upper.release());
s = table_alterer->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "No range partition found for drop range
partition step");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "no range partition to drop");
ASSERT_EQ(100, CountTableRows(table.get()));
// DROP [50, 100) <- illegal
@@ -1566,8 +1569,8 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
ASSERT_OK(upper->SetInt32("c0", 100));
table_alterer->DropRangePartition(lower.release(), upper.release());
s = table_alterer->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "No range partition found for drop range
partition step");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "no range partition to drop");
ASSERT_EQ(100, CountTableRows(table.get()));
// ADD [100, 200)
@@ -1584,8 +1587,8 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
ASSERT_OK(upper->SetInt32("c0", 150));
table_alterer->DropRangePartition(lower.release(), upper.release());
s = table_alterer->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "No range partition found for drop range
partition step");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "no range partition to drop");
ASSERT_EQ(100, CountTableRows(table.get()));
// ADD [100, 200)
@@ -1602,8 +1605,8 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
ASSERT_OK(upper->SetInt32("c0", 200));
table_alterer->DropRangePartition(lower.release(), upper.release());
s = table_alterer->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "No range partition found for drop range
partition step");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "no range partition to drop");
ASSERT_EQ(100, CountTableRows(table.get()));
// ADD [<min>, 0)
@@ -1618,8 +1621,8 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
ASSERT_OK(upper->SetInt32("c0", -50));
table_alterer->DropRangePartition(lower.release(), upper.release());
s = table_alterer->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "No range partition found for drop range
partition step");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "no range partition to drop");
ASSERT_EQ(100, CountTableRows(table.get()));
// ADD [<min>, 0)
@@ -1634,8 +1637,8 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
ASSERT_OK(upper->SetInt32("c0", 50));
table_alterer->DropRangePartition(lower.release(), upper.release());
s = table_alterer->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "No range partition found for drop range
partition step");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "no range partition to drop");
ASSERT_EQ(100, CountTableRows(table.get()));
// ADD [100, <max>)
@@ -1650,8 +1653,8 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
ASSERT_OK(lower->SetInt32("c0", 150));
table_alterer->DropRangePartition(lower.release(), upper.release());
s = table_alterer->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "No range partition found for drop range
partition step");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "no range partition to drop");
ASSERT_EQ(100, CountTableRows(table.get()));
// ADD [100, <max>)
@@ -1666,8 +1669,8 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
ASSERT_OK(lower->SetInt32("c0", 50));
table_alterer->DropRangePartition(lower.release(), upper.release());
s = table_alterer->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "No range partition found for drop range
partition step");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "no range partition to drop");
ASSERT_EQ(100, CountTableRows(table.get()));
// Setup for the next few test cases:
@@ -1691,8 +1694,8 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
ASSERT_OK(upper->SetInt32("c0", -50));
table_alterer->DropRangePartition(lower.release(), upper.release());
s = table_alterer->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "No range partition found for drop range
partition step");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "no range partition to drop");
ASSERT_EQ(100, CountTableRows(table.get()));
// DROP [<min>, 50] <- illegal
@@ -1702,8 +1705,8 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
ASSERT_OK(upper->SetInt32("c0", 50));
table_alterer->DropRangePartition(lower.release(), upper.release());
s = table_alterer->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "No range partition found for drop range
partition step");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "no range partition to drop");
ASSERT_EQ(100, CountTableRows(table.get()));
// DROP [150, <max>] <- illegal
@@ -1713,8 +1716,8 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
ASSERT_OK(lower->SetInt32("c0", 150));
table_alterer->DropRangePartition(lower.release(), upper.release());
s = table_alterer->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "No range partition found for drop range
partition step");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "no range partition to drop");
ASSERT_EQ(100, CountTableRows(table.get()));
// DROP [50, <max>] <- illegal
@@ -1724,8 +1727,8 @@ TEST_F(AlterTableTest, TestAlterRangePartitioningInvalid)
{
ASSERT_OK(lower->SetInt32("c0", 50));
table_alterer->DropRangePartition(lower.release(), upper.release());
s = table_alterer->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "No range partition found for drop range
partition step");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "no range partition to drop");
ASSERT_EQ(100, CountTableRows(table.get()));
// DROP [<min>, <max>] <- illegal
@@ -1734,15 +1737,15 @@ TEST_F(AlterTableTest,
TestAlterRangePartitioningInvalid) {
upper.reset(schema_.NewRow());
table_alterer->DropRangePartition(lower.release(), upper.release());
s = table_alterer->Alter();
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "No range partition found for drop range
partition step");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "no range partition to drop");
ASSERT_EQ(100, CountTableRows(table.get()));
// Bad arguments (null ranges)
table_alterer.reset(client_->NewTableAlterer(table_name));
table_alterer->DropRangePartition(nullptr, nullptr);
s = table_alterer->Alter();
- ASSERT_FALSE(s.ok());
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
ASSERT_STR_CONTAINS(s.ToString(), "range partition bounds may not be null");
}
@@ -1856,19 +1859,30 @@ TEST_F(AlterTableTest,
TestAddRangePartitionConflictExhaustive) {
// Add a then add b.
ASSERT_OK(add_range_partition(a_lower_bound, a_upper_bound));
- Status s = add_range_partition(b_lower_bound, b_upper_bound);
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(),
- "New range partition conflicts with existing range
partition");
+ auto s = add_range_partition(b_lower_bound, b_upper_bound);
+ if (a_lower_bound == b_lower_bound && a_upper_bound == b_upper_bound) {
+ ASSERT_TRUE(s.IsAlreadyPresent()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "range partition already exists");
+ } else {
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(),
+ "new range partition conflicts with existing one");
+ }
// Clean up by removing a.
ASSERT_OK(drop_range_partition(a_lower_bound, a_upper_bound));
// Add a and b in the same op.
s = add_range_partitions(a_lower_bound, a_upper_bound,
b_lower_bound, b_upper_bound);
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(),
- "New range partition conflicts with another new range
partition");
+ if (a_lower_bound == b_lower_bound && a_upper_bound == b_upper_bound) {
+ ASSERT_TRUE(s.IsAlreadyPresent()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(),
+ "new range partiton duplicates another newly added
one");
+ } else {
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(),
+ "new range partition conflicts with another newly
added one");
+ }
// To get some extra coverage of DROP RANGE PARTITION, check if the two
// ranges are not equal, and if so, check that adding one and dropping the
@@ -1878,17 +1892,16 @@ TEST_F(AlterTableTest,
TestAddRangePartitionConflictExhaustive) {
// Add a then drop b.
ASSERT_OK(add_range_partition(a_lower_bound, a_upper_bound));
Status s = drop_range_partition(b_lower_bound, b_upper_bound);
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(), "No range partition found for drop
range partition step");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "no range partition to drop");
// Clean up by removing a.
ASSERT_OK(drop_range_partition(a_lower_bound, a_upper_bound));
// Add a and drop b in a single op.
s = add_drop_range_partitions(a_lower_bound, a_upper_bound,
b_lower_bound, b_upper_bound);
- ASSERT_FALSE(s.ok());
- ASSERT_STR_CONTAINS(s.ToString(),
- "No range partition found for drop range partition
step");
+ ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_STR_CONTAINS(s.ToString(), "no range partition to drop");
}
};
diff --git a/src/kudu/integration-tests/txn_status_table-itest.cc
b/src/kudu/integration-tests/txn_status_table-itest.cc
index 3d85b7e..7674d55 100644
--- a/src/kudu/integration-tests/txn_status_table-itest.cc
+++ b/src/kudu/integration-tests/txn_status_table-itest.cc
@@ -326,7 +326,7 @@ TEST_F(TxnStatusTableITest,
TestCreateTxnStatusTablePartitions) {
// Now add more partitions and try again.
ASSERT_OK(txn_sys_client_->AddTxnStatusTableRange(100, 200));
s = txn_sys_client_->AddTxnStatusTableRange(100, 200);
- ASSERT_TRUE(s.IsInvalidArgument()) << s.ToString();
+ ASSERT_TRUE(s.IsAlreadyPresent()) << s.ToString();
NO_FATALS(CheckTableTypes({ { TableTypePB::TXN_STATUS_TABLE, 2 } }));
// Ensure we still create transaction status tablets even after the master is
diff --git a/src/kudu/master/catalog_manager.cc
b/src/kudu/master/catalog_manager.cc
index 5438e41..9475fa4 100644
--- a/src/kudu/master/catalog_manager.cc
+++ b/src/kudu/master/catalog_manager.cc
@@ -2431,8 +2431,9 @@ Status CatalogManager::ApplyAlterPartitioningSteps(
}
if (ops.size() != 2) {
- return Status::InvalidArgument("expected two row operations for alter
range partition step",
- SecureShortDebugString(step));
+ return Status::InvalidArgument(
+ "expected two row operations for alter range partition step",
+ SecureShortDebugString(step));
}
if ((ops[0].type != RowOperationsPB::RANGE_LOWER_BOUND &&
@@ -2441,7 +2442,7 @@ Status CatalogManager::ApplyAlterPartitioningSteps(
ops[1].type != RowOperationsPB::INCLUSIVE_RANGE_UPPER_BOUND)) {
return Status::InvalidArgument(
"expected a lower bound and upper bound row op for alter range
partition step",
- strings::Substitute("$0, $1", ops[0].ToString(schema),
ops[1].ToString(schema)));
+ Substitute("$0, $1", ops[0].ToString(schema),
ops[1].ToString(schema)));
}
if (ops[0].type == RowOperationsPB::EXCLUSIVE_RANGE_LOWER_BOUND) {
@@ -2454,65 +2455,97 @@ Status CatalogManager::ApplyAlterPartitioningSteps(
}
vector<Partition> partitions;
- RETURN_NOT_OK(partition_schema.CreatePartitions({}, {{ *ops[0].split_row,
*ops[1].split_row }},
- schema, &partitions));
-
+ RETURN_NOT_OK(partition_schema.CreatePartitions(
+ {}, {{ *ops[0].split_row, *ops[1].split_row }}, schema, &partitions));
switch (step.type()) {
case AlterTableRequestPB::ADD_RANGE_PARTITION: {
for (const Partition& partition : partitions) {
const string& lower_bound = partition.partition_key_start();
const string& upper_bound = partition.partition_key_end();
- // Check that the new tablet doesn't overlap with the existing
tablets.
- // Iter points at the tablet directly *after* the lower bound (or to
- // existing_tablets.end(), if such a tablet does not exist).
- auto existing_iter = existing_tablets.upper_bound(lower_bound);
+ // Check that the new tablet does not overlap with any of the
existing
+ // tablets. Since the elements of 'existing_tablets' are ordered by
+ // the tablets' lower bounds, the iterator points at the tablet
+ // directly *after* the lower bound or to existing_tablets.end()
+ // if such a tablet does not exist.
+ const auto existing_iter = existing_tablets.upper_bound(lower_bound);
if (existing_iter != existing_tablets.end()) {
- TabletMetadataLock metadata(existing_iter->second.get(),
LockMode::READ);
- if (upper_bound.empty() ||
- metadata.data().pb.partition().partition_key_start() <
upper_bound) {
+ TabletMetadataLock metadata(existing_iter->second.get(),
+ LockMode::READ);
+ const auto& p = metadata.data().pb.partition();
+ // Check for the overlapping ranges.
+ if (upper_bound.empty() || p.partition_key_start() < upper_bound) {
return Status::InvalidArgument(
- "New range partition conflicts with existing range
partition",
-
partition_schema.RangePartitionDebugString(*ops[0].split_row,
*ops[1].split_row));
+ "new range partition conflicts with existing one",
+ partition_schema.RangePartitionDebugString(*ops[0].split_row,
+
*ops[1].split_row));
}
}
+ // This is the case when there is an existing tablet with the lower
+ // bound being less or equal to the lower bound of the new tablet to
+ // create. This cannot be the case of an empty 'existing_tablets'
+ // container (otherwise, existing_tablets.end() would be equal to
+ // existing_tablets.begin()), so it's safe to decrement the iterator
+ // (i.e. call std::prev() on it) and de-reference it.
if (existing_iter != existing_tablets.begin()) {
TabletMetadataLock metadata(std::prev(existing_iter)->second.get(),
LockMode::READ);
- if (metadata.data().pb.partition().partition_key_end().empty() ||
- metadata.data().pb.partition().partition_key_end() >
lower_bound) {
+ const auto& p = metadata.data().pb.partition();
+ // Check for the exact match of ranges.
+ if (lower_bound == p.partition_key_start() &&
+ upper_bound == p.partition_key_end()) {
+ return Status::AlreadyPresent(
+ "range partition already exists",
+ partition_schema.RangePartitionDebugString(*ops[0].split_row,
+
*ops[1].split_row));
+ }
+ // Check for the overlapping ranges.
+ if (p.partition_key_end().empty() ||
+ p.partition_key_end() > lower_bound) {
return Status::InvalidArgument(
- "New range partition conflicts with existing range
partition",
-
partition_schema.RangePartitionDebugString(*ops[0].split_row,
*ops[1].split_row));
+ "new range partition conflicts with existing one",
+ partition_schema.RangePartitionDebugString(*ops[0].split_row,
+
*ops[1].split_row));
}
}
// Check that the new tablet doesn't overlap with any other new
tablets.
auto new_iter = new_tablets.upper_bound(lower_bound);
if (new_iter != new_tablets.end()) {
- const auto& metadata =
new_iter->second->mutable_metadata()->dirty();
- if (upper_bound.empty() ||
- metadata.pb.partition().partition_key_start() < upper_bound) {
+ // Check for the overlapping ranges.
+ const auto& p =
new_iter->second->mutable_metadata()->dirty().pb.partition();
+ if (upper_bound.empty() || p.partition_key_start() < upper_bound) {
return Status::InvalidArgument(
- "New range partition conflicts with another new range
partition",
-
partition_schema.RangePartitionDebugString(*ops[0].split_row,
*ops[1].split_row));
+ "new range partition conflicts with another newly added one",
+ partition_schema.RangePartitionDebugString(*ops[0].split_row,
+
*ops[1].split_row));
}
}
if (new_iter != new_tablets.begin()) {
- const auto& metadata =
std::prev(new_iter)->second->mutable_metadata()->dirty();
- if (metadata.pb.partition().partition_key_end().empty() ||
- metadata.pb.partition().partition_key_end() > lower_bound) {
+ const auto& p =
std::prev(new_iter)->second->mutable_metadata()->dirty().pb.partition();
+ // Check for the exact match of ranges.
+ if (lower_bound == p.partition_key_start() &&
+ upper_bound == p.partition_key_end()) {
+ return Status::AlreadyPresent(
+ "new range partiton duplicates another newly added one",
+ partition_schema.RangePartitionDebugString(*ops[0].split_row,
+
*ops[1].split_row));
+ }
+ // Check for the overlapping ranges.
+ if (p.partition_key_end().empty() || p.partition_key_end() >
lower_bound) {
return Status::InvalidArgument(
- "New range partition conflicts with another new range
partition",
-
partition_schema.RangePartitionDebugString(*ops[0].split_row,
*ops[1].split_row));
+ "new range partition conflicts with another newly added one",
+ partition_schema.RangePartitionDebugString(*ops[0].split_row,
+
*ops[1].split_row));
}
}
- PartitionPB partition_pb;
- partition.ToPB(&partition_pb);
- const optional<string> dimension_label =
step.add_range_partition().has_dimension_label()
+ const optional<string> dimension_label =
+ step.add_range_partition().has_dimension_label()
? make_optional(step.add_range_partition().dimension_label())
: none;
+ PartitionPB partition_pb;
+ partition.ToPB(&partition_pb);
new_tablets.emplace(lower_bound,
CreateTabletInfo(table, partition_pb,
dimension_label));
}
@@ -2551,15 +2584,15 @@ Status CatalogManager::ApplyAlterPartitioningSteps(
new_iter->second->mutable_metadata()->AbortMutation();
new_tablets.erase(new_iter);
} else {
- return Status::InvalidArgument(
- "No range partition found for drop range partition step",
- partition_schema.RangePartitionDebugString(*ops[0].split_row,
*ops[1].split_row));
+ return Status::InvalidArgument("no range partition to drop",
+ partition_schema.RangePartitionDebugString(*ops[0].split_row,
+ *ops[1].split_row));
}
}
break;
}
default: {
- return Status::InvalidArgument("Unknown alter table range partitioning
step",
+ return Status::InvalidArgument("unknown alter table range partitioning
step",
SecureShortDebugString(step));
}
}