kudu-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From a...@apache.org
Subject [kudu] 02/02: log: start using file cache
Date Wed, 22 Jan 2020 22:25:54 GMT
This is an automated email from the ASF dual-hosted git repository.

adar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kudu.git

commit fc4ab691a502067bc4d5bdff30507cac7feb7cfe
Author: Adar Dembo <adar@cloudera.com>
AuthorDate: Mon Jan 20 21:40:38 2020 -0800

    log: start using file cache
    
    This patch modifies the log to use the file cache. New WAL segments are
    opened through the cache from the moment we switch to them, meaning
    there's a short period of time as they're being preallocated where they're
    opened outside the cache. Log index chunks are only used through the cache.
    
    The bulk of the patch is plumbing to get the file cache down from the server
    into the various log classes. Most "interesting" log-related tests have been
    modified to instantiate a cache while other unit tests have not, ensuring a
    mix of test coverage.
    
    One important semantic change to be aware of: it is now unsafe to delete a
    log's data or bootstrap a new copy of an existing tablet without first
    closing the old log. Thankfully we only took advantage of this in tests.
    
    I added a new gflag to use as a feature flag, in case things go south.
    
    Change-Id: I2c00f6b839a693e059fa2ce79abf347dbf83bdd0
    Reviewed-on: http://gerrit.cloudera.org:8080/15082
    Tested-by: Adar Dembo <adar@cloudera.com>
    Reviewed-by: Andrew Wong <awong@cloudera.com>
---
 src/kudu/consensus/consensus_peers-test.cc         | 17 ++++----
 src/kudu/consensus/consensus_queue-test.cc         |  1 +
 src/kudu/consensus/log-test-base.h                 | 18 ++++++--
 src/kudu/consensus/log-test.cc                     | 40 +++++++++++------
 src/kudu/consensus/log.cc                          | 50 +++++++++++++++++-----
 src/kudu/consensus/log.h                           |  5 ++-
 src/kudu/consensus/log_cache-test.cc               |  3 +-
 src/kudu/consensus/log_index-test.cc               | 10 ++++-
 src/kudu/consensus/log_index.cc                    | 28 ++++++++----
 src/kudu/consensus/log_index.h                     |  6 ++-
 src/kudu/consensus/log_reader.cc                   | 13 ++++--
 src/kudu/consensus/log_reader.h                    | 11 ++++-
 src/kudu/consensus/log_util.cc                     | 23 +++++++---
 src/kudu/consensus/log_util.h                      |  2 +
 src/kudu/consensus/mt-log-test.cc                  | 11 +++--
 src/kudu/consensus/raft_consensus_quorum-test.cc   |  6 ++-
 src/kudu/integration-tests/log_verifier.cc         |  9 +++-
 .../timestamp_advancement-itest.cc                 |  7 ++-
 src/kudu/integration-tests/ts_recovery-itest.cc    |  3 +-
 src/kudu/master/sys_catalog.cc                     |  7 +--
 src/kudu/tablet/tablet_bootstrap-test.cc           | 18 ++++----
 src/kudu/tablet/tablet_bootstrap.cc                | 13 ++++--
 src/kudu/tablet/tablet_bootstrap.h                 |  4 +-
 src/kudu/tablet/tablet_replica-test.cc             | 22 +++++-----
 src/kudu/tools/kudu-tool-test.cc                   |  3 +-
 src/kudu/tools/tool_action_local_replica.cc        | 14 ++++--
 src/kudu/tools/tool_action_perf.cc                 |  3 +-
 src/kudu/tools/tool_action_wal.cc                  |  5 ++-
 .../tserver/tablet_copy_source_session-test.cc     | 11 +++--
 src/kudu/tserver/ts_tablet_manager.cc              |  3 +-
 src/kudu/tserver/ts_tablet_manager.h               |  5 +--
 31 files changed, 259 insertions(+), 112 deletions(-)

diff --git a/src/kudu/consensus/consensus_peers-test.cc b/src/kudu/consensus/consensus_peers-test.cc
index 49c9812..d3afb92 100644
--- a/src/kudu/consensus/consensus_peers-test.cc
+++ b/src/kudu/consensus/consensus_peers-test.cc
@@ -15,7 +15,8 @@
 // specific language governing permissions and limitations
 // under the License.
 
-#include <cstddef>
+#include "kudu/consensus/consensus_peers.h"
+
 #include <memory>
 #include <string>
 #include <type_traits>
@@ -32,7 +33,6 @@
 #include "kudu/common/wire_protocol.h"
 #include "kudu/consensus/consensus-test-util.h"
 #include "kudu/consensus/consensus.pb.h"
-#include "kudu/consensus/consensus_peers.h"
 #include "kudu/consensus/consensus_queue.h"
 #include "kudu/consensus/log.h"
 #include "kudu/consensus/log_util.h"
@@ -85,12 +85,13 @@ class ConsensusPeersTest : public KuduTest {
     ASSERT_OK(fs_manager_->CreateInitialFileSystemLayout());
     ASSERT_OK(fs_manager_->Open());
     ASSERT_OK(Log::Open(options_,
-                       fs_manager_.get(),
-                       kTabletId,
-                       schema_,
-                       0, // schema_version
-                       NULL,
-                       &log_));
+                        fs_manager_.get(),
+                        /*file_cache*/nullptr,
+                        kTabletId,
+                        schema_,
+                        0, // schema_version
+                        /*metric_entity*/nullptr,
+                        &log_));
     clock_.reset(new clock::HybridClock());
     ASSERT_OK(clock_->Init());
 
