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 89e1ee320 KUDU-3326 [master] add flag 
FLAGS_deleted_table_reserve_seconds to change the cluster-wide behavior of the 
DeleteTable() RPC.
89e1ee320 is described below

commit 89e1ee3202b47e0f0e247ae7beb91ac344a012a6
Author: kedeng <[email protected]>
AuthorDate: Fri Aug 19 11:03:25 2022 +0800

    KUDU-3326 [master] add flag FLAGS_deleted_table_reserve_seconds to change 
the cluster-wide
    behavior of the DeleteTable() RPC.
    
    This patch helps to change the default behavior of the DeleteTable RPC at 
the master side.
    Value 0 means DeleteTable() works the regular way, i.e. dropping the table 
and purging its
    data immediately. If it's set to anything greater than 0, then all 
DeleteTable() RPCs are
    turned into SoftDeleteTable(..., FLAGS_deleted_table_reserve_seconds)").
    
    NOTE: this flag is useless if HMS is enabled.
    
    Change-Id: I7cf3021fa0e9a425d5f8091ea3336c55a3c14bbc
    Reviewed-on: http://gerrit.cloudera.org:8080/18864
    Tested-by: Kudu Jenkins
    Reviewed-by: Yingchun Lai <[email protected]>
    Reviewed-by: Alexey Serbin <[email protected]>
---
 src/kudu/client/client-test.cc     | 126 +++++++++++++++++++++++++++++++++++++
 src/kudu/master/catalog_manager.cc |  41 ++++++++++--
 2 files changed, 162 insertions(+), 5 deletions(-)

diff --git a/src/kudu/client/client-test.cc b/src/kudu/client/client-test.cc
index d97d87ebe..f8eef831d 100644
--- a/src/kudu/client/client-test.cc
+++ b/src/kudu/client/client-test.cc
@@ -187,6 +187,7 @@ DECLARE_uint32(txn_keepalive_interval_ms);
 DECLARE_uint32(txn_staleness_tracker_interval_ms);
 DECLARE_uint32(txn_manager_status_table_num_replicas);
 DEFINE_int32(test_scan_num_rows, 1000, "Number of rows to insert and scan");
+DECLARE_uint32(default_deleted_table_reserve_seconds);
 
 METRIC_DECLARE_counter(block_manager_total_bytes_read);
 METRIC_DECLARE_counter(location_mapping_cache_hits);
@@ -5239,6 +5240,131 @@ TEST_F(ClientTest, 
TestSoftDeleteAndRecallAfterReserveTimeTable) {
   ASSERT_TRUE(tables.empty());
 }
 
