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