You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by jd...@apache.org on 2017/04/06 21:46:05 UTC

kudu git commit: KUDU-1607. Unpin tablet flush after failed bootstrap

Repository: kudu
Updated Branches:
  refs/heads/branch-1.3.x 54e60d1a1 -> 9eebcdc79


KUDU-1607. Unpin tablet flush after failed bootstrap

We have heard reports that, in certain scenarios, a failed tablet is
unable to be deleted. After some investigation, I determined that this
is because we neglect to unpin the Tablet when tablet bootstrap fails.

When a table is being deleted, we delete each tablet superblock by
calling TabletMetadata::DeleteSuperBlock(). This method double-checks
that no orphaned blocks remain referenced to ensure we don't leak disk
space. That requires TabletMetadata::DeleteTabletData() to be called
first, which invokes Flush() twice to ensure that no orphaned blocks are
referenced on disk upon returning. However, if the tablet is pinned,
Flush() silently becomes a no-op (except for a log message that is
printed) and so DeleteSuperBlock() also fails, resulting in the tablet
not being fully deleted and the following warning message being written
to the log file:

W0317 13:05:19.324373 13242 ts_tablet_manager.cc:634] Invalid argument: Unable to delete on-disk data from tablet d1b857ddaa0743c79c9bcbd9b2fda174: The metadata for tablet d1b857ddaa0743c79c9bcbd9b2fda174 still references orphaned blocks. Call DeleteTabletData() first

This patch makes the following changes:

1. Always unpin the tablet after pinning it.
2. Add a new itest that fails without that change, reproducing the
   above warning message.
3. Add a little more test infra to MiniCluster (and the MiniClusterBase
   interface) to make it easier to use the helper functions in
   cluster_itest_util.h in MiniCluster-based itests.

Change-Id: Id274c6ee1da75bc6f92ab91c0a01edaa009b8962
Reviewed-on: http://gerrit.cloudera.org:8080/6422
Tested-by: Kudu Jenkins
Reviewed-by: David Ribeiro Alves <dr...@apache.org>
(cherry picked from commit 0450f77f69c74cc6dec08ad36bb89ac12c17608f)
Reviewed-on: http://gerrit.cloudera.org:8080/6545
Reviewed-by: Jean-Daniel Cryans <jd...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/9eebcdc7
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/9eebcdc7
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/9eebcdc7

Branch: refs/heads/branch-1.3.x
Commit: 9eebcdc7974bca215b6ecdb32d78a4d10713fc2b
Parents: 54e60d1
Author: Mike Percy <mp...@apache.org>
Authored: Fri Mar 17 15:19:36 2017 -0700
Committer: Jean-Daniel Cryans <jd...@apache.org>
Committed: Thu Apr 6 21:45:00 2017 +0000

----------------------------------------------------------------------
 src/kudu/integration-tests/CMakeLists.txt       |   1 +
 .../integration-tests/delete_tablet-itest.cc    | 106 +++++++++++++++++++
 .../integration-tests/external_mini_cluster.cc  |   6 +-
 .../integration-tests/external_mini_cluster.h   |  22 +---
 src/kudu/integration-tests/mini_cluster.cc      |  23 +++-
 src/kudu/integration-tests/mini_cluster.h       |   6 ++
 src/kudu/integration-tests/mini_cluster_base.h  |  22 +++-
 src/kudu/tablet/tablet_bootstrap.cc             |  78 +++++++++-----
 src/kudu/tserver/mini_tablet_server.cc          |   5 +
 src/kudu/tserver/mini_tablet_server.h           |   3 +
 10 files changed, 224 insertions(+), 48 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kudu/blob/9eebcdc7/src/kudu/integration-tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/kudu/integration-tests/CMakeLists.txt b/src/kudu/integration-tests/CMakeLists.txt
