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 #ifdef GFLAGS 7 #pragma once 8 9 #include "rocksdb/listener.h" 10 #include "util/gflags_compat.h" 11 12 DECLARE_int32(compact_files_one_in); 13 14 namespace ROCKSDB_NAMESPACE { 15 class DbStressListener : public EventListener { 16 public: DbStressListener(const std::string & db_name,const std::vector<DbPath> & db_paths,const std::vector<ColumnFamilyDescriptor> & column_families)17 DbStressListener(const std::string& db_name, 18 const std::vector<DbPath>& db_paths, 19 const std::vector<ColumnFamilyDescriptor>& column_families) 20 : db_name_(db_name), 21 db_paths_(db_paths), 22 column_families_(column_families), 23 num_pending_file_creations_(0) {} 24 #ifndef ROCKSDB_LITE ~DbStressListener()25 ~DbStressListener() override { assert(num_pending_file_creations_ == 0); } OnFlushCompleted(DB *,const FlushJobInfo & info)26 void OnFlushCompleted(DB* /*db*/, const FlushJobInfo& info) override { 27 assert(IsValidColumnFamilyName(info.cf_name)); 28 VerifyFilePath(info.file_path); 29 // pretending doing some work here 30 RandomSleep(); 31 } 32 OnFlushBegin(DB *,const FlushJobInfo &)33 void OnFlushBegin(DB* /*db*/, 34 const FlushJobInfo& /*flush_job_info*/) override { 35 RandomSleep(); 36 } 37 OnTableFileDeleted(const TableFileDeletionInfo &)38 void OnTableFileDeleted(const TableFileDeletionInfo& /*info*/) override { 39 RandomSleep(); 40 } 41 OnCompactionBegin(DB *,const CompactionJobInfo &)42 void OnCompactionBegin(DB* /*db*/, const CompactionJobInfo& /*ci*/) override { 43 RandomSleep(); 44 } 45 OnCompactionCompleted(DB *,const CompactionJobInfo & ci)46 void OnCompactionCompleted(DB* /*db*/, const CompactionJobInfo& ci) override { 47 assert(IsValidColumnFamilyName(ci.cf_name)); 48 assert(ci.input_files.size() + ci.output_files.size() > 0U); 49 for (const auto& file_path : ci.input_files) { 50 VerifyFilePath(file_path); 51 } 52 for (const auto& file_path : ci.output_files) { 53 VerifyFilePath(file_path); 54 } 55 // pretending doing some work here 56 RandomSleep(); 57 } 58 OnTableFileCreationStarted(const TableFileCreationBriefInfo &)59 void OnTableFileCreationStarted( 60 const TableFileCreationBriefInfo& /*info*/) override { 61 ++num_pending_file_creations_; 62 } 63 OnTableFileCreated(const TableFileCreationInfo & info)64 void OnTableFileCreated(const TableFileCreationInfo& info) override { 65 assert(info.db_name == db_name_); 66 assert(IsValidColumnFamilyName(info.cf_name)); 67 if (info.file_size) { 68 VerifyFilePath(info.file_path); 69 } 70 assert(info.job_id > 0 || FLAGS_compact_files_one_in > 0); 71 if (info.status.ok() && info.file_size > 0) { 72 assert(info.table_properties.data_size > 0 || 73 info.table_properties.num_range_deletions > 0); 74 assert(info.table_properties.raw_key_size > 0); 75 assert(info.table_properties.num_entries > 0); 76 } 77 --num_pending_file_creations_; 78 } 79 OnMemTableSealed(const MemTableInfo &)80 void OnMemTableSealed(const MemTableInfo& /*info*/) override { 81 RandomSleep(); 82 } 83 OnColumnFamilyHandleDeletionStarted(ColumnFamilyHandle *)84 void OnColumnFamilyHandleDeletionStarted( 85 ColumnFamilyHandle* /*handle*/) override { 86 RandomSleep(); 87 } 88 OnExternalFileIngested(DB *,const ExternalFileIngestionInfo &)89 void OnExternalFileIngested( 90 DB* /*db*/, const ExternalFileIngestionInfo& /*info*/) override { 91 RandomSleep(); 92 } 93 OnBackgroundError(BackgroundErrorReason,Status *)94 void OnBackgroundError(BackgroundErrorReason /* reason */, 95 Status* /* bg_error */) override { 96 RandomSleep(); 97 } 98 OnStallConditionsChanged(const WriteStallInfo &)99 void OnStallConditionsChanged(const WriteStallInfo& /*info*/) override { 100 RandomSleep(); 101 } 102 OnFileReadFinish(const FileOperationInfo & info)103 void OnFileReadFinish(const FileOperationInfo& info) override { 104 // Even empty callback is valuable because sometimes some locks are 105 // released in order to make the callback. 106 107 // Sleep carefully here as it is a frequent operation and we don't want 108 // to slow down the tests. We always sleep when the read is large. 109 // When read is small, sleep in a small chance. 110 size_t length_read = info.length; 111 if (length_read >= 1000000 || Random::GetTLSInstance()->OneIn(1000)) { 112 RandomSleep(); 113 } 114 } 115 OnFileWriteFinish(const FileOperationInfo & info)116 void OnFileWriteFinish(const FileOperationInfo& info) override { 117 // Even empty callback is valuable because sometimes some locks are 118 // released in order to make the callback. 119 120 // Sleep carefully here as it is a frequent operation and we don't want 121 // to slow down the tests. When the write is large, always sleep. 122 // Otherwise, sleep in a relatively small chance. 123 size_t length_write = info.length; 124 if (length_write >= 1000000 || Random::GetTLSInstance()->OneIn(64)) { 125 RandomSleep(); 126 } 127 } 128 ShouldBeNotifiedOnFileIO()129 bool ShouldBeNotifiedOnFileIO() override { 130 RandomSleep(); 131 return static_cast<bool>(Random::GetTLSInstance()->OneIn(1)); 132 } 133 OnErrorRecoveryBegin(BackgroundErrorReason,Status,bool *)134 void OnErrorRecoveryBegin(BackgroundErrorReason /* reason */, 135 Status /* bg_error */, 136 bool* /* auto_recovery */) override { 137 RandomSleep(); 138 } 139 OnErrorRecoveryCompleted(Status)140 void OnErrorRecoveryCompleted(Status /* old_bg_error */) override { 141 RandomSleep(); 142 } 143 144 protected: IsValidColumnFamilyName(const std::string & cf_name)145 bool IsValidColumnFamilyName(const std::string& cf_name) const { 146 if (cf_name == kDefaultColumnFamilyName) { 147 return true; 148 } 149 // The column family names in the stress tests are numbers. 150 for (size_t i = 0; i < cf_name.size(); ++i) { 151 if (cf_name[i] < '0' || cf_name[i] > '9') { 152 return false; 153 } 154 } 155 return true; 156 } 157 VerifyFileDir(const std::string & file_dir)158 void VerifyFileDir(const std::string& file_dir) { 159 #ifndef NDEBUG 160 if (db_name_ == file_dir) { 161 return; 162 } 163 for (const auto& db_path : db_paths_) { 164 if (db_path.path == file_dir) { 165 return; 166 } 167 } 168 for (auto& cf : column_families_) { 169 for (const auto& cf_path : cf.options.cf_paths) { 170 if (cf_path.path == file_dir) { 171 return; 172 } 173 } 174 } 175 assert(false); 176 #else 177 (void)file_dir; 178 #endif // !NDEBUG 179 } 180 VerifyFileName(const std::string & file_name)181 void VerifyFileName(const std::string& file_name) { 182 #ifndef NDEBUG 183 uint64_t file_number; 184 FileType file_type; 185 bool result = ParseFileName(file_name, &file_number, &file_type); 186 assert(result); 187 assert(file_type == kTableFile); 188 #else 189 (void)file_name; 190 #endif // !NDEBUG 191 } 192 VerifyFilePath(const std::string & file_path)193 void VerifyFilePath(const std::string& file_path) { 194 #ifndef NDEBUG 195 size_t pos = file_path.find_last_of("/"); 196 if (pos == std::string::npos) { 197 VerifyFileName(file_path); 198 } else { 199 if (pos > 0) { 200 VerifyFileDir(file_path.substr(0, pos)); 201 } 202 VerifyFileName(file_path.substr(pos)); 203 } 204 #else 205 (void)file_path; 206 #endif // !NDEBUG 207 } 208 RandomSleep()209 void RandomSleep() { 210 std::this_thread::sleep_for( 211 std::chrono::microseconds(Random::GetTLSInstance()->Uniform(5000))); 212 } 213 #endif // !ROCKSDB_LITE 214 215 private: 216 std::string db_name_; 217 std::vector<DbPath> db_paths_; 218 std::vector<ColumnFamilyDescriptor> column_families_; 219 std::atomic<int> num_pending_file_creations_; 220 }; 221 } // namespace ROCKSDB_NAMESPACE 222 #endif // GFLAGS 223