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 &regex, const char *name);
252 
253 }  // namespace myrocks
254