YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/rocksdb/db/compaction.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/compaction.h"
25
26
#ifndef __STDC_FORMAT_MACROS
27
#define __STDC_FORMAT_MACROS
28
#endif
29
30
#include <inttypes.h>
31
32
#include <algorithm>
33
#include <vector>
34
35
#include "yb/gutil/stl_util.h"
36
37
#include "yb/rocksdb/compaction_filter.h"
38
#include "yb/rocksdb/db/column_family.h"
39
#include "yb/rocksdb/db/compaction_picker.h"
40
#include "yb/rocksdb/db/version_set.h"
41
#include "yb/rocksdb/util/logging.h"
42
#include "yb/rocksdb/util/sync_point.h"
43
44
#include "yb/util/format.h"
45
#include "yb/util/logging.h"
46
#include "yb/util/size_literals.h"
47
48
using namespace yb::size_literals;
49
50
namespace rocksdb {
51
52
namespace {
53
54
2.45M
Slice SliceDup(Arena* arena, Slice input) {
55
2.45M
  auto* mem = arena->AllocateAligned(input.size());
56
2.45M
  memcpy(mem, input.data(), input.size());
57
2.45M
  return Slice(mem, input.size());
58
2.45M
}
59
60
}
61
62
LightweightBoundaries::LightweightBoundaries(Arena* arena,
63
2.06M
                                             const FileMetaData::BoundaryValues& source) {
64
2.06M
  key = SliceDup(arena, source.key.Encode());
65
2.06M
  num_user_values = source.user_values.size();
66
2.06M
  user_tags = reinterpret_cast<UserBoundaryTag*>(
67
2.06M
    arena->AllocateAligned(sizeof(UserBoundaryTag) * num_user_values));
68
2.06M
  user_values = reinterpret_cast<Slice*>(
69
2.06M
    arena->AllocateAligned(sizeof(Slice) * num_user_values));
70
2.45M
  for (size_t i = 0; i != num_user_values; 
++i390k
) {
71
390k
    UserBoundaryValue& value = *source.user_values[i];
72
390k
    new (user_tags + i) UserBoundaryTag(value.Tag());
73
390k
    new (user_values + i) Slice(SliceDup(arena, value.Encode()));
74
390k
  }
75
2.06M
}
76
77
FdWithBoundaries::FdWithBoundaries(Arena* arena, const FileMetaData& source)
78
1.03M
    : fd(source.fd), smallest(arena, source.smallest), largest(arena, source.largest) {
79
1.03M
  if (source.largest.user_frontier) {
80
41.1k
    auto filter = source.largest.user_frontier->Filter();
81
41.1k
    if (!filter.empty()) {
82
49
      user_filter_data = SliceDup(arena, filter);
83
49
    }
84
41.1k
  }
85
1.03M
}
86
87
466k
uint64_t TotalFileSize(const std::vector<FileMetaData*>& files) {
88
466k
  uint64_t sum = 0;
89
1.11M
  for (size_t i = 0; i < files.size() && 
files[i]643k
;
i++643k
) {
90
643k
    sum += files[i]->fd.GetTotalFileSize();
91
643k
  }
92
466k
  return sum;
93
466k
}
94
95
1.75M
bool Compaction::IsCompactionStyleUniversal() const {
96
1.75M
  return cfd_->ioptions()->compaction_style == kCompactionStyleUniversal;
97
1.75M
}
98
99
23.7k
void Compaction::SetInputVersion(Version* input_version) {
100
23.7k
  input_version_number_ = input_version->GetVersionNumber();
101
23.7k
  input_version_level0_non_overlapping_ = input_version->storage_info()->level0_non_overlapping();
102
23.7k
  vset_ = input_version->version_set();
103
23.7k
  cfd_ = input_version->cfd();
104
23.7k
  cfd_->Ref();
105
106
23.7k
  if (IsCompactionStyleUniversal()) {
107
    // We don't need to lock the whole input version for universal compaction, only need input
108
    // files.
109
22.4k
    for (auto& input_level : inputs_) {
110
22.4k
      for (auto* f : input_level.files) {
111
21.5k
        ++f->refs;
112
21.5k
      }
113
22.4k
    }
114
18.3k
  } else {
115
18.3k
    input_version_ = input_version;
116
18.3k
    input_version_->Ref();
117
18.3k
  }
118
119
23.7k
  edit_.SetColumnFamily(cfd_->GetID());
120
23.7k
}
121
122
void Compaction::GetBoundaryKeys(
123
    VersionStorageInfo* vstorage,
124
    const std::vector<CompactionInputFiles>& inputs, Slice* smallest_user_key,
125
43.8k
    Slice* largest_user_key) {
126
43.8k
  bool initialized = false;
127
43.8k
  const Comparator* ucmp = vstorage->InternalComparator()->user_comparator();
128
131k
  for (size_t i = 0; i < inputs.size(); 
++i87.2k
) {
129
87.2k
    if (inputs[i].files.empty()) {
130
28.3k
      continue;
131
28.3k
    }
132
58.9k
    if (inputs[i].level == 0) {
133
      // we need to consider all files on level 0
134
59.1k
      for (const auto* f : inputs[i].files) {
135
59.1k
        Slice start_user_key = f->smallest.key.user_key();
136
59.1k
        if (!initialized ||
137
59.1k
            
ucmp->Compare(start_user_key, *smallest_user_key) < 036.1k
) {
138
34.0k
          *smallest_user_key = start_user_key;
139
34.0k
        }
140
59.1k
        Slice end_user_key = f->largest.key.user_key();
141
59.1k
        if (!initialized ||
142
59.1k
            
ucmp->Compare(end_user_key, *largest_user_key) > 036.1k
) {
143
31.0k
          *largest_user_key = end_user_key;
144
31.0k
        }
145
59.1k
        initialized = true;
146
59.1k
      }
147
35.9k
    } else {
148
      // we only need to consider the first and last file
149
35.9k
      Slice start_user_key = inputs[i].files[0]->smallest.key.user_key();
150
35.9k
      if (!initialized ||
151
35.9k
          
ucmp->Compare(start_user_key, *smallest_user_key) < 015.0k
) {
152
25.6k
        *smallest_user_key = start_user_key;
153
25.6k
      }
154
35.9k
      Slice end_user_key = inputs[i].files.back()->largest.key.user_key();
155
35.9k
      if (!initialized || 
ucmp->Compare(end_user_key, *largest_user_key) > 015.0k
) {
156
25.9k
        *largest_user_key = end_user_key;
157
25.9k
      }
158
35.9k
      initialized = true;
159
35.9k
    }
160
58.9k
  }
161
43.8k
}
162
163
// helper function to determine if compaction is creating files at the
164
// bottommost level
165
bool Compaction::IsBottommostLevel(
166
    int output_level, VersionStorageInfo* vstorage,
167
23.7k
    const std::vector<CompactionInputFiles>& inputs) {
168
23.7k
  if (inputs[0].level == 0 &&
169
23.7k
      
inputs[0].files.back() != vstorage->LevelFiles(0).back()13.3k
) {
170
3.71k
    return false;
171
3.71k
  }
172
173
20.0k
  Slice smallest_key, largest_key;
174
20.0k
  GetBoundaryKeys(vstorage, inputs, &smallest_key, &largest_key);
175
176
  // Checks whether there are files living beyond the output_level.
177
  // If lower levels have files, it checks for overlap between files
178
  // if the compaction process and those files.
179
  // Bottomlevel optimizations can be made if there are no files in
180
  // lower levels or if there is no overlap with the files in
181
  // the lower levels.
182
62.9k
  for (int i = output_level + 1; i < vstorage->num_levels(); 
i++42.9k
) {
183
    // It is not the bottommost level if there are files in higher
184
    // levels when the output level is 0 or if there are files in
185
    // higher levels which overlap with files to be compacted.
186
    // output_level == 0 means that we want it to be considered
187
    // s the bottommost level only if the last file on the level
188
    // is a part of the files to be compacted - this is verified by
189
    // the first if condition in this function
190
48.4k
    if (vstorage->NumLevelFiles(i) > 0 &&
191
48.4k
        
(22.9k
output_level == 022.9k
||
192
22.9k
         
vstorage->OverlapInLevel(i, &smallest_key, &largest_key)22.7k
)) {
193
5.53k
      return false;
194
5.53k
    }
195
48.4k
  }
196
14.5k
  return true;
197
20.0k
}
198
199
// test function to validate the functionality of IsBottommostLevel()
200
// function -- determines if compaction with inputs and storage is bottommost
201
bool Compaction::TEST_IsBottommostLevel(
202
    int output_level, VersionStorageInfo* vstorage,
203
8
    const std::vector<CompactionInputFiles>& inputs) {
204
8
  return IsBottommostLevel(output_level, vstorage, inputs);
205
8
}
206
207
bool Compaction::IsFullCompaction(
208
    VersionStorageInfo* vstorage,
209
23.7k
    const std::vector<CompactionInputFiles>& inputs) {
210
23.7k
  size_t num_files_in_compaction = 0;
211
23.7k
  size_t total_num_files = 0;
212
181k
  for (int l = 0; l < vstorage->num_levels(); 
l++157k
) {
213
157k
    total_num_files += vstorage->NumLevelFiles(l);
214
157k
  }
215
70.0k
  for (size_t i = 0; i < inputs.size(); 
i++46.2k
) {
216
46.2k
    num_files_in_compaction += inputs[i].size();
217
46.2k
  }
218
23.7k
  return num_files_in_compaction == total_num_files;
219
23.7k
}
220
221
std::unique_ptr<Compaction> Compaction::Create(
222
    VersionStorageInfo* vstorage, const MutableCFOptions& _mutable_cf_options,
223
    std::vector<CompactionInputFiles> inputs, int output_level, uint64_t target_file_size,
224
    uint64_t max_grandparent_overlap_bytes, uint32_t output_path_id, CompressionType compression,
225
    std::vector<FileMetaData*> grandparents, Logger* info_log, bool manual_compaction, double score,
226
23.7k
    bool deletion_compaction, CompactionReason compaction_reason) {
227
23.7k
  bool has_input_files = false;
228
46.2k
  for (auto& input : inputs) {
229
63.0k
    yb::EraseIf([info_log](FileMetaData* file) {
230
63.0k
      bool being_deleted = file->being_deleted;
231
63.0k
      if (being_deleted) {
232
5
        RLOG(
233
5
            InfoLogLevel::INFO_LEVEL, info_log,
234
5
            yb::Format("Skipping compaction of file that is being deleted: $0", file).c_str());
235
5
      }
236
63.0k
      return being_deleted;
237
63.0k
    }, &input.files);
238
46.2k
    has_input_files |= !input.empty();
239
46.2k
  }
240
23.7k
  if (!has_input_files) {
241
1
    RLOG(
242
1
        InfoLogLevel::INFO_LEVEL, info_log,
243
1
        "Skipping compaction creation, no input files to compact");
244
1
    return nullptr;
245
1
  }
246
  // We don't remove empty input levels, because empty input levels are handled differently
247
  // than absent ones, for example by Compaction::IsTrivialMove.
248
  // But we need to remove inputs[0] if it is empty and has level 0, otherwise
249
  // Compaction::IsBottommostLevel will fail.
250
23.7k
  if (inputs[0].level == 0 && 
inputs[0].empty()13.3k
) {
251
0
    inputs.erase(inputs.begin());
252
0
  }
253
254
23.7k
  return std::unique_ptr<Compaction>(new Compaction(
255
23.7k
      vstorage, _mutable_cf_options, inputs, output_level, target_file_size,
256
23.7k
      max_grandparent_overlap_bytes, output_path_id, compression, grandparents, manual_compaction,
257
23.7k
      score, deletion_compaction, compaction_reason));
258
23.7k
}
259
260
Compaction::Compaction(VersionStorageInfo* vstorage,
261
                       const MutableCFOptions& _mutable_cf_options,
262
                       std::vector<CompactionInputFiles> _inputs,
263
                       int _output_level, uint64_t _target_file_size,
264
                       uint64_t _max_grandparent_overlap_bytes,
265
                       uint32_t _output_path_id, CompressionType _compression,
266
                       std::vector<FileMetaData*> _grandparents,
267
                       bool _manual_compaction, double _score,
268
                       bool _deletion_compaction,
269
                       CompactionReason _compaction_reason)
270
    : start_level_(_inputs[0].level),
271
      output_level_(_output_level),
272
      max_output_file_size_(_target_file_size),
273
      max_grandparent_overlap_bytes_(_max_grandparent_overlap_bytes),
274
      mutable_cf_options_(_mutable_cf_options),
275
      input_version_(nullptr),
276
      number_levels_(vstorage->num_levels()),
277
      cfd_(nullptr),
278
      output_path_id_(_output_path_id),
279
      output_compression_(_compression),
280
      deletion_compaction_(_deletion_compaction),
281
      inputs_(std::move(_inputs)),
282
      grandparents_(std::move(_grandparents)),
283
      grandparent_index_(0),
284
      overlapped_bytes_(0),
285
      score_(_score),
286
      bottommost_level_(IsBottommostLevel(output_level_, vstorage, inputs_)),
287
      is_full_compaction_(IsFullCompaction(vstorage, inputs_)),
288
      is_manual_compaction_(_manual_compaction),
289
23.7k
      compaction_reason_(_compaction_reason) {
290
23.7k
  seen_key_.store(false, std::memory_order_release);
291
23.7k
  MarkFilesBeingCompacted(true);
292
23.7k
  if (is_manual_compaction_) {
293
5.27k
    compaction_reason_ = CompactionReason::kManualCompaction;
294
5.27k
  }
295
296
23.7k
#ifndef NDEBUG
297
46.2k
  for (size_t i = 1; i < inputs_.size(); 
++i22.4k
) {
298
22.4k
    assert(inputs_[i].level > inputs_[i - 1].level);
299
22.4k
  }
300
23.7k
#endif
301
302
  // setup input_levels_
303
23.7k
  {
304
23.7k
    input_levels_.resize(num_input_levels());
305
70.0k
    for (size_t which = 0; which < num_input_levels(); 
which++46.2k
) {
306
46.2k
      DoGenerateLevelFilesBrief(&input_levels_[which], inputs_[which].files,
307
46.2k
                                &arena_);
308
46.2k
    }
309
23.7k
  }
310
311
23.7k
  Slice smallest_user_key;
312
23.7k
  GetBoundaryKeys(vstorage, inputs_, &smallest_user_key, &largest_user_key_);
313
23.7k
}
314
315
23.7k
Compaction::~Compaction() {
316
23.7k
  if (input_version_ != nullptr) {
317
18.3k
    input_version_->Unref();
318
18.3k
  } else 
if (5.41k
cfd_ != nullptr5.41k
) {
319
    // If we don't hold input_version_, unref each input file separately.
320
22.3k
    for (auto& input_level : inputs_) {
321
22.3k
      for (auto f : input_level.files) {
322
21.4k
        vset_->UnrefFile(cfd_, f);
323
21.4k
      }
324
22.3k
    }
325
5.39k
  }
326
23.7k
  if (cfd_ != nullptr) {
327
23.7k
    if (cfd_->Unref()) {
328
0
      delete cfd_;
329
0
    }
330
23.7k
  }
331
23.7k
}
332
333
12.2k
bool Compaction::InputCompressionMatchesOutput() const {
334
12.2k
  int base_level = IsCompactionStyleUniversal()
335
12.2k
      ? 
-10
336
12.2k
      : input_version_->storage_info()->base_level();
337
12.2k
  bool matches = (GetCompressionType(*cfd_->ioptions(), start_level_,
338
12.2k
                                     base_level) == output_compression_);
339
12.2k
  if (matches) {
340
12.1k
    TEST_SYNC_POINT("Compaction::InputCompressionMatchesOutput:Matches");
341
12.1k
    return true;
342
12.1k
  }
343
116
  TEST_SYNC_POINT("Compaction::InputCompressionMatchesOutput:DidntMatch");
344
116
  return matches;
345
12.2k
}
346
347
35.0k
bool Compaction::IsTrivialMove() const {
348
  // Avoid a move if there is lots of overlapping grandparent data.
349
  // Otherwise, the move could create a parent file that will require
350
  // a very expensive merge later on.
351
  // If start_level_== output_level_, the purpose is to force compaction
352
  // filter to be applied to that level, and thus cannot be a trivial move.
353
354
  // Check if start level have files with overlapping ranges
355
35.0k
  if (start_level_ == 0 && 
!input_version_level0_non_overlapping_22.5k
) {
356
    // We cannot move files from L0 to L1 if the files are overlapping
357
8.24k
    return false;
358
8.24k
  }
359
360
26.7k
  if (is_manual_compaction_ &&
361
26.7k
      
(5.68k
cfd_->ioptions()->compaction_filter != nullptr5.68k
||
362
5.68k
       
cfd_->ioptions()->compaction_filter_factory != nullptr5.68k
)) {
363
    // This is a manual compaction and we have a compaction filter that should
364
    // be executed, we cannot do a trivial move
365
564
    return false;
366
564
  }
367
368
  // Used in universal compaction, where trivial move can be done if the
369
  // input files are non overlapping
370
26.2k
  if ((cfd_->ioptions()->compaction_options_universal.allow_trivial_move) &&
371
26.2k
      
(output_level_ != 0)980
) {
372
224
    return is_trivial_move_;
373
224
  }
374
375
25.9k
  return (start_level_ != output_level_ && 
num_input_levels() == 123.7k
&&
376
25.9k
          
input(0, 0)->fd.GetPathId() == output_path_id()12.4k
&&
377
25.9k
          
InputCompressionMatchesOutput()12.2k
&&
378
25.9k
          
TotalFileSize(grandparents_) <= max_grandparent_overlap_bytes_12.1k
);
379
26.2k
}
380
381
11.2k
void Compaction::AddInputDeletions(VersionEdit* out_edit) {
382
42.8k
  for (size_t which = 0; which < num_input_levels(); 
which++31.5k
) {
383
79.1k
    for (size_t i = 0; i < inputs_[which].size(); 
i++47.6k
) {
384
47.6k
      out_edit->DeleteFile(level(which), inputs_[which][i]->fd.GetNumber());
385
47.6k
    }
386
31.5k
  }
387
11.2k
}
388
389
bool Compaction::KeyNotExistsBeyondOutputLevel(
390
1.71M
    const Slice& user_key, std::vector<size_t>* level_ptrs) const {
391
1.71M
  assert(level_ptrs != nullptr);
392
0
  assert(level_ptrs->size() == static_cast<size_t>(number_levels_));
393
0
  assert(cfd_->ioptions()->compaction_style != kCompactionStyleFIFO);
394
1.71M
  if (IsCompactionStyleUniversal()) {
395
174k
    return bottommost_level_;
396
174k
  }
397
1.54M
  DCHECK_ONLY_NOTNULL(input_version_);
398
  // Maybe use binary search to find right entry instead of linear search?
399
1.54M
  const Comparator* user_cmp = cfd_->user_comparator();
400
8.14M
  for (int lvl = output_level_ + 1; lvl < number_levels_; 
lvl++6.60M
) {
401
6.73M
    const std::vector<FileMetaData*>& files =
402
6.73M
        input_version_->storage_info()->LevelFiles(lvl);
403
6.74M
    for (; level_ptrs->at(lvl) < files.size(); 
level_ptrs->at(lvl)++12.6k
) {
404
258k
      auto* f = files[level_ptrs->at(lvl)];
405
258k
      if (user_cmp->Compare(user_key, f->largest.key.user_key()) <= 0) {
406
        // We've advanced far enough
407
246k
        if (user_cmp->Compare(user_key, f->smallest.key.user_key()) >= 0) {
408
          // Key falls in this file's range, so definitely
409
          // exists beyond output level
410
127k
          return false;
411
127k
        }
412
119k
        break;
413
246k
      }
414
258k
    }
415
6.73M
  }
416
1.41M
  return true;
417
1.54M
}
418
419
47.2M
bool Compaction::ShouldStopBefore(const Slice& internal_key) {
420
  // Scan to find earliest grandparent file that contains key.
421
47.2M
  const InternalKeyComparator* icmp = cfd_->internal_comparator().get();
422
47.2M
  while (grandparent_index_ < grandparents_.size() &&
423
47.2M
      icmp->Compare(internal_key,
424
3.45M
                    grandparents_[grandparent_index_]->largest.key.Encode()) > 0) {
425
11.8k
    if (seen_key_.load(std::memory_order_acquire)) {
426
11.8k
      overlapped_bytes_ += grandparents_[grandparent_index_]->fd.GetTotalFileSize();
427
11.8k
    }
428
11.8k
    assert(grandparent_index_ + 1 >= grandparents_.size() ||
429
11.8k
           icmp->Compare(grandparents_[grandparent_index_]->largest.key.Encode(),
430
11.8k
                         grandparents_[grandparent_index_ + 1]->smallest.key.Encode())
431
11.8k
                         < 0);
432
0
    grandparent_index_++;
433
11.8k
  }
434
47.2M
  seen_key_.store(true, std::memory_order_release);
435
436
47.2M
  if (overlapped_bytes_ > max_grandparent_overlap_bytes_) {
437
    // Too much overlap for current output; start new output
438
1.07k
    overlapped_bytes_ = 0;
439
1.07k
    return true;
440
47.2M
  } else {
441
47.2M
    return false;
442
47.2M
  }
443
47.2M
}
444
445
// Mark (or clear) each file that is being compacted
446
47.5k
void Compaction::MarkFilesBeingCompacted(bool mark_as_compacted) {
447
139k
  for (size_t i = 0; i < num_input_levels(); 
i++92.4k
) {
448
218k
    for (size_t j = 0; j < inputs_[i].size(); 
j++125k
) {
449
125k
      assert(mark_as_compacted ? !inputs_[i][j]->being_compacted :
450
125k
                                  inputs_[i][j]->being_compacted);
451
0
      inputs_[i][j]->being_compacted = mark_as_compacted;
452
125k
    }
453
92.4k
  }
454
47.5k
}
455
456
// Sample output:
457
// If compacting 3 L0 files, 2 L3 files and 1 L4 file, and outputting to L5,
458
// print: "3@0 + 2@3 + 1@4 files to L5"
459
const char* Compaction::InputLevelSummary(
460
22.7k
    InputLevelSummaryBuffer* scratch) const {
461
22.7k
  int len = 0;
462
22.7k
  bool is_first = true;
463
63.2k
  for (auto& input_level : inputs_) {
464
63.2k
    if (input_level.empty()) {
465
25.3k
      continue;
466
25.3k
    }
467
37.8k
    if (!is_first) {
468
15.1k
      len +=
469
15.1k
          snprintf(scratch->buffer + len, sizeof(scratch->buffer) - len, " + ");
470
22.7k
    } else {
471
22.7k
      is_first = false;
472
22.7k
    }
473
37.8k
    len += snprintf(scratch->buffer + len, sizeof(scratch->buffer) - len,
474
37.8k
                    "%" ROCKSDB_PRIszt "@%d", input_level.size(),
475
37.8k
                    input_level.level);
476
37.8k
  }
477
22.7k
  snprintf(scratch->buffer + len, sizeof(scratch->buffer) - len,
478
22.7k
           " files to L%d", output_level());
479
480
22.7k
  return scratch->buffer;
481
22.7k
}
482
483
34.8k
uint64_t Compaction::CalculateTotalInputSize() const {
484
34.8k
  uint64_t size = 0;
485
75.5k
  for (auto& input_level : inputs_) {
486
121k
    for (auto f : input_level.files) {
487
121k
      size += f->fd.GetTotalFileSize();
488
121k
    }
489
75.5k
  }
490
34.8k
  return size;
491
34.8k
}
492
493
23.7k
void Compaction::ReleaseCompactionFiles(Status status) {
494
23.7k
  MarkFilesBeingCompacted(false);
495
23.7k
  cfd_->compaction_picker()->ReleaseCompactionFiles(this, status);
496
23.7k
}
497
498
120
void Compaction::ResetNextCompactionIndex() {
499
120
  if (!IsCompactionStyleUniversal()) {
500
69
    DCHECK_ONLY_NOTNULL(input_version_);
501
69
    input_version_->storage_info()->ResetNextCompactionIndex(start_level_);
502
69
  }
503
120
}
504
505
namespace {
506
int InputSummary(const std::vector<FileMetaData*>& files, char* output,
507
31.7k
                 int len) {
508
31.7k
  *output = '\0';
509
31.7k
  int write = 0;
510
79.9k
  for (size_t i = 0; i < files.size(); 
i++48.2k
) {
511
48.2k
    int sz = len - write;
512
48.2k
    int ret;
513
48.2k
    char sztxt[16];
514
48.2k
    AppendHumanBytes(files.at(i)->fd.GetTotalFileSize(), sztxt, 16);
515
48.2k
    ret = snprintf(output + write, sz, "%" PRIu64 "(%s) ",
516
48.2k
                   files.at(i)->fd.GetNumber(), sztxt);
517
48.2k
    if (ret < 0 || ret >= sz) 
break0
;
518
48.2k
    write += ret;
519
48.2k
  }
520
  // if files.size() is non-zero, overwrite the last space
521
31.7k
  return write - !!files.size();
522
31.7k
}
523
}  // namespace
524
525
11.4k
void Compaction::Summary(char* output, int len) {
526
11.4k
  int write =
527
11.4k
      snprintf(output, len, "Base version %" PRIu64
528
11.4k
                            " Base level %d, inputs: [",
529
11.4k
               input_version_number_, start_level_);
530
11.4k
  if (write < 0 || write >= len) {
531
0
    return;
532
0
  }
533
534
43.1k
  
for (size_t level_iter = 0; 11.4k
level_iter < num_input_levels();
++level_iter31.7k
) {
535
31.7k
    if (level_iter > 0) {
536
20.3k
      write += snprintf(output + write, len - write, "], [");
537
20.3k
      if (write < 0 || write >= len) {
538
0
        return;
539
0
      }
540
20.3k
    }
541
31.7k
    write +=
542
31.7k
        InputSummary(inputs_[level_iter].files, output + write, len - write);
543
31.7k
    if (write < 0 || write >= len) {
544
0
      return;
545
0
    }
546
31.7k
  }
547
548
11.4k
  snprintf(output + write, len - write, "]");
549
11.4k
}
550
551
22.9k
uint64_t Compaction::OutputFilePreallocationSize() {
552
22.9k
  uint64_t preallocation_size = 0;
553
554
22.9k
  if (cfd_->ioptions()->compaction_style == kCompactionStyleLevel ||
555
22.9k
      
output_level() > 07.84k
) {
556
20.1k
    preallocation_size = max_output_file_size_;
557
20.1k
  } else {
558
    // output_level() == 0
559
2.83k
    assert(num_input_levels() > 0);
560
9.73k
    for (const auto& f : inputs_[0].files) {
561
9.73k
      preallocation_size += f->fd.GetTotalFileSize();
562
9.73k
    }
563
2.83k
  }
564
0
  constexpr uint64_t kMaxPreAllocationSize = 1_GB;
565
  // Over-estimate slightly so we don't end up just barely crossing
566
  // the threshold
567
22.9k
  return std::min(kMaxPreAllocationSize, preallocation_size + (preallocation_size / 10));
568
22.9k
}
569
570
11.4k
std::unique_ptr<CompactionFilter> Compaction::CreateCompactionFilter() const {
571
11.4k
  if (!cfd_->ioptions()->compaction_filter_factory) {
572
8.25k
    return nullptr;
573
8.25k
  }
574
575
3.16k
  CompactionFilter::Context context;
576
3.16k
  context.is_full_compaction = is_full_compaction_;
577
3.16k
  context.is_manual_compaction = is_manual_compaction_;
578
3.16k
  context.column_family_id = cfd_->GetID();
579
3.16k
  return cfd_->ioptions()->compaction_filter_factory->CreateCompactionFilter(
580
3.16k
      context);
581
11.4k
}
582
583
279
bool Compaction::IsOutputLevelEmpty() const {
584
279
  return inputs_.back().level != output_level_ || 
inputs_.back().empty()151
;
585
279
}
586
587
22.8k
bool Compaction::ShouldFormSubcompactions() const {
588
22.8k
  if (mutable_cf_options_.max_subcompactions <= 1 || 
cfd_ == nullptr2.71k
) {
589
20.1k
    return false;
590
20.1k
  }
591
2.71k
  if (cfd_->ioptions()->compaction_style == kCompactionStyleLevel) {
592
497
    return start_level_ == 0 && 
!IsOutputLevelEmpty()279
;
593
2.21k
  } else if (IsCompactionStyleUniversal()) {
594
2.21k
    return number_levels_ > 1 && 
output_level_ > 02.01k
;
595
2.21k
  } else {
596
0
    return false;
597
0
  }
598
2.71k
}
599
600
}  // namespace rocksdb