// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). #ifdef GFLAGS #pragma once #include "rocksdb/listener.h" #include "util/gflags_compat.h" DECLARE_int32(compact_files_one_in); namespace rocksdb { class DbStressListener : public EventListener { public: DbStressListener(const std::string& db_name, const std::vector& db_paths, const std::vector& column_families) : db_name_(db_name), db_paths_(db_paths), column_families_(column_families), num_pending_file_creations_(0) {} virtual ~DbStressListener() { assert(num_pending_file_creations_ == 0); } #ifndef ROCKSDB_LITE virtual void OnFlushCompleted(DB* /*db*/, const FlushJobInfo& info) override { assert(IsValidColumnFamilyName(info.cf_name)); VerifyFilePath(info.file_path); // pretending doing some work here std::this_thread::sleep_for( std::chrono::microseconds(Random::GetTLSInstance()->Uniform(5000))); } virtual void OnCompactionCompleted(DB* /*db*/, const CompactionJobInfo& ci) override { assert(IsValidColumnFamilyName(ci.cf_name)); assert(ci.input_files.size() + ci.output_files.size() > 0U); for (const auto& file_path : ci.input_files) { VerifyFilePath(file_path); } for (const auto& file_path : ci.output_files) { VerifyFilePath(file_path); } // pretending doing some work here std::this_thread::sleep_for( std::chrono::microseconds(Random::GetTLSInstance()->Uniform(5000))); } virtual void OnTableFileCreationStarted( const TableFileCreationBriefInfo& /*info*/) override { ++num_pending_file_creations_; } virtual void OnTableFileCreated(const TableFileCreationInfo& info) override { assert(info.db_name == db_name_); assert(IsValidColumnFamilyName(info.cf_name)); if (info.file_size) { VerifyFilePath(info.file_path); } assert(info.job_id > 0 || FLAGS_compact_files_one_in > 0); if (info.status.ok() && info.file_size > 0) { assert(info.table_properties.data_size > 0 || info.table_properties.num_range_deletions > 0); assert(info.table_properties.raw_key_size > 0); assert(info.table_properties.num_entries > 0); } --num_pending_file_creations_; } protected: bool IsValidColumnFamilyName(const std::string& cf_name) const { if (cf_name == kDefaultColumnFamilyName) { return true; } // The column family names in the stress tests are numbers. for (size_t i = 0; i < cf_name.size(); ++i) { if (cf_name[i] < '0' || cf_name[i] > '9') { return false; } } return true; } void VerifyFileDir(const std::string& file_dir) { #ifndef NDEBUG if (db_name_ == file_dir) { return; } for (const auto& db_path : db_paths_) { if (db_path.path == file_dir) { return; } } for (auto& cf : column_families_) { for (const auto& cf_path : cf.options.cf_paths) { if (cf_path.path == file_dir) { return; } } } assert(false); #else (void)file_dir; #endif // !NDEBUG } void VerifyFileName(const std::string& file_name) { #ifndef NDEBUG uint64_t file_number; FileType file_type; bool result = ParseFileName(file_name, &file_number, &file_type); assert(result); assert(file_type == kTableFile); #else (void)file_name; #endif // !NDEBUG } void VerifyFilePath(const std::string& file_path) { #ifndef NDEBUG size_t pos = file_path.find_last_of("/"); if (pos == std::string::npos) { VerifyFileName(file_path); } else { if (pos > 0) { VerifyFileDir(file_path.substr(0, pos)); } VerifyFileName(file_path.substr(pos)); } #else (void)file_path; #endif // !NDEBUG } #endif // !ROCKSDB_LITE private: std::string db_name_; std::vector db_paths_; std::vector column_families_; std::atomic num_pending_file_creations_; }; } // namespace rocksdb #endif // GFLAGS