You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by al...@apache.org on 2023/04/01 05:15:13 UTC

[kudu] branch master updated: [rowset_metadata] update min/max encoded keys during bootstrapping

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 b00431df6 [rowset_metadata] update min/max encoded keys during bootstrapping
b00431df6 is described below

commit b00431df6d2e084f1866924c609591344e7a47d0
Author: kedeng <kd...@gmail.com>
AuthorDate: Fri Mar 24 10:54:42 2023 +0800

    [rowset_metadata] update min/max encoded keys during bootstrapping
    
    We can cache the encoded min/max keys in rowset metadata to help
    tablets to bootstrap without having to fully initialize the CFileReaders
    for the key columns of each rowset. However, we can only update the
    min/max encoded keys during insert or update operations right now.
    This means that if we didn't save the min/max encoded key before,
    we won't have the opportunity to use this feature to accelerate bootstrap
    in the future.
    
    Considering that we will read the min/max key values during the bootstrap
    process, we can set the min/max encoded keys in the metadata at the same
    time.
    
    I added a small test case to ensure we can get the same keys from the bootstrap
    process at startup.
    
    Change-Id: I1b7ed75bdf7a2ff0e16c2670f1a6f9819ee8e8d3
    Reviewed-on: http://gerrit.cloudera.org:8080/19650
    Tested-by: Kudu Jenkins
    Reviewed-by: Yuqi Du <sh...@gmail.com>
    Reviewed-by: Yingchun Lai <la...@apache.org>
    Reviewed-by: Alexey Serbin <al...@apache.org>
---
 src/kudu/tablet/cfile_set.cc           |  7 +++
 src/kudu/tablet/cfile_set.h            |  8 ++-
 src/kudu/tablet/diskrowset.h           |  5 ++
 src/kudu/tablet/tablet.h               |  5 ++
 src/kudu/tserver/tablet_server-test.cc | 99 ++++++++++++++++++++++++++++++++--
 5 files changed, 119 insertions(+), 5 deletions(-)

diff --git a/src/kudu/tablet/cfile_set.cc b/src/kudu/tablet/cfile_set.cc
index 7620eea51..ab46bf3aa 100644
--- a/src/kudu/tablet/cfile_set.cc
+++ b/src/kudu/tablet/cfile_set.cc
@@ -170,6 +170,7 @@ Status CFileSet::DoOpen(const IOContext* io_context) {
   } else {
     RETURN_NOT_OK(LoadMinMaxKeys(io_context));
   }
