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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
16 #pragma once
17 
18 #include "rdb_mariadb_port.h"
19 
20 /* C++ standard header files */
21 #include <chrono>
22 #include <string>
23 #include <vector>
24 #include <functional>
25 
26 /* MySQL header files */
27 #include "../sql/log.h"
28 #include "./my_stacktrace.h"
load_duh(const char * filename)29 #include "./sql_string.h"
30 
31 /* RocksDB header files */
32 #include "rocksdb/slice.h"
33 #include "rocksdb/status.h"
34 
35 #ifdef HAVE_JEMALLOC
36 #include <jemalloc/jemalloc.h>
37 #endif
38 
39 namespace myrocks {
40 
41 /*
42   Guess what?
43   An interface is a class where all members are public by default.
44 */
45 
46 #ifndef interface
47 #define interface struct
48 #endif  // interface
49 
50 /*
51   Introduce C-style pseudo-namespaces, a handy way to make code more readble
52   when calling into a legacy API, which does not have any namespace defined.
53   Since we cannot or don't want to change the API in any way, we can use this
54   mechanism to define readability tokens that look like C++ namespaces, but are
55   not enforced in any way by the compiler, since the pre-compiler strips them
56   out. However, on the calling side, code looks like my_core::thd_get_ha_data()
57   rather than plain a thd_get_ha_data() call. This technique adds an immediate
58   visible cue on what type of API we are calling into.
59 */
60 
61 #ifndef my_core
62 // C-style pseudo-namespace for MySQL Core API, to be used in decorating calls
63 // to non-obvious MySQL functions, like the ones that do not start with well
64 // known prefixes: "my_", "sql_", and "mysql_".
65 #define my_core
66 #endif  // my_core
67 
68 /*
69   The intent behind a SHIP_ASSERT() macro is to have a mechanism for validating
70   invariants in retail builds. Traditionally assertions (such as macros defined
71   in <cassert>) are evaluated for performance reasons only in debug builds and
72   become NOOP in retail builds when DBUG_OFF is defined.
73 
74   This macro is intended to validate the invariants which are critical for
75   making sure that data corruption and data loss won't take place. Proper
76   intended usage can be described as "If a particular condition is not true then
77   stop everything what's going on and terminate the process because continued
78   execution will cause really bad things to happen".
79 
80   Use the power of SHIP_ASSERT() wisely.
81 */
82 
83 #ifndef SHIP_ASSERT
84 #define SHIP_ASSERT(expr)                                              \
85   do {                                                                 \
86     if (!(expr)) {                                                     \
87       my_safe_printf_stderr("\nShip assert failure: \'%s\'\n", #expr); \
88       abort();                                                         \
89     }                                                                  \
90   } while (0)
91 #endif  // SHIP_ASSERT
92 
93 /*
94   Assert a implies b.
95   If a is true, then b must be true.
96   If a is false, then the value is b does not matter.
97 */
98 #ifndef DBUG_ASSERT_IMP
99 #define DBUG_ASSERT_IMP(a, b) DBUG_ASSERT(!(a) || (b))
100 #endif
101 
102 /*
103   Assert a if and only if b.
104   a and b must be both true or both false.
105 */
106 #ifndef DBUG_ASSERT_IFF
107 #define DBUG_ASSERT_IFF(a, b) \
108   DBUG_ASSERT(static_cast<bool>(a) == static_cast<bool>(b))
109 #endif
110 
111 
112 /*
113   Portability: use __PRETTY_FUNCTION__ when available, otherwise use __func__
114   which is in the standard.
115 */
116 
117 #ifdef __GNUC__
118 #  define __MYROCKS_PORTABLE_PRETTY_FUNCTION__  __PRETTY_FUNCTION__
119 #else
120 #  define __MYROCKS_PORTABLE_PRETTY_FUNCTION__  __func__
121 #endif
122 
123 /*
124   Intent behind this macro is to avoid manually typing the function name every
125   time we want to add the debugging statement and use the compiler for this
126   work. This avoids typical refactoring problems when one renames a function,
127   but the tracing message doesn't get updated.
128 
129   We could use __func__ or __FUNCTION__ macros, but __PRETTY_FUNCTION__
130   contains the signature of the function as well as its bare name and provides
131   therefore more context when interpreting the logs.
132 */
133 #define DBUG_ENTER_FUNC() DBUG_ENTER(__MYROCKS_PORTABLE_PRETTY_FUNCTION__)
134 
135 /*
136   Error handling pattern used across MySQL abides by the following rules: "All
137   functions that can report an error (usually an allocation error), should
138   return 0/FALSE/false on success, 1/TRUE/true on failure."
139 
140   https://dev.mysql.com/doc/internals/en/additional-suggestions.html has more
141   details.
142 
143   To increase the comprehension and readability of MyRocks codebase we'll use
144   constants similar to ones from C standard (EXIT_SUCCESS and EXIT_FAILURE) to
145   make sure that both failure and success paths are clearly identifiable. The
146   definitions of FALSE and TRUE come from <my_global.h>.
147 */
148 #define HA_EXIT_SUCCESS FALSE
149 #define HA_EXIT_FAILURE TRUE
150 
151 /*
152   Macros to better convey the intent behind checking the results from locking
153   and unlocking mutexes.
154 */
155 #define RDB_MUTEX_LOCK_CHECK(m) \
156   rdb_check_mutex_call_result(__MYROCKS_PORTABLE_PRETTY_FUNCTION__, true,      \
157                               mysql_mutex_lock(&m))
158 #define RDB_MUTEX_UNLOCK_CHECK(m)                         \
159   rdb_check_mutex_call_result(__MYROCKS_PORTABLE_PRETTY_FUNCTION__, false,     \
160                               mysql_mutex_unlock(&m))
161 
162 /*
163   Generic constant.
164 */
165 const size_t RDB_MAX_HEXDUMP_LEN = 1000;
166 
167 /*
168   Helper function to get an NULL terminated uchar* out of a given MySQL String.
169 */
170 
171 inline uchar *rdb_mysql_str_to_uchar_str(my_core::String *str) {
172   DBUG_ASSERT(str != nullptr);
173   return reinterpret_cast<uchar *>(str->c_ptr());
174 }
175 
176 /*
177   Helper function to get plain (not necessary NULL terminated) uchar* out of a
178   given STL string.
179 */
180 
181 inline const uchar *rdb_std_str_to_uchar_ptr(const std::string &str) {
182   return reinterpret_cast<const uchar *>(str.data());
183 }
184 
185 /*
186   Helper function to convert seconds to milliseconds.
187 */
188 
189 constexpr int rdb_convert_sec_to_ms(int sec) {
190   return std::chrono::milliseconds(std::chrono::seconds(sec)).count();
191 }
192 
193 /*
194   Helper function to get plain (not necessary NULL terminated) uchar* out of a
195   given RocksDB item.
196 */
197 
198 inline const uchar *rdb_slice_to_uchar_ptr(const rocksdb::Slice *item) {
199   DBUG_ASSERT(item != nullptr);
200   return reinterpret_cast<const uchar *>(item->data());
201 }
202 
203 /*
204   Call this function in cases when you can't rely on garbage collector and need
205   to explicitly purge all unused dirty pages. This should be a relatively rare
206   scenario for cases where it has been verified that this intervention has
207   noticeable benefits.
208 */
209 inline int purge_all_jemalloc_arenas() {
210 #ifdef HAVE_JEMALLOC
211   unsigned narenas = 0;
212   size_t sz = sizeof(unsigned);
213   char name[25] = {0};
214 
215   // Get the number of arenas first. Please see `jemalloc` documentation for
216   // all the various options.
217   int result = mallctl("arenas.narenas", &narenas, &sz, nullptr, 0);
218 
219   // `mallctl` returns 0 on success and we really want caller to know if all the
220   // trickery actually works.
221   if (result) {
222     return result;
223   }
224 
225   // Form the command to be passed to `mallctl` and purge all the unused dirty
226   // pages.
227   snprintf(name, sizeof(name) / sizeof(char), "arena.%d.purge", narenas);
228   result = mallctl(name, nullptr, nullptr, nullptr, 0);
229 
230   return result;
231 #else
232   return EXIT_SUCCESS;
233 #endif
234 }
235 
236 /*
237   Helper function to check the result of locking or unlocking a mutex. We'll
238   intentionally abort in case of a failure because it's better to terminate
239   the process instead of continuing in an undefined state and corrupting data
240   as a result.
241 */
242 inline void rdb_check_mutex_call_result(const char *function_name,
243                                         const bool attempt_lock,
244                                         const int result) {
245   if (unlikely(result)) {
246     /* NO_LINT_DEBUG */
247     sql_print_error(
248         "%s a mutex inside %s failed with an "
249         "error code %d.",
250         attempt_lock ? "Locking" : "Unlocking", function_name, result);
251 
252     // This will hopefully result in a meaningful stack trace which we can use
253     // to efficiently debug the root cause.
254     abort();
255   }
256 }
257 
258 void rdb_log_status_error(const rocksdb::Status &s, const char *msg = nullptr);
259 
260 // return true if the marker file exists which indicates that the corruption
261 // has been detected
262 bool rdb_check_rocksdb_corruption();
263 
264 // stores a marker file in the data directory so that after restart server
265 // is still aware that rocksdb data is corrupted
266 void rdb_persist_corruption_marker();
267 
268 /*
269   Helper functions to parse strings.
270 */
271 
272 const char *rdb_skip_spaces(const struct charset_info_st *const cs,
273                             const char *str)
274     MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
275 
276 bool rdb_compare_strings_ic(const char *const str1, const char *const str2)
277     MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
278 
279 const char *rdb_find_in_string(const char *str, const char *pattern,
280                                bool *const succeeded)
281     MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
282 
283 const char *rdb_check_next_token(const struct charset_info_st *const cs,
284                                  const char *str, const char *const pattern,
285                                  bool *const succeeded)
286     MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
287 
288 const char *rdb_parse_id(const struct charset_info_st *const cs,
289                          const char *str, std::string *const id)
290     MY_ATTRIBUTE((__nonnull__(1, 2), __warn_unused_result__));
291 
292 const char *rdb_skip_id(const struct charset_info_st *const cs, const char *str)
293     MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
294 
295 const std::vector<std::string> parse_into_tokens(const std::string &s,
296                                                  const char delim);
297 
298 /*
299   Helper functions to populate strings.
300 */
301 
302 std::string rdb_hexdump(const char *data, const std::size_t data_len,
303                         const std::size_t maxsize = 0)
304     MY_ATTRIBUTE((__nonnull__));
305 
306 /*
307   Helper function to see if a database exists
308  */
309 bool rdb_database_exists(const std::string &db_name);
310 
311 const char *get_rocksdb_supported_compression_types();
312 
313 /*
314   Helper class to make sure cleanup always happens. Helpful for complicated
315   logic where there can be multiple exits/returns requiring cleanup
316  */
317 class Ensure_cleanup {
318  public:
319   explicit Ensure_cleanup(std::function<void()> cleanup)
320       : m_cleanup(cleanup), m_skip_cleanup(false) {}
321 
322   ~Ensure_cleanup() {
323     if (!m_skip_cleanup) {
324       m_cleanup();
325     }
326   }
327 
328   // If you want to skip cleanup (such as when the operation is successful)
329   void skip() { m_skip_cleanup = true; }
330 
331  private:
332   std::function<void()> m_cleanup;
333   bool m_skip_cleanup;
334 };
335 }  // namespace myrocks
336