1 //  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 //
6 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7 // Use of this source code is governed by a BSD-style license that can be
8 // found in the LICENSE file. See the AUTHORS file for names of contributors.
9 
10 #pragma once
11 #include <atomic>
12 #include <sstream>
13 #include <string>
14 
15 #include "file/random_access_file_reader.h"
16 #include "port/port.h"
17 #include "rocksdb/env.h"
18 #include "rocksdb/options.h"
19 #include "util/aligned_buffer.h"
20 
21 namespace ROCKSDB_NAMESPACE {
22 
23 // FilePrefetchBuffer is a smart buffer to store and read data from a file.
24 class FilePrefetchBuffer {
25  public:
26   static const int kMinNumFileReadsToStartAutoReadahead = 2;
27   // Constructor.
28   //
29   // All arguments are optional.
30   // file_reader        : the file reader to use. Can be a nullptr.
31   // readahead_size     : the initial readahead size.
32   // max_readahead_size : the maximum readahead size.
33   //   If max_readahead_size > readahead_size, the readahead size will be
34   //   doubled on every IO until max_readahead_size is hit.
35   //   Typically this is set as a multiple of readahead_size.
36   //   max_readahead_size should be greater than equal to readahead_size.
37   // enable : controls whether reading from the buffer is enabled.
38   //   If false, TryReadFromCache() always return false, and we only take stats
39   //   for the minimum offset if track_min_offset = true.
40   // track_min_offset : Track the minimum offset ever read and collect stats on
41   //   it. Used for adaptable readahead of the file footer/metadata.
42   // implicit_auto_readahead : Readahead is enabled implicitly by rocksdb after
43   //   doing sequential scans for two times.
44   //
45   // Automatic readhead is enabled for a file if file_reader, readahead_size,
46   // and max_readahead_size are passed in.
47   // If file_reader is a nullptr, setting readahead_size and max_readahead_size
48   // does not make any sense. So it does nothing.
49   // A user can construct a FilePrefetchBuffer without any arguments, but use
50   // `Prefetch` to load data into the buffer.
51   FilePrefetchBuffer(RandomAccessFileReader* file_reader = nullptr,
52                      size_t readahead_size = 0, size_t max_readahead_size = 0,
53                      bool enable = true, bool track_min_offset = false,
54                      bool implicit_auto_readahead = false)
55       : buffer_offset_(0),
56         file_reader_(file_reader),
57         readahead_size_(readahead_size),
58         max_readahead_size_(max_readahead_size),
59         initial_readahead_size_(readahead_size),
60         min_offset_read_(port::kMaxSizet),
61         enable_(enable),
62         track_min_offset_(track_min_offset),
63         implicit_auto_readahead_(implicit_auto_readahead),
64         prev_offset_(0),
65         prev_len_(0),
66         num_file_reads_(kMinNumFileReadsToStartAutoReadahead + 1) {}
67 
68   // Load data into the buffer from a file.
69   // reader : the file reader.
70   // offset : the file offset to start reading from.
71   // n      : the number of bytes to read.
72   // for_compaction : if prefetch is done for compaction read.
73   Status Prefetch(const IOOptions& opts, RandomAccessFileReader* reader,
74                   uint64_t offset, size_t n, bool for_compaction = false);
75 
76   // Tries returning the data for a file raed from this buffer, if that data is
77   // in the buffer.
78   // It handles tracking the minimum read offset if track_min_offset = true.
79   // It also does the exponential readahead when readahead_size is set as part
80   // of the constructor.
81   //
82   // offset : the file offset.
83   // n      : the number of bytes.
84   // result : output buffer to put the data into.
85   // for_compaction : if cache read is done for compaction read.
86   bool TryReadFromCache(const IOOptions& opts, uint64_t offset, size_t n,
87                         Slice* result, Status* s, bool for_compaction = false);
88 
89   // The minimum `offset` ever passed to TryReadFromCache(). This will nly be
90   // tracked if track_min_offset = true.
min_offset_read()91   size_t min_offset_read() const { return min_offset_read_; }
92 
UpdateReadPattern(const size_t & offset,const size_t & len)93   void UpdateReadPattern(const size_t& offset, const size_t& len) {
94     prev_offset_ = offset;
95     prev_len_ = len;
96   }
97 
IsBlockSequential(const size_t & offset)98   bool IsBlockSequential(const size_t& offset) {
99     return (prev_len_ == 0 || (prev_offset_ + prev_len_ == offset));
100   }
101 
ResetValues()102   void ResetValues() {
103     num_file_reads_ = 1;
104     readahead_size_ = initial_readahead_size_;
105   }
106 
107  private:
108   AlignedBuffer buffer_;
109   uint64_t buffer_offset_;
110   RandomAccessFileReader* file_reader_;
111   size_t readahead_size_;
112   size_t max_readahead_size_;
113   size_t initial_readahead_size_;
114   // The minimum `offset` ever passed to TryReadFromCache().
115   size_t min_offset_read_;
116   // if false, TryReadFromCache() always return false, and we only take stats
117   // for track_min_offset_ if track_min_offset_ = true
118   bool enable_;
119   // If true, track minimum `offset` ever passed to TryReadFromCache(), which
120   // can be fetched from min_offset_read().
121   bool track_min_offset_;
122 
123   // implicit_auto_readahead is enabled by rocksdb internally after 2 sequential
124   // IOs.
125   bool implicit_auto_readahead_;
126   size_t prev_offset_;
127   size_t prev_len_;
128   int num_file_reads_;
129 };
130 }  // namespace ROCKSDB_NAMESPACE
131