1 /*
2    Copyright (c) 2016, Facebook, Inc.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
16 #pragma once
17 
18 /* C++ standard header files */
19 #include <chrono>
20 #include <regex>
21 #include <string>
22 #include <vector>
23 #include <unordered_map>
24 
25 /* MySQL header files */
26 #include "log.h"
27 #include "my_stacktrace.h"
28 #include "sql_regex.h"
29 #include "sql_string.h"
30 
31 /* RocksDB header files */
32 #include "rocksdb/slice.h"
33 #include "rocksdb/status.h"
34 
35 /* MyRocks header files */
36 #include "./rdb_global.h"
37 
38 #ifdef HAVE_JEMALLOC
39 #include <jemalloc/jemalloc.h>
40 #endif
41 
42 namespace myrocks {
43 
44 /*
45   Guess what?
46   An interface is a class where all members are public by default.
47 */
48 
49 #ifndef interface
50 #define interface struct
51 #endif  // interface
52 
53 /*
54   Introduce C-style pseudo-namespaces, a handy way to make code more readble
55   when calling into a legacy API, which does not have any namespace defined.
56   Since we cannot or don't want to change the API in any way, we can use this
57   mechanism to define readability tokens that look like C++ namespaces, but are
58   not enforced in any way by the compiler, since the pre-compiler strips them
59   out. However, on the calling side, code looks like my_core::thd_ha_data()
60   rather than plain a thd_ha_data() call. This technique adds an immediate
61   visible cue on what type of API we are calling into.
62 */
63 
64 #ifndef my_core
65 // C-style pseudo-namespace for MySQL Core API, to be used in decorating calls
66 // to non-obvious MySQL functions, like the ones that do not start with well
67 // known prefixes: "my_", "sql_", and "mysql_".
68 #define my_core
69 #endif  // my_core
70 
71 /*
72   The intent behind a SHIP_ASSERT() macro is to have a mechanism for validating
73   invariants in retail builds. Traditionally assertions (such as macros defined
74   in <cassert>) are evaluated for performance reasons only in debug builds and
75   become NOOP in retail builds when NDEBUG is defined.
76 
77   This macro is intended to validate the invariants which are critical for
78   making sure that data corruption and data loss won't take place. Proper
79   intended usage can be described as "If a particular condition is not true then
80   stop everything what's going on and terminate the process because continued
81   execution will cause really bad things to happen".
82 
83   Use the power of SHIP_ASSERT() wisely.
84 */
85 #ifndef SHIP_ASSERT
86 #define SHIP_ASSERT(expr)                                              \
87   do {                                                                 \
88     if (!(expr)) {                                                     \
89       my_safe_printf_stderr("\nShip assert failure: \'%s\'\n", #expr); \
90       abort();                                                         \
91     }                                                                  \
92   } while (0)
93 #endif  // SHIP_ASSERT
94 
95 /*
96   Assert a implies b.
97   If a is true, then b must be true.
98   If a is false, then the value is b does not matter.
99 */
100 #ifndef assert_IMP
101 #define assert_IMP(a, b) assert(!(a) || (b))
102 #endif
103 
104 /*
105   Assert a if and only if b.
106   a and b must be both true or both false.
107 */
108 #ifndef assert_IFF
109 #define assert_IFF(a, b) \
110   assert(static_cast<bool>(a) == static_cast<bool>(b))
111 #endif
112 
113 /*
114   Intent behind this macro is to avoid manually typing the function name every
115   time we want to add the debugging statement and use the compiler for this
116   work. This avoids typical refactoring problems when one renames a function,
117   but the tracing message doesn't get updated.
118 
119   We could use __func__ or __FUNCTION__ macros, but __PRETTY_FUNCTION__
120   contains the signature of the function as well as its bare name and provides
121   therefore more context when interpreting the logs.
122 */
123 #define DBUG_ENTER_FUNC() DBUG_ENTER(__PRETTY_FUNCTION__)
124 
125 /*
126   Error handling pattern used across MySQL abides by the following rules: "All
127   functions that can report an error (usually an allocation error), should
128   return 0/FALSE/false on success, 1/TRUE/true on failure."
129 
130   https://dev.mysql.com/doc/internals/en/additional-suggestions.html has more
131   details.
132 
133   To increase the comprehension and readability of MyRocks codebase we'll use
134   constants similar to ones from C standard (EXIT_SUCCESS and EXIT_FAILURE) to
135   make sure that both failure and success paths are clearly identifiable. The
136   definitions of FALSE and TRUE come from <my_global.h>.
137 */
138 #define HA_EXIT_SUCCESS false
139 #define HA_EXIT_FAILURE true
140 
141 /*
142   Macros to better convey the intent behind checking the results from locking
143   and unlocking mutexes.
144 */
145 #define RDB_MUTEX_LOCK_CHECK(m) \
146   rdb_check_mutex_call_result(__PRETTY_FUNCTION__, true, mysql_mutex_lock(&m))
147 #define RDB_MUTEX_UNLOCK_CHECK(m)                         \
148   rdb_check_mutex_call_result(__PRETTY_FUNCTION__, false, \
149                               mysql_mutex_unlock(&m))
150 
151 /*
152   Generic constant.
153 */
154 const constexpr size_t RDB_MAX_HEXDUMP_LEN = 1000;
155 
156 /*
157   Helper function to get an NULL terminated uchar* out of a given MySQL String.
158 */
159 
rdb_mysql_str_to_uchar_str(my_core::String * str)160 inline uchar *rdb_mysql_str_to_uchar_str(my_core::String *str) {
161   assert(str != nullptr);
162   return reinterpret_cast<uchar *>(str->c_ptr());
163 }
164 
165 /*
166   Helper function to get plain (not necessary NULL terminated) uchar* out of a
167   given STL string.
168 */
169 
rdb_std_str_to_uchar_ptr(const std::string & str)170 inline const uchar *rdb_std_str_to_uchar_ptr(const std::string &str) {
171   return reinterpret_cast<const uchar *>(str.data());
172 }
173 
174 /*
175   Helper function to convert seconds to milliseconds.
176 */
177 
rdb_convert_sec_to_ms(int sec)178 constexpr int rdb_convert_sec_to_ms(int sec) {
179   return std::chrono::milliseconds(std::chrono::seconds(sec)).count();
180 }
181 
182 /*
183   Helper function to get plain (not necessary NULL terminated) uchar* out of a
184   given RocksDB item.
185 */
186 
rdb_slice_to_uchar_ptr(const rocksdb::Slice * item)187 inline const uchar *rdb_slice_to_uchar_ptr(const rocksdb::Slice *item) {
188   assert(item != nullptr);
189   return reinterpret_cast<const uchar *>(item->data());
190 }
191 
192 /*
193   Call this function in cases when you can't rely on garbage collector and need
194   to explicitly purge all unused dirty pages. This should be a relatively rare
195   scenario for cases where it has been verified that this intervention has
196   noticeable benefits.
197 */
purge_all_jemalloc_arenas()198 inline int purge_all_jemalloc_arenas() {
199 #ifdef HAVE_JEMALLOC
200   unsigned narenas = 0;
201   size_t sz = sizeof(unsigned);
202   char name[25] = {0};
203 
204   // Get the number of arenas first. Please see `jemalloc` documentation for
205   // all the various options.
206   int result = mallctl("arenas.narenas", &narenas, &sz, nullptr, 0);
207 
208   // `mallctl` returns 0 on success and we really want caller to know if all the
209   // trickery actually works.
210   if (result) {
211     return result;
212   }
213 
214   // Form the command to be passed to `mallctl` and purge all the unused dirty
215   // pages.
216   snprintf(name, sizeof(name) / sizeof(char), "arena.%d.purge", narenas);
217   result = mallctl(name, nullptr, nullptr, nullptr, 0);
218 
219   return result;
220 #else
221   return EXIT_SUCCESS;
222 #endif
223 }
224 
225 /*
226   Helper function to check the result of locking or unlocking a mutex. We'll
227   intentionally abort in case of a failure because it's better to terminate
228   the process instead of continuing in an undefined state and corrupting data
229   as a result.
230 */
rdb_check_mutex_call_result(const char * function_name,const bool attempt_lock,const int result)231 inline void rdb_check_mutex_call_result(const char *function_name,
232                                         const bool attempt_lock,
233                                         const int result) {
234   if (unlikely(result)) {
235     /* NO_LINT_DEBUG */
236     sql_print_error(
237         "%s a mutex inside %s failed with an "
238         "error code %d.",
239         attempt_lock ? "Locking" : "Unlocking", function_name, result);
240 
241     // This will hopefully result in a meaningful stack trace which we can use
242     // to efficiently debug the root cause.
243     abort();
244   }
245 }
246 
247 void rdb_log_status_error(const rocksdb::Status &s, const char *msg = nullptr);
248 
249 // return true if the marker file exists which indicates that the corruption
250 // has been detected
251 bool rdb_check_rocksdb_corruption();
252 
253 // stores a marker file in the data directory so that after restart server
254 // is still aware that rocksdb data is corrupted
255 void rdb_persist_corruption_marker();
256 
257 /*
258   Helper functions to parse strings.
259 */
260 
261 const char *rdb_skip_spaces(const struct charset_info_st *const cs,
262                             const char *str)
263     MY_ATTRIBUTE((__warn_unused_result__));
264 
265 bool rdb_compare_strings_ic(const char *const str1, const char *const str2)
266     MY_ATTRIBUTE((__warn_unused_result__));
267 
268 const char *rdb_find_in_string(const char *str, const char *pattern,
269                                bool *const succeeded)
270     MY_ATTRIBUTE((__warn_unused_result__));
271 
272 const char *rdb_check_next_token(const struct charset_info_st *const cs,
273                                  const char *str, const char *const pattern,
274                                  bool *const succeeded)
275     MY_ATTRIBUTE((__warn_unused_result__));
276 
277 const char *rdb_parse_id(const struct charset_info_st *const cs,
278                          const char *str, std::string *const id)
279     MY_ATTRIBUTE((__warn_unused_result__));
280 
281 const char *rdb_skip_id(const struct charset_info_st *const cs, const char *str)
282     MY_ATTRIBUTE((__warn_unused_result__));
283 
284 const std::vector<std::string> parse_into_tokens(const std::string &s,
285                                                  const char delim);
286 
287 /*
288   Helper functions to populate strings.
289 */
290 
291 std::string rdb_hexdump(const char *data, const std::size_t data_len,
292                         const std::size_t maxsize = 0);
293 
294 /*
295   Helper function to see if a database exists
296  */
297 bool rdb_database_exists(const std::string &db_name);
298 
299 void warn_about_bad_patterns(const Regex &regex, const char *name);
300 
301 std::vector<std::string> split_into_vector(const std::string &input,
302                                            char delimiter);
303 
304 /**
305   Helper class wrappers to meansure startup time
306   Warning: not thread safe. It is mainly designed to
307   be used during the server startup to collect stats
308   on startup function's exection time.
309 
310 Usage:
311   * member function: MyClass::func(args...)
312   *   Rdb_exec_time::record(
313   *     str, std::mem_fn(MyClass::func), &obj, args...);
314   * static function: static MyClass::fun(args...)
315   *   Rdb_exec_time::record(
316   *     str, &MyClass::func, args...);
317   *
318   * To report:
319   *   Rdb_exec_time::report();
320 */
321 class Rdb_exec_time {
322  private:
323   std::unordered_map<std::string, uint64_t> entries_;
324 
325   struct Auto_timer {
Auto_timerAuto_timer326     explicit Auto_timer(std::function<void(uint64_t &)> &&cb)
327         : start_(std::chrono::high_resolution_clock::now()), callback_(cb) {}
328 
~Auto_timerAuto_timer329     ~Auto_timer() {
330       auto end = std::chrono::high_resolution_clock::now();
331       uint64_t elapsed =
332           std::chrono::duration_cast<std::chrono::microseconds>(end - start_)
333               .count();
334 
335       callback_(elapsed);
336     }
337 
338     std::chrono::high_resolution_clock::time_point start_;
339     std::function<void(uint64_t &)> callback_;
340   };
341 
342  public:
343   /**
344    * Currently overloaded functions are not cleanly supported as
345    * template (static_cast on the designated function is required
346    * so that compiler can select the right overloaded version,
347    * but the syntax is ugly). Boost has a lift API (BOOST_HOF_LIFT)
348    * which solves this problem but it only supports c++14 and
349    * we're currently on c++11. Until then, this API requires
350    * static cast on overloaded functions passed in as template param.
351    */
352   template <class Fn, class... Args>
353   auto exec(const std::string &key, const Fn &&fn, Args &&... args)
354       -> decltype(fn(args...)) {
355     Auto_timer timer([&](uint64_t &e) { entries_.emplace(key, e); });
356     return fn(args...);
357   }
358 
report()359   void report() {
360     if (entries_.size() == 0) {
361       return;
362     }
363 
364     std::string result = "\n{\n";
365     for (auto const &t : entries_) {
366       result += "  \"" + t.first + "\" : ";
367       result += std::to_string(t.second) + "\n";
368     }
369     entries_.clear();
370 
371     result += "}";
372 
373     /* NO_LINT_DEBUG */
374     sql_print_information("MyRocks: rdb execution report (microsec): %s",
375                           result.c_str());
376   }
377 };
378 
379 /*
380   Helper class to make sure cleanup always happens. Helpful for complicated
381   logic where there can be multiple exits/returns requiring cleanup
382  */
383 class Ensure_cleanup {
384  public:
Ensure_cleanup(std::function<void ()> cleanup)385   explicit Ensure_cleanup(std::function<void()> cleanup)
386       : m_cleanup(cleanup), m_skip_cleanup(false) {}
387 
~Ensure_cleanup()388   ~Ensure_cleanup() {
389     if (!m_skip_cleanup) {
390       m_cleanup();
391     }
392   }
393 
394   // If you want to skip cleanup (such as when the operation is successful)
skip()395   void skip() { m_skip_cleanup = true; }
396 
397  private:
398   std::function<void()> m_cleanup;
399   bool m_skip_cleanup;
400 };
401 }  // namespace myrocks
402