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 <string>
21 #include <regex>
22
23 /* MySQL header files */
24 #include "./sql_string.h"
25 #include "./sql_regex.h"
26
27 /* RocksDB header files */
28 #include "rocksdb/slice.h"
29
30 #ifdef HAVE_JEMALLOC
31 #include <jemalloc/jemalloc.h>
32 #endif
33
34 namespace myrocks {
35
36 /*
37 Guess what?
38 An interface is a class where all members are public by default.
39 */
40
41 #ifndef interface
42 #define interface struct
43 #endif // interface
44
45 /*
46 Introduce C-style pseudo-namespaces, a handy way to make code more readble
47 when calling into a legacy API, which does not have any namespace defined.
48 Since we cannot or don't want to change the API in any way, we can use this
49 mechanism to define readability tokens that look like C++ namespaces, but are
50 not enforced in any way by the compiler, since the pre-compiler strips them
51 out. However, on the calling side, code looks like my_core::thd_ha_data()
52 rather than plain a thd_ha_data() call. This technique adds an immediate
53 visible cue on what type of API we are calling into.
54 */
55
56 #ifndef my_core
57 // C-style pseudo-namespace for MySQL Core API, to be used in decorating calls
58 // to non-obvious MySQL functions, like the ones that do not start with well
59 // known prefixes: "my_", "sql_", and "mysql_".
60 #define my_core
61 #endif // my_core
62
63 /*
64 The intent behind a SHIP_ASSERT() macro is to have a mechanism for validating
65 invariants in retail builds. Traditionally assertions (such as macros defined
66 in <cassert>) are evaluated for performance reasons only in debug builds and
67 become NOOP in retail builds when NDEBUG is defined.
68
69 This macro is intended to validate the invariants which are critical for
70 making sure that data corruption and data loss won't take place. Proper
71 intended usage can be described as "If a particular condition is not true then
72 stop everything what's going on and terminate the process because continued
73 execution will cause really bad things to happen".
74
75 Use the power of SHIP_ASSERT() wisely.
76 */
77 #ifndef abort_with_stack_traces
78 #define abort_with_stack_traces abort
79 #endif
80
81 #ifndef SHIP_ASSERT
82 #define SHIP_ASSERT(expr) \
83 do { \
84 if (!(expr)) { \
85 my_safe_printf_stderr("\nShip assert failure: \'%s\'\n", #expr); \
86 abort_with_stack_traces(); \
87 } \
88 } while (0)
89 #endif // SHIP_ASSERT
90
91 /*
92 Assert a implies b.
93 If a is true, then b must be true.
94 If a is false, then the value is b does not matter.
95 */
96 #ifndef DBUG_ASSERT_IMP
97 #define DBUG_ASSERT_IMP(a, b) DBUG_ASSERT(!(a) || (b))
98 #endif
99
100 /*
101 Assert a if and only if b.
102 a and b must be both true or both false.
103 */
104 #ifndef DBUG_ASSERT_IFF
105 #define DBUG_ASSERT_IFF(a, b) \
106 DBUG_ASSERT(static_cast<bool>(a) == static_cast<bool>(b))
107 #endif
108
109 /*
110 Intent behind this macro is to avoid manually typing the function name every
111 time we want to add the debugging statement and use the compiler for this
112 work. This avoids typical refactoring problems when one renames a function,
113 but the tracing message doesn't get updated.
114
115 We could use __func__ or __FUNCTION__ macros, but __PRETTY_FUNCTION__
116 contains the signature of the function as well as its bare name and provides
117 therefore more context when interpreting the logs.
118 */
119 #define DBUG_ENTER_FUNC() DBUG_ENTER(__PRETTY_FUNCTION__)
120
121 /*
122 Error handling pattern used across MySQL abides by the following rules: "All
123 functions that can report an error (usually an allocation error), should
124 return 0/FALSE/false on success, 1/TRUE/true on failure."
125
126 https://dev.mysql.com/doc/internals/en/additional-suggestions.html has more
127 details.
128
129 To increase the comprehension and readability of MyRocks codebase we'll use
130 constants similar to ones from C standard (EXIT_SUCCESS and EXIT_FAILURE) to
131 make sure that both failure and success paths are clearly identifiable. The
132 definitions of FALSE and TRUE come from <my_global.h>.
133 */
134 #define HA_EXIT_SUCCESS FALSE
135 #define HA_EXIT_FAILURE TRUE
136
137 /*
138 Generic constant.
139 */
140 const size_t RDB_MAX_HEXDUMP_LEN = 1000;
141
142 /*
143 Helper function to get an NULL terminated uchar* out of a given MySQL String.
144 */
145
rdb_mysql_str_to_uchar_str(my_core::String * str)146 inline uchar *rdb_mysql_str_to_uchar_str(my_core::String *str) {
147 DBUG_ASSERT(str != nullptr);
148 return reinterpret_cast<uchar *>(str->c_ptr());
149 }
150
151 /*
152 Helper function to get plain (not necessary NULL terminated) uchar* out of a
153 given STL string.
154 */
155
rdb_std_str_to_uchar_ptr(const std::string & str)156 inline const uchar *rdb_std_str_to_uchar_ptr(const std::string &str) {
157 return reinterpret_cast<const uchar *>(str.data());
158 }
159
160 /*
161 Helper function to convert seconds to milliseconds.
162 */
163
rdb_convert_sec_to_ms(int sec)164 constexpr int rdb_convert_sec_to_ms(int sec) {
165 return std::chrono::milliseconds(std::chrono::seconds(sec)).count();
166 }
167
168 /*
169 Helper function to get plain (not necessary NULL terminated) uchar* out of a
170 given RocksDB item.
171 */
172
rdb_slice_to_uchar_ptr(const rocksdb::Slice * item)173 inline const uchar *rdb_slice_to_uchar_ptr(const rocksdb::Slice *item) {
174 DBUG_ASSERT(item != nullptr);
175 return reinterpret_cast<const uchar *>(item->data());
176 }
177
178 /*
179 Call this function in cases when you can't rely on garbage collector and need
180 to explicitly purge all unused dirty pages. This should be a relatively rare
181 scenario for cases where it has been verified that this intervention has
182 noticeable benefits.
183 */
purge_all_jemalloc_arenas()184 inline int purge_all_jemalloc_arenas() {
185 #ifdef HAVE_JEMALLOC
186 unsigned narenas = 0;
187 size_t sz = sizeof(unsigned);
188 char name[25] = {0};
189
190 // Get the number of arenas first. Please see `jemalloc` documentation for
191 // all the various options.
192 int result = mallctl("arenas.narenas", &narenas, &sz, nullptr, 0);
193
194 // `mallctl` returns 0 on success and we really want caller to know if all the
195 // trickery actually works.
196 if (result) {
197 return result;
198 }
199
200 // Form the command to be passed to `mallctl` and purge all the unused dirty
201 // pages.
202 snprintf(name, sizeof(name) / sizeof(char), "arena.%d.purge", narenas);
203 result = mallctl(name, nullptr, nullptr, nullptr, 0);
204
205 return result;
206 #else
207 return EXIT_SUCCESS;
208 #endif
209 }
210
211 /*
212 Helper functions to parse strings.
213 */
214
215 const char *rdb_skip_spaces(const struct charset_info_st *const cs,
216 const char *str)
217 __attribute__((__nonnull__, __warn_unused_result__));
218
219 bool rdb_compare_strings_ic(const char *const str1, const char *const str2)
220 __attribute__((__nonnull__, __warn_unused_result__));
221
222 const char *rdb_find_in_string(const char *str, const char *pattern,
223 bool *const succeeded)
224 __attribute__((__nonnull__, __warn_unused_result__));
225
226 const char *rdb_check_next_token(const struct charset_info_st *const cs,
227 const char *str, const char *const pattern,
228 bool *const succeeded)
229 __attribute__((__nonnull__, __warn_unused_result__));
230
231 const char *rdb_parse_id(const struct charset_info_st *const cs,
232 const char *str, std::string *const id)
233 __attribute__((__nonnull__(1, 2), __warn_unused_result__));
234
235 const char *rdb_skip_id(const struct charset_info_st *const cs, const char *str)
236 __attribute__((__nonnull__, __warn_unused_result__));
237
238 /*
239 Helper functions to populate strings.
240 */
241
242 std::string rdb_hexdump(const char *data, const std::size_t data_len,
243 const std::size_t maxsize = 0)
244 __attribute__((__nonnull__));
245
246 /*
247 Helper function to see if a database exists
248 */
249 bool rdb_database_exists(const std::string &db_name);
250
251 void warn_about_bad_patterns(const Regex ®ex, const char *name);
252
253 } // namespace myrocks
254