+TEST_F(ClientTest, TestDeleteWithDeletedTableReserveSeconds) {
+  // Open the table before deleting it.
+  ASSERT_OK(client_->OpenTable(kTableName, &client_table_));
+
+  // Insert a few rows, and scan them back. This is to populate the MetaCache.
+  NO_FATALS(InsertTestRows(client_.get(), client_table_.get(), 10));
+  vector<string> rows;
+  ScanTableToStrings(client_table_.get(), &rows);
+  ASSERT_EQ(10, rows.size());
+
+  ASSERT_EQ(0, FLAGS_default_deleted_table_reserve_seconds);
+  FLAGS_default_deleted_table_reserve_seconds = 60;
+
+  // Delete the table, the table won't be purged immediately if
+  // FLAGS_default_deleted_table_reserve_seconds set to anything greater than 
0.
+  ASSERT_OK(client_->DeleteTable(kTableName));
+  CatalogManager *catalog_manager = 
cluster_->mini_master()->master()->catalog_manager();
+  {
+    CatalogManager::ScopedLeaderSharedLock l(catalog_manager);
+    ASSERT_OK(l.first_failed_status());
+    bool exists;
+    ASSERT_OK(catalog_manager->TableNameExists(kTableName, &exists));
+    ASSERT_TRUE(exists);
+  }
+
+  // The table is in soft-deleted state.
+  vector<string> tables;
+  ASSERT_OK(client_->ListSoftDeletedTables(&tables));
+  ASSERT_EQ(1, tables.size());
+  ASSERT_EQ(kTableName, tables[0]);
+  ASSERT_OK(client_->ListTables(&tables));
+  ASSERT_EQ(0, tables.size());
+
+  // Try to recall the table.
+  ASSERT_OK(client_->RecallTable(client_table_->id()));
+
+  // Check the data in the table.
+  ScanTableToStrings(client_table_.get(), &rows);
+  ASSERT_EQ(10, rows.size());
+
+  // Force to delete the table with 
FLAGS_default_deleted_table_reserve_seconds set to 0.
+  FLAGS_default_deleted_table_reserve_seconds = 0;
+  ASSERT_OK(client_->DeleteTable(kTableName));
+
+  // No tables left.
+  ASSERT_OK(client_->ListTables(&tables));
+  ASSERT_TRUE(tables.empty());
+  ASSERT_OK(client_->ListSoftDeletedTables(&tables));
+  ASSERT_TRUE(tables.empty());
+}
+
+TEST_F(ClientTest, TestDeleteWithDeletedTableReserveSecondsWorks) {
+  SKIP_IF_SLOW_NOT_ALLOWED();
+  // Open the table before deleting it.
+  ASSERT_OK(client_->OpenTable(kTableName, &client_table_));
+
+  ASSERT_EQ(0, FLAGS_default_deleted_table_reserve_seconds);
+  FLAGS_default_deleted_table_reserve_seconds = 5;
+
+  // Delete the table, the table won't be purged immediately if
+  // FLAGS_default_deleted_table_reserve_seconds set to anything greater than 
0.
+  ASSERT_OK(client_->DeleteTable(kTableName));
+  CatalogManager *catalog_manager = 
cluster_->mini_master()->master()->catalog_manager();
+  {
+    CatalogManager::ScopedLeaderSharedLock l(catalog_manager);
+    ASSERT_OK(l.first_failed_status());
+    bool exists;
+    ASSERT_OK(catalog_manager->TableNameExists(kTableName, &exists));
+    ASSERT_TRUE(exists);
+  }
+
+  // The table is in soft-deleted state.
+  vector<string> tables;
+  ASSERT_OK(client_->ListSoftDeletedTables(&tables));
+  ASSERT_EQ(1, tables.size());
+  ASSERT_EQ(kTableName, tables[0]);
+  ASSERT_OK(client_->ListTables(&tables));
+  ASSERT_TRUE(tables.empty());
+
+  // Test FLAGS_table_reserve_seconds.
+  SleepFor(MonoDelta::FromMilliseconds(5 * 1000));
+
+  // No tables left.
+  ASSERT_OK(client_->ListTables(&tables));
+  ASSERT_TRUE(tables.empty());
+  ASSERT_OK(client_->ListSoftDeletedTables(&tables));
+  ASSERT_TRUE(tables.empty());
+}
+
+TEST_F(ClientTest, TestDeleteSoftDeleteStatusFromDeletedTableReserveSeconds) {
+  // Open the table before deleting it.
+  ASSERT_OK(client_->OpenTable(kTableName, &client_table_));
+
+  ASSERT_EQ(0, FLAGS_default_deleted_table_reserve_seconds);
+  FLAGS_default_deleted_table_reserve_seconds = 600;
+
+  // Get a soft-deleted table.
+  ASSERT_OK(client_->SoftDeleteTable(kTableName, 60));
+  CatalogManager *catalog_manager = 
cluster_->mini_master()->master()->catalog_manager();
+  {
+    CatalogManager::ScopedLeaderSharedLock l(catalog_manager);
+    ASSERT_OK(l.first_failed_status());
+    bool exists;
+    ASSERT_OK(catalog_manager->TableNameExists(kTableName, &exists));
+    ASSERT_TRUE(exists);
+  }
+
+  // The table is in soft-deleted state.
+  vector<string> tables;
+  ASSERT_OK(client_->ListSoftDeletedTables(&tables));
+  ASSERT_EQ(1, tables.size());
+  ASSERT_EQ(kTableName, tables[0]);
+  ASSERT_OK(client_->ListTables(&tables));
+  ASSERT_TRUE(tables.empty());
+
+  // purge the soft-deleted table
+  ASSERT_OK(client_->DeleteTable(kTableName));
+
+  // No tables left.
+  ASSERT_OK(client_->ListTables(&tables));
+  ASSERT_TRUE(tables.empty());
+  ASSERT_OK(client_->ListSoftDeletedTables(&tables));
+  ASSERT_TRUE(tables.empty());
+}
+
 TEST_F(ClientTest, TestGetTableSchema) {
   KuduSchema schema;
 
diff --git a/src/kudu/master/catalog_manager.cc 
b/src/kudu/master/catalog_manager.cc
index 76397ee3e..d16447acd 100644
--- a/src/kudu/master/catalog_manager.cc
+++ b/src/kudu/master/catalog_manager.cc
@@ -407,6 +407,32 @@ 
DEFINE_bool(require_new_spec_for_custom_hash_schema_range_bound, false,
 TAG_FLAG(require_new_spec_for_custom_hash_schema_range_bound, experimental);
 TAG_FLAG(require_new_spec_for_custom_hash_schema_range_bound, runtime);
 
+DEFINE_uint32(default_deleted_table_reserve_seconds, 0,
+              "Time in seconds to be reserved before purging a deleted table 
for the table "
+              "from DeleteTable request. Value 0 means DeleteTable() works the 
regular way, "
+              "i.e. dropping the table and purging its data immediately. If 
it's set to "
+              "anything greater than 0, then all DeleteTable() RPCs are turned 
into "
+              "SoftDeleteTable(..., 
FLAGS_default_deleted_table_reserve_seconds). "
+              "NOTE : this flag make no sense for soft-delete function because 
the "
+              "reserve_seconds has been specified by user while calling 
SoftDeleteTable.");
+TAG_FLAG(default_deleted_table_reserve_seconds, advanced);
+TAG_FLAG(default_deleted_table_reserve_seconds, runtime);
+
+DECLARE_string(hive_metastore_uris);
+
+bool ValidateDeletedTableReserveSeconds()  {
+  if (FLAGS_default_deleted_table_reserve_seconds > 0 &&
+      !FLAGS_hive_metastore_uris.empty()) {
+    LOG(ERROR) << "If enabling HMS, 
FLAGS_default_deleted_table_reserve_seconds "
+                  "makes no sense.";
+    return false;
+  }
+  return true;
+}
+
+GROUP_FLAG_VALIDATOR(default_deleted_table_reserve_seconds,
+                     ValidateDeletedTableReserveSeconds);
+
 DECLARE_bool(raft_prepare_replacement_before_eviction);
 DECLARE_int64(tsk_rotation_seconds);
 DECLARE_string(ranger_config_path);
@@ -2391,8 +2417,11 @@ Status CatalogManager::SoftDeleteTableRpc(const 
DeleteTableRequestPB& req,
         resp, MasterErrorPB::TABLE_SOFT_DELETED);
   }
 
-  // Reserve seconds equal 0 means delete it directly.
-  if (req.reserve_seconds() == 0) {
+  // Reserve seconds equal 0 means delete it directly if 
default_deleted_table_reserve_seconds
+  // set to 0, which means the cluster-wide behavior of the DeleteTable() RPC 
is keep default,
+  // or the table is in soft-deleted status.
+  if (req.reserve_seconds() == 0 &&
+      (FLAGS_default_deleted_table_reserve_seconds == 0 || 
is_soft_deleted_table)) {
     return DeleteTableRpc(req, resp, rpc);
   }
 
@@ -2401,8 +2430,8 @@ Status CatalogManager::SoftDeleteTableRpc(const 
DeleteTableRequestPB& req,
 }
 
 Status CatalogManager::SoftDeleteTable(const DeleteTableRequestPB& req,
-                                      DeleteTableResponsePB* resp,
-                                      rpc::RpcContext* rpc) {
+                                       DeleteTableResponsePB* resp,
+                                       rpc::RpcContext* rpc) {
   leader_lock_.AssertAcquiredForReading();
 
   // TODO(kedeng) : soft_deleted state need sync to HMS.
@@ -2437,7 +2466,9 @@ Status CatalogManager::SoftDeleteTable(const 
DeleteTableRequestPB& req,
   // soft delete state change
   l.mutable_data()->set_state(SysTablesEntryPB::SOFT_DELETED, deletion_msg);
   l.mutable_data()->set_delete_timestamp(WallTime_Now());
-  l.mutable_data()->set_soft_deleted_reserved_seconds(req.reserve_seconds());
+  uint32_t reserve_seconds = req.reserve_seconds() == 0 ?
+      FLAGS_default_deleted_table_reserve_seconds : req.reserve_seconds();
+  l.mutable_data()->set_soft_deleted_reserved_seconds(reserve_seconds);
 
   // 2. Look up the tablets, lock them, and mark them as soft deleted.
   {

Reply via email to