+
   // Verify the loaded keys are valid.
   if (Slice(min_encoded_key_) > max_encoded_key_) {
     return Status::Corruption(Substitute("Min key $0 > max key $1",
@@ -178,6 +179,12 @@ Status CFileSet::DoOpen(const IOContext* io_context) {
                               ToString());
   }
 
+  // Update the min/max key in metadata explicitly if user specified.
+  if (FLAGS_rowset_metadata_store_keys && !rowset_metadata_->has_encoded_keys()) {
+    rowset_metadata_->set_min_encoded_key(min_encoded_key_);
+    rowset_metadata_->set_max_encoded_key(max_encoded_key_);
+  }
+
   return Status::OK();
 }
 
diff --git a/src/kudu/tablet/cfile_set.h b/src/kudu/tablet/cfile_set.h
index 7a119c4c6..f8730686e 100644
--- a/src/kudu/tablet/cfile_set.h
+++ b/src/kudu/tablet/cfile_set.h
@@ -21,6 +21,7 @@
 #include <memory>
 #include <optional>
 #include <string>
+#include <type_traits>
 #include <utility>
 #include <vector>
 
@@ -36,7 +37,7 @@
 #include "kudu/gutil/macros.h"
 #include "kudu/gutil/map-util.h"
 #include "kudu/gutil/port.h"
-#include "kudu/tablet/rowset_metadata.h"
+#include "kudu/tablet/rowset_metadata.h" // IWYU pragma: keep
 #include "kudu/util/make_shared.h"
 #include "kudu/util/memory/arena.h"
 #include "kudu/util/status.h"
@@ -57,6 +58,10 @@ namespace fs {
 struct IOContext;
 }  // namespace fs
 
+namespace tserver {
+class TabletServerTest_SetEncodedKeysWhenStartingUp_Test;
+} // namespace tserver
+
 namespace tablet {
 
 class RowSetKeyProbe;
@@ -134,6 +139,7 @@ class CFileSet :
 
  private:
   friend class Iterator;
+  FRIEND_TEST(tserver::TabletServerTest, SetEncodedKeysWhenStartingUp);
 
   DISALLOW_COPY_AND_ASSIGN(CFileSet);
 
diff --git a/src/kudu/tablet/diskrowset.h b/src/kudu/tablet/diskrowset.h
index ce7184822..da5236379 100644
--- a/src/kudu/tablet/diskrowset.h
+++ b/src/kudu/tablet/diskrowset.h
@@ -79,6 +79,10 @@ namespace log {
 class LogAnchorRegistry;
 }
 
+namespace tserver {
+class TabletServerTest_SetEncodedKeysWhenStartingUp_Test;
+} // namespace tserver
+
 namespace tools {
 Status DumpRowSetInternal(const fs::IOContext& ctx,
                           const std::shared_ptr<tablet::RowSetMetadata>& rs_meta,
@@ -478,6 +482,7 @@ class DiskRowSet :
   FRIEND_TEST(TestCompaction, TestOneToOne);
   FRIEND_TEST(TestRowSet, TestRowSetUpdate);
   FRIEND_TEST(TestRowSet, TestDMSFlush);
+  FRIEND_TEST(tserver::TabletServerTest, SetEncodedKeysWhenStartingUp);
 
   friend class CompactionInput;
   friend class Tablet;
diff --git a/src/kudu/tablet/tablet.h b/src/kudu/tablet/tablet.h
index 2bdf6dc34..04c213955 100644
--- a/src/kudu/tablet/tablet.h
+++ b/src/kudu/tablet/tablet.h
@@ -82,6 +82,10 @@ namespace log {
 class LogAnchorRegistry;
 } // namespace log
 
+namespace tserver {
+class TabletServerTest_SetEncodedKeysWhenStartingUp_Test;
+} // namespace tserver
+
 namespace tablet {
 
 class AlterSchemaOpState;
@@ -562,6 +566,7 @@ class Tablet {
   FRIEND_TEST(TestTabletStringKey, TestSplitKeyRangeWithNonOverlappingRowSets);
   FRIEND_TEST(TestTabletStringKey, TestSplitKeyRangeWithMinimumValueRowSet);
   FRIEND_TEST(TxnParticipantTest, TestFlushMultipleMRSs);
+  FRIEND_TEST(tserver::TabletServerTest, SetEncodedKeysWhenStartingUp);
 
   // Lifecycle states that a Tablet can be in. Legal state transitions for a
   // Tablet object:
diff --git a/src/kudu/tserver/tablet_server-test.cc b/src/kudu/tserver/tablet_server-test.cc
index 4916d796a..5a626096f 100644
--- a/src/kudu/tserver/tablet_server-test.cc
+++ b/src/kudu/tserver/tablet_server-test.cc
@@ -82,8 +82,11 @@
 #include "kudu/server/rpc_server.h"
 #include "kudu/server/server_base.pb.h"
 #include "kudu/server/server_base.proxy.h"
+#include "kudu/tablet/diskrowset.h"
 #include "kudu/tablet/local_tablet_writer.h"
 #include "kudu/tablet/metadata.pb.h"
+#include "kudu/tablet/rowset.h"
+#include "kudu/tablet/rowset_tree.h" // IWYU pragma: keep
 #include "kudu/tablet/tablet.h"
 #include "kudu/tablet/tablet_metadata.h"
 #include "kudu/tablet/tablet_metrics.h"
@@ -237,10 +240,6 @@ METRIC_DECLARE_histogram(op_apply_queue_time);
 
 namespace kudu {
 
-namespace tablet {
-class RowSet;
-}
-
 namespace tserver {
 
 class TabletServerTest : public TabletServerTestBase {
@@ -4610,6 +4609,98 @@ TEST_F(TabletServerTest, TestKeysInRowsetMetadataPreventStartupSeeks) {
   restart_server_and_check_bytes_read(/*keys_in_rowset_meta=*/ true);
 }
 
+TEST_F(TabletServerTest, SetEncodedKeysWhenStartingUp) {
+  // Don't write the min/max keys to the rowset metadata.
+  // So we can test the min/max encoded key load and set
+  // it to the rowset metadata when restarting.
+  FLAGS_rowset_metadata_store_keys = false;
+  InsertTestRowsDirect(0, 100);
+  ASSERT_OK(tablet_replica_->tablet()->Flush());
+
+  // Disable the maintenance manager so we don't get any seeks from
+  // maintenance operations when we restart.
+  FLAGS_enable_maintenance_manager = false;
+  TabletSuperBlockPB superblock_pb;
+  tablet_replica_->tablet()->metadata()->ToSuperBlock(&superblock_pb);
+  // Make sure the min/max key do not exist in the rowset metadata.
+  for (int rowset_no = 0; rowset_no < superblock_pb.rowsets_size(); rowset_no++) {
+    RowSetDataPB* rowset_pb = superblock_pb.mutable_rowsets(rowset_no);
+    ASSERT_FALSE(rowset_pb->has_min_encoded_key());
+    ASSERT_FALSE(rowset_pb->has_max_encoded_key());
+  }
+  {
+    scoped_refptr<tablet::TabletComponents> comps;
+    tablet_replica_->tablet()->GetComponents(&comps);
+    for (const auto &rowset : comps->rowsets->all_rowsets()) {
+      ASSERT_FALSE(rowset->metadata()->has_encoded_keys());
+    }
+  }
+
+  // Used to record the min/max encoded key value in memory when we restart.
+  string min_key;
+  string max_key;
+
+  const auto restart_server_and_check_encoded_key = [&] (bool set_keys_during_restart,
+                                                         string* min_key,
+                                                         string* max_key) {
+    FLAGS_rowset_metadata_store_keys = set_keys_during_restart;
+    // Reset the replica to avoid any lingering references.
+    // Restart the server and wait for the tablet to bootstrap.
+    tablet_replica_.reset();
+    mini_server_->Shutdown();
+
+    ASSERT_OK(mini_server_->Restart());
+    ASSERT_OK(mini_server_->WaitStarted());
+
+    ASSERT_OK(mini_server_->server()->tablet_manager()->GetTabletReplica(kTabletId,
+                                                                         &tablet_replica_));
+    scoped_refptr<tablet::TabletComponents> comps;
+    tablet_replica_->tablet()->GetComponents(&comps);
+    if (!set_keys_during_restart) {
+      // We can get the encoded min/max value from the 'CFileSet'.
+      const auto& rowsets = comps->rowsets->all_rowsets();
+      ASSERT_EQ(1, rowsets.size());
+      auto const& rs = rowsets[0];
+      auto* dsr = down_cast<tablet::DiskRowSet*>(rs.get());
+      ASSERT_FALSE(dsr->base_data_->min_encoded_key_.empty());
+      ASSERT_FALSE(dsr->base_data_->max_encoded_key_.empty());
+      *min_key = dsr->base_data_->min_encoded_key_;
+      *max_key = dsr->base_data_->max_encoded_key_;
+    } else {
+      for (const auto &rowset : comps->rowsets->all_rowsets()) {
+        ASSERT_TRUE(rowset->metadata()->has_encoded_keys());
+        ASSERT_EQ(*min_key, rowset->metadata()->min_encoded_key());
+        ASSERT_EQ(*max_key, rowset->metadata()->max_encoded_key());
+      }
+    }
+
+    TabletSuperBlockPB superblock_pb;
+    tablet_replica_->tablet()->metadata()->ToSuperBlock(&superblock_pb);
+    for (int rowset_no = 0; rowset_no < superblock_pb.rowsets_size(); rowset_no++) {
+      RowSetDataPB* rowset_pb = superblock_pb.mutable_rowsets(rowset_no);
+      if (set_keys_during_restart) {
+        ASSERT_TRUE(rowset_pb->has_min_encoded_key());
+        ASSERT_TRUE(rowset_pb->has_max_encoded_key());
+        // The encoded key is same to the load.
+        ASSERT_EQ(*min_key, rowset_pb->min_encoded_key());
+        ASSERT_EQ(*max_key, rowset_pb->max_encoded_key());
+      } else {
+        // The encoded key doesn't exist without --rowset_metadata_store_keys set.
+        ASSERT_FALSE(rowset_pb->has_min_encoded_key());
+        ASSERT_FALSE(rowset_pb->has_max_encoded_key());
+      }
+    }
+  };
+
+  // Test both reading and not reading the keys from the rowset metadata,
+  // making sure we can get the encoded keys if we set the --rowset_metadata_store_keys
+  // flag.
+  restart_server_and_check_encoded_key(/*set_keys_during_restart=*/ false,
+                                       &min_key, &max_key);
+  restart_server_and_check_encoded_key(/*set_keys_during_restart=*/ true,
+                                       &min_key, &max_key);
+}
+
 // Test that each scanner can only be accessed by the user who created it.
 TEST_F(TabletServerTest, TestScannerCheckMatchingUser) {
   rpc::UserCredentials user;