Bug Summary

File:home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc
Warning:line 286, column 24
The left operand of '<' is a garbage value

Annotated Source Code

[?] Use j/k keys for keyboard navigation

/home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc

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 "util/sst_file_manager_impl.h"
7
8#ifndef __STDC_FORMAT_MACROS
9#define __STDC_FORMAT_MACROS
10#endif
11
12#include <inttypes.h>
13#include <vector>
14
15#include "db/db_impl.h"
16#include "port/port.h"
17#include "rocksdb/env.h"
18#include "rocksdb/sst_file_manager.h"
19#include "util/mutexlock.h"
20#include "util/sync_point.h"
21
22namespace rocksdb {
23
24#ifndef ROCKSDB_LITE
25SstFileManagerImpl::SstFileManagerImpl(Env* env, std::shared_ptr<Logger> logger,
26 int64_t rate_bytes_per_sec,
27 double max_trash_db_ratio,
28 uint64_t bytes_max_delete_chunk)
29 : env_(env),
30 logger_(logger),
31 total_files_size_(0),
32 in_progress_files_size_(0),
33 compaction_buffer_size_(0),
34 cur_compactions_reserved_size_(0),
35 max_allowed_space_(0),
36 delete_scheduler_(env, rate_bytes_per_sec, logger.get(), this,
37 max_trash_db_ratio, bytes_max_delete_chunk),
38 cv_(&mu_),
39 closing_(false),
40 bg_thread_(nullptr),
41 reserved_disk_buffer_(0),
42 free_space_trigger_(0),
43 cur_instance_(nullptr) {
44}
45
46SstFileManagerImpl::~SstFileManagerImpl() {
47 Close();
48}
49
50void SstFileManagerImpl::Close() {
51 {
52 MutexLock l(&mu_);
53 if (closing_) {
54 return;
55 }
56 closing_ = true;
57 cv_.SignalAll();
58 }
59 if (bg_thread_) {
60 bg_thread_->join();
61 }
62}
63
64Status SstFileManagerImpl::OnAddFile(const std::string& file_path,
65 bool compaction) {
66 uint64_t file_size;
67 Status s = env_->GetFileSize(file_path, &file_size);
68 if (s.ok()) {
69 MutexLock l(&mu_);
70 OnAddFileImpl(file_path, file_size, compaction);
71 }
72 TEST_SYNC_POINT("SstFileManagerImpl::OnAddFile");
73 return s;
74}
75
76Status SstFileManagerImpl::OnDeleteFile(const std::string& file_path) {
77 {
78 MutexLock l(&mu_);
79 OnDeleteFileImpl(file_path);
80 }
81 TEST_SYNC_POINT("SstFileManagerImpl::OnDeleteFile");
82 return Status::OK();
83}
84
85void SstFileManagerImpl::OnCompactionCompletion(Compaction* c) {
86 MutexLock l(&mu_);
87 uint64_t size_added_by_compaction = 0;
88 for (size_t i = 0; i < c->num_input_levels(); i++) {
89 for (size_t j = 0; j < c->num_input_files(i); j++) {
90 FileMetaData* filemeta = c->input(i, j);
91 size_added_by_compaction += filemeta->fd.GetFileSize();
92 }
93 }
94 cur_compactions_reserved_size_ -= size_added_by_compaction;
95
96 auto new_files = c->edit()->GetNewFiles();
97 for (auto& new_file : new_files) {
98 auto fn = TableFileName(c->immutable_cf_options()->cf_paths,
99 new_file.second.fd.GetNumber(),
100 new_file.second.fd.GetPathId());
101 if (in_progress_files_.find(fn) != in_progress_files_.end()) {
102 auto tracked_file = tracked_files_.find(fn);
103 assert(tracked_file != tracked_files_.end())(static_cast<void> (0));
104 in_progress_files_size_ -= tracked_file->second;
105 in_progress_files_.erase(fn);
106 }
107 }
108}
109
110Status SstFileManagerImpl::OnMoveFile(const std::string& old_path,
111 const std::string& new_path,
112 uint64_t* file_size) {
113 {
114 MutexLock l(&mu_);
115 if (file_size != nullptr) {
116 *file_size = tracked_files_[old_path];
117 }
118 OnAddFileImpl(new_path, tracked_files_[old_path], false);
119 OnDeleteFileImpl(old_path);
120 }
121 TEST_SYNC_POINT("SstFileManagerImpl::OnMoveFile");
122 return Status::OK();
123}
124
125void SstFileManagerImpl::SetMaxAllowedSpaceUsage(uint64_t max_allowed_space) {
126 MutexLock l(&mu_);
127 max_allowed_space_ = max_allowed_space;
128}
129
130void SstFileManagerImpl::SetCompactionBufferSize(
131 uint64_t compaction_buffer_size) {
132 MutexLock l(&mu_);
133 compaction_buffer_size_ = compaction_buffer_size;
134}
135
136bool SstFileManagerImpl::IsMaxAllowedSpaceReached() {
137 MutexLock l(&mu_);
138 if (max_allowed_space_ <= 0) {
139 return false;
140 }
141 return total_files_size_ >= max_allowed_space_;
142}
143
144bool SstFileManagerImpl::IsMaxAllowedSpaceReachedIncludingCompactions() {
145 MutexLock l(&mu_);
146 if (max_allowed_space_ <= 0) {
147 return false;
148 }
149 return total_files_size_ + cur_compactions_reserved_size_ >=
150 max_allowed_space_;
151}
152
153bool SstFileManagerImpl::EnoughRoomForCompaction(
154 ColumnFamilyData* cfd, const std::vector<CompactionInputFiles>& inputs,
155 Status bg_error) {
156 MutexLock l(&mu_);
157 uint64_t size_added_by_compaction = 0;
158 // First check if we even have the space to do the compaction
159 for (size_t i = 0; i < inputs.size(); i++) {
160 for (size_t j = 0; j < inputs[i].size(); j++) {
161 FileMetaData* filemeta = inputs[i][j];
162 size_added_by_compaction += filemeta->fd.GetFileSize();
163 }
164 }
165
166 // Update cur_compactions_reserved_size_ so concurrent compaction
167 // don't max out space
168 size_t needed_headroom =
169 cur_compactions_reserved_size_ + size_added_by_compaction +
170 compaction_buffer_size_;
171 if (max_allowed_space_ != 0 &&
172 (needed_headroom + total_files_size_ > max_allowed_space_)) {
173 return false;
174 }
175
176 // Implement more aggressive checks only if this DB instance has already
177 // seen a NoSpace() error. This is tin order to contain a single potentially
178 // misbehaving DB instance and prevent it from slowing down compactions of
179 // other DB instances
180 if (CheckFreeSpace() && bg_error == Status::NoSpace()) {
181 auto fn =
182 TableFileName(cfd->ioptions()->cf_paths, inputs[0][0]->fd.GetNumber(),
183 inputs[0][0]->fd.GetPathId());
184 uint64_t free_space = 0;
185 env_->GetFreeSpace(fn, &free_space);
186 // needed_headroom is based on current size reserved by compactions,
187 // minus any files created by running compactions as they would count
188 // against the reserved size. If user didn't specify any compaction
189 // buffer, add reserved_disk_buffer_ that's calculated by default so the
190 // compaction doesn't end up leaving nothing for logs and flush SSTs
191 if (compaction_buffer_size_ == 0) {
192 needed_headroom += reserved_disk_buffer_;
193 }
194 needed_headroom -= in_progress_files_size_;
195 if (free_space < needed_headroom + size_added_by_compaction) {
196 // We hit the condition of not enough disk space
197 ROCKS_LOG_ERROR(logger_,rocksdb::Log(InfoLogLevel::ERROR_LEVEL, logger_, ("[%s:" "201"
"] " "free space [%" "l" "u" " bytes] is less than " "needed headroom [%"
"zu" " bytes]\n"), RocksLogShorterFileName("/home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc"
), free_space, needed_headroom)
198 "free space [%" PRIu64rocksdb::Log(InfoLogLevel::ERROR_LEVEL, logger_, ("[%s:" "201"
"] " "free space [%" "l" "u" " bytes] is less than " "needed headroom [%"
"zu" " bytes]\n"), RocksLogShorterFileName("/home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc"
), free_space, needed_headroom)
199 " bytes] is less than "rocksdb::Log(InfoLogLevel::ERROR_LEVEL, logger_, ("[%s:" "201"
"] " "free space [%" "l" "u" " bytes] is less than " "needed headroom [%"
"zu" " bytes]\n"), RocksLogShorterFileName("/home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc"
), free_space, needed_headroom)
200 "needed headroom [%" ROCKSDB_PRIszt " bytes]\n",rocksdb::Log(InfoLogLevel::ERROR_LEVEL, logger_, ("[%s:" "201"
"] " "free space [%" "l" "u" " bytes] is less than " "needed headroom [%"
"zu" " bytes]\n"), RocksLogShorterFileName("/home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc"
), free_space, needed_headroom)
201 free_space, needed_headroom)rocksdb::Log(InfoLogLevel::ERROR_LEVEL, logger_, ("[%s:" "201"
"] " "free space [%" "l" "u" " bytes] is less than " "needed headroom [%"
"zu" " bytes]\n"), RocksLogShorterFileName("/home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc"
), free_space, needed_headroom)
;
202 return false;
203 }
204 }
205
206 cur_compactions_reserved_size_ += size_added_by_compaction;
207 // Take a snapshot of cur_compactions_reserved_size_ for when we encounter
208 // a NoSpace error.
209 free_space_trigger_ = cur_compactions_reserved_size_;
210 return true;
211}
212
213uint64_t SstFileManagerImpl::GetCompactionsReservedSize() {
214 MutexLock l(&mu_);
215 return cur_compactions_reserved_size_;
216}
217
218uint64_t SstFileManagerImpl::GetTotalSize() {
219 MutexLock l(&mu_);
220 return total_files_size_;
221}
222
223std::unordered_map<std::string, uint64_t>
224SstFileManagerImpl::GetTrackedFiles() {
225 MutexLock l(&mu_);
226 return tracked_files_;
227}
228
229int64_t SstFileManagerImpl::GetDeleteRateBytesPerSecond() {
230 return delete_scheduler_.GetRateBytesPerSecond();
231}
232
233void SstFileManagerImpl::SetDeleteRateBytesPerSecond(int64_t delete_rate) {
234 return delete_scheduler_.SetRateBytesPerSecond(delete_rate);
235}
236
237double SstFileManagerImpl::GetMaxTrashDBRatio() {
238 return delete_scheduler_.GetMaxTrashDBRatio();
239}
240
241void SstFileManagerImpl::SetMaxTrashDBRatio(double r) {
242 return delete_scheduler_.SetMaxTrashDBRatio(r);
243}
244
245uint64_t SstFileManagerImpl::GetTotalTrashSize() {
246 return delete_scheduler_.GetTotalTrashSize();
247}
248
249void SstFileManagerImpl::ReserveDiskBuffer(uint64_t size,
250 const std::string& path) {
251 MutexLock l(&mu_);
252
253 reserved_disk_buffer_ += size;
254 if (path_.empty()) {
255 path_ = path;
256 }
257}
258
259void SstFileManagerImpl::ClearError() {
260 while (true) {
1
Loop condition is true. Entering loop body
9
Loop condition is true. Entering loop body
17
Loop condition is true. Entering loop body
25
Loop condition is true. Entering loop body
261 MutexLock l(&mu_);
262
263 if (closing_) {
2
Assuming the condition is false
3
Taking false branch
10
Assuming the condition is false
11
Taking false branch
18
Assuming the condition is false
19
Taking false branch
26
Assuming the condition is false
27
Taking false branch
264 return;
265 }
266
267 uint64_t free_space;
28
'free_space' declared without an initial value
268 Status s = env_->GetFreeSpace(path_, &free_space);
29
Calling 'Env::GetFreeSpace'
32
Returning from 'Env::GetFreeSpace'
269 if (s.ok()) {
4
Taking false branch
12
Taking false branch
20
Taking false branch
33
Taking true branch
270 // In case of multi-DB instances, some of them may have experienced a
271 // soft error and some a hard error. In the SstFileManagerImpl, a hard
272 // error will basically override previously reported soft errors. Once
273 // we clear the hard error, we don't keep track of previous errors for
274 // now
275 if (bg_err_.severity() == Status::Severity::kHardError) {
34
Assuming the condition is false
35
Taking false branch
276 if (free_space < reserved_disk_buffer_) {
277 ROCKS_LOG_ERROR(logger_,rocksdb::Log(InfoLogLevel::ERROR_LEVEL, logger_, ("[%s:" "281"
"] " "free space [%" "l" "u" " bytes] is less than " "required disk buffer [%"
"l" "u" " bytes]\n"), RocksLogShorterFileName("/home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc"
), free_space, reserved_disk_buffer_)
278 "free space [%" PRIu64rocksdb::Log(InfoLogLevel::ERROR_LEVEL, logger_, ("[%s:" "281"
"] " "free space [%" "l" "u" " bytes] is less than " "required disk buffer [%"
"l" "u" " bytes]\n"), RocksLogShorterFileName("/home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc"
), free_space, reserved_disk_buffer_)
279 " bytes] is less than "rocksdb::Log(InfoLogLevel::ERROR_LEVEL, logger_, ("[%s:" "281"
"] " "free space [%" "l" "u" " bytes] is less than " "required disk buffer [%"
"l" "u" " bytes]\n"), RocksLogShorterFileName("/home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc"
), free_space, reserved_disk_buffer_)
280 "required disk buffer [%" PRIu64 " bytes]\n",rocksdb::Log(InfoLogLevel::ERROR_LEVEL, logger_, ("[%s:" "281"
"] " "free space [%" "l" "u" " bytes] is less than " "required disk buffer [%"
"l" "u" " bytes]\n"), RocksLogShorterFileName("/home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc"
), free_space, reserved_disk_buffer_)
281 free_space, reserved_disk_buffer_)rocksdb::Log(InfoLogLevel::ERROR_LEVEL, logger_, ("[%s:" "281"
"] " "free space [%" "l" "u" " bytes] is less than " "required disk buffer [%"
"l" "u" " bytes]\n"), RocksLogShorterFileName("/home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc"
), free_space, reserved_disk_buffer_)
;
282 ROCKS_LOG_ERROR(logger_, "Cannot clear hard error\n")rocksdb::Log(InfoLogLevel::ERROR_LEVEL, logger_, ("[%s:" "282"
"] " "Cannot clear hard error\n"), RocksLogShorterFileName("/home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc"
))
;
283 s = Status::NoSpace();
284 }
285 } else if (bg_err_.severity() == Status::Severity::kSoftError) {
36
Assuming the condition is true
37
Taking true branch
286 if (free_space < free_space_trigger_) {
38
The left operand of '<' is a garbage value
287 ROCKS_LOG_WARN(logger_,rocksdb::Log(InfoLogLevel::WARN_LEVEL, logger_, ("[%s:" "292"
"] " "free space [%" "l" "u" " bytes] is less than " "free space for compaction trigger [%"
"l" "u" " bytes]\n"), RocksLogShorterFileName("/home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc"
), free_space, free_space_trigger_)
288 "free space [%" PRIu64rocksdb::Log(InfoLogLevel::WARN_LEVEL, logger_, ("[%s:" "292"
"] " "free space [%" "l" "u" " bytes] is less than " "free space for compaction trigger [%"
"l" "u" " bytes]\n"), RocksLogShorterFileName("/home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc"
), free_space, free_space_trigger_)
289 " bytes] is less than "rocksdb::Log(InfoLogLevel::WARN_LEVEL, logger_, ("[%s:" "292"
"] " "free space [%" "l" "u" " bytes] is less than " "free space for compaction trigger [%"
"l" "u" " bytes]\n"), RocksLogShorterFileName("/home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc"
), free_space, free_space_trigger_)
290 "free space for compaction trigger [%" PRIu64rocksdb::Log(InfoLogLevel::WARN_LEVEL, logger_, ("[%s:" "292"
"] " "free space [%" "l" "u" " bytes] is less than " "free space for compaction trigger [%"
"l" "u" " bytes]\n"), RocksLogShorterFileName("/home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc"
), free_space, free_space_trigger_)
291 " bytes]\n",rocksdb::Log(InfoLogLevel::WARN_LEVEL, logger_, ("[%s:" "292"
"] " "free space [%" "l" "u" " bytes] is less than " "free space for compaction trigger [%"
"l" "u" " bytes]\n"), RocksLogShorterFileName("/home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc"
), free_space, free_space_trigger_)
292 free_space, free_space_trigger_)rocksdb::Log(InfoLogLevel::WARN_LEVEL, logger_, ("[%s:" "292"
"] " "free space [%" "l" "u" " bytes] is less than " "free space for compaction trigger [%"
"l" "u" " bytes]\n"), RocksLogShorterFileName("/home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc"
), free_space, free_space_trigger_)
;
293 ROCKS_LOG_WARN(logger_, "Cannot clear soft error\n")rocksdb::Log(InfoLogLevel::WARN_LEVEL, logger_, ("[%s:" "293"
"] " "Cannot clear soft error\n"), RocksLogShorterFileName("/home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc"
))
;
294 s = Status::NoSpace();
295 }
296 }
297 }
298
299 // Someone could have called CancelErrorRecovery() and the list could have
300 // become empty, so check again here
301 if (s.ok() && !error_handler_list_.empty()) {
302 auto error_handler = error_handler_list_.front();
303 // Since we will release the mutex, set cur_instance_ to signal to the
304 // shutdown thread, if it calls // CancelErrorRecovery() the meantime,
305 // to indicate that this DB instance is busy. The DB instance is
306 // guaranteed to not be deleted before RecoverFromBGError() returns,
307 // since the ErrorHandler::recovery_in_prog_ flag would be true
308 cur_instance_ = error_handler;
309 mu_.Unlock();
310 s = error_handler->RecoverFromBGError();
311 mu_.Lock();
312 // The DB instance might have been deleted while we were
313 // waiting for the mutex, so check cur_instance_ to make sure its
314 // still non-null
315 if (cur_instance_) {
316 // Check for error again, since the instance may have recovered but
317 // immediately got another error. If that's the case, and the new
318 // error is also a NoSpace() non-fatal error, leave the instance in
319 // the list
320 Status err = cur_instance_->GetBGError();
321 if (s.ok() && err == Status::NoSpace() &&
322 err.severity() < Status::Severity::kFatalError) {
323 s = err;
324 }
325 cur_instance_ = nullptr;
326 }
327
328 if (s.ok() || s.IsShutdownInProgress() ||
329 (!s.ok() && s.severity() >= Status::Severity::kFatalError)) {
330 // If shutdown is in progress, abandon this handler instance
331 // and continue with the others
332 error_handler_list_.pop_front();
333 }
334 }
335
336 if (!error_handler_list_.empty()) {
5
Assuming the condition is false
6
Taking false branch
13
Assuming the condition is false
14
Taking false branch
21
Assuming the condition is false
22
Taking false branch
337 // If there are more instances to be recovered, reschedule after 5
338 // seconds
339 int64_t wait_until = env_->NowMicros() + 5000000;
340 cv_.TimedWait(wait_until);
341 }
342
343 // Check again for error_handler_list_ empty, as a DB instance shutdown
344 // could have removed it from the queue while we were in timed wait
345 if (error_handler_list_.empty()) {
7
Assuming the condition is false
8
Taking false branch
15
Assuming the condition is false
16
Taking false branch
23
Assuming the condition is false
24
Taking false branch
346 ROCKS_LOG_INFO(logger_, "Clearing error\n")rocksdb::Log(InfoLogLevel::INFO_LEVEL, logger_, ("[%s:" "346"
"] " "Clearing error\n"), RocksLogShorterFileName("/home/bhubbard/working/src/ceph/src/rocksdb/util/sst_file_manager_impl.cc"
))
;
347 bg_err_ = Status::OK();
348 return;
349 }
350 }
351}
352
353void SstFileManagerImpl::StartErrorRecovery(ErrorHandler* handler,
354 Status bg_error) {
355 MutexLock l(&mu_);
356 if (bg_error.severity() == Status::Severity::kSoftError) {
357 if (bg_err_.ok()) {
358 // Setting bg_err_ basically means we're in degraded mode
359 // Assume that all pending compactions will fail similarly. The trigger
360 // for clearing this condition is set to current compaction reserved
361 // size, so we stop checking disk space available in
362 // EnoughRoomForCompaction once this much free space is available
363 bg_err_ = bg_error;
364 }
365 } else if (bg_error.severity() == Status::Severity::kHardError) {
366 bg_err_ = bg_error;
367 } else {
368 assert(false)(static_cast<void> (0));
369 }
370
371 // If this is the first instance of this error, kick of a thread to poll
372 // and recover from this condition
373 if (error_handler_list_.empty()) {
374 error_handler_list_.push_back(handler);
375 // Release lock before calling join. Its ok to do so because
376 // error_handler_list_ is now non-empty, so no other invocation of this
377 // function will execute this piece of code
378 mu_.Unlock();
379 if (bg_thread_) {
380 bg_thread_->join();
381 }
382 // Start a new thread. The previous one would have exited.
383 bg_thread_.reset(new port::Thread(&SstFileManagerImpl::ClearError, this));
384 mu_.Lock();
385 } else {
386 // Check if this DB instance is already in the list
387 for (auto iter = error_handler_list_.begin();
388 iter != error_handler_list_.end(); ++iter) {
389 if ((*iter) == handler) {
390 return;
391 }
392 }
393 error_handler_list_.push_back(handler);
394 }
395}
396
397bool SstFileManagerImpl::CancelErrorRecovery(ErrorHandler* handler) {
398 MutexLock l(&mu_);
399
400 if (cur_instance_ == handler) {
401 // This instance is currently busy attempting to recover
402 // Nullify it so the recovery thread doesn't attempt to access it again
403 cur_instance_ = nullptr;
404 return false;
405 }
406
407 for (auto iter = error_handler_list_.begin();
408 iter != error_handler_list_.end(); ++iter) {
409 if ((*iter) == handler) {
410 error_handler_list_.erase(iter);
411 return true;
412 }
413 }
414 return false;
415}
416
417Status SstFileManagerImpl::ScheduleFileDeletion(
418 const std::string& file_path, const std::string& path_to_sync,
419 const bool force_bg) {
420 TEST_SYNC_POINT("SstFileManagerImpl::ScheduleFileDeletion");
421 return delete_scheduler_.DeleteFile(file_path, path_to_sync,
422 force_bg);
423}
424
425void SstFileManagerImpl::WaitForEmptyTrash() {
426 delete_scheduler_.WaitForEmptyTrash();
427}
428
429void SstFileManagerImpl::OnAddFileImpl(const std::string& file_path,
430 uint64_t file_size, bool compaction) {
431 auto tracked_file = tracked_files_.find(file_path);
432 if (tracked_file != tracked_files_.end()) {
433 // File was added before, we will just update the size
434 assert(!compaction)(static_cast<void> (0));
435 total_files_size_ -= tracked_file->second;
436 total_files_size_ += file_size;
437 cur_compactions_reserved_size_ -= file_size;
438 } else {
439 total_files_size_ += file_size;
440 if (compaction) {
441 // Keep track of the size of files created by in-progress compactions.
442 // When calculating whether there's enough headroom for new compactions,
443 // this will be subtracted from cur_compactions_reserved_size_.
444 // Otherwise, compactions will be double counted.
445 in_progress_files_size_ += file_size;
446 in_progress_files_.insert(file_path);
447 }
448 }
449 tracked_files_[file_path] = file_size;
450}
451
452void SstFileManagerImpl::OnDeleteFileImpl(const std::string& file_path) {
453 auto tracked_file = tracked_files_.find(file_path);
454 if (tracked_file == tracked_files_.end()) {
455 // File is not tracked
456 assert(in_progress_files_.find(file_path) == in_progress_files_.end())(static_cast<void> (0));
457 return;
458 }
459
460 total_files_size_ -= tracked_file->second;
461 // Check if it belonged to an in-progress compaction
462 if (in_progress_files_.find(file_path) != in_progress_files_.end()) {
463 in_progress_files_size_ -= tracked_file->second;
464 in_progress_files_.erase(file_path);
465 }
466 tracked_files_.erase(tracked_file);
467}
468
469SstFileManager* NewSstFileManager(Env* env, std::shared_ptr<Logger> info_log,
470 std::string trash_dir,
471 int64_t rate_bytes_per_sec,
472 bool delete_existing_trash, Status* status,
473 double max_trash_db_ratio,
474 uint64_t bytes_max_delete_chunk) {
475 SstFileManagerImpl* res =
476 new SstFileManagerImpl(env, info_log, rate_bytes_per_sec,
477 max_trash_db_ratio, bytes_max_delete_chunk);
478
479 // trash_dir is deprecated and not needed anymore, but if user passed it
480 // we will still remove files in it.
481 Status s;
482 if (delete_existing_trash && trash_dir != "") {
483 std::vector<std::string> files_in_trash;
484 s = env->GetChildren(trash_dir, &files_in_trash);
485 if (s.ok()) {
486 for (const std::string& trash_file : files_in_trash) {
487 if (trash_file == "." || trash_file == "..") {
488 continue;
489 }
490
491 std::string path_in_trash = trash_dir + "/" + trash_file;
492 res->OnAddFile(path_in_trash);
493 Status file_delete =
494 res->ScheduleFileDeletion(path_in_trash, trash_dir);
495 if (s.ok() && !file_delete.ok()) {
496 s = file_delete;
497 }
498 }
499 }
500 }
501
502 if (status) {
503 *status = s;
504 }
505
506 return res;
507}
508
509#else
510
511SstFileManager* NewSstFileManager(Env* /*env*/,
512 std::shared_ptr<Logger> /*info_log*/,
513 std::string /*trash_dir*/,
514 int64_t /*rate_bytes_per_sec*/,
515 bool /*delete_existing_trash*/,
516 Status* status, double /*max_trash_db_ratio*/,
517 uint64_t /*bytes_max_delete_chunk*/) {
518 if (status) {
519 *status =
520 Status::NotSupported("SstFileManager is not supported in ROCKSDB_LITE");
521 }
522 return nullptr;
523}
524
525#endif // ROCKSDB_LITE
526
527} // namespace rocksdb

