1 /*
2    Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
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, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #ifndef PC_H
26 #define PC_H
27 
28 
29 #include "Emulator.hpp"
30 #include <NdbOut.hpp>
31 #include <ndb_limits.h>
32 #include <NdbThread.h>
33 
34 #define JAM_FILE_ID 282
35 
36 /* Jam buffer pointer. */
37 struct EmulatedJamBuffer;
38 extern thread_local EmulatedJamBuffer* NDB_THREAD_TLS_JAM;
39 
40 /* Thread self pointer. */
41 struct thr_data;
42 extern thread_local thr_data* NDB_THREAD_TLS_THREAD;
43 
44 #ifdef NDB_DEBUG_RES_OWNERSHIP
45 
46 /* (Debug only) Shared resource owner. */
47 extern thread_local Uint32 NDB_THREAD_TLS_RES_OWNER;
48 
49 #endif
50 
51 /**
52  * To enable jamDebug and its siblings in a production simply
53  * remove the comment and get EXTRA_JAM defined.
54  * It is enabled in builds using ERROR_INSERT to simplify tracing
55  * of bugs from autotest.
56  *
57  * Similarly enable initialisation of global variables in a block
58  * thread before executing each asynchronous signal by enabling
59  * USE_INIT_GLOBAL_VARIABLES. This is also enabled in all builds
60  * using ERROR_INSERT to ensure that we quickly discover failures
61  * in using global variables.
62  */
63 #if defined(ERROR_INSERT)
64 #define EXTRA_JAM 1
65 #define USE_INIT_GLOBAL_VARIABLES 1
66 #endif
67 
68 #ifdef NO_EMULATED_JAM
69 
70 #define jam()
71 #define jamLine(line)
72 #define jamEntry()
73 #define jamDebug()
74 #define jamLineDebug(line)
75 #define jamEntryDebug()
76 #define jamEntryLine(line)
77 #define jamBlock(block)
78 #define jamBlockLine(block, line)
79 #define jamEntryBlock(block)
80 #define jamEntryBlockLine(block, line)
81 #define jamNoBlock()
82 #define jamNoBlockLine(line)
83 #define thrjamEntry(buf)
84 #define thrjamEntryLine(buf, line)
85 #define thrjam(buf)
86 #define thrjamLine(buf, line)
87 #define thrjamEntryDebug(buf)
88 #define thrjamEntryLineDebug(buf, line)
89 #define thrjamDebug(buf)
90 #define thrjamLineDebug(buf, line)
91 
92 #else
93 
94 #define thrjamEntryBlockLine(jamBufferArg, blockNo, line) \
95   thrjamLine(jamBufferArg, line)
96 
97 /**
98  * Make an entry in the jamBuffer to record that execution reached a given
99  * point in the source code. For a description of how to maintain and debug
100  * JAM_FILE_IDs, please refer to the comments for jamFileNames in Emulator.cpp.
101  */
102 #define thrjamLine(jamBufferArg, line) \
103   do { \
104     EmulatedJamBuffer* const jamBuffer = jamBufferArg; \
105     Uint32 jamIndex = jamBuffer->theEmulatedJamIndex; \
106     jamBuffer->theEmulatedJam[jamIndex++] = JamEvent((JAM_FILE_ID), (line)); \
107     jamBuffer->theEmulatedJamIndex = jamIndex & JAM_MASK; \
108     /* Occasionally check that the jam buffer belongs to this thread.*/ \
109     assert((jamIndex & 3) != 0 || jamBuffer == NDB_THREAD_TLS_JAM);       \
110     /* Occasionally check that jamFileNames[JAM_FILE_ID] matches __FILE__.*/ \
111     assert((jamIndex & 0xff) != 0 ||                     \
112            JamEvent::verifyId((JAM_FILE_ID), __FILE__)); \
113   } while(0)
114 
115 #define jamBlockLine(block, line) thrjamLine(block->jamBuffer(), line)
116 #define jamBlock(block) jamBlockLine((block), __LINE__)
117 #define jamLine(line) jamBlockLine(this, (line))
118 #define jam() jamLine(__LINE__)
119 #define jamBlockEntryLine(block, line) \
120   thrjamEntryBlockLine(block->jamBuffer(), block->number(), line)
121 #define jamEntryBlock(block) jamEntryBlockLine(block, __LINE__)
122 #define jamEntryLine(line) jamBlockEntryLine(this, (line))
123 #define jamEntry() jamEntryLine(__LINE__)
124 
125 #define jamNoBlockLine(line) \
126     thrjamLine(NDB_THREAD_TLS_JAM, line)
127 #define jamNoBlock() jamNoBlockLine(__LINE__)
128 
129 #define thrjamEntryLine(buf, line) thrjamEntryBlockLine(buf, number(), line)
130 
131 #define thrjam(buf) thrjamLine(buf, __LINE__)
132 #define thrjamEntry(buf) thrjamEntryLine(buf, __LINE__)
133 
134 #if defined VM_TRACE || defined ERROR_INSERT || defined EXTRA_JAM
135 #define jamDebug() jam()
136 #define jamLineDebug(line) jamLine(line)
137 #define jamEntryDebug() jamEntry()
138 #define thrjamEntryDebug(buf) thrjamEntry(buf)
139 #define thrjamEntryLineDebug(buf, line) thrJamEntryLine(guf, line)
140 #define thrjamDebug(buf) thrjam(buf)
141 #define thrjamLineDebug(buf, line) thrjamLine(buf, line)
142 #else
143 #define jamDebug()
144 #define jamLineDebug(line)
145 #define jamEntryDebug()
146 #define thrjamEntryDebug(buf)
147 #define thrjamEntryLineDebug(buf, line)
148 #define thrjamDebug(buf)
149 #define thrjamLineDebug(buf, line)
150 #endif
151 #endif
152 
153 #ifndef NDB_OPT
154 #define ptrCheck(ptr, limit, rec) if (ptr.i < (limit)) ptr.p = &rec[ptr.i]; else ptr.p = NULL
155 
156 /**
157  * Sets the p-value of a ptr-struct to be a pointer to record no i
158  * (where i is the i-value of the ptr-struct)
159  *
160  * @param ptr    ptr-struct with a set i-value  (the p-value in this gets set)
161  * @param limit  max no of records in rec
162  * @param rec    pointer to first record in an array of records
163  */
164 #define ptrCheckGuardErr(ptr, limit, rec, error) {\
165   UintR TxxzLimit; \
166   TxxzLimit = (limit); \
167   UintR TxxxPtr; \
168   TxxxPtr = ptr.i; \
169   ptr.p = &rec[TxxxPtr]; \
170   if (TxxxPtr < (TxxzLimit)) { \
171     ; \
172   } else { \
173     progError(__LINE__, error, __FILE__); \
174   }}
175 #define ptrAss(ptr, rec) ptr.p = &rec[ptr.i]
176 #define ptrNull(ptr) ptr.p = NULL
177 #define ptrGuardErr(ptr, error) if (ptr.p == NULL) \
178     progError(__LINE__, error, __FILE__)
179 #define arrGuardErr(ind, size, error) if ((ind) >= (size)) \
180     progError(__LINE__, error, __FILE__)
181 #else
182 #define ptrCheck(ptr, limit, rec) ptr.p = &rec[ptr.i]
183 #define ptrCheckGuardErr(ptr, limit, rec, error) ptr.p = &rec[ptr.i]
184 #define ptrAss(ptr, rec) ptr.p = &rec[ptr.i]
185 #define ptrNull(ptr) ptr.p = NULL
186 #define ptrGuardErr(ptr, error)
187 #define arrGuardErr(ind, size, error)
188 #endif
189 
190 #define ptrCheckGuard(ptr, limit, rec) \
191   ptrCheckGuardErr(ptr, limit, rec, NDBD_EXIT_POINTER_NOTINRANGE)
192 #define ptrGuard(ptr) ptrGuardErr(ptr, NDBD_EXIT_POINTER_NOTINRANGE)
193 #define arrGuard(ind, size) arrGuardErr(ind, size, NDBD_EXIT_INDEX_NOTINRANGE)
194 
195 // -------- ERROR INSERT MACROS -------
196 #ifdef ERROR_INSERT
197 #define ERROR_INSERT_VARIABLE mutable UintR cerrorInsert, c_error_insert_extra
198 #define ERROR_INSERTED(x) (cerrorInsert == (x))
199 #define ERROR_INSERTED_CLEAR(x) (cerrorInsert == (x) ? (cerrorInsert = 0, true) : false)
200 #define ERROR_INSERT_VALUE cerrorInsert
201 #define ERROR_INSERT_EXTRA c_error_insert_extra
202 #define SET_ERROR_INSERT_VALUE(x) cerrorInsert = x
203 #define SET_ERROR_INSERT_VALUE2(x,y) cerrorInsert = x; c_error_insert_extra = y
204 #define CLEAR_ERROR_INSERT_VALUE cerrorInsert = 0
205 #define CLEAR_ERROR_INSERT_EXTRA c_error_insert_extra = 0
206 #else
207 #define ERROR_INSERT_VARIABLE typedef void * cerrorInsert // Will generate compiler error if used
208 #define ERROR_INSERTED(x) false
209 #define ERROR_INSERTED_CLEAR(x) false
210 #define ERROR_INSERT_VALUE 0
211 #define ERROR_INSERT_EXTRA Uint32(0)
212 #define SET_ERROR_INSERT_VALUE(x) do { } while(0)
213 #define SET_ERROR_INSERT_VALUE2(x,y) do { } while(0)
214 #define CLEAR_ERROR_INSERT_VALUE do { } while(0)
215 #define CLEAR_ERROR_INSERT_EXTRA do { } while(0)
216 #endif
217 
218 #define DECLARE_DUMP0(BLOCK, CODE, DESC) if (arg == CODE)
219 
220 /* ------------------------------------------------------------------------- */
221 /*       COMMONLY USED CONSTANTS.                                            */
222 /* ------------------------------------------------------------------------- */
223 #define ZFALSE 0
224 #define ZTRUE 1
225 #define ZSET 1
226 #define ZOK 0
227 #define ZNOT_OK 1
228 #define ZCLOSE_FILE 2
229 #define ZNIL 0xffff
230 #define Z8NIL 255
231 #define UINT28_MAX ((1 << 28) - 1)
232 
233 /* ------------------------------------------------------------------------- */
234 // Number of fragments stored per node. Should be settable on a table basis
235 // in future version since small tables want small value and large tables
236 // need large value.
237 /* ------------------------------------------------------------------------- */
238 #define NO_OF_FRAG_PER_NODE 1
239 #define MAX_FRAG_PER_LQH 8
240 
241 /**
242 * DIH allocates fragments in chunk for fast find of fragment record.
243 * These parameters define chunk size and log of chunk size.
244 */
245 #define NO_OF_FRAGS_PER_CHUNK 4
246 #define LOG_NO_OF_FRAGS_PER_CHUNK 2
247 
248 /* ---------------------------------------------------------------- */
249 // To avoid synching too big chunks at a time we synch after writing
250 // a certain number of data/UNDO pages. (e.g. 2 MBytes).
251 /* ---------------------------------------------------------------- */
252 #define MAX_REDO_PAGES_WITHOUT_SYNCH 32
253 
254 /* ------------------------------------------------------------------ */
255 // We have these constants to ensure that we can easily change the
256 // parallelism of node recovery and the amount of scan
257 // operations needed for node recovery.
258 /* ------------------------------------------------------------------ */
259 #define MAX_NO_WORDS_OUTSTANDING_COPY_FRAGMENT 6000
260 #define MAGIC_CONSTANT 56
261 #define NODE_RECOVERY_SCAN_OP_RECORDS \
262          (4 + ((4*MAX_NO_WORDS_OUTSTANDING_COPY_FRAGMENT)/ \
263          ((MAGIC_CONSTANT + 2) * 5)))
264 
265 #ifdef NO_CHECKPOINT
266 #define NO_LCP
267 #define NO_GCP
268 #endif
269 #define ZUNDEFINED_GCI_LIMIT 1
270 #define DEFAULT_SPIN_TIME 0
271 #define MEASURE_SPIN_TIME 60
272 #define MAX_SPIN_TIME 500
273 #define MAX_SPIN_OVERHEAD 10000
274 #define MIN_SPINTIME_PER_CALL 300
275 #define MAX_SPINTIME_PER_CALL 8000
276 
277 /**
278  * Ndb kernel blocks assertion handling
279  *
280  * Two type of assertions:
281  * - ndbassert  - Only used when compiling VM_TRACE
282  * - ndbrequire - Always checked
283  *
284  * If a ndbassert/ndbrequire fails, the system will
285  * shutdown and generate an error log
286  *
287  *
288  * NOTE these may only be used within blocks
289  */
290 #if defined VM_TRACE
291 #define ndbassert(check) \
292   if(likely(check)){ \
293   } else {     \
294     jamNoBlock(); \
295     progError(__LINE__, NDBD_EXIT_NDBASSERT, __FILE__, #check); \
296   }
297 #else
298 #define ndbassert(check) do { } while(0)
299 #endif
300 
301 #define ndbrequireErr(check, error) \
302   if(likely(check)){ \
303   } else {     \
304     jamNoBlock(); \
305     progError(__LINE__, error, __FILE__, #check); \
306   }
307 
308 #define ndbrequire(check) \
309   ndbrequireErr(check, NDBD_EXIT_NDBREQUIRE)
310 
311 #define ndbabort() \
312   do { \
313     jamNoBlock(); \
314     progError(__LINE__, NDBD_EXIT_PRGERR, __FILE__, ""); \
315   } while (false)
316 
317 #define CRASH_INSERTION(errorType) \
318   if (!ERROR_INSERTED((errorType))) { \
319   } else { \
320     jamNoBlock(); \
321     progError(__LINE__, NDBD_EXIT_ERROR_INSERT, __FILE__); \
322   }
323 
324 #define CRASH_INSERTION2(errorNum, condition) \
325   if (!(ERROR_INSERTED(errorNum) && condition)) { \
326   } else { \
327     jamNoBlock(); \
328     progError(__LINE__, NDBD_EXIT_ERROR_INSERT, __FILE__); \
329   }
330 
331 #define CRASH_INSERTION3() \
332   { \
333     jamNoBlock(); \
334     progError(__LINE__, NDBD_EXIT_ERROR_INSERT, __FILE__); \
335   }
336 #define MEMCOPY_PAGE(to, from, page_size_in_bytes) \
337   memcpy((void*)(to), (void*)(from), (size_t)(page_size_in_bytes));
338 #define MEMCOPY_NO_WORDS(to, from, no_of_words) \
339   memcpy((to), (void*)(from), (size_t)((no_of_words) << 2));
340 
341 // Get the jam buffer for the current thread.
getThrJamBuf()342 inline EmulatedJamBuffer* getThrJamBuf()
343 {
344   return NDB_THREAD_TLS_JAM;
345 }
346 
347 #undef JAM_FILE_ID
348 
349 #endif
350