index 7a0d32a..ce72daf 100644
--- a/src/kudu/integration-tests/CMakeLists.txt
+++ b/src/kudu/integration-tests/CMakeLists.txt
@@ -60,6 +60,7 @@ ADD_KUDU_TEST(consistency-itest)
 ADD_KUDU_TEST(create-table-itest)
 ADD_KUDU_TEST(create-table-stress-test)
 ADD_KUDU_TEST(delete_table-test)
+ADD_KUDU_TEST(delete_tablet-itest)
 ADD_KUDU_TEST(disk_reservation-itest)
 ADD_KUDU_TEST(exactly_once_writes-itest)
 ADD_KUDU_TEST(external_mini_cluster-test RESOURCE_LOCK "master-rpc-ports")

http://git-wip-us.apache.org/repos/asf/kudu/blob/9eebcdc7/src/kudu/integration-tests/delete_tablet-itest.cc
----------------------------------------------------------------------
diff --git a/src/kudu/integration-tests/delete_tablet-itest.cc b/src/kudu/integration-tests/delete_tablet-itest.cc
new file mode 100644
index 0000000..e145701
--- /dev/null
+++ b/src/kudu/integration-tests/delete_tablet-itest.cc
@@ -0,0 +1,106 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 <vector>
+
+#include "kudu/gutil/stl_util.h"
+#include "kudu/gutil/strings/substitute.h"
+#include "kudu/integration-tests/cluster_itest_util.h"
+#include "kudu/integration-tests/mini_cluster-itest-base.h"
+#include "kudu/integration-tests/test_workload.h"
+#include "kudu/master/mini_master.h"
+#include "kudu/tablet/tablet_peer.h"
+#include "kudu/tserver/mini_tablet_server.h"
+#include "kudu/tserver/tablet_server.h"
+#include "kudu/tserver/ts_tablet_manager.h"
+
+DECLARE_int64(fs_wal_dir_reserved_bytes);
+
+using kudu::tablet::TabletPeer;
+using std::vector;
+
+namespace kudu {
+
+class DeleteTabletITest : public MiniClusterITestBase {
+};
+
+// Test deleting a failed replica. Regression test for KUDU-1607.
+TEST_F(DeleteTabletITest, TestDeleteFailedReplica) {
+  NO_FATALS(StartCluster(1)); // 1 TS.
+  TestWorkload workload(cluster_.get());
+  workload.set_num_replicas(1);
+  workload.Setup();
+
+  std::unordered_map<std::string, itest::TServerDetails*> ts_map;
+  ValueDeleter del(&ts_map);
+  ASSERT_OK(itest::CreateTabletServerMap(cluster_->master_proxy().get(),
+                                         cluster_->messenger(),
+                                         &ts_map));
+  auto* mts = cluster_->mini_tablet_server(0);
+  auto* ts = ts_map[mts->uuid()];
+
+  scoped_refptr<TabletPeer> tablet_peer;
+  AssertEventually([&] {
+    vector<scoped_refptr<TabletPeer>> tablet_peers;
+    mts->server()->tablet_manager()->GetTabletPeers(&tablet_peers);
+    ASSERT_EQ(1, tablet_peers.size());
+    tablet_peer = tablet_peers[0];
+  });
+  NO_FATALS();
+
+  workload.Start();
+  while (workload.rows_inserted() < 100) {
+    SleepFor(MonoDelta::FromMilliseconds(10));
+  }
+  workload.StopAndJoin();
+
+  // We need blocks on-disk for this regression test, so force an MRS flush.
+  ASSERT_OK(tablet_peer->tablet()->Flush());
+
+  // Shut down the master so it doesn't crash the test process when we make the
+  // disk appear to be full.
+  cluster_->mini_master()->Shutdown();
+
+  // Shut down the TS and restart it after changing flags to ensure no data can
+  // be written during tablet bootstrap.
+  mts->Shutdown();
+  FLAGS_fs_wal_dir_reserved_bytes = INT64_MAX;
+  ASSERT_OK(mts->Restart());
+  Status s = mts->server()->tablet_manager()->WaitForAllBootstrapsToFinish();
+  ASSERT_TRUE(s.IsIOError());
+  ASSERT_STR_CONTAINS(s.ToString(), "Insufficient disk space");
+
+  // Tablet bootstrap failure should result in tablet status == FAILED.
+  {
+    vector<scoped_refptr<TabletPeer>> tablet_peers;
+    mts->server()->tablet_manager()->GetTabletPeers(&tablet_peers);
+    ASSERT_EQ(1, tablet_peers.size());
+    tablet_peer = tablet_peers[0];
+    ASSERT_EQ(tablet::FAILED, tablet_peer->state());
+  }
+
+  // We should still be able to delete the failed tablet.
+  ASSERT_OK(itest::DeleteTablet(ts, tablet_peer->tablet_id(), tablet::TABLET_DATA_DELETED,
+                                boost::none, MonoDelta::FromSeconds(30)));
+  AssertEventually([&] {
+    vector<scoped_refptr<TabletPeer>> tablet_peers;
+    mts->server()->tablet_manager()->GetTabletPeers(&tablet_peers);
+    ASSERT_EQ(0, tablet_peers.size());
+  });
+}
+
+} // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/9eebcdc7/src/kudu/integration-tests/external_mini_cluster.cc
----------------------------------------------------------------------
diff --git a/src/kudu/integration-tests/external_mini_cluster.cc b/src/kudu/integration-tests/external_mini_cluster.cc
index a57f92a..c5eb77f 100644
--- a/src/kudu/integration-tests/external_mini_cluster.cc
+++ b/src/kudu/integration-tests/external_mini_cluster.cc
@@ -537,16 +537,16 @@ vector<ExternalDaemon*> ExternalMiniCluster::daemons() const {
   return results;
 }
 