/home/bhubbard/working/src/ceph/src/rocksdb/include/rocksdb/env.h

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// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
6// Use of this source code is governed by a BSD-style license that can be
7// found in the LICENSE file. See the AUTHORS file for names of contributors.
8//
9// An Env is an interface used by the rocksdb implementation to access
10// operating system functionality like the filesystem etc. Callers
11// may wish to provide a custom Env object when opening a database to
12// get fine gain control; e.g., to rate limit file system operations.
13//
14// All Env implementations are safe for concurrent access from
15// multiple threads without any external synchronization.
16
17#pragma once
18
19#include <stdint.h>
20#include <cstdarg>
21#include <functional>
22#include <limits>
23#include <memory>
24#include <string>
25#include <vector>
26#include "rocksdb/status.h"
27#include "rocksdb/thread_status.h"
28
29#ifdef _WIN32
30// Windows API macro interference
31#undef DeleteFile
32#undef GetCurrentTime
33#endif
34
35#if defined(__GNUC__4) || defined(__clang__1)
36#define ROCKSDB_PRINTF_FORMAT_ATTR(format_param, dots_param)__attribute__((__format__(__printf__, format_param, dots_param
)))
\
37 __attribute__((__format__(__printf__, format_param, dots_param)))
38#else
39#define ROCKSDB_PRINTF_FORMAT_ATTR(format_param, dots_param)__attribute__((__format__(__printf__, format_param, dots_param
)))
40#endif
41
42namespace rocksdb {
43
44class FileLock;
45class Logger;
46class RandomAccessFile;
47class SequentialFile;
48class Slice;
49class WritableFile;
50class RandomRWFile;
51class MemoryMappedFileBuffer;
52class Directory;
53struct DBOptions;
54struct ImmutableDBOptions;
55struct MutableDBOptions;
56class RateLimiter;
57class ThreadStatusUpdater;
58struct ThreadStatus;
59
60const size_t kDefaultPageSize = 4 * 1024;
61
62// Options while opening a file to read/write
63struct EnvOptions {
64 // Construct with default Options
65 EnvOptions();
66
67 // Construct from Options
68 explicit EnvOptions(const DBOptions& options);
69
70 // If true, then use mmap to read data
71 bool use_mmap_reads = false;
72
73 // If true, then use mmap to write data
74 bool use_mmap_writes = true;
75
76 // If true, then use O_DIRECT for reading data
77 bool use_direct_reads = false;
78
79 // If true, then use O_DIRECT for writing data
80 bool use_direct_writes = false;
81
82 // If false, fallocate() calls are bypassed
83 bool allow_fallocate = true;
84
85 // If true, set the FD_CLOEXEC on open fd.
86 bool set_fd_cloexec = true;
87
88 // Allows OS to incrementally sync files to disk while they are being
89 // written, in the background. Issue one request for every bytes_per_sync
90 // written. 0 turns it off.
91 // Default: 0
92 uint64_t bytes_per_sync = 0;
93
94 // If true, we will preallocate the file with FALLOC_FL_KEEP_SIZE flag, which
95 // means that file size won't change as part of preallocation.
96 // If false, preallocation will also change the file size. This option will
97 // improve the performance in workloads where you sync the data on every
98 // write. By default, we set it to true for MANIFEST writes and false for
99 // WAL writes
100 bool fallocate_with_keep_size = true;
101
102 // See DBOptions doc
103 size_t compaction_readahead_size;
104
105 // See DBOptions doc
106 size_t random_access_max_buffer_size;
107
108 // See DBOptions doc
109 size_t writable_file_max_buffer_size = 1024 * 1024;
110
111 // If not nullptr, write rate limiting is enabled for flush and compaction
112 RateLimiter* rate_limiter = nullptr;
113};
114
115class Env {
116 public:
117 struct FileAttributes {
118 // File name
119 std::string name;
120
121 // Size of file in bytes
122 uint64_t size_bytes;
123 };
124
125 Env() : thread_status_updater_(nullptr) {}
126
127 virtual ~Env();
128
129 // Return a default environment suitable for the current operating
130 // system. Sophisticated users may wish to provide their own Env
131 // implementation instead of relying on this default environment.
132 //
133 // The result of Default() belongs to rocksdb and must never be deleted.
134 static Env* Default();
135
136 // Create a brand new sequentially-readable file with the specified name.
137 // On success, stores a pointer to the new file in *result and returns OK.
138 // On failure stores nullptr in *result and returns non-OK. If the file does
139 // not exist, returns a non-OK status.
140 //
141 // The returned file will only be accessed by one thread at a time.
142 virtual Status NewSequentialFile(const std::string& fname,
143 std::unique_ptr<SequentialFile>* result,
144 const EnvOptions& options) = 0;
145
146 // Create a brand new random access read-only file with the
147 // specified name. On success, stores a pointer to the new file in
148 // *result and returns OK. On failure stores nullptr in *result and
149 // returns non-OK. If the file does not exist, returns a non-OK
150 // status.
151 //
152 // The returned file may be concurrently accessed by multiple threads.
153 virtual Status NewRandomAccessFile(const std::string& fname,
154 std::unique_ptr<RandomAccessFile>* result,
155 const EnvOptions& options) = 0;
156 // These values match Linux definition
157 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/fcntl.h#n56
158 enum WriteLifeTimeHint {
159 WLTH_NOT_SET = 0, // No hint information set
160 WLTH_NONE, // No hints about write life time
161 WLTH_SHORT, // Data written has a short life time
162 WLTH_MEDIUM, // Data written has a medium life time
163 WLTH_LONG, // Data written has a long life time
164 WLTH_EXTREME, // Data written has an extremely long life time
165 };
166
167 // Create an object that writes to a new file with the specified
168 // name. Deletes any existing file with the same name and creates a
169 // new file. On success, stores a pointer to the new file in
170 // *result and returns OK. On failure stores nullptr in *result and
171 // returns non-OK.
172 //
173 // The returned file will only be accessed by one thread at a time.
174 virtual Status NewWritableFile(const std::string& fname,
175 std::unique_ptr<WritableFile>* result,
176 const EnvOptions& options) = 0;
177
178 // Create an object that writes to a new file with the specified
179 // name. Deletes any existing file with the same name and creates a
180 // new file. On success, stores a pointer to the new file in
181 // *result and returns OK. On failure stores nullptr in *result and
182 // returns non-OK.
183 //
184 // The returned file will only be accessed by one thread at a time.
185 virtual Status ReopenWritableFile(const std::string& /*fname*/,
186 std::unique_ptr<WritableFile>* /*result*/,
187 const EnvOptions& /*options*/) {
188 return Status::NotSupported();
189 }
190
191 // Reuse an existing file by renaming it and opening it as writable.
192 virtual Status ReuseWritableFile(const std::string& fname,
193 const std::string& old_fname,
194 std::unique_ptr<WritableFile>* result,
195 const EnvOptions& options);
196
197 // Open `fname` for random read and write, if file doesn't exist the file
198 // will be created. On success, stores a pointer to the new file in
199 // *result and returns OK. On failure returns non-OK.
200 //
201 // The returned file will only be accessed by one thread at a time.
202 virtual Status NewRandomRWFile(const std::string& /*fname*/,
203 std::unique_ptr<RandomRWFile>* /*result*/,
204 const EnvOptions& /*options*/) {
205 return Status::NotSupported("RandomRWFile is not implemented in this Env");
206 }
207
208 // Opens `fname` as a memory-mapped file for read and write (in-place updates
209 // only, i.e., no appends). On success, stores a raw buffer covering the whole
210 // file in `*result`. The file must exist prior to this call.
211 virtual Status NewMemoryMappedFileBuffer(
212 const std::string& /*fname*/,
213 std::unique_ptr<MemoryMappedFileBuffer>* /*result*/) {
214 return Status::NotSupported(
215 "MemoryMappedFileBuffer is not implemented in this Env");
216 }
217
218 // Create an object that represents a directory. Will fail if directory
219 // doesn't exist. If the directory exists, it will open the directory
220 // and create a new Directory object.
221 //
222 // On success, stores a pointer to the new Directory in
223 // *result and returns OK. On failure stores nullptr in *result and
224 // returns non-OK.
225 virtual Status NewDirectory(const std::string& name,
226 std::unique_ptr<Directory>* result) = 0;
227
228 // Returns OK if the named file exists.
229 // NotFound if the named file does not exist,
230 // the calling process does not have permission to determine
231 // whether this file exists, or if the path is invalid.
232 // IOError if an IO Error was encountered
233 virtual Status FileExists(const std::string& fname) = 0;
234
235 // Store in *result the names of the children of the specified directory.
236 // The names are relative to "dir".
237 // Original contents of *results are dropped.
238 // Returns OK if "dir" exists and "*result" contains its children.
239 // NotFound if "dir" does not exist, the calling process does not have
240 // permission to access "dir", or if "dir" is invalid.
241 // IOError if an IO Error was encountered
242 virtual Status GetChildren(const std::string& dir,
243 std::vector<std::string>* result) = 0;
244
245 // Store in *result the attributes of the children of the specified directory.
246 // In case the implementation lists the directory prior to iterating the files
247 // and files are concurrently deleted, the deleted files will be omitted from
248 // result.
249 // The name attributes are relative to "dir".
250 // Original contents of *results are dropped.
251 // Returns OK if "dir" exists and "*result" contains its children.
252 // NotFound if "dir" does not exist, the calling process does not have
253 // permission to access "dir", or if "dir" is invalid.
254 // IOError if an IO Error was encountered
255 virtual Status GetChildrenFileAttributes(const std::string& dir,
256 std::vector<FileAttributes>* result);
257
258 // Delete the named file.
259 virtual Status DeleteFile(const std::string& fname) = 0;
260
261 // Truncate the named file to the specified size.
262 virtual Status Truncate(const std::string& /*fname*/, size_t /*size*/) {
263 return Status::NotSupported("Truncate is not supported for this Env");
264 }
265
266 // Create the specified directory. Returns error if directory exists.
267 virtual Status CreateDir(const std::string& dirname) = 0;
268
269 // Creates directory if missing. Return Ok if it exists, or successful in
270 // Creating.
271 virtual Status CreateDirIfMissing(const std::string& dirname) = 0;
272
273 // Delete the specified directory.
274 virtual Status DeleteDir(const std::string& dirname) = 0;
275
276 // Store the size of fname in *file_size.
277 virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) = 0;
278
279 // Store the last modification time of fname in *file_mtime.
280 virtual Status GetFileModificationTime(const std::string& fname,
281 uint64_t* file_mtime) = 0;
282 // Rename file src to target.
283 virtual Status RenameFile(const std::string& src,
284 const std::string& target) = 0;
285
286 // Hard Link file src to target.
287 virtual Status LinkFile(const std::string& /*src*/,
288 const std::string& /*target*/) {
289 return Status::NotSupported("LinkFile is not supported for this Env");
290 }
291
292 virtual Status NumFileLinks(const std::string& /*fname*/,
293 uint64_t* /*count*/) {
294 return Status::NotSupported(
295 "Getting number of file links is not supported for this Env");
296 }
297
298 virtual Status AreFilesSame(const std::string& /*first*/,
299 const std::string& /*second*/, bool* /*res*/) {
300 return Status::NotSupported("AreFilesSame is not supported for this Env");
301 }
302
303 // Lock the specified file. Used to prevent concurrent access to
304 // the same db by multiple processes. On failure, stores nullptr in
305 // *lock and returns non-OK.
306 //
307 // On success, stores a pointer to the object that represents the
308 // acquired lock in *lock and returns OK. The caller should call
309 // UnlockFile(*lock) to release the lock. If the process exits,
310 // the lock will be automatically released.
311 //
312 // If somebody else already holds the lock, finishes immediately
313 // with a failure. I.e., this call does not wait for existing locks
314 // to go away.
315 //
316 // May create the named file if it does not already exist.
317 virtual Status LockFile(const std::string& fname, FileLock** lock) = 0;
318
319 // Release the lock acquired by a previous successful call to LockFile.
320 // REQUIRES: lock was returned by a successful LockFile() call
321 // REQUIRES: lock has not already been unlocked.
322 virtual Status UnlockFile(FileLock* lock) = 0;
323
324 // Priority for scheduling job in thread pool
325 enum Priority { BOTTOM, LOW, HIGH, USER, TOTAL };
326
327 static std::string PriorityToString(Priority priority);
328
329 // Priority for requesting bytes in rate limiter scheduler
330 enum IOPriority { IO_LOW = 0, IO_HIGH = 1, IO_TOTAL = 2 };
331
332 // Arrange to run "(*function)(arg)" once in a background thread, in
333 // the thread pool specified by pri. By default, jobs go to the 'LOW'
334 // priority thread pool.
335
336 // "function" may run in an unspecified thread. Multiple functions
337 // added to the same Env may run concurrently in different threads.
338 // I.e., the caller may not assume that background work items are
339 // serialized.
340 // When the UnSchedule function is called, the unschedFunction
341 // registered at the time of Schedule is invoked with arg as a parameter.
342 virtual void Schedule(void (*function)(void* arg), void* arg,
343 Priority pri = LOW, void* tag = nullptr,
344 void (*unschedFunction)(void* arg) = nullptr) = 0;
345
346 // Arrange to remove jobs for given arg from the queue_ if they are not
347 // already scheduled. Caller is expected to have exclusive lock on arg.
348 virtual int UnSchedule(void* /*arg*/, Priority /*pri*/) { return 0; }
349
350 // Start a new thread, invoking "function(arg)" within the new thread.
351 // When "function(arg)" returns, the thread will be destroyed.
352 virtual void StartThread(void (*function)(void* arg), void* arg) = 0;
353
354 // Wait for all threads started by StartThread to terminate.
355 virtual void WaitForJoin() {}
356
357 // Get thread pool queue length for specific thread pool.
358 virtual unsigned int GetThreadPoolQueueLen(Priority /*pri*/ = LOW) const {
359 return 0;
360 }
361
362 // *path is set to a temporary directory that can be used for testing. It may
363 // or many not have just been created. The directory may or may not differ
364 // between runs of the same process, but subsequent calls will return the
365 // same directory.
366 virtual Status GetTestDirectory(std::string* path) = 0;
367
368 // Create and return a log file for storing informational messages.
369 virtual Status NewLogger(const std::string& fname,
370 std::shared_ptr<Logger>* result) = 0;
371
372 // Returns the number of micro-seconds since some fixed point in time.
373 // It is often used as system time such as in GenericRateLimiter
374 // and other places so a port needs to return system time in order to work.
375 virtual uint64_t NowMicros() = 0;
376
377 // Returns the number of nano-seconds since some fixed point in time. Only
378 // useful for computing deltas of time in one run.
379 // Default implementation simply relies on NowMicros.
380 // In platform-specific implementations, NowNanos() should return time points
381 // that are MONOTONIC.
382 virtual uint64_t NowNanos() { return NowMicros() * 1000; }
383
384 // 0 indicates not supported.
385 virtual uint64_t NowCPUNanos() { return 0; }
386
387 // Sleep/delay the thread for the prescribed number of micro-seconds.
388 virtual void SleepForMicroseconds(int micros) = 0;
389
390 // Get the current host name.
391 virtual Status GetHostName(char* name, uint64_t len) = 0;
392
393 // Get the number of seconds since the Epoch, 1970-01-01 00:00:00 (UTC).
394 // Only overwrites *unix_time on success.
395 virtual Status GetCurrentTime(int64_t* unix_time) = 0;
396
397 // Get full directory name for this db.
398 virtual Status GetAbsolutePath(const std::string& db_path,
399 std::string* output_path) = 0;
400
401 // The number of background worker threads of a specific thread pool
402 // for this environment. 'LOW' is the default pool.
403 // default number: 1
404 virtual void SetBackgroundThreads(int number, Priority pri = LOW) = 0;
405 virtual int GetBackgroundThreads(Priority pri = LOW) = 0;
406
407 virtual Status SetAllowNonOwnerAccess(bool /*allow_non_owner_access*/) {
408 return Status::NotSupported("Not supported.");
409 }
410
411 // Enlarge number of background worker threads of a specific thread pool
412 // for this environment if it is smaller than specified. 'LOW' is the default
413 // pool.
414 virtual void IncBackgroundThreadsIfNeeded(int number, Priority pri) = 0;
415
416 // Lower IO priority for threads from the specified pool.
417 virtual void LowerThreadPoolIOPriority(Priority /*pool*/ = LOW) {}
418
419 // Lower CPU priority for threads from the specified pool.
420 virtual void LowerThreadPoolCPUPriority(Priority /*pool*/ = LOW) {}
421
422 // Converts seconds-since-Jan-01-1970 to a printable string
423 virtual std::string TimeToString(uint64_t time) = 0;
424
425 // Generates a unique id that can be used to identify a db
426 virtual std::string GenerateUniqueId();
427
428 // OptimizeForLogWrite will create a new EnvOptions object that is a copy of
429 // the EnvOptions in the parameters, but is optimized for reading log files.
430 virtual EnvOptions OptimizeForLogRead(const EnvOptions& env_options) const;
431
432 // OptimizeForManifestRead will create a new EnvOptions object that is a copy
433 // of the EnvOptions in the parameters, but is optimized for reading manifest
434 // files.
435 virtual EnvOptions OptimizeForManifestRead(
436 const EnvOptions& env_options) const;
437
438 // OptimizeForLogWrite will create a new EnvOptions object that is a copy of
439 // the EnvOptions in the parameters, but is optimized for writing log files.
440 // Default implementation returns the copy of the same object.
441 virtual EnvOptions OptimizeForLogWrite(const EnvOptions& env_options,
442 const DBOptions& db_options) const;
443 // OptimizeForManifestWrite will create a new EnvOptions object that is a copy
444 // of the EnvOptions in the parameters, but is optimized for writing manifest
445 // files. Default implementation returns the copy of the same object.
446 virtual EnvOptions OptimizeForManifestWrite(
447 const EnvOptions& env_options) const;
448
449 // OptimizeForCompactionTableWrite will create a new EnvOptions object that is
450 // a copy of the EnvOptions in the parameters, but is optimized for writing
451 // table files.
452 virtual EnvOptions OptimizeForCompactionTableWrite(
453 const EnvOptions& env_options,
454 const ImmutableDBOptions& immutable_ops) const;
455
456 // OptimizeForCompactionTableWrite will create a new EnvOptions object that
457 // is a copy of the EnvOptions in the parameters, but is optimized for reading
458 // table files.
459 virtual EnvOptions OptimizeForCompactionTableRead(
460 const EnvOptions& env_options,
461 const ImmutableDBOptions& db_options) const;
462
463 // Returns the status of all threads that belong to the current Env.
464 virtual Status GetThreadList(std::vector<ThreadStatus>* /*thread_list*/) {
465 return Status::NotSupported("Not supported.");
466 }
467
468 // Returns the pointer to ThreadStatusUpdater. This function will be
469 // used in RocksDB internally to update thread status and supports
470 // GetThreadList().
471 virtual ThreadStatusUpdater* GetThreadStatusUpdater() const {
472 return thread_status_updater_;
473 }
474
475 // Returns the ID of the current thread.
476 virtual uint64_t GetThreadID() const;
477
478// This seems to clash with a macro on Windows, so #undef it here
479#undef GetFreeSpace
480
481 // Get the amount of free disk space
482 virtual Status GetFreeSpace(const std::string& /*path*/,
483 uint64_t* /*diskfree*/) {
484 return Status::NotSupported();
30
Calling 'Status::NotSupported'
31
Returning from 'Status::NotSupported'
485 }
486
487 // If you're adding methods here, remember to add them to EnvWrapper too.
488
489 protected:
490 // The pointer to an internal structure that will update the
491 // status of each thread.
492 ThreadStatusUpdater* thread_status_updater_;
493
494 private:
495 // No copying allowed
496 Env(const Env&);
497 void operator=(const Env&);
498};
499
500// The factory function to construct a ThreadStatusUpdater. Any Env
501// that supports GetThreadList() feature should call this function in its
502// constructor to initialize thread_status_updater_.
503ThreadStatusUpdater* CreateThreadStatusUpdater();
504
505// A file abstraction for reading sequentially through a file
506class SequentialFile {
507 public:
508 SequentialFile() {}
509 virtual ~SequentialFile();
510
511 // Read up to "n" bytes from the file. "scratch[0..n-1]" may be
512 // written by this routine. Sets "*result" to the data that was
513 // read (including if fewer than "n" bytes were successfully read).
514 // May set "*result" to point at data in "scratch[0..n-1]", so
515 // "scratch[0..n-1]" must be live when "*result" is used.
516 // If an error was encountered, returns a non-OK status.
517 //
518 // REQUIRES: External synchronization
519 virtual Status Read(size_t n, Slice* result, char* scratch) = 0;
520
521 // Skip "n" bytes from the file. This is guaranteed to be no
522 // slower that reading the same data, but may be faster.
523 //
524 // If end of file is reached, skipping will stop at the end of the
525 // file, and Skip will return OK.
526 //
527 // REQUIRES: External synchronization
528 virtual Status Skip(uint64_t n) = 0;
529
530 // Indicates the upper layers if the current SequentialFile implementation
531 // uses direct IO.
532 virtual bool use_direct_io() const { return false; }
533
534 // Use the returned alignment value to allocate
535 // aligned buffer for Direct I/O
536 virtual size_t GetRequiredBufferAlignment() const { return kDefaultPageSize; }
537
538 // Remove any kind of caching of data from the offset to offset+length
539 // of this file. If the length is 0, then it refers to the end of file.
540 // If the system is not caching the file contents, then this is a noop.
541 virtual Status InvalidateCache(size_t /*offset*/, size_t /*length*/) {
542 return Status::NotSupported("InvalidateCache not supported.");
543 }
544
545 // Positioned Read for direct I/O
546 // If Direct I/O enabled, offset, n, and scratch should be properly aligned
547 virtual Status PositionedRead(uint64_t /*offset*/, size_t /*n*/,
548 Slice* /*result*/, char* /*scratch*/) {
549 return Status::NotSupported();
550 }
551
552 // If you're adding methods here, remember to add them to
553 // SequentialFileWrapper too.
554};
555
556// A file abstraction for randomly reading the contents of a file.
557class RandomAccessFile {
558 public:
559 RandomAccessFile() {}
560 virtual ~RandomAccessFile();
561
562 // Read up to "n" bytes from the file starting at "offset".
563 // "scratch[0..n-1]" may be written by this routine. Sets "*result"
564 // to the data that was read (including if fewer than "n" bytes were
565 // successfully read). May set "*result" to point at data in
566 // "scratch[0..n-1]", so "scratch[0..n-1]" must be live when
567 // "*result" is used. If an error was encountered, returns a non-OK
568 // status.
569 //
570 // Safe for concurrent use by multiple threads.
571 // If Direct I/O enabled, offset, n, and scratch should be aligned properly.
572 virtual Status Read(uint64_t offset, size_t n, Slice* result,
573 char* scratch) const = 0;
574
575 // Readahead the file starting from offset by n bytes for caching.
576 virtual Status Prefetch(uint64_t /*offset*/, size_t /*n*/) {
577 return Status::OK();
578 }
579
580 // Tries to get an unique ID for this file that will be the same each time
581 // the file is opened (and will stay the same while the file is open).
582 // Furthermore, it tries to make this ID at most "max_size" bytes. If such an
583 // ID can be created this function returns the length of the ID and places it
584 // in "id"; otherwise, this function returns 0, in which case "id"
585 // may not have been modified.
586 //
587 // This function guarantees, for IDs from a given environment, two unique ids
588 // cannot be made equal to each other by adding arbitrary bytes to one of
589 // them. That is, no unique ID is the prefix of another.
590 //
591 // This function guarantees that the returned ID will not be interpretable as
592 // a single varint.
593 //
594 // Note: these IDs are only valid for the duration of the process.
595 virtual size_t GetUniqueId(char* /*id*/, size_t /*max_size*/) const {
596 return 0; // Default implementation to prevent issues with backwards
597 // compatibility.
598 };
599
600 enum AccessPattern { NORMAL, RANDOM, SEQUENTIAL, WILLNEED, DONTNEED };
601
602 virtual void Hint(AccessPattern /*pattern*/) {}
603
604 // Indicates the upper layers if the current RandomAccessFile implementation
605 // uses direct IO.
606 virtual bool use_direct_io() const { return false; }
607
608 // Use the returned alignment value to allocate
609 // aligned buffer for Direct I/O
610 virtual size_t GetRequiredBufferAlignment() const { return kDefaultPageSize; }
611
612 // Remove any kind of caching of data from the offset to offset+length
613 // of this file. If the length is 0, then it refers to the end of file.
614 // If the system is not caching the file contents, then this is a noop.
615 virtual Status InvalidateCache(size_t /*offset*/, size_t /*length*/) {
616 return Status::NotSupported("InvalidateCache not supported.");
617 }
618
619 // If you're adding methods here, remember to add them to
620 // RandomAccessFileWrapper too.
621};
622
623// A file abstraction for sequential writing. The implementation
624// must provide buffering since callers may append small fragments
625// at a time to the file.
626class WritableFile {
627 public:
628 WritableFile()
629 : last_preallocated_block_(0),
630 preallocation_block_size_(0),
631 io_priority_(Env::IO_TOTAL),
632 write_hint_(Env::WLTH_NOT_SET) {}
633 virtual ~WritableFile();
634
635 // Append data to the end of the file
636 // Note: A WriteabelFile object must support either Append or
637 // PositionedAppend, so the users cannot mix the two.
638 virtual Status Append(const Slice& data) = 0;
639
640 // PositionedAppend data to the specified offset. The new EOF after append
641 // must be larger than the previous EOF. This is to be used when writes are
642 // not backed by OS buffers and hence has to always start from the start of
643 // the sector. The implementation thus needs to also rewrite the last
644 // partial sector.
645 // Note: PositionAppend does not guarantee moving the file offset after the
646 // write. A WritableFile object must support either Append or
647 // PositionedAppend, so the users cannot mix the two.
648 //
649 // PositionedAppend() can only happen on the page/sector boundaries. For that
650 // reason, if the last write was an incomplete sector we still need to rewind
651 // back to the nearest sector/page and rewrite the portion of it with whatever
652 // we need to add. We need to keep where we stop writing.
653 //
654 // PositionedAppend() can only write whole sectors. For that reason we have to
655 // pad with zeros for the last write and trim the file when closing according
656 // to the position we keep in the previous step.
657 //
658 // PositionedAppend() requires aligned buffer to be passed in. The alignment
659 // required is queried via GetRequiredBufferAlignment()
660 virtual Status PositionedAppend(const Slice& /* data */,
661 uint64_t /* offset */) {
662 return Status::NotSupported();
663 }
664
665 // Truncate is necessary to trim the file to the correct size
666 // before closing. It is not always possible to keep track of the file
667 // size due to whole pages writes. The behavior is undefined if called
668 // with other writes to follow.
669 virtual Status Truncate(uint64_t /*size*/) { return Status::OK(); }
670 virtual Status Close() = 0;
671 virtual Status Flush() = 0;
672 virtual Status Sync() = 0; // sync data
673
674 /*
675 * Sync data and/or metadata as well.
676 * By default, sync only data.
677 * Override this method for environments where we need to sync
678 * metadata as well.
679 */
680 virtual Status Fsync() { return Sync(); }
681
682 // true if Sync() and Fsync() are safe to call concurrently with Append()
683 // and Flush().
684 virtual bool IsSyncThreadSafe() const { return false; }
685
686 // Indicates the upper layers if the current WritableFile implementation
687 // uses direct IO.
688 virtual bool use_direct_io() const { return false; }
689
690 // Use the returned alignment value to allocate
691 // aligned buffer for Direct I/O
692 virtual size_t GetRequiredBufferAlignment() const { return kDefaultPageSize; }
693 /*
694 * Change the priority in rate limiter if rate limiting is enabled.
695 * If rate limiting is not enabled, this call has no effect.
696 */
697 virtual void SetIOPriority(Env::IOPriority pri) { io_priority_ = pri; }
698
699 virtual Env::IOPriority GetIOPriority() { return io_priority_; }
700
701 virtual void SetWriteLifeTimeHint(Env::WriteLifeTimeHint hint) {
702 write_hint_ = hint;
703 }
704
705 virtual Env::WriteLifeTimeHint GetWriteLifeTimeHint() { return write_hint_; }
706 /*
707 * Get the size of valid data in the file.
708 */
709 virtual uint64_t GetFileSize() { return 0; }
710
711 /*
712 * Get and set the default pre-allocation block size for writes to
713 * this file. If non-zero, then Allocate will be used to extend the
714 * underlying storage of a file (generally via fallocate) if the Env
715 * instance supports it.
716 */
717 virtual void SetPreallocationBlockSize(size_t size) {
718 preallocation_block_size_ = size;
719 }
720
721 virtual void GetPreallocationStatus(size_t* block_size,
722 size_t* last_allocated_block) {
723 *last_allocated_block = last_preallocated_block_;
724 *block_size = preallocation_block_size_;
725 }
726
727 // For documentation, refer to RandomAccessFile::GetUniqueId()
728 virtual size_t GetUniqueId(char* /*id*/, size_t /*max_size*/) const {
729 return 0; // Default implementation to prevent issues with backwards
730 }
731
732 // Remove any kind of caching of data from the offset to offset+length
733 // of this file. If the length is 0, then it refers to the end of file.
734 // If the system is not caching the file contents, then this is a noop.
735 // This call has no effect on dirty pages in the cache.
736 virtual Status InvalidateCache(size_t /*offset*/, size_t /*length*/) {
737 return Status::NotSupported("InvalidateCache not supported.");
738 }
739
740 // Sync a file range with disk.
741 // offset is the starting byte of the file range to be synchronized.
742 // nbytes specifies the length of the range to be synchronized.
743 // This asks the OS to initiate flushing the cached data to disk,
744 // without waiting for completion.
745 // Default implementation does nothing.
746 virtual Status RangeSync(uint64_t /*offset*/, uint64_t /*nbytes*/) {
747 return Status::OK();
748 }
749
750 // PrepareWrite performs any necessary preparation for a write
751 // before the write actually occurs. This allows for pre-allocation
752 // of space on devices where it can result in less file
753 // fragmentation and/or less waste from over-zealous filesystem
754 // pre-allocation.
755 virtual void PrepareWrite(size_t offset, size_t len) {
756 if (preallocation_block_size_ == 0) {
757 return;
758 }
759 // If this write would cross one or more preallocation blocks,
760 // determine what the last preallocation block necessary to
761 // cover this write would be and Allocate to that point.
762 const auto block_size = preallocation_block_size_;
763 size_t new_last_preallocated_block =
764 (offset + len + block_size - 1) / block_size;
765 if (new_last_preallocated_block > last_preallocated_block_) {
766 size_t num_spanned_blocks =
767 new_last_preallocated_block - last_preallocated_block_;
768 Allocate(block_size * last_preallocated_block_,
769 block_size * num_spanned_blocks);
770 last_preallocated_block_ = new_last_preallocated_block;
771 }
772 }
773
774 // Pre-allocates space for a file.
775 virtual Status Allocate(uint64_t /*offset*/, uint64_t /*len*/) {
776 return Status::OK();
777 }
778
779 // If you're adding methods here, remember to add them to
780 // WritableFileWrapper too.
781
782 protected:
783 size_t preallocation_block_size() { return preallocation_block_size_; }
784
785 private:
786 size_t last_preallocated_block_;
787 size_t preallocation_block_size_;
788 // No copying allowed
789 WritableFile(const WritableFile&);
790 void operator=(const WritableFile&);
791
792 protected:
793 Env::IOPriority io_priority_;
794 Env::WriteLifeTimeHint write_hint_;
795};
796
797// A file abstraction for random reading and writing.
798class RandomRWFile {
799 public:
800 RandomRWFile() {}
801 virtual ~RandomRWFile() {}
802
803 // Indicates if the class makes use of direct I/O
804 // If false you must pass aligned buffer to Write()
805 virtual bool use_direct_io() const { return false; }
806
807 // Use the returned alignment value to allocate
808 // aligned buffer for Direct I/O
809 virtual size_t GetRequiredBufferAlignment() const { return kDefaultPageSize; }
810
811 // Write bytes in `data` at offset `offset`, Returns Status::OK() on success.
812 // Pass aligned buffer when use_direct_io() returns true.
813 virtual Status Write(uint64_t offset, const Slice& data) = 0;
814
815 // Read up to `n` bytes starting from offset `offset` and store them in
816 // result, provided `scratch` size should be at least `n`.
817 // Returns Status::OK() on success.
818 virtual Status Read(uint64_t offset, size_t n, Slice* result,
819 char* scratch) const = 0;
820
821 virtual Status Flush() = 0;
822
823 virtual Status Sync() = 0;
824
825 virtual Status Fsync() { return Sync(); }
826
827 virtual Status Close() = 0;
828
829 // If you're adding methods here, remember to add them to
830 // RandomRWFileWrapper too.
831
832 // No copying allowed
833 RandomRWFile(const RandomRWFile&) = delete;
834 RandomRWFile& operator=(const RandomRWFile&) = delete;
835};
836
837// MemoryMappedFileBuffer object represents a memory-mapped file's raw buffer.
838// Subclasses should release the mapping upon destruction.
839class MemoryMappedFileBuffer {
840 public:
841 MemoryMappedFileBuffer(void* _base, size_t _length)
842 : base_(_base), length_(_length) {}
843
844 virtual ~MemoryMappedFileBuffer() = 0;
845
846 // We do not want to unmap this twice. We can make this class
847 // movable if desired, however, since
848 MemoryMappedFileBuffer(const MemoryMappedFileBuffer&) = delete;
849 MemoryMappedFileBuffer& operator=(const MemoryMappedFileBuffer&) = delete;
850
851 void* GetBase() const { return base_; }
852 size_t GetLen() const { return length_; }
853
854 protected:
855 void* base_;
856 const size_t length_;
857};
858
859// Directory object represents collection of files and implements
860// filesystem operations that can be executed on directories.
861class Directory {
862 public:
863 virtual ~Directory() {}
864 // Fsync directory. Can be called concurrently from multiple threads.
865 virtual Status Fsync() = 0;
866
867 virtual size_t GetUniqueId(char* /*id*/, size_t /*max_size*/) const {
868 return 0;
869 }
870
871 // If you're adding methods here, remember to add them to
872 // DirectoryWrapper too.
873};
874
875enum InfoLogLevel : unsigned char {
876 DEBUG_LEVEL = 0,
877 INFO_LEVEL,
878 WARN_LEVEL,
879 ERROR_LEVEL,
880 FATAL_LEVEL,
881 HEADER_LEVEL,
882 NUM_INFO_LOG_LEVELS,
883};
884
885// An interface for writing log messages.
886class Logger {
887 public:
888 size_t kDoNotSupportGetLogFileSize = (std::numeric_limits<size_t>::max)();
889
890 explicit Logger(const InfoLogLevel log_level = InfoLogLevel::INFO_LEVEL)
891 : closed_(false), log_level_(log_level) {}
892 virtual ~Logger();
893
894 // Close the log file. Must be called before destructor. If the return
895 // status is NotSupported(), it means the implementation does cleanup in
896 // the destructor
897 virtual Status Close();
898
899 // Write a header to the log file with the specified format
900 // It is recommended that you log all header information at the start of the
901 // application. But it is not enforced.
902 virtual void LogHeader(const char* format, va_list ap) {
903 // Default implementation does a simple INFO level log write.
904 // Please override as per the logger class requirement.
905 Logv(format, ap);
906 }
907
908 // Write an entry to the log file with the specified format.
909 virtual void Logv(const char* format, va_list ap) = 0;
910
911 // Write an entry to the log file with the specified log level
912 // and format. Any log with level under the internal log level
913 // of *this (see @SetInfoLogLevel and @GetInfoLogLevel) will not be
914 // printed.
915 virtual void Logv(const InfoLogLevel log_level, const char* format,
916 va_list ap);
917
918 virtual size_t GetLogFileSize() const { return kDoNotSupportGetLogFileSize; }
919 // Flush to the OS buffers
920 virtual void Flush() {}
921 virtual InfoLogLevel GetInfoLogLevel() const { return log_level_; }
922 virtual void SetInfoLogLevel(const InfoLogLevel log_level) {
923 log_level_ = log_level;
924 }
925
926 // If you're adding methods here, remember to add them to LoggerWrapper too.
927
928 protected:
929 virtual Status CloseImpl();
930 bool closed_;
931
932 private:
933 // No copying allowed
934 Logger(const Logger&);
935 void operator=(const Logger&);
936 InfoLogLevel log_level_;
937};
938
939// Identifies a locked file.
940class FileLock {
941 public:
942 FileLock() {}
943 virtual ~FileLock();
944
945 private:
946 // No copying allowed
947 FileLock(const FileLock&);
948 void operator=(const FileLock&);
949};
950
951extern void LogFlush(const std::shared_ptr<Logger>& info_log);
952
953extern void Log(const InfoLogLevel log_level,
954 const std::shared_ptr<Logger>& info_log, const char* format,
955 ...) ROCKSDB_PRINTF_FORMAT_ATTR(3, 4)__attribute__((__format__(__printf__, 3, 4)));
956
957// a set of log functions with different log levels.
958extern void Header(const std::shared_ptr<Logger>& info_log, const char* format,
959 ...) ROCKSDB_PRINTF_FORMAT_ATTR(2, 3)__attribute__((__format__(__printf__, 2, 3)));
960extern void Debug(const std::shared_ptr<Logger>& info_log, const char* format,
961 ...) ROCKSDB_PRINTF_FORMAT_ATTR(2, 3)__attribute__((__format__(__printf__, 2, 3)));
962extern void Info(const std::shared_ptr<Logger>& info_log, const char* format,
963 ...) ROCKSDB_PRINTF_FORMAT_ATTR(2, 3)__attribute__((__format__(__printf__, 2, 3)));
964extern void Warn(const std::shared_ptr<Logger>& info_log, const char* format,
965 ...) ROCKSDB_PRINTF_FORMAT_ATTR(2, 3)__attribute__((__format__(__printf__, 2, 3)));
966extern void Error(const std::shared_ptr<Logger>& info_log, const char* format,
967 ...) ROCKSDB_PRINTF_FORMAT_ATTR(2, 3)__attribute__((__format__(__printf__, 2, 3)));
968extern void Fatal(const std::shared_ptr<Logger>& info_log, const char* format,
969 ...) ROCKSDB_PRINTF_FORMAT_ATTR(2, 3)__attribute__((__format__(__printf__, 2, 3)));
970
971// Log the specified data to *info_log if info_log is non-nullptr.
972// The default info log level is InfoLogLevel::INFO_LEVEL.
973extern void Log(const std::shared_ptr<Logger>& info_log, const char* format,
974 ...) ROCKSDB_PRINTF_FORMAT_ATTR(2, 3)__attribute__((__format__(__printf__, 2, 3)));
975
976extern void LogFlush(Logger* info_log);
977
978extern void Log(const InfoLogLevel log_level, Logger* info_log,
979 const char* format, ...) ROCKSDB_PRINTF_FORMAT_ATTR(3, 4)__attribute__((__format__(__printf__, 3, 4)));
980
981// The default info log level is InfoLogLevel::INFO_LEVEL.
982extern void Log(Logger* info_log, const char* format, ...)
983 ROCKSDB_PRINTF_FORMAT_ATTR(2, 3)__attribute__((__format__(__printf__, 2, 3)));
984
985// a set of log functions with different log levels.
986extern void Header(Logger* info_log, const char* format, ...)
987 ROCKSDB_PRINTF_FORMAT_ATTR(2, 3)__attribute__((__format__(__printf__, 2, 3)));
988extern void Debug(Logger* info_log, const char* format, ...)
989 ROCKSDB_PRINTF_FORMAT_ATTR(2, 3)__attribute__((__format__(__printf__, 2, 3)));
990extern void Info(Logger* info_log, const char* format, ...)
991 ROCKSDB_PRINTF_FORMAT_ATTR(2, 3)__attribute__((__format__(__printf__, 2, 3)));
992extern void Warn(Logger* info_log, const char* format, ...)
993 ROCKSDB_PRINTF_FORMAT_ATTR(2, 3)__attribute__((__format__(__printf__, 2, 3)));
994extern void Error(Logger* info_log, const char* format, ...)
995 ROCKSDB_PRINTF_FORMAT_ATTR(2, 3)__attribute__((__format__(__printf__, 2, 3)));
996extern void Fatal(Logger* info_log, const char* format, ...)
997 ROCKSDB_PRINTF_FORMAT_ATTR(2, 3)__attribute__((__format__(__printf__, 2, 3)));
998
999// A utility routine: write "data" to the named file.
1000extern Status WriteStringToFile(Env* env, const Slice& data,
1001 const std::string& fname,
1002 bool should_sync = false);
1003
1004// A utility routine: read contents of named file into *data
1005extern Status ReadFileToString(Env* env, const std::string& fname,
1006 std::string* data);
1007
1008// Below are helpers for wrapping most of the classes in this file.
1009// They forward all calls to another instance of the class.
1010// Useful when wrapping the default implementations.
1011// Typical usage is to inherit your wrapper from *Wrapper, e.g.:
1012//
1013// class MySequentialFileWrapper : public rocksdb::SequentialFileWrapper {
1014// public:
1015// MySequentialFileWrapper(rocksdb::SequentialFile* target):
1016// rocksdb::SequentialFileWrapper(target) {}
1017// Status Read(size_t n, Slice* result, char* scratch) override {
1018// cout << "Doing a read of size " << n << "!" << endl;
1019// return rocksdb::SequentialFileWrapper::Read(n, result, scratch);
1020// }
1021// // All other methods are forwarded to target_ automatically.
1022// };
1023//
1024// This is often more convenient than inheriting the class directly because
1025// (a) Don't have to override and forward all methods - the Wrapper will
1026// forward everything you're not explicitly overriding.
1027// (b) Don't need to update the wrapper when more methods are added to the
1028// rocksdb class. Unless you actually want to override the behavior.
1029// (And unless rocksdb people forgot to update the *Wrapper class.)
1030
1031// An implementation of Env that forwards all calls to another Env.
1032// May be useful to clients who wish to override just part of the
1033// functionality of another Env.
1034class EnvWrapper : public Env {
1035 public:
1036 // Initialize an EnvWrapper that delegates all calls to *t
1037 explicit EnvWrapper(Env* t) : target_(t) {}
1038 ~EnvWrapper() override;
1039
1040 // Return the target to which this Env forwards all calls
1041 Env* target() const { return target_; }
1042
1043 // The following text is boilerplate that forwards all methods to target()
1044 Status NewSequentialFile(const std::string& f,
1045 std::unique_ptr<SequentialFile>* r,
1046 const EnvOptions& options) override {
1047 return target_->NewSequentialFile(f, r, options);
1048 }
1049 Status NewRandomAccessFile(const std::string& f,
1050 std::unique_ptr<RandomAccessFile>* r,
1051 const EnvOptions& options) override {
1052 return target_->NewRandomAccessFile(f, r, options);
1053 }
1054 Status NewWritableFile(const std::string& f, std::unique_ptr<WritableFile>* r,
1055 const EnvOptions& options) override {
1056 return target_->NewWritableFile(f, r, options);
1057 }
1058 Status ReopenWritableFile(const std::string& fname,
1059 std::unique_ptr<WritableFile>* result,
1060 const EnvOptions& options) override {
1061 return target_->ReopenWritableFile(fname, result, options);
1062 }
1063 Status ReuseWritableFile(const std::string& fname,
1064 const std::string& old_fname,
1065 std::unique_ptr<WritableFile>* r,
1066 const EnvOptions& options) override {
1067 return target_->ReuseWritableFile(fname, old_fname, r, options);
1068 }
1069 Status NewRandomRWFile(const std::string& fname,
1070 std::unique_ptr<RandomRWFile>* result,
1071 const EnvOptions& options) override {
1072 return target_->NewRandomRWFile(fname, result, options);
1073 }
1074 Status NewMemoryMappedFileBuffer(
1075 const std::string& fname,
1076 std::unique_ptr<MemoryMappedFileBuffer>* result) override {
1077 return target_->NewMemoryMappedFileBuffer(fname, result);
1078 }
1079 Status NewDirectory(const std::string& name,
1080 std::unique_ptr<Directory>* result) override {
1081 return target_->NewDirectory(name, result);
1082 }
1083 Status FileExists(const std::string& f) override {
1084 return target_->FileExists(f);
1085 }
1086 Status GetChildren(const std::string& dir,
1087 std::vector<std::string>* r) override {
1088 return target_->GetChildren(dir, r);
1089 }
1090 Status GetChildrenFileAttributes(
1091 const std::string& dir, std::vector<FileAttributes>* result) override {
1092 return target_->GetChildrenFileAttributes(dir, result);
1093 }
1094 Status DeleteFile(const std::string& f) override {
1095 return target_->DeleteFile(f);
1096 }
1097 Status Truncate(const std::string& fname, size_t size) override {
1098 return target_->Truncate(fname, size);
1099 }
1100 Status CreateDir(const std::string& d) override {
1101 return target_->CreateDir(d);
1102 }
1103 Status CreateDirIfMissing(const std::string& d) override {
1104 return target_->CreateDirIfMissing(d);
1105 }
1106 Status DeleteDir(const std::string& d) override {
1107 return target_->DeleteDir(d);
1108 }
1109 Status GetFileSize(const std::string& f, uint64_t* s) override {
1110 return target_->GetFileSize(f, s);
1111 }
1112
1113 Status GetFileModificationTime(const std::string& fname,
1114 uint64_t* file_mtime) override {
1115 return target_->GetFileModificationTime(fname, file_mtime);
1116 }
1117
1118 Status RenameFile(const std::string& s, const std::string& t) override {
1119 return target_->RenameFile(s, t);
1120 }
1121
1122 Status LinkFile(const std::string& s, const std::string& t) override {
1123 return target_->LinkFile(s, t);
1124 }
1125
1126 Status NumFileLinks(const std::string& fname, uint64_t* count) override {
1127 return target_->NumFileLinks(fname, count);
1128 }
1129
1130 Status AreFilesSame(const std::string& first, const std::string& second,
1131 bool* res) override {
1132 return target_->AreFilesSame(first, second, res);
1133 }
1134
1135 Status LockFile(const std::string& f, FileLock** l) override {
1136 return target_->LockFile(f, l);
1137 }
1138
1139 Status UnlockFile(FileLock* l) override { return target_->UnlockFile(l); }
1140
1141 void Schedule(void (*f)(void* arg), void* a, Priority pri,
1142 void* tag = nullptr, void (*u)(void* arg) = nullptr) override {
1143 return target_->Schedule(f, a, pri, tag, u);
1144 }
1145
1146 int UnSchedule(void* tag, Priority pri) override {
1147 return target_->UnSchedule(tag, pri);
1148 }
1149
1150 void StartThread(void (*f)(void*), void* a) override {
1151 return target_->StartThread(f, a);
1152 }
1153 void WaitForJoin() override { return target_->WaitForJoin(); }
1154 unsigned int GetThreadPoolQueueLen(Priority pri = LOW) const override {
1155 return target_->GetThreadPoolQueueLen(pri);
1156 }
1157 Status GetTestDirectory(std::string* path) override {
1158 return target_->GetTestDirectory(path);
1159 }
1160 Status NewLogger(const std::string& fname,
1161 std::shared_ptr<Logger>* result) override {
1162 return target_->NewLogger(fname, result);
1163 }
1164 uint64_t NowMicros() override { return target_->NowMicros(); }
1165 uint64_t NowNanos() override { return target_->NowNanos(); }
1166 uint64_t NowCPUNanos() override { return target_->NowCPUNanos(); }
1167
1168 void SleepForMicroseconds(int micros) override {
1169 target_->SleepForMicroseconds(micros);
1170 }
1171 Status GetHostName(char* name, uint64_t len) override {
1172 return target_->GetHostName(name, len);
1173 }
1174 Status GetCurrentTime(int64_t* unix_time) override {
1175 return target_->GetCurrentTime(unix_time);
1176 }
1177 Status GetAbsolutePath(const std::string& db_path,
1178 std::string* output_path) override {
1179 return target_->GetAbsolutePath(db_path, output_path);
1180 }
1181 void SetBackgroundThreads(int num, Priority pri) override {
1182 return target_->SetBackgroundThreads(num, pri);
1183 }
1184 int GetBackgroundThreads(Priority pri) override {
1185 return target_->GetBackgroundThreads(pri);
1186 }
1187
1188 Status SetAllowNonOwnerAccess(bool allow_non_owner_access) override {
1189 return target_->SetAllowNonOwnerAccess(allow_non_owner_access);
1190 }
1191
1192 void IncBackgroundThreadsIfNeeded(int num, Priority pri) override {
1193 return target_->IncBackgroundThreadsIfNeeded(num, pri);
1194 }
1195
1196 void LowerThreadPoolIOPriority(Priority pool = LOW) override {
1197 target_->LowerThreadPoolIOPriority(pool);
1198 }
1199
1200 void LowerThreadPoolCPUPriority(Priority pool = LOW) override {
1201 target_->LowerThreadPoolCPUPriority(pool);
1202 }
1203
1204 std::string TimeToString(uint64_t time) override {
1205 return target_->TimeToString(time);
1206 }
1207
1208 Status GetThreadList(std::vector<ThreadStatus>* thread_list) override {
1209 return target_->GetThreadList(thread_list);
1210 }
1211
1212 ThreadStatusUpdater* GetThreadStatusUpdater() const override {
1213 return target_->GetThreadStatusUpdater();
1214 }
1215
1216 uint64_t GetThreadID() const override { return target_->GetThreadID(); }
1217
1218 std::string GenerateUniqueId() override {
1219 return target_->GenerateUniqueId();
1220 }
1221
1222 EnvOptions OptimizeForLogRead(const EnvOptions& env_options) const override {
1223 return target_->OptimizeForLogRead(env_options);
1224 }
1225 EnvOptions OptimizeForManifestRead(
1226 const EnvOptions& env_options) const override {
1227 return target_->OptimizeForManifestRead(env_options);
1228 }
1229 EnvOptions OptimizeForLogWrite(const EnvOptions& env_options,
1230 const DBOptions& db_options) const override {
1231 return target_->OptimizeForLogWrite(env_options, db_options);
1232 }
1233 EnvOptions OptimizeForManifestWrite(
1234 const EnvOptions& env_options) const override {
1235 return target_->OptimizeForManifestWrite(env_options);
1236 }
1237 EnvOptions OptimizeForCompactionTableWrite(
1238 const EnvOptions& env_options,
1239 const ImmutableDBOptions& immutable_ops) const override {
1240 return target_->OptimizeForCompactionTableWrite(env_options, immutable_ops);
1241 }
1242 EnvOptions OptimizeForCompactionTableRead(
1243 const EnvOptions& env_options,
1244 const ImmutableDBOptions& db_options) const override {
1245 return target_->OptimizeForCompactionTableRead(env_options, db_options);
1246 }
1247 Status GetFreeSpace(const std::string& path, uint64_t* diskfree) override {
1248 return target_->GetFreeSpace(path, diskfree);
1249 }
1250
1251 private:
1252 Env* target_;
1253};
1254
1255class SequentialFileWrapper : public SequentialFile {
1256 public:
1257 explicit SequentialFileWrapper(SequentialFile* target) : target_(target) {}
1258
1259 Status Read(size_t n, Slice* result, char* scratch) override {
1260 return target_->Read(n, result, scratch);
1261 }
1262 Status Skip(uint64_t n) override { return target_->Skip(n); }
1263 bool use_direct_io() const override { return target_->use_direct_io(); }
1264 size_t GetRequiredBufferAlignment() const override {
1265 return target_->GetRequiredBufferAlignment();
1266 }
1267 Status InvalidateCache(size_t offset, size_t length) override {
1268 return target_->InvalidateCache(offset, length);
1269 }
1270 Status PositionedRead(uint64_t offset, size_t n, Slice* result,
1271 char* scratch) override {
1272 return target_->PositionedRead(offset, n, result, scratch);
1273 }
1274
1275 private:
1276 SequentialFile* target_;
1277};
1278
1279class RandomAccessFileWrapper : public RandomAccessFile {
1280 public:
1281 explicit RandomAccessFileWrapper(RandomAccessFile* target)
1282 : target_(target) {}
1283
1284 Status Read(uint64_t offset, size_t n, Slice* result,
1285 char* scratch) const override {
1286 return target_->Read(offset, n, result, scratch);
1287 }
1288 Status Prefetch(uint64_t offset, size_t n) override {
1289 return target_->Prefetch(offset, n);
1290 }
1291 size_t GetUniqueId(char* id, size_t max_size) const override {
1292 return target_->GetUniqueId(id, max_size);
1293 };
1294 void Hint(AccessPattern pattern) override { target_->Hint(pattern); }
1295 bool use_direct_io() const override { return target_->use_direct_io(); }
1296 size_t GetRequiredBufferAlignment() const override {
1297 return target_->GetRequiredBufferAlignment();
1298 }
1299 Status InvalidateCache(size_t offset, size_t length) override {
1300 return target_->InvalidateCache(offset, length);
1301 }
1302
1303 private:
1304 RandomAccessFile* target_;
1305};
1306
1307class WritableFileWrapper : public WritableFile {
1308 public:
1309 explicit WritableFileWrapper(WritableFile* t) : target_(t) {}
1310
1311 Status Append(const Slice& data) override { return target_->Append(data); }
1312 Status PositionedAppend(const Slice& data, uint64_t offset) override {
1313 return target_->PositionedAppend(data, offset);
1314 }
1315 Status Truncate(uint64_t size) override { return target_->Truncate(size); }
1316 Status Close() override { return target_->Close(); }
1317 Status Flush() override { return target_->Flush(); }
1318 Status Sync() override { return target_->Sync(); }
1319 Status Fsync() override { return target_->Fsync(); }
1320 bool IsSyncThreadSafe() const override { return target_->IsSyncThreadSafe(); }
1321
1322 bool use_direct_io() const override { return target_->use_direct_io(); }
1323
1324 size_t GetRequiredBufferAlignment() const override {
1325 return target_->GetRequiredBufferAlignment();
1326 }
1327
1328 void SetIOPriority(Env::IOPriority pri) override {
1329 target_->SetIOPriority(pri);
1330 }
1331
1332 Env::IOPriority GetIOPriority() override { return target_->GetIOPriority(); }
1333
1334 void SetWriteLifeTimeHint(Env::WriteLifeTimeHint hint) override {
1335 target_->SetWriteLifeTimeHint(hint);
1336 }
1337
1338 Env::WriteLifeTimeHint GetWriteLifeTimeHint() override {
1339 return target_->GetWriteLifeTimeHint();
1340 }
1341
1342 uint64_t GetFileSize() override { return target_->GetFileSize(); }
1343
1344 void SetPreallocationBlockSize(size_t size) override {
1345 target_->SetPreallocationBlockSize(size);
1346 }
1347
1348 void GetPreallocationStatus(size_t* block_size,
1349 size_t* last_allocated_block) override {
1350 target_->GetPreallocationStatus(block_size, last_allocated_block);
1351 }
1352
1353 size_t GetUniqueId(char* id, size_t max_size) const override {
1354 return target_->GetUniqueId(id, max_size);
1355 }
1356
1357 Status InvalidateCache(size_t offset, size_t length) override {
1358 return target_->InvalidateCache(offset, length);
1359 }
1360
1361 Status RangeSync(uint64_t offset, uint64_t nbytes) override {
1362 return target_->RangeSync(offset, nbytes);
1363 }
1364
1365 void PrepareWrite(size_t offset, size_t len) override {
1366 target_->PrepareWrite(offset, len);
1367 }
1368
1369 Status Allocate(uint64_t offset, uint64_t len) override {
1370 return target_->Allocate(offset, len);
1371 }
1372
1373 private:
1374 WritableFile* target_;
1375};
1376
1377class RandomRWFileWrapper : public RandomRWFile {
1378 public:
1379 explicit RandomRWFileWrapper(RandomRWFile* target) : target_(target) {}
1380
1381 bool use_direct_io() const override { return target_->use_direct_io(); }
1382 size_t GetRequiredBufferAlignment() const override {
1383 return target_->GetRequiredBufferAlignment();
1384 }
1385 Status Write(uint64_t offset, const Slice& data) override {
1386 return target_->Write(offset, data);
1387 }
1388 Status Read(uint64_t offset, size_t n, Slice* result,
1389 char* scratch) const override {
1390 return target_->Read(offset, n, result, scratch);
1391 }
1392 Status Flush() override { return target_->Flush(); }
1393 Status Sync() override { return target_->Sync(); }
1394 Status Fsync() override { return target_->Fsync(); }
1395 Status Close() override { return target_->Close(); }
1396
1397 private:
1398 RandomRWFile* target_;
1399};
1400
1401class DirectoryWrapper : public Directory {
1402 public:
1403 explicit DirectoryWrapper(Directory* target) : target_(target) {}
1404
1405 Status Fsync() override { return target_->Fsync(); }
1406 size_t GetUniqueId(char* id, size_t max_size) const override {
1407 return target_->GetUniqueId(id, max_size);
1408 }
1409
1410 private:
1411 Directory* target_;
1412};
1413
1414class LoggerWrapper : public Logger {
1415 public:
1416 explicit LoggerWrapper(Logger* target) : target_(target) {}
1417
1418 Status Close() override { return target_->Close(); }
1419 void LogHeader(const char* format, va_list ap) override {
1420 return target_->LogHeader(format, ap);
1421 }
1422 void Logv(const char* format, va_list ap) override {
1423 return target_->Logv(format, ap);
1424 }
1425 void Logv(const InfoLogLevel log_level, const char* format,
1426 va_list ap) override {
1427 return target_->Logv(log_level, format, ap);
1428 }
1429 size_t GetLogFileSize() const override { return target_->GetLogFileSize(); }
1430 void Flush() override { return target_->Flush(); }
1431 InfoLogLevel GetInfoLogLevel() const override {
1432 return target_->GetInfoLogLevel();
1433 }
1434 void SetInfoLogLevel(const InfoLogLevel log_level) override {
1435 return target_->SetInfoLogLevel(log_level);
1436 }
1437
1438 private:
1439 Logger* target_;
1440};
1441
1442// Returns a new environment that stores its data in memory and delegates
1443// all non-file-storage tasks to base_env. The caller must delete the result
1444// when it is no longer needed.
1445// *base_env must remain live while the result is in use.
1446Env* NewMemEnv(Env* base_env);
1447
1448// Returns a new environment that is used for HDFS environment.
1449// This is a factory method for HdfsEnv declared in hdfs/env_hdfs.h
1450Status NewHdfsEnv(Env** hdfs_env, const std::string& fsname);
1451
1452// Returns a new environment that measures function call times for filesystem
1453// operations, reporting results to variables in PerfContext.
1454// This is a factory method for TimedEnv defined in utilities/env_timed.cc.
1455Env* NewTimedEnv(Env* base_env);
1456
1457} // namespace rocksdb