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 "db/event_helpers.h"
7 
8 namespace ROCKSDB_NAMESPACE {
9 
10 namespace {
11 template <class T>
SafeDivide(T a,T b)12 inline T SafeDivide(T a, T b) {
13   return b == 0 ? 0 : a / b;
14 }
15 }  // namespace
16 
AppendCurrentTime(JSONWriter * jwriter)17 void EventHelpers::AppendCurrentTime(JSONWriter* jwriter) {
18   *jwriter << "time_micros"
19            << std::chrono::duration_cast<std::chrono::microseconds>(
20                   std::chrono::system_clock::now().time_since_epoch())
21                   .count();
22 }
23 
24 #ifndef ROCKSDB_LITE
NotifyTableFileCreationStarted(const std::vector<std::shared_ptr<EventListener>> & listeners,const std::string & db_name,const std::string & cf_name,const std::string & file_path,int job_id,TableFileCreationReason reason)25 void EventHelpers::NotifyTableFileCreationStarted(
26     const std::vector<std::shared_ptr<EventListener>>& listeners,
27     const std::string& db_name, const std::string& cf_name,
28     const std::string& file_path, int job_id, TableFileCreationReason reason) {
29   TableFileCreationBriefInfo info;
30   info.db_name = db_name;
31   info.cf_name = cf_name;
32   info.file_path = file_path;
33   info.job_id = job_id;
34   info.reason = reason;
35   for (auto& listener : listeners) {
36     listener->OnTableFileCreationStarted(info);
37   }
38 }
39 #endif  // !ROCKSDB_LITE
40 
NotifyOnBackgroundError(const std::vector<std::shared_ptr<EventListener>> & listeners,BackgroundErrorReason reason,Status * bg_error,InstrumentedMutex * db_mutex,bool * auto_recovery)41 void EventHelpers::NotifyOnBackgroundError(
42     const std::vector<std::shared_ptr<EventListener>>& listeners,
43     BackgroundErrorReason reason, Status* bg_error, InstrumentedMutex* db_mutex,
44     bool* auto_recovery) {
45 #ifndef ROCKSDB_LITE
46   if (listeners.size() == 0U) {
47     return;
48   }
49   db_mutex->AssertHeld();
50   // release lock while notifying events
51   db_mutex->Unlock();
52   for (auto& listener : listeners) {
53     listener->OnBackgroundError(reason, bg_error);
54     if (*auto_recovery) {
55       listener->OnErrorRecoveryBegin(reason, *bg_error, auto_recovery);
56     }
57   }
58   db_mutex->Lock();
59 #else
60   (void)listeners;
61   (void)reason;
62   (void)bg_error;
63   (void)db_mutex;
64   (void)auto_recovery;
65 #endif  // ROCKSDB_LITE
66 }
67 
LogAndNotifyTableFileCreationFinished(EventLogger * event_logger,const std::vector<std::shared_ptr<EventListener>> & listeners,const std::string & db_name,const std::string & cf_name,const std::string & file_path,int job_id,const FileDescriptor & fd,uint64_t oldest_blob_file_number,const TableProperties & table_properties,TableFileCreationReason reason,const Status & s)68 void EventHelpers::LogAndNotifyTableFileCreationFinished(
69     EventLogger* event_logger,
70     const std::vector<std::shared_ptr<EventListener>>& listeners,
71     const std::string& db_name, const std::string& cf_name,
72     const std::string& file_path, int job_id, const FileDescriptor& fd,
73     uint64_t oldest_blob_file_number, const TableProperties& table_properties,
74     TableFileCreationReason reason, const Status& s) {
75   if (s.ok() && event_logger) {
76     JSONWriter jwriter;
77     AppendCurrentTime(&jwriter);
78     jwriter << "cf_name" << cf_name << "job" << job_id << "event"
79             << "table_file_creation"
80             << "file_number" << fd.GetNumber() << "file_size"
81             << fd.GetFileSize();
82 
83     // table_properties
84     {
85       jwriter << "table_properties";
86       jwriter.StartObject();
87 
88       // basic properties:
89       jwriter << "data_size" << table_properties.data_size << "index_size"
90               << table_properties.index_size << "index_partitions"
91               << table_properties.index_partitions << "top_level_index_size"
92               << table_properties.top_level_index_size
93               << "index_key_is_user_key"
94               << table_properties.index_key_is_user_key
95               << "index_value_is_delta_encoded"
96               << table_properties.index_value_is_delta_encoded << "filter_size"
97               << table_properties.filter_size << "raw_key_size"
98               << table_properties.raw_key_size << "raw_average_key_size"
99               << SafeDivide(table_properties.raw_key_size,
100                             table_properties.num_entries)
101               << "raw_value_size" << table_properties.raw_value_size
102               << "raw_average_value_size"
103               << SafeDivide(table_properties.raw_value_size,
104                             table_properties.num_entries)
105               << "num_data_blocks" << table_properties.num_data_blocks
106               << "num_entries" << table_properties.num_entries
107               << "num_deletions" << table_properties.num_deletions
108               << "num_merge_operands" << table_properties.num_merge_operands
109               << "num_range_deletions" << table_properties.num_range_deletions
110               << "format_version" << table_properties.format_version
111               << "fixed_key_len" << table_properties.fixed_key_len
112               << "filter_policy" << table_properties.filter_policy_name
113               << "column_family_name" << table_properties.column_family_name
114               << "column_family_id" << table_properties.column_family_id
115               << "comparator" << table_properties.comparator_name
116               << "merge_operator" << table_properties.merge_operator_name
117               << "prefix_extractor_name"
118               << table_properties.prefix_extractor_name << "property_collectors"
119               << table_properties.property_collectors_names << "compression"
120               << table_properties.compression_name << "compression_options"
121               << table_properties.compression_options << "creation_time"
122               << table_properties.creation_time << "oldest_key_time"
123               << table_properties.oldest_key_time << "file_creation_time"
124               << table_properties.file_creation_time;
125 
126       // user collected properties
127       for (const auto& prop : table_properties.readable_properties) {
128         jwriter << prop.first << prop.second;
129       }
130       jwriter.EndObject();
131     }
132 
133     if (oldest_blob_file_number != kInvalidBlobFileNumber) {
134       jwriter << "oldest_blob_file_number" << oldest_blob_file_number;
135     }
136 
137     jwriter.EndObject();
138 
139     event_logger->Log(jwriter);
140   }
141 
142 #ifndef ROCKSDB_LITE
143   if (listeners.size() == 0) {
144     return;
145   }
146   TableFileCreationInfo info;
147   info.db_name = db_name;
148   info.cf_name = cf_name;
149   info.file_path = file_path;
150   info.file_size = fd.file_size;
151   info.job_id = job_id;
152   info.table_properties = table_properties;
153   info.reason = reason;
154   info.status = s;
155   for (auto& listener : listeners) {
156     listener->OnTableFileCreated(info);
157   }
158 #else
159   (void)listeners;
160   (void)db_name;
161   (void)cf_name;
162   (void)file_path;
163   (void)reason;
164 #endif  // !ROCKSDB_LITE
165 }
166 
LogAndNotifyTableFileDeletion(EventLogger * event_logger,int job_id,uint64_t file_number,const std::string & file_path,const Status & status,const std::string & dbname,const std::vector<std::shared_ptr<EventListener>> & listeners)167 void EventHelpers::LogAndNotifyTableFileDeletion(
168     EventLogger* event_logger, int job_id, uint64_t file_number,
169     const std::string& file_path, const Status& status,
170     const std::string& dbname,
171     const std::vector<std::shared_ptr<EventListener>>& listeners) {
172   JSONWriter jwriter;
173   AppendCurrentTime(&jwriter);
174 
175   jwriter << "job" << job_id << "event"
176           << "table_file_deletion"
177           << "file_number" << file_number;
178   if (!status.ok()) {
179     jwriter << "status" << status.ToString();
180   }
181 
182   jwriter.EndObject();
183 
184   event_logger->Log(jwriter);
185 
186 #ifndef ROCKSDB_LITE
187   TableFileDeletionInfo info;
188   info.db_name = dbname;
189   info.job_id = job_id;
190   info.file_path = file_path;
191   info.status = status;
192   for (auto& listener : listeners) {
193     listener->OnTableFileDeleted(info);
194   }
195 #else
196   (void)file_path;
197   (void)dbname;
198   (void)listeners;
199 #endif  // !ROCKSDB_LITE
200 }
201 
NotifyOnErrorRecoveryCompleted(const std::vector<std::shared_ptr<EventListener>> & listeners,Status old_bg_error,InstrumentedMutex * db_mutex)202 void EventHelpers::NotifyOnErrorRecoveryCompleted(
203     const std::vector<std::shared_ptr<EventListener>>& listeners,
204     Status old_bg_error, InstrumentedMutex* db_mutex) {
205 #ifndef ROCKSDB_LITE
206   if (listeners.size() == 0U) {
207     return;
208   }
209   db_mutex->AssertHeld();
210   // release lock while notifying events
211   db_mutex->Unlock();
212   for (auto& listener : listeners) {
213     listener->OnErrorRecoveryCompleted(old_bg_error);
214   }
215   db_mutex->Lock();
216 #else
217   (void)listeners;
218   (void)old_bg_error;
219   (void)db_mutex;
220 #endif  // ROCKSDB_LITE
221 }
222 
223 }  // namespace ROCKSDB_NAMESPACE
224