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 #include "file/random_access_file_reader.h"
15 #include "port/port.h"
16 #include "rocksdb/env.h"
17 #include "util/aligned_buffer.h"
18 
19 namespace ROCKSDB_NAMESPACE {
20 
21 // FilePrefetchBuffer is a smart buffer to store and read data from a file.
22 class FilePrefetchBuffer {
23  public:
24   // Constructor.
25   //
26   // All arguments are optional.
27   // file_reader        : the file reader to use. Can be a nullptr.
28   // readahead_size     : the initial readahead size.
29   // max_readahead_size : the maximum readahead size.
30   //   If max_readahead_size > readahead_size, the readahead size will be
31   //   doubled on every IO until max_readahead_size is hit.
32   //   Typically this is set as a multiple of readahead_size.
33   //   max_readahead_size should be greater than equal to readahead_size.
34   // enable : controls whether reading from the buffer is enabled.
35   //   If false, TryReadFromCache() always return false, and we only take stats
36   //   for the minimum offset if track_min_offset = true.
37   // track_min_offset : Track the minimum offset ever read and collect stats on
38   //   it. Used for adaptable readahead of the file footer/metadata.
39   //
40   // Automatic readhead is enabled for a file if file_reader, readahead_size,
41   // and max_readahead_size are passed in.
42   // If file_reader is a nullptr, setting readadhead_size and max_readahead_size
43   // does not make any sense. So it does nothing.
44   // A user can construct a FilePrefetchBuffer without any arguments, but use
45   // `Prefetch` to load data into the buffer.
46   FilePrefetchBuffer(RandomAccessFileReader* file_reader = nullptr,
47                      size_t readadhead_size = 0, size_t max_readahead_size = 0,
48                      bool enable = true, bool track_min_offset = false)
49       : buffer_offset_(0),
50         file_reader_(file_reader),
51         readahead_size_(readadhead_size),
52         max_readahead_size_(max_readahead_size),
53         min_offset_read_(port::kMaxSizet),
54         enable_(enable),
55         track_min_offset_(track_min_offset) {}
56 
57   // Load data into the buffer from a file.
58   // reader : the file reader.
59   // offset : the file offset to start reading from.
60   // n      : the number of bytes to read.
61   // for_compaction : if prefetch is done for compaction read.
62   Status Prefetch(RandomAccessFileReader* reader, uint64_t offset, size_t n,
63                   bool for_compaction = false);
64 
65   // Tries returning the data for a file raed from this buffer, if that data is
66   // in the buffer.
67   // It handles tracking the minimum read offset if track_min_offset = true.
68   // It also does the exponential readahead when readadhead_size is set as part
69   // of the constructor.
70   //
71   // offset : the file offset.
72   // n      : the number of bytes.
73   // result : output buffer to put the data into.
74   // for_compaction : if cache read is done for compaction read.
75   bool TryReadFromCache(uint64_t offset, size_t n, Slice* result,
76                         bool for_compaction = false);
77 
78   // The minimum `offset` ever passed to TryReadFromCache(). This will nly be
79   // tracked if track_min_offset = true.
min_offset_read()80   size_t min_offset_read() const { return min_offset_read_; }
81 
82  private:
83   AlignedBuffer buffer_;
84   uint64_t buffer_offset_;
85   RandomAccessFileReader* file_reader_;
86   size_t readahead_size_;
87   size_t max_readahead_size_;
88   // The minimum `offset` ever passed to TryReadFromCache().
89   size_t min_offset_read_;
90   // if false, TryReadFromCache() always return false, and we only take stats
91   // for track_min_offset_ if track_min_offset_ = true
92   bool enable_;
93   // If true, track minimum `offset` ever passed to TryReadFromCache(), which
94   // can be fetched from min_offset_read().
95   bool track_min_offset_;
96 };
97 }  // namespace ROCKSDB_NAMESPACE
98