YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/rocksdb/db/file_indexer.cc
Line
Count
Source (jump to first uncovered line)
1
//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2
//  This source code is licensed under the BSD-style license found in the
3
//  LICENSE file in the root directory of this source tree. An additional grant
4
//  of patent rights can be found in the PATENTS file in the same directory.
5
//
6
// The following only applies to changes made to this file as part of YugaByte development.
7
//
8
// Portions Copyright (c) YugaByte, Inc.
9
//
10
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
11
// in compliance with the License.  You may obtain a copy of the License at
12
//
13
// http://www.apache.org/licenses/LICENSE-2.0
14
//
15
// Unless required by applicable law or agreed to in writing, software distributed under the License
16
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17
// or implied.  See the License for the specific language governing permissions and limitations
18
// under the License.
19
//
20
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
21
// Use of this source code is governed by a BSD-style license that can be
22
// found in the LICENSE file. See the AUTHORS file for names of contributors.
23
24
#include "yb/rocksdb/db/file_indexer.h"
25
#include <algorithm>
26
#include "yb/rocksdb/comparator.h"
27
#include "yb/rocksdb/db/version_edit.h"
28
29
namespace rocksdb {
30
31
FileIndexer::FileIndexer(const Comparator* ucmp)
32
1.65M
    : num_levels_(0), ucmp_(ucmp), level_rb_(nullptr) {}
33
34
0
size_t FileIndexer::NumLevelIndex() const { return next_level_index_.size(); }
35
36
3
size_t FileIndexer::LevelIndexSize(size_t level) const {
37
3
  if (level >= next_level_index_.size()) {
38
3
    return 0;
39
3
  }
40
0
  return next_level_index_[level].num_index;
41
3
}
42
43
void FileIndexer::GetNextLevelIndex(const size_t level, const size_t file_index,
44
                                    const int cmp_smallest,
45
                                    const int cmp_largest, int32_t* left_bound,
46
2.65M
                                    int32_t* right_bound) const {
47
2.65M
  assert(level > 0);
48
49
  // Last level, no hint
50
2.65M
  if (level == num_levels_ - 1) {
51
1.91M
    *left_bound = 0;
52
1.91M
    *right_bound = -1;
53
1.91M
    return;
54
1.91M
  }
55
56
734k
  assert(level < num_levels_ - 1);
57
0
  assert(static_cast<int32_t>(file_index) <= level_rb_[level]);
58
59
0
  const IndexUnit* index_units = next_level_index_[level].index_units;
60
734k
  const auto& index = index_units[file_index];
61
62
734k
  if (cmp_smallest < 0) {
63
270k
    *left_bound = (level > 0 && file_index > 0)
64
270k
                      ? 
index_units[file_index - 1].largest_lb137k
65
270k
                      : 
0132k
;
66
270k
    *right_bound = index.smallest_rb;
67
464k
  } else if (cmp_smallest == 0) {
68
646
    *left_bound = index.smallest_lb;
69
646
    *right_bound = index.smallest_rb;
70
464k
  } else if (cmp_smallest > 0 && cmp_largest < 0) {
71
459k
    *left_bound = index.smallest_lb;
72
459k
    *right_bound = index.largest_rb;
73
459k
  } else 
if (4.74k
cmp_largest == 04.74k
) {
74
619
    *left_bound = index.largest_lb;
75
619
    *right_bound = index.largest_rb;
76
4.12k
  } else if (cmp_largest > 0) {
77
4.12k
    *left_bound = index.largest_lb;
78
4.12k
    *right_bound = level_rb_[level + 1];
79
4.12k
  } else {
80
0
    assert(false);
81
0
  }
82
83
0
  assert(*left_bound >= 0);
84
0
  assert(*left_bound <= *right_bound + 1);
85
0
  assert(*right_bound <= level_rb_[level + 1]);
86
734k
}
87
88
void FileIndexer::UpdateIndex(Arena* arena, const size_t num_levels,
89
774k
                              std::vector<FileMetaData*>* const files) {
90
774k
  if (files == nullptr) {
91
0
    return;
92
0
  }
93
774k
  if (num_levels == 0) {  // uint_32 0-1 would cause bad behavior
94
698k
    num_levels_ = num_levels;
95
698k
    return;
96
698k
  }
97
75.9k
  assert(level_rb_ == nullptr);  // level_rb_ should be init here
98
99
0
  num_levels_ = num_levels;
100
75.9k
  next_level_index_.resize(num_levels);
101
102
75.9k
  char* mem = arena->AllocateAligned(num_levels_ * sizeof(int32_t));
103
75.9k
  level_rb_ = new (mem) int32_t[num_levels_];
104
332k
  for (size_t i = 0; i < num_levels_; 
i++256k
) {
105
256k
    level_rb_[i] = -1;
106
256k
  }
107
108
  // L1 - Ln-1
109
208k
  for (size_t level = 1; level < num_levels_ - 1; 
++level132k
) {
110
132k
    const auto& upper_files = files[level];
111
132k
    const int32_t upper_size = static_cast<int32_t>(upper_files.size());
112
132k
    const auto& lower_files = files[level + 1];
113
132k
    level_rb_[level] = static_cast<int32_t>(upper_files.size()) - 1;
114
132k
    if (upper_size == 0) {
115
75.8k
      continue;
116
75.8k
    }
117
56.9k
    IndexLevel& index_level = next_level_index_[level];
118
56.9k
    index_level.num_index = upper_size;
119
56.9k
    mem = arena->AllocateAligned(upper_size * sizeof(IndexUnit));
120
56.9k
    index_level.index_units = new (mem) IndexUnit[upper_size];
121
122
56.9k
    CalculateLB(
123
56.9k
        upper_files, lower_files, &index_level,
124
685k
        [this](const FileMetaData * a, const FileMetaData * b)->int {
125
685k
          return ucmp_->Compare(a->smallest.key.user_key(), b->largest.key.user_key());
126
685k
        },
127
250k
        [](IndexUnit* index, int32_t f_idx) { index->smallest_lb = f_idx; });
128
56.9k
    CalculateLB(
129
56.9k
        upper_files, lower_files, &index_level,
130
677k
        [this](const FileMetaData * a, const FileMetaData * b)->int {
131
677k
          return ucmp_->Compare(a->largest.key.user_key(), b->largest.key.user_key());
132
677k
        },
133
250k
        [](IndexUnit* index, int32_t f_idx) { index->largest_lb = f_idx; });
134
56.9k
    CalculateRB(
135
56.9k
        upper_files, lower_files, &index_level,
136
630k
        [this](const FileMetaData * a, const FileMetaData * b)->int {
137
630k
          return ucmp_->Compare(a->smallest.key.user_key(), b->smallest.key.user_key());
138
630k
        },
139
250k
        [](IndexUnit* index, int32_t f_idx) { index->smallest_rb = f_idx; });
140
56.9k
    CalculateRB(
141
56.9k
        upper_files, lower_files, &index_level,
142
629k
        [this](const FileMetaData * a, const FileMetaData * b)->int {
143
629k
          return ucmp_->Compare(a->largest.key.user_key(), b->smallest.key.user_key());
144
629k
        },
145
250k
        [](IndexUnit* index, int32_t f_idx) { index->largest_rb = f_idx; });
146
56.9k
  }
147
148
75.9k
  level_rb_[num_levels_ - 1] =
149
75.9k
      static_cast<int32_t>(files[num_levels_ - 1].size()) - 1;
150
75.9k
}
151
152
void FileIndexer::CalculateLB(
153
    const std::vector<FileMetaData*>& upper_files,
154
    const std::vector<FileMetaData*>& lower_files, IndexLevel* index_level,
155
    std::function<int(const FileMetaData*, const FileMetaData*)> cmp_op,
156
113k
    std::function<void(IndexUnit*, int32_t)> set_index) {
157
113k
  const int32_t upper_size = static_cast<int32_t>(upper_files.size());
158
113k
  const int32_t lower_size = static_cast<int32_t>(lower_files.size());
159
113k
  int32_t upper_idx = 0;
160
113k
  int32_t lower_idx = 0;
161
162
113k
  IndexUnit* index = index_level->index_units;
163
1.47M
  while (upper_idx < upper_size && 
lower_idx < lower_size1.41M
) {
164
1.36M
    int cmp = cmp_op(upper_files[upper_idx], lower_files[lower_idx]);
165
166
1.36M
    if (cmp == 0) {
167
28.8k
      set_index(&index[upper_idx], lower_idx);
168
28.8k
      ++upper_idx;
169
28.8k
      ++lower_idx;
170
1.33M
    } else if (cmp > 0) {
171
      // Lower level's file (largest) is smaller, a key won't hit in that
172
      // file. Move to next lower file
173
966k
      ++lower_idx;
174
966k
    } else {
175
      // Lower level's file becomes larger, update the index, and
176
      // move to the next upper file
177
368k
      set_index(&index[upper_idx], lower_idx);
178
368k
      ++upper_idx;
179
368k
    }
180
1.36M
  }
181
182
218k
  while (upper_idx < upper_size) {
183
    // Lower files are exhausted, that means the remaining upper files are
184
    // greater than any lower files. Set the index to be the lower level size.
185
104k
    set_index(&index[upper_idx], lower_size);
186
104k
    ++upper_idx;
187
104k
  }
188
113k
}
189
190
void FileIndexer::CalculateRB(
191
    const std::vector<FileMetaData*>& upper_files,
192
    const std::vector<FileMetaData*>& lower_files, IndexLevel* index_level,
193
    std::function<int(const FileMetaData*, const FileMetaData*)> cmp_op,
194
113k
    std::function<void(IndexUnit*, int32_t)> set_index) {
195
113k
  const int32_t upper_size = static_cast<int32_t>(upper_files.size());
196
113k
  const int32_t lower_size = static_cast<int32_t>(lower_files.size());
197
113k
  int32_t upper_idx = upper_size - 1;
198
113k
  int32_t lower_idx = lower_size - 1;
199
200
113k
  IndexUnit* index = index_level->index_units;
201
1.37M
  while (upper_idx >= 0 && 
lower_idx >= 01.28M
) {
202
1.25M
    int cmp = cmp_op(upper_files[upper_idx], lower_files[lower_idx]);
203
204
1.25M
    if (cmp == 0) {
205
29.5k
      set_index(&index[upper_idx], lower_idx);
206
29.5k
      --upper_idx;
207
29.5k
      --lower_idx;
208
1.22M
    } else if (cmp < 0) {
209
      // Lower level's file (smallest) is larger, a key won't hit in that
210
      // file. Move to next lower file.
211
797k
      --lower_idx;
212
797k
    } else {
213
      // Lower level's file becomes smaller, update the index, and move to
214
      // the next the upper file
215
432k
      set_index(&index[upper_idx], lower_idx);
216
432k
      --upper_idx;
217
432k
    }
218
1.25M
  }
219
153k
  while (upper_idx >= 0) {
220
    // Lower files are exhausted, that means the remaining upper files are
221
    // smaller than any lower files. Set it to -1.
222
39.2k
    set_index(&index[upper_idx], -1);
223
39.2k
    --upper_idx;
224
39.2k
  }
225
113k
}
226
227
}  // namespace rocksdb