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 #pragma once 7 8 #ifndef ROCKSDB_LITE 9 10 #include <map> 11 #include <queue> 12 #include <string> 13 #include <thread> 14 15 #include "monitoring/instrumented_mutex.h" 16 #include "port/port.h" 17 18 #include "rocksdb/status.h" 19 20 namespace ROCKSDB_NAMESPACE { 21 22 class Env; 23 class FileSystem; 24 class Logger; 25 class SstFileManagerImpl; 26 class SystemClock; 27 28 // DeleteScheduler allows the DB to enforce a rate limit on file deletion, 29 // Instead of deleteing files immediately, files are marked as trash 30 // and deleted in a background thread that apply sleep penalty between deletes 31 // if they are happening in a rate faster than rate_bytes_per_sec, 32 // 33 // Rate limiting can be turned off by setting rate_bytes_per_sec = 0, In this 34 // case DeleteScheduler will delete files immediately. 35 class DeleteScheduler { 36 public: 37 DeleteScheduler(SystemClock* clock, FileSystem* fs, 38 int64_t rate_bytes_per_sec, Logger* info_log, 39 SstFileManagerImpl* sst_file_manager, 40 double max_trash_db_ratio, uint64_t bytes_max_delete_chunk); 41 42 ~DeleteScheduler(); 43 44 // Return delete rate limit in bytes per second GetRateBytesPerSecond()45 int64_t GetRateBytesPerSecond() { return rate_bytes_per_sec_.load(); } 46 47 // Set delete rate limit in bytes per second SetRateBytesPerSecond(int64_t bytes_per_sec)48 void SetRateBytesPerSecond(int64_t bytes_per_sec) { 49 rate_bytes_per_sec_.store(bytes_per_sec); 50 MaybeCreateBackgroundThread(); 51 } 52 53 // Mark file as trash directory and schedule its deletion. If force_bg is 54 // set, it forces the file to always be deleted in the background thread, 55 // except when rate limiting is disabled 56 Status DeleteFile(const std::string& fname, const std::string& dir_to_sync, 57 const bool force_bg = false); 58 59 // Wait for all files being deleteing in the background to finish or for 60 // destructor to be called. 61 void WaitForEmptyTrash(); 62 63 // Return a map containing errors that happened in BackgroundEmptyTrash 64 // file_path => error status 65 std::map<std::string, Status> GetBackgroundErrors(); 66 GetTotalTrashSize()67 uint64_t GetTotalTrashSize() { return total_trash_size_.load(); } 68 69 // Return trash/DB size ratio where new files will be deleted immediately GetMaxTrashDBRatio()70 double GetMaxTrashDBRatio() { 71 return max_trash_db_ratio_.load(); 72 } 73 74 // Update trash/DB size ratio where new files will be deleted immediately SetMaxTrashDBRatio(double r)75 void SetMaxTrashDBRatio(double r) { 76 assert(r >= 0); 77 max_trash_db_ratio_.store(r); 78 } 79 80 static const std::string kTrashExtension; 81 static bool IsTrashFile(const std::string& file_path); 82 83 // Check if there are any .trash files in path, and schedule their deletion 84 // Or delete immediately if sst_file_manager is nullptr 85 static Status CleanupDirectory(Env* env, SstFileManagerImpl* sfm, 86 const std::string& path); 87 SetStatisticsPtr(const std::shared_ptr<Statistics> & stats)88 void SetStatisticsPtr(const std::shared_ptr<Statistics>& stats) { 89 InstrumentedMutexLock l(&mu_); 90 stats_ = stats; 91 } 92 93 private: 94 Status MarkAsTrash(const std::string& file_path, std::string* path_in_trash); 95 96 Status DeleteTrashFile(const std::string& path_in_trash, 97 const std::string& dir_to_sync, 98 uint64_t* deleted_bytes, bool* is_complete); 99 100 void BackgroundEmptyTrash(); 101 102 void MaybeCreateBackgroundThread(); 103 104 SystemClock* clock_; 105 FileSystem* fs_; 106 107 // total size of trash files 108 std::atomic<uint64_t> total_trash_size_; 109 // Maximum number of bytes that should be deleted per second 110 std::atomic<int64_t> rate_bytes_per_sec_; 111 // Mutex to protect queue_, pending_files_, bg_errors_, closing_, stats_ 112 InstrumentedMutex mu_; 113 114 struct FileAndDir { FileAndDirFileAndDir115 FileAndDir(const std::string& f, const std::string& d) : fname(f), dir(d) {} 116 std::string fname; 117 std::string dir; // empty will be skipped. 118 }; 119 120 // Queue of trash files that need to be deleted 121 std::queue<FileAndDir> queue_; 122 // Number of trash files that are waiting to be deleted 123 int32_t pending_files_; 124 uint64_t bytes_max_delete_chunk_; 125 // Errors that happened in BackgroundEmptyTrash (file_path => error) 126 std::map<std::string, Status> bg_errors_; 127 128 bool num_link_error_printed_ = false; 129 // Set to true in ~DeleteScheduler() to force BackgroundEmptyTrash to stop 130 bool closing_; 131 // Condition variable signaled in these conditions 132 // - pending_files_ value change from 0 => 1 133 // - pending_files_ value change from 1 => 0 134 // - closing_ value is set to true 135 InstrumentedCondVar cv_; 136 // Background thread running BackgroundEmptyTrash 137 std::unique_ptr<port::Thread> bg_thread_; 138 // Mutex to protect threads from file name conflicts 139 InstrumentedMutex file_move_mu_; 140 Logger* info_log_; 141 SstFileManagerImpl* sst_file_manager_; 142 // If the trash size constitutes for more than this fraction of the total DB 143 // size we will start deleting new files passed to DeleteScheduler 144 // immediately 145 std::atomic<double> max_trash_db_ratio_; 146 static const uint64_t kMicrosInSecond = 1000 * 1000LL; 147 std::shared_ptr<Statistics> stats_; 148 }; 149 150 } // namespace ROCKSDB_NAMESPACE 151 152 #endif // ROCKSDB_LITE 153