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