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 #include "db/logs_with_prep_tracker.h"
7 
8 #include "port/likely.h"
9 
10 namespace ROCKSDB_NAMESPACE {
MarkLogAsHavingPrepSectionFlushed(uint64_t log)11 void LogsWithPrepTracker::MarkLogAsHavingPrepSectionFlushed(uint64_t log) {
12   assert(log != 0);
13   std::lock_guard<std::mutex> lock(prepared_section_completed_mutex_);
14   auto it = prepared_section_completed_.find(log);
15   if (UNLIKELY(it == prepared_section_completed_.end())) {
16     prepared_section_completed_[log] = 1;
17   } else {
18     it->second += 1;
19   }
20 }
21 
MarkLogAsContainingPrepSection(uint64_t log)22 void LogsWithPrepTracker::MarkLogAsContainingPrepSection(uint64_t log) {
23   assert(log != 0);
24   std::lock_guard<std::mutex> lock(logs_with_prep_mutex_);
25 
26   auto rit = logs_with_prep_.rbegin();
27   bool updated = false;
28   // Most probably the last log is the one that is being marked for
29   // having a prepare section; so search from the end.
30   for (; rit != logs_with_prep_.rend() && rit->log >= log; ++rit) {
31     if (rit->log == log) {
32       rit->cnt++;
33       updated = true;
34       break;
35     }
36   }
37   if (!updated) {
38     // We are either at the start, or at a position with rit->log < log
39     logs_with_prep_.insert(rit.base(), {log, 1});
40   }
41 }
42 
FindMinLogContainingOutstandingPrep()43 uint64_t LogsWithPrepTracker::FindMinLogContainingOutstandingPrep() {
44   std::lock_guard<std::mutex> lock(logs_with_prep_mutex_);
45   auto it = logs_with_prep_.begin();
46   // start with the smallest log
47   for (; it != logs_with_prep_.end();) {
48     auto min_log = it->log;
49     {
50       std::lock_guard<std::mutex> lock2(prepared_section_completed_mutex_);
51       auto completed_it = prepared_section_completed_.find(min_log);
52       if (completed_it == prepared_section_completed_.end() ||
53           completed_it->second < it->cnt) {
54         return min_log;
55       }
56       assert(completed_it != prepared_section_completed_.end() &&
57              completed_it->second == it->cnt);
58       prepared_section_completed_.erase(completed_it);
59     }
60     // erase from beginning in vector is not efficient but this function is not
61     // on the fast path.
62     it = logs_with_prep_.erase(it);
63   }
64   // no such log found
65   return 0;
66 }
67 }  // namespace ROCKSDB_NAMESPACE
68