diff --git a/src/kudu/consensus/consensus_queue-test.cc b/src/kudu/consensus/consensus_queue-test.cc
index eba226c..572fe31 100644
--- a/src/kudu/consensus/consensus_queue-test.cc
+++ b/src/kudu/consensus/consensus_queue-test.cc
@@ -96,6 +96,7 @@ class ConsensusQueueTest : public KuduTest {
     ASSERT_OK(fs_manager_->Open());
     CHECK_OK(log::Log::Open(log::LogOptions(),
                             fs_manager_.get(),
+                            /*file_cache*/nullptr,
                             kTestTablet,
                             schema_,
                             /*schema_version*/0,
diff --git a/src/kudu/consensus/log-test-base.h b/src/kudu/consensus/log-test-base.h
index 62f3284..345492a 100644
--- a/src/kudu/consensus/log-test-base.h
+++ b/src/kudu/consensus/log-test-base.h
@@ -44,6 +44,7 @@
 #include "kudu/tserver/tserver.pb.h"
 #include "kudu/util/async_util.h"
 #include "kudu/util/env_util.h"
+#include "kudu/util/file_cache.h"
 #include "kudu/util/metrics.h"
 #include "kudu/util/path_util.h"
 #include "kudu/util/pb_util.h"
@@ -51,6 +52,7 @@
 #include "kudu/util/test_macros.h"
 #include "kudu/util/test_util.h"
 
+METRIC_DECLARE_entity(server);
 METRIC_DECLARE_entity(tablet);
 
 namespace kudu {
@@ -155,7 +157,14 @@ class LogTestBase : public KuduTest {
     current_index_ = kStartIndex;
     fs_manager_.reset(new FsManager(env_, FsManagerOpts(GetTestPath("fs_root"))));
     metric_registry_.reset(new MetricRegistry());
-    metric_entity_ = METRIC_ENTITY_tablet.Instantiate(metric_registry_.get(), "log-test-base");
+    metric_entity_tablet_ = METRIC_ENTITY_tablet.Instantiate(
+        metric_registry_.get(), "tablet");
+    metric_entity_server_ = METRIC_ENTITY_server.Instantiate(
+        metric_registry_.get(), "server");
+    // Capacity was chosen arbitrarily: high enough to cache multiple files, but
+    // low enough to see some eviction.
+    file_cache_.reset(new FileCache("log-test-base", env_, 5, metric_entity_server_));
+    ASSERT_OK(file_cache_->Init());
     ASSERT_OK(fs_manager_->CreateInitialFileSystemLayout());
     ASSERT_OK(fs_manager_->Open());
 
@@ -171,10 +180,11 @@ class LogTestBase : public KuduTest {
     Schema schema_with_ids = SchemaBuilder(schema_).Build();
     return Log::Open(options_,
                      fs_manager_.get(),
+                     file_cache_.get(),
                      kTestTablet,
                      schema_with_ids,
                      0, // schema_version
-                     metric_entity_.get(),
+                     metric_entity_tablet_.get(),
                      &log_);
   }
 
@@ -375,7 +385,9 @@ class LogTestBase : public KuduTest {
   const Schema schema_;
   std::unique_ptr<FsManager> fs_manager_;
   std::unique_ptr<MetricRegistry> metric_registry_;
-  scoped_refptr<MetricEntity> metric_entity_;
+  std::unique_ptr<FileCache> file_cache_;
+  scoped_refptr<MetricEntity> metric_entity_tablet_;
+  scoped_refptr<MetricEntity> metric_entity_server_;
   scoped_refptr<Log> log_;
   int64_t current_index_;
   LogOptions options_;
diff --git a/src/kudu/consensus/log-test.cc b/src/kudu/consensus/log-test.cc
index 653ed00..3800554 100644
--- a/src/kudu/consensus/log-test.cc
+++ b/src/kudu/consensus/log-test.cc
@@ -43,7 +43,6 @@
 #include "kudu/consensus/log_util.h"
 #include "kudu/consensus/opid.pb.h"
 #include "kudu/consensus/opid_util.h"
-#include "kudu/fs/fs_manager.h"
 #include "kudu/gutil/gscoped_ptr.h"
 #include "kudu/gutil/ref_counted.h"
 #include "kudu/gutil/stl_util.h"
@@ -53,6 +52,7 @@
 #include "kudu/util/debug/sanitizer_scopes.h"
 #include "kudu/util/env.h"
 #include "kudu/util/faststring.h"
+#include "kudu/util/file_cache.h"
 #include "kudu/util/metrics.h"
 #include "kudu/util/random.h"
 #include "kudu/util/status.h"
@@ -127,15 +127,11 @@ class LogTest : public LogTestBase {
                                        int first_repl_index,
                                        LogReader* reader) {
     string fqp = GetTestPath(strings::Substitute("wal-00000000$0", sequence_number));
-    unique_ptr<WritableFile> w_log_seg;
-    RETURN_NOT_OK(fs_manager_->env()->NewWritableFile(fqp, &w_log_seg));
-    unique_ptr<RWFile> r_log_seg;
-    RWFileOptions opts;
-    opts.mode = Env::MUST_EXIST;
-    RETURN_NOT_OK(fs_manager_->env()->NewRWFile(opts, fqp, &r_log_seg));
+    shared_ptr<RWFile> log_seg;
+    RETURN_NOT_OK(file_cache_->OpenFile<Env::MUST_CREATE>(fqp, &log_seg));
 
     scoped_refptr<ReadableLogSegment> readable_segment(
-        new ReadableLogSegment(fqp, shared_ptr<RWFile>(r_log_seg.release())));
+        new ReadableLogSegment(fqp, std::move(log_seg)));
 
     LogSegmentHeaderPB header;
     header.set_sequence_number(sequence_number);
@@ -350,8 +346,13 @@ void LogTest::DoCorruptionTest(CorruptionType type, CorruptionPosition place,
   // because it has a cached header.
   shared_ptr<LogReader> reader;
   ASSERT_OK(LogReader::Open(fs_manager_.get(),
-                            make_scoped_refptr(new LogIndex(env_, log_->log_dir_)),
-                            kTestTablet, nullptr, &reader));
+                            make_scoped_refptr(new LogIndex(env_,
+                                                            file_cache_.get(),
+                                                            log_->log_dir_)),
+                            kTestTablet,
+                            metric_entity_tablet_,
+                            file_cache_.get(),
+                            &reader));
   ASSERT_EQ(1, reader->num_segments());
 
   SegmentSequence segments;
@@ -412,7 +413,12 @@ TEST_P(LogTestOptionalCompression, TestSegmentRollover) {
   ASSERT_OK(log_->Close());
 
   shared_ptr<LogReader> reader;
-  ASSERT_OK(LogReader::Open(fs_manager_.get(), nullptr, kTestTablet, nullptr, &reader));
+  ASSERT_OK(LogReader::Open(fs_manager_.get(),
+                            /*index*/nullptr,
+                            kTestTablet,
+                            metric_entity_tablet_,
+                            file_cache_.get(),
+                            &reader));
   reader->GetSegmentsSnapshot(&segments);
 
   ASSERT_TRUE(segments.back()->HasFooter());
@@ -760,7 +766,12 @@ TEST_P(LogTestOptionalCompression, TestWriteManyBatches) {
     vector<scoped_refptr<ReadableLogSegment> > segments;
 
     shared_ptr<LogReader> reader;
-    ASSERT_OK(LogReader::Open(fs_manager_.get(), nullptr, kTestTablet, nullptr, &reader));
+    ASSERT_OK(LogReader::Open(fs_manager_.get(),
+                              /*index*/nullptr,
+                              kTestTablet,
+                              metric_entity_tablet_,
+                              file_cache_.get(),
+                              &reader));
     reader->GetSegmentsSnapshot(&segments);
 
     for (const scoped_refptr<ReadableLogSegment>& entry : segments) {
@@ -781,9 +792,10 @@ TEST_P(LogTestOptionalCompression, TestWriteManyBatches) {
 // seg004: 0.30 through 0.39
 TEST_P(LogTestOptionalCompression, TestLogReader) {
   LogReader reader(env_,
-                   scoped_refptr<LogIndex>(),
+                   /*index*/nullptr,
                    kTestTablet,
-                   nullptr);
+                   metric_entity_tablet_,
+                   file_cache_.get());
   reader.InitEmptyReaderForTests();
   ASSERT_OK(AppendNewEmptySegmentToReader(2, 10, &reader));
   ASSERT_OK(AppendNewEmptySegmentToReader(3, 20, &reader));
diff --git a/src/kudu/consensus/log.cc b/src/kudu/consensus/log.cc
index 429036f..f9a6018 100644
--- a/src/kudu/consensus/log.cc
+++ b/src/kudu/consensus/log.cc
@@ -47,6 +47,7 @@
 #include "kudu/util/env.h"
 #include "kudu/util/env_util.h"
 #include "kudu/util/fault_injection.h"
+#include "kudu/util/file_cache.h"
 #include "kudu/util/flag_tags.h"
 #include "kudu/util/kernel_stack_watchdog.h"
 #include "kudu/util/logging.h"
@@ -146,6 +147,8 @@ DEFINE_double(log_inject_io_error_on_preallocate_fraction, 0.0,
 TAG_FLAG(log_inject_io_error_on_preallocate_fraction, unsafe);
 TAG_FLAG(log_inject_io_error_on_preallocate_fraction, runtime);
 
+// Other flags.
+// -----------------------------
 DEFINE_int64(fs_wal_dir_reserved_bytes, -1,
              "Number of bytes to reserve on the log directory filesystem for "
              "non-Kudu usage. The default, which is represented by -1, is that "
@@ -155,7 +158,12 @@ DEFINE_int64(fs_wal_dir_reserved_bytes, -1,
              "are not currently supported");
 DEFINE_validator(fs_wal_dir_reserved_bytes, [](const char* /*n*/, int64_t v) { return v >= -1; });
 TAG_FLAG(fs_wal_dir_reserved_bytes, runtime);
-TAG_FLAG(fs_wal_dir_reserved_bytes, evolving);
+
+DEFINE_bool(fs_wal_use_file_cache, true,
+            "Whether to use the server-wide file cache for WAL segments and "
+            "WAL index chunks.");
+TAG_FLAG(fs_wal_use_file_cache, runtime);
+TAG_FLAG(fs_wal_use_file_cache, advanced);
 
 // Validate that log_min_segments_to_retain >= 1
 static bool ValidateLogsToRetain(const char* flagname, int value) {
@@ -173,7 +181,6 @@ namespace log {
 
 using consensus::CommitMsg;
 using consensus::ReplicateRefPtr;
-using env_util::OpenFileForRandom;
 using std::shared_ptr;
 using std::string;
 using std::vector;
@@ -634,6 +641,9 @@ Status SegmentAllocator::AllocateNewSegment() {
     allocation_state_ = kAllocationFinished;
   });
 
+  // We could create the new segment file through the cache, but that's tricky
+  // because of the file rename that'll happen later. So instead, we'll create
+  // it outside the cache now, then reopen via the cache when we switch to it.
   string tmp_suffix = Substitute("$0$1", kTmpInfix, ".newsegmentXXXXXX");
   string path_tmpl = JoinPathSegments(ctx_->log_dir, tmp_suffix);
   VLOG_WITH_PREFIX(2) << "Creating temp. file for place holder segment, template: " << path_tmpl;
@@ -676,6 +686,12 @@ Status SegmentAllocator::SwitchToAllocatedSegment(
     RETURN_NOT_OK(env->SyncDir(ctx_->log_dir));
   }
 
+  // Reopen the allocated segment file thru the file cache.
+  if (PREDICT_TRUE(ctx_->file_cache && FLAGS_fs_wal_use_file_cache)) {
+    RETURN_NOT_OK(ctx_->file_cache->OpenFile<Env::MUST_EXIST>(
+        new_segment_path, &next_segment_file_));
+  }
+
   // Create a new segment in memory.
   unique_ptr<WritableLogSegment> new_segment(
       new WritableLogSegment(new_segment_path, next_segment_file_));
@@ -702,9 +718,6 @@ Status SegmentAllocator::SwitchToAllocatedSegment(
 
   // Open the segment we just created in readable form; it is the caller's
   // responsibility to add it to the reader.
-  //
-  // TODO(todd): consider using a global FileCache here? With short log segments and
-  // lots of tablets, this file descriptor usage may add up.
   {
     scoped_refptr<ReadableLogSegment> readable_segment(
         new ReadableLogSegment(new_segment_path, std::move(next_segment_file_)));
@@ -748,6 +761,7 @@ const uint64_t Log::kInitialLogSegmentSequenceNumber = 0L;
 
 Status Log::Open(LogOptions options,
                  FsManager* fs_manager,
+                 FileCache* file_cache,
                  const string& tablet_id,
                  Schema schema,
                  uint32_t schema_version,
@@ -761,6 +775,7 @@ Status Log::Open(LogOptions options,
   ctx.metric_entity = metric_entity;
   ctx.metrics.reset(metric_entity ? new LogMetrics(metric_entity) : nullptr);
   ctx.fs_manager = fs_manager;
+  ctx.file_cache = file_cache;
   scoped_refptr<Log> new_log(new Log(std::move(options), std::move(ctx), std::move(schema),
                                      schema_version));
   RETURN_NOT_OK(new_log->Init());
@@ -781,14 +796,17 @@ Log::Log(LogOptions options, LogContext ctx, Schema schema, uint32_t schema_vers
 Status Log::Init() {
   CHECK_EQ(kLogInitialized, log_state_);
 
-  // Init the index
-  log_index_.reset(new LogIndex(ctx_.fs_manager->env(), ctx_.log_dir));
+  // Init the index.
+  log_index_.reset(new LogIndex(ctx_.fs_manager->env(),
+                                ctx_.file_cache,
+                                ctx_.log_dir));
 
   // Reader for previous segments.
   RETURN_NOT_OK(LogReader::Open(ctx_.fs_manager,
                                 log_index_,
                                 ctx_.tablet_id,
                                 ctx_.metric_entity.get(),
+                                ctx_.file_cache,
                                 &reader_));
 
   // The case where we are continuing an existing log.
@@ -988,7 +1006,7 @@ int GetPrefixSizeToGC(RetentionIndexes retention_indexes, const SegmentSequence&
 }
 
 void Log::GetSegmentsToGCUnlocked(RetentionIndexes retention_indexes,
-                                    SegmentSequence* segments_to_gc) const {
+                                  SegmentSequence* segments_to_gc) const {
   reader_->GetSegmentsSnapshot(segments_to_gc);
   segments_to_gc->resize(GetPrefixSizeToGC(retention_indexes, *segments_to_gc));
 }
@@ -1046,7 +1064,7 @@ Status Log::GC(RetentionIndexes retention_indexes, int32_t* num_gced) {
 
     // Now that they are no longer referenced by the Log, delete the files.
     *num_gced = 0;
-    for (const scoped_refptr<ReadableLogSegment>& segment : segments_to_delete) {
+    for (const auto& segment : segments_to_delete) {
       string ops_str;
       if (segment->HasFooter() && segment->footer().has_min_replicate_index()) {
         DCHECK(segment->footer().has_max_replicate_index());
@@ -1055,7 +1073,13 @@ Status Log::GC(RetentionIndexes retention_indexes, int32_t* num_gced) {
                              segment->footer().max_replicate_index());
       }
       LOG_WITH_PREFIX(INFO) << "Deleting log segment in path: " << segment->path() << ops_str;
-      RETURN_NOT_OK(ctx_.fs_manager->env()->DeleteFile(segment->path()));
+      if (PREDICT_TRUE(ctx_.file_cache)) {
+        // Note: the segment files will only be deleted from disk when
+        // segments_to_delete goes out of scope.
+        RETURN_NOT_OK(ctx_.file_cache->DeleteFile(segment->path()));
+      } else {
+        RETURN_NOT_OK(ctx_.fs_manager->env()->DeleteFile(segment->path()));
+      }
       (*num_gced)++;
     }
 
@@ -1170,6 +1194,9 @@ Status Log::DeleteOnDiskData(FsManager* fs_manager, const string& tablet_id) {
   }
   LOG(INFO) << Substitute("T $0 P $1: Deleting WAL directory at $2",
                           tablet_id, fs_manager->uuid(), wal_dir);
+  // We don't need to delete through the file cache; we're guaranteed that
+  // the log has been closed (though this invariant isn't verifiable here
+  // without additional plumbing).
   RETURN_NOT_OK_PREPEND(env->DeleteRecursively(wal_dir),
                         "Unable to recursively delete WAL dir for tablet " + tablet_id);
   return Status::OK();
@@ -1198,6 +1225,9 @@ Status Log::RemoveRecoveryDirIfExists(FsManager* fs_manager, const string& table
     return Status::OK();
   }
   VLOG(1) << kLogPrefix << "Deleting all files from renamed log recovery directory " << tmp_path;
+  // We don't need to delete through the file cache; we're guaranteed that
+  // the log has been closed (though this invariant isn't verifiable here
+  // without additional plumbing).
   RETURN_NOT_OK_PREPEND(fs_manager->env()->DeleteRecursively(tmp_path),
                         "Could not remove renamed recovery dir " + tmp_path);
   VLOG(1) << kLogPrefix << "Completed deletion of old log recovery files and directory "
diff --git a/src/kudu/consensus/log.h b/src/kudu/consensus/log.h
index b16d074..cd2907b 100644
--- a/src/kudu/consensus/log.h
+++ b/src/kudu/consensus/log.h
@@ -54,6 +54,7 @@
 namespace kudu {
 
 class CompressionCodec;
+class FileCache;
 class FsManager;
 class RWFile;
 
@@ -74,6 +75,7 @@ struct LogContext {
   scoped_refptr<MetricEntity> metric_entity;
   std::unique_ptr<LogMetrics> metrics;
   FsManager* fs_manager;
+  FileCache* file_cache;
 
   std::string LogPrefix() const;
 };
@@ -277,7 +279,8 @@ class Log : public RefCountedThreadSafe<Log> {
   // Opens or continues a log and sets 'log' to the newly built Log.
   // After a successful Open() the Log is ready to receive entries.
   static Status Open(LogOptions options,
-                     FsManager *fs_manager,
+                     FsManager* fs_manager,
+                     FileCache* file_cache,
                      const std::string& tablet_id,
                      Schema schema,
                      uint32_t schema_version,
diff --git a/src/kudu/consensus/log_cache-test.cc b/src/kudu/consensus/log_cache-test.cc
index 2c58e4b..8ebc97a 100644
--- a/src/kudu/consensus/log_cache-test.cc
+++ b/src/kudu/consensus/log_cache-test.cc
@@ -88,10 +88,11 @@ class LogCacheTest : public KuduTest {
     ASSERT_OK(fs_manager_->Open());
     CHECK_OK(log::Log::Open(log::LogOptions(),
                             fs_manager_.get(),
+                            /*file_cache*/nullptr,
                             kTestTablet,
                             schema_,
                             0, // schema_version
-                            nullptr,
+                            /*metric_entity*/nullptr,
                             &log_));
 
     CloseAndReopenCache(MinimumOpId());
diff --git a/src/kudu/consensus/log_index-test.cc b/src/kudu/consensus/log_index-test.cc
index b9eda61..9572b28 100644
--- a/src/kudu/consensus/log_index-test.cc
+++ b/src/kudu/consensus/log_index-test.cc
@@ -25,6 +25,8 @@
 #include "kudu/consensus/opid_util.h"
 #include "kudu/gutil/port.h"
 #include "kudu/gutil/ref_counted.h"
+#include "kudu/util/file_cache.h"
+#include "kudu/util/metrics.h"
 #include "kudu/util/status.h"
 #include "kudu/util/test_macros.h"
 #include "kudu/util/test_util.h"
@@ -37,9 +39,14 @@ using consensus::OpId;
 
 class LogIndexTest : public KuduTest {
  public:
+  LogIndexTest()
+      : file_cache_("test", env_, 1, /*metric_entity*/ nullptr),
+        index_(new LogIndex(env_, &file_cache_, test_dir_)) {
+  }
+
   virtual void SetUp() OVERRIDE {
     KuduTest::SetUp();
-    index_ = new LogIndex(env_, test_dir_);
+    ASSERT_OK(file_cache_.Init());
   }
 
  protected:
@@ -68,6 +75,7 @@ class LogIndexTest : public KuduTest {
     EXPECT_TRUE(s.IsNotFound()) << s.ToString();
   }
 
+  FileCache file_cache_;
   scoped_refptr<LogIndex> index_;
 };
 
diff --git a/src/kudu/consensus/log_index.cc b/src/kudu/consensus/log_index.cc
index 743a297..a891dc5 100644
--- a/src/kudu/consensus/log_index.cc
+++ b/src/kudu/consensus/log_index.cc
@@ -37,6 +37,7 @@
 #include <utility>
 #include <vector>
 
+#include <gflags/gflags_declare.h>
 #include <glog/logging.h>
 
 #include "kudu/consensus/opid_util.h"
@@ -45,8 +46,12 @@
 #include "kudu/gutil/stringprintf.h"
 #include "kudu/gutil/strings/substitute.h"
 #include "kudu/util/env.h"
+#include "kudu/util/file_cache.h"
 #include "kudu/util/slice.h"
 
+DECLARE_bool(fs_wal_use_file_cache);
+
+using std::shared_ptr;
 using std::string;
 using std::unique_ptr;
 using std::vector;
@@ -82,14 +87,14 @@ class LogIndex::IndexChunk : public RefCountedThreadSafe<LogIndex::IndexChunk> {
   IndexChunk(Env* env, string path);
   ~IndexChunk() = default;
 
-  Status Open();
+  Status Open(FileCache* file_cache);
   Status GetEntry(int entry_index, PhysicalEntry* ret) const;
   Status SetEntry(int entry_index, const PhysicalEntry& entry);
 
  private:
   Env* env_;
   const string path_;
-  unique_ptr<RWFile> file_;
+  shared_ptr<RWFile> file_;
 };
 
 LogIndex::IndexChunk::IndexChunk(Env* env, string path)
@@ -97,10 +102,16 @@ LogIndex::IndexChunk::IndexChunk(Env* env, string path)
       path_(std::move(path)) {
 }
 
-Status LogIndex::IndexChunk::Open() {
-  RWFileOptions opts;
-  opts.mode = Env::CREATE_OR_OPEN;
-  RETURN_NOT_OK(env_->NewRWFile(opts, path_, &file_));
+Status LogIndex::IndexChunk::Open(FileCache* file_cache) {
+  if (PREDICT_TRUE(file_cache && FLAGS_fs_wal_use_file_cache)) {
+    RETURN_NOT_OK(file_cache->OpenFile<Env::CREATE_OR_OPEN>(path_, &file_));
+  } else {
+    unique_ptr<RWFile> f;
+    RWFileOptions opts;
+    opts.mode = Env::CREATE_OR_OPEN;
+    RETURN_NOT_OK(env_->NewRWFile(opts, path_, &f));
+    file_.reset(f.release());
+  }
   return file_->Truncate(kChunkFileSize);
 }
 
@@ -124,8 +135,9 @@ Status LogIndex::IndexChunk::SetEntry(int entry_index, const PhysicalEntry& entr
 // LogIndex
 ////////////////////////////////////////////////////////////
 
-LogIndex::LogIndex(Env* env, string base_dir)
+LogIndex::LogIndex(Env* env, FileCache* file_cache, string base_dir)
     : env_(env),
+      file_cache_(file_cache),
       base_dir_(std::move(base_dir)) {
 }
 
@@ -140,7 +152,7 @@ Status LogIndex::OpenChunk(int64_t chunk_idx, scoped_refptr<IndexChunk>* chunk)
   string path = GetChunkPath(chunk_idx);
 
   scoped_refptr<IndexChunk> new_chunk(new IndexChunk(env_, path));
-  RETURN_NOT_OK(new_chunk->Open());
+  RETURN_NOT_OK(new_chunk->Open(file_cache_));
   *chunk = std::move(new_chunk);
   return Status::OK();
 }
diff --git a/src/kudu/consensus/log_index.h b/src/kudu/consensus/log_index.h
index 44f4734..1a4a725 100644
--- a/src/kudu/consensus/log_index.h
+++ b/src/kudu/consensus/log_index.h
@@ -29,6 +29,7 @@
 namespace kudu {
 
 class Env;
+class FileCache;
 
 namespace log {
 
@@ -62,7 +63,7 @@ struct LogIndexEntry {
 // See .cc file for implementation notes.
 class LogIndex : public RefCountedThreadSafe<LogIndex> {
  public:
-  LogIndex(Env* env, std::string base_dir);
+  LogIndex(Env* env, FileCache* file_cache, std::string base_dir);
 
   // Record an index entry in the index.
   Status AddEntry(const LogIndexEntry& entry);
@@ -98,6 +99,9 @@ class LogIndex : public RefCountedThreadSafe<LogIndex> {
   // Environment with which to do file I/O.
   Env* env_;
 
+  // Optional cache thru which index files are opened.
+  FileCache* file_cache_;
+
   // The base directory where index files are located.
   const std::string base_dir_;
 
diff --git a/src/kudu/consensus/log_reader.cc b/src/kudu/consensus/log_reader.cc
index f4367ee..0721c70 100644
--- a/src/kudu/consensus/log_reader.cc
+++ b/src/kudu/consensus/log_reader.cc
@@ -84,8 +84,10 @@ Status LogReader::Open(Env* env,
                        const scoped_refptr<LogIndex>& index,
                        const string& tablet_id,
                        const scoped_refptr<MetricEntity>& metric_entity,
+                       FileCache* file_cache,
                        shared_ptr<LogReader>* reader) {
-  auto log_reader = LogReader::make_shared(env, index, tablet_id, metric_entity);
+  auto log_reader = LogReader::make_shared(env, index, tablet_id,
+                                           metric_entity, file_cache);
 
   RETURN_NOT_OK_PREPEND(log_reader->Init(tablet_wal_dir),
                         "Unable to initialize log reader");
@@ -97,16 +99,19 @@ Status LogReader::Open(FsManager* fs_manager,
                        const scoped_refptr<LogIndex>& index,
                        const std::string& tablet_id,
                        const scoped_refptr<MetricEntity>& metric_entity,
+                       FileCache* file_cache,
                        std::shared_ptr<LogReader>* reader) {
   return LogReader::Open(fs_manager->env(), fs_manager->GetTabletWalDir(tablet_id),
-                         index, tablet_id, metric_entity, reader);
+                         index, tablet_id, metric_entity, file_cache, reader);
 }
 
 LogReader::LogReader(Env* env,
                      scoped_refptr<LogIndex> index,
                      string tablet_id,
-                     const scoped_refptr<MetricEntity>& metric_entity)
+                     const scoped_refptr<MetricEntity>& metric_entity,
+                     FileCache* file_cache)
     : env_(env),
+      file_cache_(file_cache),
       log_index_(std::move(index)),
       tablet_id_(std::move(tablet_id)),
       state_(kLogReaderInitialized) {
@@ -146,7 +151,7 @@ Status LogReader::Init(const string& tablet_wal_path) {
     if (HasPrefixString(log_file, FsManager::kWalFileNamePrefix)) {
       string fqp = JoinPathSegments(tablet_wal_path, log_file);
       scoped_refptr<ReadableLogSegment> segment;
-      Status s = ReadableLogSegment::Open(env_, fqp, &segment);
+      Status s = ReadableLogSegment::Open(env_, file_cache_, fqp, &segment);
       if (s.IsUninitialized()) {
         // This indicates that the segment was created but the writer
         // crashed before the header was successfully written. In this
diff --git a/src/kudu/consensus/log_reader.h b/src/kudu/consensus/log_reader.h
index ca80179..2809c1a 100644
--- a/src/kudu/consensus/log_reader.h
+++ b/src/kudu/consensus/log_reader.h
@@ -34,6 +34,7 @@ namespace kudu {
 
 class Counter;
 class Env;
+class FileCache;
 class FsManager;
 class Histogram;
 class MetricEntity;
@@ -73,6 +74,7 @@ class LogReader : public enable_make_shared<LogReader> {
                      const scoped_refptr<LogIndex>& index,
                      const std::string& tablet_id,
                      const scoped_refptr<MetricEntity>& metric_entity,
+                     FileCache* file_cache,
                      std::shared_ptr<LogReader>* reader);
 
   // Same as above, but will use `fs_manager` to determine the default WAL dir
@@ -81,6 +83,7 @@ class LogReader : public enable_make_shared<LogReader> {
                      const scoped_refptr<LogIndex>& index,
                      const std::string& tablet_id,
                      const scoped_refptr<MetricEntity>& metric_entity,
+                     FileCache* file_cache,
                      std::shared_ptr<LogReader>* reader);
 
   // Return the minimum replicate index that is retained in the currently available
@@ -120,8 +123,11 @@ class LogReader : public enable_make_shared<LogReader> {
   std::string ToString() const;
 
  protected:
-  LogReader(Env* env, scoped_refptr<LogIndex> index, std::string tablet_id,
-            const scoped_refptr<MetricEntity>& metric_entity);
+  LogReader(Env* env,
+            scoped_refptr<LogIndex> index,
+            std::string tablet_id,
+            const scoped_refptr<MetricEntity>& metric_entity,
+            FileCache* file_cache);
 
  private:
   FRIEND_TEST(LogTestOptionalCompression, TestLogReader);
@@ -184,6 +190,7 @@ class LogReader : public enable_make_shared<LogReader> {
   void InitEmptyReaderForTests();
 
   Env* env_;
+  FileCache* file_cache_;
   const scoped_refptr<LogIndex> log_index_;
   const std::string tablet_id_;
 
diff --git a/src/kudu/consensus/log_util.cc b/src/kudu/consensus/log_util.cc
index 9783630..7fcfc1e 100644
--- a/src/kudu/consensus/log_util.cc
+++ b/src/kudu/consensus/log_util.cc
@@ -42,6 +42,7 @@
 #include "kudu/util/crc.h"
 #include "kudu/util/debug/trace_event.h"
 #include "kudu/util/fault_injection.h"
+#include "kudu/util/file_cache.h"
 #include "kudu/util/flag_tags.h"
 #include "kudu/util/logging.h"
 #include "kudu/util/pb_util.h"
@@ -66,6 +67,8 @@ DEFINE_double(fault_crash_before_write_log_segment_header, 0.0,
               "Fraction of the time we will crash just before writing the log segment header");
 TAG_FLAG(fault_crash_before_write_log_segment_header, unsafe);
 
+DECLARE_bool(fs_wal_use_file_cache);
+
 using kudu::consensus::OpId;
 using std::string;
 using std::shared_ptr;
@@ -258,16 +261,24 @@ Status LogEntryReader::MakeCorruptionStatus(const Status& status) const {
 ////////////////////////////////////////////////////////////
 
 Status ReadableLogSegment::Open(Env* env,
+                                FileCache* file_cache,
                                 const string& path,
                                 scoped_refptr<ReadableLogSegment>* segment) {
   VLOG(1) << "Parsing wal segment: " << path;
-  unique_ptr<RWFile> file;
-  RWFileOptions opts;
-  opts.mode = Env::MUST_EXIST;
-  RETURN_NOT_OK_PREPEND(env->NewRWFile(opts, path, &file),
-                        "Unable to open file for reading");
+  shared_ptr<RWFile> file;
+  if (PREDICT_TRUE(file_cache && FLAGS_fs_wal_use_file_cache)) {
+    RETURN_NOT_OK_PREPEND(file_cache->OpenFile<Env::MUST_EXIST>(path, &file),
+                          "unable to open file for reading");
+  } else {
+    unique_ptr<RWFile> f;
+    RWFileOptions opts;
+    opts.mode = Env::MUST_EXIST;
+    RETURN_NOT_OK_PREPEND(env->NewRWFile(opts, path, &f),
+                          "Unable to open file for reading");
+    file.reset(f.release());
+  }
 
-  segment->reset(new ReadableLogSegment(path, shared_ptr<RWFile>(file.release())));
+  segment->reset(new ReadableLogSegment(path, std::move(file)));
   RETURN_NOT_OK_PREPEND((*segment)->Init(), "Unable to initialize segment");
   return Status::OK();
 }
diff --git a/src/kudu/consensus/log_util.h b/src/kudu/consensus/log_util.h
index 27e8159..62571f1 100644
--- a/src/kudu/consensus/log_util.h
+++ b/src/kudu/consensus/log_util.h
@@ -44,6 +44,7 @@ DECLARE_bool(log_force_fsync_all);
 namespace kudu {
 
 class CompressionCodec;
+class FileCache;
 
 namespace log {
 
@@ -177,6 +178,7 @@ class ReadableLogSegment : public RefCountedThreadSafe<ReadableLogSegment> {
  public:
   // Factory method to construct a ReadableLogSegment from a file on the FS.
   static Status Open(Env* env,
+                     FileCache* file_cache,
                      const std::string& path,
                      scoped_refptr<ReadableLogSegment>* segment);
 
diff --git a/src/kudu/consensus/mt-log-test.cc b/src/kudu/consensus/mt-log-test.cc
index cb9329f..5a540d4 100644
--- a/src/kudu/consensus/mt-log-test.cc
+++ b/src/kudu/consensus/mt-log-test.cc
@@ -22,11 +22,11 @@
 #include <memory>
 #include <mutex>
 #include <ostream>
+#include <utility>
 #include <thread>
 #include <vector>
 
 #include <gflags/gflags.h>
-#include <gflags/gflags_declare.h>
 #include <glog/logging.h>
 #include <gtest/gtest.h>
 
@@ -43,7 +43,6 @@
 #include "kudu/consensus/opid.pb.h"
 #include "kudu/consensus/ref_counted_replicate.h"
 #include "kudu/gutil/bind.h"
-#include "kudu/gutil/gscoped_ptr.h"
 #include "kudu/gutil/port.h"
 #include "kudu/gutil/ref_counted.h"
 #include "kudu/gutil/strings/substitute.h"
@@ -51,7 +50,6 @@
 #include "kudu/util/countdown_latch.h"
 #include "kudu/util/fault_injection.h"
 #include "kudu/util/locks.h"
-#include "kudu/util/metrics.h"
 #include "kudu/util/random.h"
 #include "kudu/util/status.h"
 #include "kudu/util/status_callback.h"
@@ -204,7 +202,12 @@ class MultiThreadedLogTest : public LogTestBase {
 
   void VerifyLog() {
     shared_ptr<LogReader> reader;
-    ASSERT_OK(LogReader::Open(fs_manager_.get(), nullptr, kTestTablet, nullptr, &reader));
+    ASSERT_OK(LogReader::Open(fs_manager_.get(),
+                              /*index*/nullptr,
+                              kTestTablet,
+                              metric_entity_tablet_,
+                              file_cache_.get(),
+                              &reader));
     SegmentSequence segments;
     reader->GetSegmentsSnapshot(&segments);
 
diff --git a/src/kudu/consensus/raft_consensus_quorum-test.cc b/src/kudu/consensus/raft_consensus_quorum-test.cc
index 4615ff5..3a60f68 100644
--- a/src/kudu/consensus/raft_consensus_quorum-test.cc
+++ b/src/kudu/consensus/raft_consensus_quorum-test.cc
@@ -154,10 +154,11 @@ class RaftConsensusQuorumTest : public KuduTest {
       scoped_refptr<Log> log;
       RETURN_NOT_OK(Log::Open(LogOptions(),
                               fs_manager.get(),
+                              /*file_cache*/nullptr,
                               kTestTablet,
                               schema_,
                               0, // schema_version
-                              nullptr,
+                              /*metric_entity*/nullptr,
                               &log));
       logs_.emplace_back(std::move(log));
       fs_managers_.push_back(std::move(fs_manager));
@@ -435,9 +436,10 @@ class RaftConsensusQuorumTest : public KuduTest {
     log->Close();
     shared_ptr<LogReader> log_reader;
     ASSERT_OK(log::LogReader::Open(fs_managers_[idx].get(),
-                                   scoped_refptr<log::LogIndex>(),
+                                   /*index*/nullptr,
                                    kTestTablet,
                                    metric_entity_.get(),
+                                   /*file_cache*/nullptr,
                                    &log_reader));
     log::SegmentSequence segments;
     log_reader->GetSegmentsSnapshot(&segments);
diff --git a/src/kudu/integration-tests/log_verifier.cc b/src/kudu/integration-tests/log_verifier.cc
index 48be779..df21938 100644
--- a/src/kudu/integration-tests/log_verifier.cc
+++ b/src/kudu/integration-tests/log_verifier.cc
@@ -75,8 +75,13 @@ Status LogVerifier::ScanForCommittedOpIds(int ts_idx, const string& tablet_id,
 
   shared_ptr<LogReader> reader;
   const string wal_dir = JoinPathSegments(inspector_->WalDirForTS(ts_idx), tablet_id);
-  RETURN_NOT_OK(LogReader::Open(env_, wal_dir, scoped_refptr<log::LogIndex>(), tablet_id,
-                                scoped_refptr<MetricEntity>(), &reader));
+  RETURN_NOT_OK(LogReader::Open(env_,
+                                wal_dir,
+                                /*index*/nullptr,
+                                tablet_id,
+                                /*metric_entity*/nullptr,
+                                /*file_cache*/nullptr,
+                                &reader));
   log::SegmentSequence segs;
   reader->GetSegmentsSnapshot(&segs);
   unique_ptr<log::LogEntryPB> entry;
diff --git a/src/kudu/integration-tests/timestamp_advancement-itest.cc b/src/kudu/integration-tests/timestamp_advancement-itest.cc
index 8166052..5924e3b 100644
--- a/src/kudu/integration-tests/timestamp_advancement-itest.cc
+++ b/src/kudu/integration-tests/timestamp_advancement-itest.cc
@@ -182,8 +182,11 @@ class TimestampAdvancementITest : public MiniClusterITestBase {
     shared_ptr<LogReader> reader;
     RETURN_NOT_OK(LogReader::Open(
        ts->server()->fs_manager(),
-       scoped_refptr<log::LogIndex>(), tablet_id,
-       scoped_refptr<MetricEntity>(), &reader));
+       /*index*/nullptr,
+       tablet_id,
+       /*metric_entity*/nullptr,
+       ts->server()->file_cache(),
+       &reader));
     log::SegmentSequence segs;
     reader->GetSegmentsSnapshot(&segs);
     unique_ptr<log::LogEntryPB> entry;
diff --git a/src/kudu/integration-tests/ts_recovery-itest.cc b/src/kudu/integration-tests/ts_recovery-itest.cc
index 36b9ea8..04541ac 100644
--- a/src/kudu/integration-tests/ts_recovery-itest.cc
+++ b/src/kudu/integration-tests/ts_recovery-itest.cc
@@ -601,10 +601,11 @@ TEST_P(TsRecoveryITestDeathTest, TestRecoverFromOpIdOverflow) {
       scoped_refptr<Log> log;
       ASSERT_OK(Log::Open(LogOptions(),
                           fs_manager.get(),
+                          /*file_cache*/nullptr,
                           tablet_id,
                           SchemaBuilder(GetSimpleTestSchema()).Build(),
                           0, // schema_version
-                          nullptr,
+                          /*metric_entity*/nullptr,
                           &log));
 
       // Write a series of negative OpIds.
diff --git a/src/kudu/master/sys_catalog.cc b/src/kudu/master/sys_catalog.cc
index e716c23..c095096 100644
--- a/src/kudu/master/sys_catalog.cc
+++ b/src/kudu/master/sys_catalog.cc
@@ -419,12 +419,13 @@ Status SysCatalogTable::SetupTablet(
       cmeta->CommittedConfig(),
       master_->clock(),
       master_->mem_tracker(),
-      scoped_refptr<rpc::ResultTracker>(),
+      /*result_tracker*/nullptr,
       metric_registry_,
+      master_->file_cache(),
       tablet_replica_,
+      tablet_replica_->log_anchor_registry(),
       &tablet,
       &log,
-      tablet_replica_->log_anchor_registry(),
       &consensus_info), "failed to bootstrap system catalog");
 
   // TODO(matteo): Do we have a setSplittable(false) or something from the
@@ -435,7 +436,7 @@ Status SysCatalogTable::SetupTablet(
       tablet,
       master_->clock(),
       master_->messenger(),
-      scoped_refptr<rpc::ResultTracker>(),
+      /*result_tracker*/nullptr,
       log,
       master_->tablet_prepare_pool(),
       master_->dns_resolver()), "failed to start system catalog replica");
diff --git a/src/kudu/tablet/tablet_bootstrap-test.cc b/src/kudu/tablet/tablet_bootstrap-test.cc
index fd29b29..46229f7 100644
--- a/src/kudu/tablet/tablet_bootstrap-test.cc
+++ b/src/kudu/tablet/tablet_bootstrap-test.cc
@@ -96,9 +96,6 @@ using std::unique_ptr;
 using std::vector;
 
 namespace kudu {
-
-class MemTracker;
-
 namespace tablet {
 
 class BootstrapTest : public LogTestBase {
@@ -160,19 +157,24 @@ class BootstrapTest : public LogTestBase {
     scoped_refptr<ConsensusMetadata> cmeta;
     RETURN_NOT_OK(cmeta_manager_->Load(meta->tablet_id(), &cmeta));
 
+    // Close the existing log to evict any segments from the file cache so that
+    // bootstrap won't access any stale (cached) segments.
+    RETURN_NOT_OK(log_->Close());
+
     scoped_refptr<LogAnchorRegistry> log_anchor_registry(new LogAnchorRegistry());
     // Now attempt to recover the log
     RETURN_NOT_OK(BootstrapTablet(
         meta,
         cmeta->CommittedConfig(),
         clock_.get(),
-        shared_ptr<MemTracker>(),
-        scoped_refptr<rpc::ResultTracker>(),
-        nullptr,
-        nullptr, // no status listener
+        /*mem_tracker*/nullptr,
+        /*result_tracker*/nullptr,
+        metric_registry_.get(),
+        file_cache_.get(),
+        /*tablet_replica*/nullptr,
+        std::move(log_anchor_registry),
         tablet,
         &log_,
-        log_anchor_registry,
         boot_info));
 
     return Status::OK();
diff --git a/src/kudu/tablet/tablet_bootstrap.cc b/src/kudu/tablet/tablet_bootstrap.cc
index baf1537..1f3e8b3 100644
--- a/src/kudu/tablet/tablet_bootstrap.cc
+++ b/src/kudu/tablet/tablet_bootstrap.cc
@@ -197,6 +197,7 @@ class TabletBootstrap {
                   shared_ptr<MemTracker> mem_tracker,
                   scoped_refptr<ResultTracker> result_tracker,
                   MetricRegistry* metric_registry,
+                  FileCache* file_cache,
                   scoped_refptr<TabletReplica> tablet_replica,
                   scoped_refptr<LogAnchorRegistry> log_anchor_registry);
 
@@ -377,6 +378,7 @@ class TabletBootstrap {
   shared_ptr<MemTracker> mem_tracker_;
   scoped_refptr<rpc::ResultTracker> result_tracker_;
   MetricRegistry* metric_registry_;
+  FileCache* file_cache_;
   scoped_refptr<TabletReplica> tablet_replica_;
   unique_ptr<tablet::Tablet> tablet_;
   const scoped_refptr<log::LogAnchorRegistry> log_anchor_registry_;
@@ -445,10 +447,11 @@ Status BootstrapTablet(scoped_refptr<TabletMetadata> tablet_meta,
                        shared_ptr<MemTracker> mem_tracker,
                        scoped_refptr<ResultTracker> result_tracker,
                        MetricRegistry* metric_registry,
+                       FileCache* file_cache,
                        scoped_refptr<TabletReplica> tablet_replica,
+                       scoped_refptr<log::LogAnchorRegistry> log_anchor_registry,
                        shared_ptr<tablet::Tablet>* rebuilt_tablet,
                        scoped_refptr<log::Log>* rebuilt_log,
-                       scoped_refptr<log::LogAnchorRegistry> log_anchor_registry,
                        ConsensusBootstrapInfo* consensus_info) {
   TRACE_EVENT1("tablet", "BootstrapTablet",
                "tablet_id", tablet_meta->tablet_id());
@@ -458,6 +461,7 @@ Status BootstrapTablet(scoped_refptr<TabletMetadata> tablet_meta,
                             std::move(mem_tracker),
                             std::move(result_tracker),
                             metric_registry,
+                            file_cache,
                             std::move(tablet_replica),
                             std::move(log_anchor_registry));
   RETURN_NOT_OK(bootstrap.Bootstrap(rebuilt_tablet, rebuilt_log, consensus_info));
@@ -494,6 +498,7 @@ TabletBootstrap::TabletBootstrap(
     shared_ptr<MemTracker> mem_tracker,
     scoped_refptr<ResultTracker> result_tracker,
     MetricRegistry* metric_registry,
+    FileCache* file_cache,
     scoped_refptr<TabletReplica> tablet_replica,
     scoped_refptr<LogAnchorRegistry> log_anchor_registry)
     : tablet_meta_(std::move(tablet_meta)),
@@ -502,6 +507,7 @@ TabletBootstrap::TabletBootstrap(
       mem_tracker_(std::move(mem_tracker)),
       result_tracker_(std::move(result_tracker)),
       metric_registry_(metric_registry),
+      file_cache_(file_cache),
       tablet_replica_(std::move(tablet_replica)),
       log_anchor_registry_(std::move(log_anchor_registry)) {}
 
@@ -720,17 +726,16 @@ Status TabletBootstrap::OpenLogReaderInRecoveryDir() {
   const string recovery_dir = fs_manager->GetTabletWalRecoveryDir(tablet_id);
   RETURN_NOT_OK_PREPEND(LogReader::Open(fs_manager->env(), recovery_dir, log_index, tablet_id,
                                         tablet_->GetMetricEntity().get(),
+                                        file_cache_,
                                         &log_reader_),
                         "Could not open LogReader. Reason");
   return Status::OK();
 }
 
 Status TabletBootstrap::OpenNewLog() {
-  OpId init;
-  init.set_term(0);
-  init.set_index(0);
   RETURN_NOT_OK(Log::Open(LogOptions(),
                           tablet_->metadata()->fs_manager(),
+                          file_cache_,
                           tablet_->tablet_id(),
                           *tablet_->schema(),
                           tablet_->metadata()->schema_version(),
diff --git a/src/kudu/tablet/tablet_bootstrap.h b/src/kudu/tablet/tablet_bootstrap.h
index 5bfa5a5..1bcdf24 100644
--- a/src/kudu/tablet/tablet_bootstrap.h
+++ b/src/kudu/tablet/tablet_bootstrap.h
@@ -23,6 +23,7 @@
 
 namespace kudu {
 
+class FileCache;
 class MemTracker;
 class MetricRegistry;
 
@@ -63,10 +64,11 @@ Status BootstrapTablet(scoped_refptr<TabletMetadata> tablet_meta,
                        std::shared_ptr<MemTracker> mem_tracker,
                        scoped_refptr<rpc::ResultTracker> result_tracker,
                        MetricRegistry* metric_registry,
+                       FileCache* file_cache,
                        scoped_refptr<TabletReplica> tablet_replica,
+                       scoped_refptr<log::LogAnchorRegistry> log_anchor_registry,
                        std::shared_ptr<Tablet>* rebuilt_tablet,
                        scoped_refptr<log::Log>* rebuilt_log,
-                       scoped_refptr<log::LogAnchorRegistry> log_anchor_registry,
                        consensus::ConsensusBootstrapInfo* consensus_info);
 
 }  // namespace tablet
diff --git a/src/kudu/tablet/tablet_replica-test.cc b/src/kudu/tablet/tablet_replica-test.cc
index b1bf7df..3d60c47 100644
--- a/src/kudu/tablet/tablet_replica-test.cc
+++ b/src/kudu/tablet/tablet_replica-test.cc
@@ -28,7 +28,6 @@
 #include <glog/logging.h>
 #include <gtest/gtest.h>
 
-#include "kudu/clock/clock.h"
 #include "kudu/common/common.pb.h"
 #include "kudu/common/partial_row.h"
 #include "kudu/common/row_operations.h"
@@ -109,9 +108,6 @@ using std::string;
 using std::unique_ptr;
 
 namespace kudu {
-
-class MemTracker;
-
 namespace tablet {
 
 static Schema GetTestSchema() {
@@ -181,9 +177,14 @@ class TabletReplicaTest : public KuduTabletTest {
 
   Status StartReplica(const ConsensusBootstrapInfo& info) {
     scoped_refptr<Log> log;
-    RETURN_NOT_OK(Log::Open(LogOptions(), fs_manager(), tablet()->tablet_id(),
-                            *tablet()->schema(), tablet()->metadata()->schema_version(),
-                            metric_entity_.get(), &log));
+    RETURN_NOT_OK(Log::Open(LogOptions(),
+                            fs_manager(),
+                            /*file_cache*/nullptr,
+                            tablet()->tablet_id(),
+                            *tablet()->schema(),
+                            tablet()->metadata()->schema_version(),
+                            metric_entity_.get(),
+                            &log));
     tablet_replica_->SetBootstrapping();
     return tablet_replica_->Start(info,
                                   tablet(),
@@ -226,13 +227,14 @@ class TabletReplicaTest : public KuduTabletTest {
     ASSERT_OK(BootstrapTablet(tablet_replica_->tablet_metadata(),
                               cmeta->CommittedConfig(),
                               clock(),
-                              shared_ptr<MemTracker>(),
-                              scoped_refptr<ResultTracker>(),
+                              /*mem_tracker*/nullptr,
+                              /*result_tracker*/nullptr,
                               &metric_registry_,
+                              /*file_cache*/nullptr,
                               tablet_replica_,
+                              tablet_replica_->log_anchor_registry(),
                               &tablet,
                               &log,
-                              tablet_replica_->log_anchor_registry(),
                               &bootstrap_info));
     ASSERT_OK(tablet_replica_->Start(bootstrap_info,
                                      tablet,
diff --git a/src/kudu/tools/kudu-tool-test.cc b/src/kudu/tools/kudu-tool-test.cc
index 0c47957..fd8b66c 100644
--- a/src/kudu/tools/kudu-tool-test.cc
+++ b/src/kudu/tools/kudu-tool-test.cc
@@ -1586,10 +1586,11 @@ TEST_F(ToolTest, TestWalDump) {
     scoped_refptr<Log> log;
     ASSERT_OK(Log::Open(LogOptions(),
                         &fs,
+                        /*file_cache*/nullptr,
                         kTestTablet,
                         kSchemaWithIds,
                         0, // schema_version
-                        scoped_refptr<MetricEntity>(),
+                        /*metric_entity*/nullptr,
                         &log));
 
     OpId opid = consensus::MakeOpId(1, 1);
diff --git a/src/kudu/tools/tool_action_local_replica.cc b/src/kudu/tools/tool_action_local_replica.cc
index 347d1b6..36b1005 100644
--- a/src/kudu/tools/tool_action_local_replica.cc
+++ b/src/kudu/tools/tool_action_local_replica.cc
@@ -50,6 +50,7 @@
 #include "kudu/fs/block_id.h"
 #include "kudu/fs/block_manager.h"
 #include "kudu/fs/data_dirs.h"
+#include "kudu/fs/dir_manager.h"
 #include "kudu/fs/fs_manager.h"
 #include "kudu/fs/io_context.h"
 #include "kudu/gutil/map-util.h"
@@ -186,8 +187,12 @@ Status ParseHostPortString(const string& hostport_str, HostPort* hostport) {
 Status FindLastLoggedOpId(FsManager* fs, const string& tablet_id,
                           OpId* last_logged_opid) {
   shared_ptr<LogReader> reader;
-  RETURN_NOT_OK(LogReader::Open(fs, scoped_refptr<log::LogIndex>(), tablet_id,
-                                scoped_refptr<MetricEntity>(), &reader));
+  RETURN_NOT_OK(LogReader::Open(fs,
+                                /*index*/nullptr,
+                                tablet_id,
+                                /*metric_entity*/nullptr,
+                                /*file_cache*/nullptr,
+                                &reader));
   SegmentSequence segs;
   reader->GetSegmentsSnapshot(&segs);
   // Reverse iterate the segments to find the 'last replicated' entry quickly.
@@ -521,9 +526,10 @@ Status DumpWals(const RunnerContext& context) {
 
   shared_ptr<LogReader> reader;
   RETURN_NOT_OK(LogReader::Open(fs_manager.get(),
-                                scoped_refptr<LogIndex>(),
+                                /*index*/nullptr,
                                 tablet_id,
-                                scoped_refptr<MetricEntity>(),
+                                /*metric_entity*/nullptr,
+                                /*file_cache*/nullptr,
                                 &reader));
 
   SegmentSequence segments;
diff --git a/src/kudu/tools/tool_action_perf.cc b/src/kudu/tools/tool_action_perf.cc
index c31f19d..c961c8a 100644
--- a/src/kudu/tools/tool_action_perf.cc
+++ b/src/kudu/tools/tool_action_perf.cc
@@ -829,10 +829,11 @@ Status TabletScan(const RunnerContext& context) {
                                         /*mem_tracker=*/ nullptr,
                                         /*result_tracker=*/ nullptr,
                                         /*metric_registry=*/ nullptr,
+                                        /*file_cache=*/ nullptr,
                                         /*tablet_replica=*/ nullptr,
+                                        std::move(registry),
                                         &tablet,
                                         &log,
-                                        std::move(registry),
                                         &cbi));
 
   // Tablet has been bootstrapped and opened. We can now scan it.
diff --git a/src/kudu/tools/tool_action_wal.cc b/src/kudu/tools/tool_action_wal.cc
index 0c2a600..a27ab91 100644
--- a/src/kudu/tools/tool_action_wal.cc
+++ b/src/kudu/tools/tool_action_wal.cc
@@ -44,7 +44,10 @@ Status Dump(const RunnerContext& context) {
   const string& segment_path = FindOrDie(context.required_args, kPathArg);
 
   scoped_refptr<ReadableLogSegment> segment;
-  RETURN_NOT_OK(ReadableLogSegment::Open(Env::Default(), segment_path, &segment));
+  RETURN_NOT_OK(ReadableLogSegment::Open(Env::Default(),
+                                         /*file_cache*/nullptr,
+                                         segment_path,
+                                         &segment));
   RETURN_NOT_OK(PrintSegment(segment));
   return Status::OK();
 }
diff --git a/src/kudu/tserver/tablet_copy_source_session-test.cc b/src/kudu/tserver/tablet_copy_source_session-test.cc
index 8aa5eec..1041d9b 100644
--- a/src/kudu/tserver/tablet_copy_source_session-test.cc
+++ b/src/kudu/tserver/tablet_copy_source_session-test.cc
@@ -14,7 +14,8 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
-#include "kudu/tablet/tablet-test-util.h"
+
+#include "kudu/tserver/tablet_copy_source_session.h"
 
 #include <cstdint>
 #include <memory>
@@ -26,7 +27,6 @@
 #include <glog/logging.h>
 #include <gtest/gtest.h>
 
-#include "kudu/clock/clock.h"
 #include "kudu/common/common.pb.h"
 #include "kudu/common/partial_row.h"
 #include "kudu/common/row_operations.h"
@@ -52,13 +52,13 @@
 #include "kudu/rpc/messenger.h"
 #include "kudu/rpc/result_tracker.h"
 #include "kudu/tablet/metadata.pb.h"
+#include "kudu/tablet/tablet-test-util.h"
 #include "kudu/tablet/tablet.h"
 #include "kudu/tablet/tablet_metadata.h"
 #include "kudu/tablet/tablet_replica.h"
 #include "kudu/tablet/transactions/transaction.h"
 #include "kudu/tablet/transactions/write_transaction.h"
 #include "kudu/tserver/tablet_copy.pb.h"
-#include "kudu/tserver/tablet_copy_source_session.h"
 #include "kudu/tserver/tserver.pb.h"
 #include "kudu/util/countdown_latch.h"
 #include "kudu/util/crc.h"
@@ -134,7 +134,10 @@ class TabletCopyTest : public KuduTabletTest {
  protected:
   void SetUpTabletReplica() {
     scoped_refptr<Log> log;
-    ASSERT_OK(Log::Open(LogOptions(), fs_manager(), tablet()->tablet_id(),
+    ASSERT_OK(Log::Open(LogOptions(),
+                        fs_manager(),
+                        /*file_cache=*/ nullptr,
+                        tablet()->tablet_id(),
                         *tablet()->schema(),
                         /*schema_version=*/ 0,
                         /*metric_entity=*/ nullptr,
diff --git a/src/kudu/tserver/ts_tablet_manager.cc b/src/kudu/tserver/ts_tablet_manager.cc
index f96d45b..ee578ba 100644
--- a/src/kudu/tserver/ts_tablet_manager.cc
+++ b/src/kudu/tserver/ts_tablet_manager.cc
@@ -1124,10 +1124,11 @@ void TSTabletManager::OpenTablet(const scoped_refptr<TabletReplica>& replica,
                         server_->mem_tracker(),
                         server_->result_tracker(),
                         metric_registry_,
+                        server_->file_cache(),
                         replica,
+                        replica->log_anchor_registry(),
                         &tablet,
                         &log,
-                        replica->log_anchor_registry(),
                         &bootstrap_info);
     if (!s.ok()) {
       LOG(ERROR) << LogPrefix(tablet_id) << "Tablet failed to bootstrap: "
diff --git a/src/kudu/tserver/ts_tablet_manager.h b/src/kudu/tserver/ts_tablet_manager.h
index 68cc4b7..01f3518 100644
--- a/src/kudu/tserver/ts_tablet_manager.h
+++ b/src/kudu/tserver/ts_tablet_manager.h
@@ -49,16 +49,13 @@ class optional;
 }
 
 namespace kudu {
-class TableExtraConfigPB;
-}  // namespace kudu
-
-namespace kudu {
 
 class FsManager;
 class NodeInstancePB;
 class Partition;
 class PartitionSchema;
 class Schema;
+class TableExtraConfigPB;
 class ThreadPool;
 
 namespace consensus {


Mime
View raw message