Coverage Report

Created: 2026-08-14 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rocksdb/table/plain/plain_table_key_coding.h
Line
Count
Source
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
#pragma once
7
8
#include <array>
9
10
#include "rocksdb/slice.h"
11
#include "table/plain/plain_table_reader.h"
12
13
// The file contains three helper classes of PlainTable format,
14
// PlainTableKeyEncoder, PlainTableKeyDecoder and PlainTableFileReader.
15
// These classes issue the lowest level of operations of PlainTable.
16
// Actual data format of the key is documented in comments of class
17
// PlainTableFactory.
18
namespace ROCKSDB_NAMESPACE {
19
20
class WritableFile;
21
struct ParsedInternalKey;
22
struct PlainTableReaderFileInfo;
23
enum PlainTableEntryType : unsigned char;
24
25
// Helper class for PlainTable format to write out a key to an output file
26
// The class is used in PlainTableBuilder.
27
class PlainTableKeyEncoder {
28
 public:
29
  explicit PlainTableKeyEncoder(EncodingType encoding_type,
30
                                uint32_t user_key_len,
31
                                const SliceTransform* prefix_extractor,
32
                                size_t index_sparseness)
33
0
      : encoding_type_((prefix_extractor != nullptr) ? encoding_type : kPlain),
34
0
        fixed_user_key_len_(user_key_len),
35
0
        prefix_extractor_(prefix_extractor),
36
0
        index_sparseness_((index_sparseness > 1) ? index_sparseness : 1),
37
0
        key_count_for_prefix_(0) {}
38
  // key: the key to write out, in the format of internal key.
39
  // file: the output file to write out
40
  // offset: offset in the file. Needs to be updated after appending bytes
41
  //         for the key
42
  // meta_bytes_buf: buffer for extra meta bytes
43
  // meta_bytes_buf_size: offset to append extra meta bytes. Will be updated
44
  //                      if meta_bytes_buf is updated.
45
  IOStatus AppendKey(const Slice& key, WritableFileWriter* file,
46
                     uint64_t* offset, char* meta_bytes_buf,
47
                     size_t* meta_bytes_buf_size);
48
49
  // Return actual encoding type to be picked
50
0
  EncodingType GetEncodingType() { return encoding_type_; }
51
52
 private:
53
  EncodingType encoding_type_;
54
  uint32_t fixed_user_key_len_;
55
  const SliceTransform* prefix_extractor_;
56
  const size_t index_sparseness_;
57
  size_t key_count_for_prefix_;
58
  IterKey pre_prefix_;
59
};
60
61
// The class does raw file reads for PlainTableReader.
62
// It hides whether it is a mmap-read, or a non-mmap read.
63
// The class is implemented in a way to favor the performance of mmap case.
64
// The class is used by PlainTableReader.
65
class PlainTableFileReader {
66
 public:
67
  explicit PlainTableFileReader(const PlainTableReaderFileInfo* _file_info)
68
0
      : file_info_(_file_info), num_buf_(0) {}
69
70
0
  ~PlainTableFileReader() {
71
    // Should fix.
72
0
    status_.PermitUncheckedError();
73
0
  }
74
75
  // In mmaped mode, the results point to mmaped area of the file, which
76
  // means it is always valid before closing the file.
77
  // In non-mmap mode, the results point to an internal buffer. If the caller
78
  // makes another read call, the results may not be valid. So callers should
79
  // make a copy when needed.
80
  // In order to save read calls to files, we keep two internal buffers:
81
  // the first read and the most recent read. This is efficient because it
82
  // columns these two common use cases:
83
  // (1) hash index only identify one location, we read the key to verify
84
  //     the location, and read key and value if it is the right location.
85
  // (2) after hash index checking, we identify two locations (because of
86
  //     hash bucket conflicts), we binary search the two location to see
87
  //     which one is what we need and start to read from the location.
88
  // These two most common use cases will be covered by the two buffers
89
  // so that we don't need to re-read the same location.
90
  // Currently we keep a fixed size buffer. If a read doesn't exactly fit
91
  // the buffer, we replace the second buffer with the location user reads.
92
  //
93
  // If return false, status code is stored in status_.
94
0
  bool Read(uint32_t file_offset, uint32_t len, Slice* out) {
95
0
    if (file_info_->is_mmap_mode) {
96
0
      assert(file_offset + len <= file_info_->data_end_offset);
97
0
      *out = Slice(file_info_->file_data.data() + file_offset, len);
98
0
      return true;
99
0
    } else {
100
0
      return ReadNonMmap(file_offset, len, out);
101
0
    }
102
0
  }
103
104
  // If return false, status code is stored in status_.
105
  bool ReadNonMmap(uint32_t file_offset, uint32_t len, Slice* output);
106
107
  // *bytes_read = 0 means eof. false means failure and status is saved
108
  // in status_. Not directly returning Status to save copying status
109
  // object to map previous performance of mmap mode.
110
  inline bool ReadVarint32(uint32_t offset, uint32_t* output,
111
                           uint32_t* bytes_read);
112
113
  bool ReadVarint32NonMmap(uint32_t offset, uint32_t* output,
114
                           uint32_t* bytes_read);
115
116
0
  Status status() const { return status_; }
117
118
0
  const PlainTableReaderFileInfo* file_info() { return file_info_; }
119
120
 private:
121
  const PlainTableReaderFileInfo* file_info_;
122
123
  struct Buffer {
124
0
    Buffer() : buf_start_offset(0), buf_len(0), buf_capacity(0) {}
125
    std::unique_ptr<char[]> buf;
126
    uint32_t buf_start_offset;
127
    uint32_t buf_len;
128
    uint32_t buf_capacity;
129
  };
130
131
  // Keep buffers for two recent reads.
132
  std::array<std::unique_ptr<Buffer>, 2> buffers_;
133
  uint32_t num_buf_;
134
  Status status_;
135
136
  Slice GetFromBuffer(Buffer* buf, uint32_t file_offset, uint32_t len);
137
};
138
139
// A helper class to decode keys from input buffer
140
// The class is used by PlainTableBuilder.
141
class PlainTableKeyDecoder {
142
 public:
143
  explicit PlainTableKeyDecoder(const PlainTableReaderFileInfo* file_info,
144
                                EncodingType encoding_type,
145
                                uint32_t user_key_len,
146
                                const SliceTransform* prefix_extractor)
147
0
      : file_reader_(file_info),
148
0
        encoding_type_(encoding_type),
149
0
        prefix_len_(0),
150
0
        fixed_user_key_len_(user_key_len),
151
0
        prefix_extractor_(prefix_extractor),
152
0
        in_prefix_(false) {}
153
154
  // Find the next key.
155
  // start: char array where the key starts.
156
  // limit: boundary of the char array
157
  // parsed_key: the output of the result key
158
  // internal_key: if not null, fill with the output of the result key in
159
  //               un-parsed format
160
  // bytes_read: how many bytes read from start. Output
161
  // seekable: whether key can be read from this place. Used when building
162
  //           indexes. Output.
163
  Status NextKey(uint32_t start_offset, ParsedInternalKey* parsed_key,
164
                 Slice* internal_key, Slice* value, uint32_t* bytes_read,
165
                 bool* seekable = nullptr);
166
167
  Status NextKeyNoValue(uint32_t start_offset, ParsedInternalKey* parsed_key,
168
                        Slice* internal_key, uint32_t* bytes_read,
169
                        bool* seekable = nullptr);
170
171
  PlainTableFileReader file_reader_;
172
  EncodingType encoding_type_;
173
  uint32_t prefix_len_;
174
  uint32_t fixed_user_key_len_;
175
  Slice saved_user_key_;
176
  IterKey cur_key_;
177
  const SliceTransform* prefix_extractor_;
178
  bool in_prefix_;
179
180
 private:
181
  Status NextPlainEncodingKey(uint32_t start_offset,
182
                              ParsedInternalKey* parsed_key,
183
                              Slice* internal_key, uint32_t* bytes_read,
184
                              bool* seekable = nullptr);
185
  Status NextPrefixEncodingKey(uint32_t start_offset,
186
                               ParsedInternalKey* parsed_key,
187
                               Slice* internal_key, uint32_t* bytes_read,
188
                               bool* seekable = nullptr);
189
  Status ReadInternalKey(uint32_t file_offset, uint32_t user_key_size,
190
                         ParsedInternalKey* parsed_key, uint32_t* bytes_read,
191
                         bool* internal_key_valid, Slice* internal_key);
192
  inline Status DecodeSize(uint32_t start_offset,
193
                           PlainTableEntryType* entry_type, uint32_t* key_size,
194
                           uint32_t* bytes_read);
195
};
196
197
}  // namespace ROCKSDB_NAMESPACE