-std::shared_ptr<rpc::Messenger> ExternalMiniCluster::messenger() {
+std::shared_ptr<rpc::Messenger> ExternalMiniCluster::messenger() const {
   return messenger_;
 }
 
-std::shared_ptr<MasterServiceProxy> ExternalMiniCluster::master_proxy() {
+std::shared_ptr<MasterServiceProxy> ExternalMiniCluster::master_proxy() const {
   CHECK_EQ(masters_.size(), 1);
   return master_proxy(0);
 }
 
-std::shared_ptr<MasterServiceProxy> ExternalMiniCluster::master_proxy(int idx) {
+std::shared_ptr<MasterServiceProxy> ExternalMiniCluster::master_proxy(int idx) const {
   CHECK_LT(idx, masters_.size());
   return std::shared_ptr<MasterServiceProxy>(
       new MasterServiceProxy(messenger_, CHECK_NOTNULL(master(idx))->bound_rpc_addr()));

http://git-wip-us.apache.org/repos/asf/kudu/blob/9eebcdc7/src/kudu/integration-tests/external_mini_cluster.h
----------------------------------------------------------------------
diff --git a/src/kudu/integration-tests/external_mini_cluster.h b/src/kudu/integration-tests/external_mini_cluster.h
index 57fdba1..a562f8e 100644
--- a/src/kudu/integration-tests/external_mini_cluster.h
+++ b/src/kudu/integration-tests/external_mini_cluster.h
@@ -46,14 +46,6 @@ class NodeInstancePB;
 class Sockaddr;
 class Subprocess;
 
-namespace master {
-class MasterServiceProxy;
-} // namespace master
-
-namespace rpc {
-class Messenger;
-} // namespace rpc
-
 namespace server {
 class ServerStatusPB;
 } // namespace server
@@ -235,17 +227,9 @@ class ExternalMiniCluster : public MiniClusterBase {
     return masters_.size();
   }
 
-  // Return the client messenger used by the ExternalMiniCluster.
-  std::shared_ptr<rpc::Messenger> messenger();
-
-  // If the cluster is configured for a single non-distributed master,
-  // return a proxy to that master. Requires that the single master is
-  // running.
-  std::shared_ptr<master::MasterServiceProxy> master_proxy();
-
-  // Returns an RPC proxy to the master at 'idx'. Requires that the
-  // master at 'idx' is running.
-  std::shared_ptr<master::MasterServiceProxy> master_proxy(int idx);
+  std::shared_ptr<rpc::Messenger> messenger() const override;
+  std::shared_ptr<master::MasterServiceProxy> master_proxy() const override;
+  std::shared_ptr<master::MasterServiceProxy> master_proxy(int idx) const override;
 
   // Wait until the number of registered tablet servers reaches the given count
   // on all of the running masters. Returns Status::TimedOut if the desired

http://git-wip-us.apache.org/repos/asf/kudu/blob/9eebcdc7/src/kudu/integration-tests/mini_cluster.cc
----------------------------------------------------------------------
diff --git a/src/kudu/integration-tests/mini_cluster.cc b/src/kudu/integration-tests/mini_cluster.cc
index d50c339..c910502 100644
--- a/src/kudu/integration-tests/mini_cluster.cc
+++ b/src/kudu/integration-tests/mini_cluster.cc
@@ -23,6 +23,7 @@
 #include "kudu/gutil/strings/substitute.h"
 #include "kudu/master/catalog_manager.h"
 #include "kudu/master/master.h"
+#include "kudu/master/master.proxy.h"
 #include "kudu/master/mini_master.h"
 #include "kudu/master/ts_descriptor.h"
 #include "kudu/master/ts_manager.h"
@@ -41,8 +42,8 @@ namespace kudu {
 using client::KuduClient;
 using client::KuduClientBuilder;
 using master::CatalogManager;
+using master::MasterServiceProxy;
 using master::MiniMaster;
-using master::TabletLocationsPB;
 using master::TSDescriptor;
 using std::shared_ptr;
 using tserver::MiniTabletServer;
@@ -96,6 +97,12 @@ Status MiniCluster::Start() {
   RETURN_NOT_OK_PREPEND(WaitForTabletServerCount(num_ts_initial_),
                         "Waiting for tablet servers to start");
 
+  RETURN_NOT_OK_PREPEND(rpc::MessengerBuilder("minicluster-messenger")
+                        .set_num_reactors(1)
+                        .set_max_negotiation_threads(1)
+                        .Build(&messenger_),
+                        "Failed to start Messenger for minicluster");
+
   running_ = true;
   return Status::OK();
 }
@@ -324,4 +331,18 @@ Status MiniCluster::GetLeaderMasterIndex(int* idx) const {
   return Status::OK();
 }
 
+std::shared_ptr<rpc::Messenger> MiniCluster::messenger() const {
+  return messenger_;
+}
+
+std::shared_ptr<MasterServiceProxy> MiniCluster::master_proxy() const {
+  CHECK_EQ(1, mini_masters_.size());
+  return master_proxy(0);
+}
+
+std::shared_ptr<MasterServiceProxy> MiniCluster::master_proxy(int idx) const {
+  return std::shared_ptr<MasterServiceProxy>(
+      new MasterServiceProxy(messenger_, CHECK_NOTNULL(mini_master(idx))->bound_rpc_addr()));
+}
+
 } // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/9eebcdc7/src/kudu/integration-tests/mini_cluster.h
----------------------------------------------------------------------
diff --git a/src/kudu/integration-tests/mini_cluster.h b/src/kudu/integration-tests/mini_cluster.h
index be5928e..cf49aee 100644
--- a/src/kudu/integration-tests/mini_cluster.h
+++ b/src/kudu/integration-tests/mini_cluster.h
@@ -162,6 +162,10 @@ class MiniCluster : public MiniClusterBase {
   // last result may not be valid.
   Status GetLeaderMasterIndex(int* idx) const;
 
+  std::shared_ptr<rpc::Messenger> messenger() const override;
+  std::shared_ptr<master::MasterServiceProxy> master_proxy() const override;
+  std::shared_ptr<master::MasterServiceProxy> master_proxy(int idx) const override;
+
  private:
   enum {
     kRegistrationWaitTimeSeconds = 15,
@@ -180,6 +184,8 @@ class MiniCluster : public MiniClusterBase {
   std::vector<std::shared_ptr<master::MiniMaster> > mini_masters_;
   std::vector<std::shared_ptr<tserver::MiniTabletServer> > mini_tablet_servers_;
 
+  std::shared_ptr<rpc::Messenger> messenger_;
+
   DISALLOW_COPY_AND_ASSIGN(MiniCluster);
 };
 

http://git-wip-us.apache.org/repos/asf/kudu/blob/9eebcdc7/src/kudu/integration-tests/mini_cluster_base.h
----------------------------------------------------------------------
diff --git a/src/kudu/integration-tests/mini_cluster_base.h b/src/kudu/integration-tests/mini_cluster_base.h
index 1fd1985..a71b807 100644
--- a/src/kudu/integration-tests/mini_cluster_base.h
+++ b/src/kudu/integration-tests/mini_cluster_base.h
@@ -24,7 +24,15 @@ class Status;
 namespace client {
 class KuduClient;
 class KuduClientBuilder;
-}
+} // namespace client
+
+namespace master {
+class MasterServiceProxy;
+} // namespace master
+
+namespace rpc {
+class Messenger;
+} // namespace rpc
 
 // Mode to which node types a certain action (like Shutdown()) should apply.
 enum class ClusterNodes {
@@ -65,6 +73,18 @@ class MiniClusterBase {
   // REQUIRES: the cluster must have already been Start()ed.
   virtual Status CreateClient(client::KuduClientBuilder* builder,
                               client::sp::shared_ptr<client::KuduClient>* client) const = 0;
+
+  // Return a messenger for use by clients.
+  virtual std::shared_ptr<rpc::Messenger> messenger() const = 0;
+
+  // If the cluster is configured for a single non-distributed master,
+  // return a proxy to that master. Requires that the single master is
+  // running.
+  virtual std::shared_ptr<master::MasterServiceProxy> master_proxy() const = 0;
+
+  // Returns an RPC proxy to the master at 'idx'. Requires that the
+  // master at 'idx' is running.
+  virtual std::shared_ptr<master::MasterServiceProxy> master_proxy(int idx) const = 0;
 };
 
 } // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/9eebcdc7/src/kudu/tablet/tablet_bootstrap.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tablet/tablet_bootstrap.cc b/src/kudu/tablet/tablet_bootstrap.cc
index a7cd658..0749486 100644
--- a/src/kudu/tablet/tablet_bootstrap.cc
+++ b/src/kudu/tablet/tablet_bootstrap.cc
@@ -58,6 +58,7 @@
 #include "kudu/util/logging.h"
 #include "kudu/util/path_util.h"
 #include "kudu/util/pb_util.h"
+#include "kudu/util/scoped_cleanup.h"
 #include "kudu/util/stopwatch.h"
 
 DEFINE_bool(skip_remove_old_recovery_dir, false,
@@ -177,10 +178,17 @@ class TabletBootstrap {
   // A successful call will yield the rebuilt tablet and the rebuilt log.
   Status Bootstrap(shared_ptr<Tablet>* rebuilt_tablet,
                    scoped_refptr<Log>* rebuilt_log,
-                   ConsensusBootstrapInfo* results);
+                   ConsensusBootstrapInfo* consensus_info);
 
  private:
 
+  // The method that does the actual work of tablet bootstrap. Bootstrap() is
+  // actually a wrapper method that is responsible for pinning and unpinning
+  // the tablet metadata flush.
+  Status RunBootstrap(shared_ptr<Tablet>* rebuilt_tablet,
+                      scoped_refptr<Log>* rebuilt_log,
+                      ConsensusBootstrapInfo* consensus_info);
+
   // Opens the tablet.
   // Sets '*has_blocks' to true if there was any data on disk for this tablet.
   Status OpenTablet(bool* has_blocks);
@@ -213,9 +221,9 @@ class TabletBootstrap {
   Status OpenNewLog();
 
   // Finishes bootstrap, setting 'rebuilt_log' and 'rebuilt_tablet'.
-  Status FinishBootstrap(const string& message,
-                         scoped_refptr<log::Log>* rebuilt_log,
-                         shared_ptr<Tablet>* rebuilt_tablet);
+  void FinishBootstrap(const string& message,
+                       scoped_refptr<log::Log>* rebuilt_log,
+                       shared_ptr<Tablet>* rebuilt_tablet);
 
   // Plays the log segments into the tablet being built.
   // The process of playing the segments generates a new log that can be continued
@@ -439,6 +447,43 @@ TabletBootstrap::TabletBootstrap(
 Status TabletBootstrap::Bootstrap(shared_ptr<Tablet>* rebuilt_tablet,
                                   scoped_refptr<Log>* rebuilt_log,
                                   ConsensusBootstrapInfo* consensus_info) {
+  // We pin (prevent) metadata flush at the beginning of the bootstrap process
+  // and always unpin it at the end.
+  meta_->PinFlush();
+
+  // Now run the actual bootstrap process.
+  Status bootstrap_status = RunBootstrap(rebuilt_tablet, rebuilt_log, consensus_info);
+
+  // Add a callback to TabletMetadata that makes sure that each time we flush the metadata
+  // we also wait for in-flights to finish and for their wal entry to be fsynced.
+  // This might be a bit conservative in some situations but it will prevent us from
+  // ever flushing the metadata referring to tablet data blocks containing data whose
+  // commit entries are not durable, a pre-requisite for recovery.
+  CHECK((*rebuilt_tablet && *rebuilt_log) || !bootstrap_status.ok())
+      << "Tablet and Log not initialized";
+  if (bootstrap_status.ok()) {
+    meta_->SetPreFlushCallback(
+        Bind(&FlushInflightsToLogCallback::WaitForInflightsAndFlushLog,
+             make_scoped_refptr(new FlushInflightsToLogCallback(
+                 rebuilt_tablet->get(), *rebuilt_log))));
+  }
+
+  // This will cause any pending TabletMetadata flush to be executed.
+  Status unpin_status = meta_->UnPinFlush();
+
+  constexpr char kFailedUnpinMsg[] = "Failed to flush after unpinning";
+  if (PREDICT_FALSE(!bootstrap_status.ok() && !unpin_status.ok())) {
+    LOG_WITH_PREFIX(WARNING) << kFailedUnpinMsg << ": " << unpin_status.ToString();
+    return bootstrap_status;
+  }
+  RETURN_NOT_OK(bootstrap_status);
+  RETURN_NOT_OK_PREPEND(unpin_status, Substitute("$0$1", LogPrefix(), kFailedUnpinMsg));
+  return Status::OK();
+}
+
+Status TabletBootstrap::RunBootstrap(shared_ptr<Tablet>* rebuilt_tablet,
+                                     scoped_refptr<Log>* rebuilt_log,
+                                     ConsensusBootstrapInfo* consensus_info) {
   string tablet_id = meta_->tablet_id();
 
   // Replay requires a valid Consensus metadata file to exist in order to
@@ -458,8 +503,6 @@ Status TabletBootstrap::Bootstrap(shared_ptr<Tablet>* rebuilt_tablet,
                               TabletDataState_Name(tablet_data_state));
   }
 
-  meta_->PinFlush();
-
   StatusMessage("Bootstrap starting.");
 
   if (VLOG_IS_ON(1)) {
@@ -483,9 +526,7 @@ Status TabletBootstrap::Bootstrap(shared_ptr<Tablet>* rebuilt_tablet,
   if (!has_blocks && !needs_recovery) {
     LOG_WITH_PREFIX(INFO) << "No blocks or log segments found. Creating new log.";
     RETURN_NOT_OK_PREPEND(OpenNewLog(), "Failed to open new log");
-    RETURN_NOT_OK(FinishBootstrap("No bootstrap required, opened a new log",
-                                  rebuilt_log,
-                                  rebuilt_tablet));
+    FinishBootstrap("No bootstrap required, opened a new log", rebuilt_log, rebuilt_tablet);
     consensus_info->last_id = MinimumOpId();
     consensus_info->last_committed_id = MinimumOpId();
     return Status::OK();
@@ -506,29 +547,18 @@ Status TabletBootstrap::Bootstrap(shared_ptr<Tablet>* rebuilt_tablet,
   cmeta_->Flush();
 
   RETURN_NOT_OK(RemoveRecoveryDir());
-  RETURN_NOT_OK(FinishBootstrap("Bootstrap complete.", rebuilt_log, rebuilt_tablet));
+  FinishBootstrap("Bootstrap complete.", rebuilt_log, rebuilt_tablet);
 
   return Status::OK();
 }
 
-Status TabletBootstrap::FinishBootstrap(const string& message,
-                                        scoped_refptr<log::Log>* rebuilt_log,
-                                        shared_ptr<Tablet>* rebuilt_tablet) {
-  // Add a callback to TabletMetadata that makes sure that each time we flush the metadata
-  // we also wait for in-flights to finish and for their wal entry to be fsynced.
-  // This might be a bit conservative in some situations but it will prevent us from
-  // ever flushing the metadata referring to tablet data blocks containing data whose
-  // commit entries are not durable, a pre-requisite for recovery.
-  meta_->SetPreFlushCallback(
-      Bind(&FlushInflightsToLogCallback::WaitForInflightsAndFlushLog,
-           make_scoped_refptr(new FlushInflightsToLogCallback(tablet_.get(),
-                                                              log_))));
+void TabletBootstrap::FinishBootstrap(const string& message,
+                                      scoped_refptr<log::Log>* rebuilt_log,
+                                      shared_ptr<Tablet>* rebuilt_tablet) {
   tablet_->MarkFinishedBootstrapping();
-  RETURN_NOT_OK(tablet_->metadata()->UnPinFlush());
   StatusMessage(message);
   rebuilt_tablet->reset(tablet_.release());
   rebuilt_log->swap(log_);
-  return Status::OK();
 }
 
 Status TabletBootstrap::OpenTablet(bool* has_blocks) {

http://git-wip-us.apache.org/repos/asf/kudu/blob/9eebcdc7/src/kudu/tserver/mini_tablet_server.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tserver/mini_tablet_server.cc b/src/kudu/tserver/mini_tablet_server.cc
index f4cb331..aabb9df 100644
--- a/src/kudu/tserver/mini_tablet_server.cc
+++ b/src/kudu/tserver/mini_tablet_server.cc
@@ -135,5 +135,10 @@ const Sockaddr MiniTabletServer::bound_http_addr() const {
   return server_->first_http_address();
 }
 
+const string& MiniTabletServer::uuid() const {
+  CHECK(started_);
+  return server_->fs_manager()->uuid();
+}
+
 } // namespace tserver
 } // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/9eebcdc7/src/kudu/tserver/mini_tablet_server.h
----------------------------------------------------------------------
diff --git a/src/kudu/tserver/mini_tablet_server.h b/src/kudu/tserver/mini_tablet_server.h
index 4c205fd..34ed945 100644
--- a/src/kudu/tserver/mini_tablet_server.h
+++ b/src/kudu/tserver/mini_tablet_server.h
@@ -87,6 +87,9 @@ class MiniTabletServer {
   const TabletServer* server() const { return server_.get(); }
   TabletServer* server() { return server_.get(); }
 
+  // Return TS uuid.
+  const std::string& uuid() const;
+
   bool is_started() const { return started_; }
 
   void FailHeartbeats();