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 
12 #include <string>
13 #include <vector>
14 
15 #include "db/log_writer.h"
16 #include "db/column_family.h"
17 
18 namespace ROCKSDB_NAMESPACE {
19 
20 class MemTable;
21 struct SuperVersion;
22 
23 struct SuperVersionContext {
24   struct WriteStallNotification {
25     WriteStallInfo write_stall_info;
26     const ImmutableCFOptions* immutable_cf_options;
27   };
28 
29   autovector<SuperVersion*> superversions_to_free;
30 #ifndef ROCKSDB_DISABLE_STALL_NOTIFICATION
31   autovector<WriteStallNotification> write_stall_notifications;
32 #endif
33   std::unique_ptr<SuperVersion>
34       new_superversion;  // if nullptr no new superversion
35 
36   explicit SuperVersionContext(bool create_superversion = false)
37     : new_superversion(create_superversion ? new SuperVersion() : nullptr) {}
38 
SuperVersionContextSuperVersionContext39   explicit SuperVersionContext(SuperVersionContext&& other)
40       : superversions_to_free(std::move(other.superversions_to_free)),
41 #ifndef ROCKSDB_DISABLE_STALL_NOTIFICATION
42         write_stall_notifications(std::move(other.write_stall_notifications)),
43 #endif
44         new_superversion(std::move(other.new_superversion)) {
45   }
46 
NewSuperVersionSuperVersionContext47   void NewSuperVersion() {
48     new_superversion = std::unique_ptr<SuperVersion>(new SuperVersion());
49   }
50 
HaveSomethingToDeleteSuperVersionContext51   inline bool HaveSomethingToDelete() const {
52 #ifndef ROCKSDB_DISABLE_STALL_NOTIFICATION
53     return !superversions_to_free.empty() ||
54            !write_stall_notifications.empty();
55 #else
56     return !superversions_to_free.empty();
57 #endif
58   }
59 
PushWriteStallNotificationSuperVersionContext60   void PushWriteStallNotification(
61       WriteStallCondition old_cond, WriteStallCondition new_cond,
62       const std::string& name, const ImmutableCFOptions* ioptions) {
63 #if !defined(ROCKSDB_LITE) && !defined(ROCKSDB_DISABLE_STALL_NOTIFICATION)
64     WriteStallNotification notif;
65     notif.write_stall_info.cf_name = name;
66     notif.write_stall_info.condition.prev = old_cond;
67     notif.write_stall_info.condition.cur = new_cond;
68     notif.immutable_cf_options = ioptions;
69     write_stall_notifications.push_back(notif);
70 #else
71     (void)old_cond;
72     (void)new_cond;
73     (void)name;
74     (void)ioptions;
75 #endif  // !defined(ROCKSDB_LITE) && !defined(ROCKSDB_DISABLE_STALL_NOTIFICATION)
76   }
77 
CleanSuperVersionContext78   void Clean() {
79 #if !defined(ROCKSDB_LITE) && !defined(ROCKSDB_DISABLE_STALL_NOTIFICATION)
80     // notify listeners on changed write stall conditions
81     for (auto& notif : write_stall_notifications) {
82       for (auto& listener : notif.immutable_cf_options->listeners) {
83         listener->OnStallConditionsChanged(notif.write_stall_info);
84       }
85     }
86     write_stall_notifications.clear();
87 #endif  // !ROCKSDB_LITE
88     // free superversions
89     for (auto s : superversions_to_free) {
90       delete s;
91     }
92     superversions_to_free.clear();
93   }
94 
~SuperVersionContextSuperVersionContext95   ~SuperVersionContext() {
96 #ifndef ROCKSDB_DISABLE_STALL_NOTIFICATION
97     assert(write_stall_notifications.empty());
98 #endif
99     assert(superversions_to_free.empty());
100   }
101 };
102 
103 struct JobContext {
HaveSomethingToDeleteJobContext104   inline bool HaveSomethingToDelete() const {
105     return full_scan_candidate_files.size() || sst_delete_files.size() ||
106            log_delete_files.size() || manifest_delete_files.size();
107   }
108 
HaveSomethingToCleanJobContext109   inline bool HaveSomethingToClean() const {
110     bool sv_have_sth = false;
111     for (const auto& sv_ctx : superversion_contexts) {
112       if (sv_ctx.HaveSomethingToDelete()) {
113         sv_have_sth = true;
114         break;
115       }
116     }
117     return memtables_to_free.size() > 0 || logs_to_free.size() > 0 ||
118            sv_have_sth;
119   }
120 
121   // Structure to store information for candidate files to delete.
122   struct CandidateFileInfo {
123     std::string file_name;
124     std::string file_path;
CandidateFileInfoJobContext::CandidateFileInfo125     CandidateFileInfo(std::string name, std::string path)
126         : file_name(std::move(name)), file_path(std::move(path)) {}
127     bool operator==(const CandidateFileInfo& other) const {
128       return file_name == other.file_name &&
129              file_path == other.file_path;
130     }
131   };
132 
133   // Unique job id
134   int job_id;
135 
136   // a list of all files that we'll consider deleting
137   // (every once in a while this is filled up with all files
138   // in the DB directory)
139   // (filled only if we're doing full scan)
140   std::vector<CandidateFileInfo> full_scan_candidate_files;
141 
142   // the list of all live sst files that cannot be deleted
143   std::vector<FileDescriptor> sst_live;
144 
145   // a list of sst files that we need to delete
146   std::vector<ObsoleteFileInfo> sst_delete_files;
147 
148   // a list of log files that we need to delete
149   std::vector<uint64_t> log_delete_files;
150 
151   // a list of log files that we need to preserve during full purge since they
152   // will be reused later
153   std::vector<uint64_t> log_recycle_files;
154 
155   // a list of manifest files that we need to delete
156   std::vector<std::string> manifest_delete_files;
157 
158   // a list of memtables to be free
159   autovector<MemTable*> memtables_to_free;
160 
161   // contexts for installing superversions for multiple column families
162   std::vector<SuperVersionContext> superversion_contexts;
163 
164   autovector<log::Writer*> logs_to_free;
165 
166   // the current manifest_file_number, log_number and prev_log_number
167   // that corresponds to the set of files in 'live'.
168   uint64_t manifest_file_number;
169   uint64_t pending_manifest_file_number;
170   uint64_t log_number;
171   uint64_t prev_log_number;
172 
173   uint64_t min_pending_output = 0;
174   uint64_t prev_total_log_size = 0;
175   size_t num_alive_log_files = 0;
176   uint64_t size_log_to_delete = 0;
177 
178   // Snapshot taken before flush/compaction job.
179   std::unique_ptr<ManagedSnapshot> job_snapshot;
180 
181   explicit JobContext(int _job_id, bool create_superversion = false) {
182     job_id = _job_id;
183     manifest_file_number = 0;
184     pending_manifest_file_number = 0;
185     log_number = 0;
186     prev_log_number = 0;
187     superversion_contexts.emplace_back(
188         SuperVersionContext(create_superversion));
189   }
190 
191   // For non-empty JobContext Clean() has to be called at least once before
192   // before destruction (see asserts in ~JobContext()). Should be called with
193   // unlocked DB mutex. Destructor doesn't call Clean() to avoid accidentally
194   // doing potentially slow Clean() with locked DB mutex.
CleanJobContext195   void Clean() {
196     // free superversions
197     for (auto& sv_context : superversion_contexts) {
198       sv_context.Clean();
199     }
200     // free pending memtables
201     for (auto m : memtables_to_free) {
202       delete m;
203     }
204     for (auto l : logs_to_free) {
205       delete l;
206     }
207 
208     memtables_to_free.clear();
209     logs_to_free.clear();
210     job_snapshot.reset();
211   }
212 
~JobContextJobContext213   ~JobContext() {
214     assert(memtables_to_free.size() == 0);
215     assert(logs_to_free.size() == 0);
216   }
217 };
218 
219 }  // namespace ROCKSDB_NAMESPACE
220