1 /*
2 Copyright (c) 2003, 2021, Oracle and/or its affiliates.
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 SIMULATEDBLOCK_H
26 #define SIMULATEDBLOCK_H
27
28 #include <NdbTick.h>
29 #include <kernel_types.h>
30 #include <util/version.h>
31 #include <ndb_limits.h>
32
33 #include "VMSignal.hpp"
34 #include <RefConvert.hpp>
35 #include <BlockNumbers.h>
36 #include <GlobalSignalNumbers.h>
37
38 #include "pc.hpp"
39 #include "Pool.hpp"
40 #include <NodeInfo.hpp>
41 #include <NodeState.hpp>
42 #include "GlobalData.hpp"
43 #include "LongSignal.hpp"
44 #include <SignalLoggerManager.hpp>
45
46 #include <ErrorReporter.hpp>
47 #include <ErrorHandlingMacros.hpp>
48
49 #include "IntrusiveList.hpp"
50 #include "ArrayPool.hpp"
51 #include "DLHashTable.hpp"
52 #include "WOPool.hpp"
53 #include "RWPool.hpp"
54 #include "Callback.hpp"
55 #include "SafeCounter.hpp"
56
57 #include <mgmapi.h>
58 #include <mgmapi_config_parameters.h>
59 #include <mgmapi_config_parameters_debug.h>
60 #include <kernel_config_parameters.h>
61 #include <Configuration.hpp>
62
63 #include <signaldata/ReadConfig.hpp>
64 #include "ndbd_malloc_impl.hpp"
65 #include <blocks/record_types.hpp>
66
67 #include "Ndbinfo.hpp"
68
69 #define JAM_FILE_ID 248
70
71
72 #ifdef VM_TRACE
73 #define D(x) \
74 do { \
75 char buf[200]; \
76 if (!debugOutOn()) break; \
77 debugOutLock(); \
78 debugOutStream() << debugOutTag(buf, __LINE__) << x << dec << "\n"; \
79 debugOutUnlock(); \
80 } while (0)
81 #define V(x) " " << #x << ":" << (x)
82 #else
83 #define D(x) do { } while(0)
84 #undef V
85 #endif
86
87 /**
88 * LCP scans and Backup scans always use batch size 16, there are even
89 * optimisations in allocation and handling LCP scans and Backup scans
90 * keeping proper rates using this particular batch size. This is also
91 * true for Node recovery scans as started by COPY_FRAGREQ.
92 */
93 #define ZRESERVED_SCAN_BATCH_SIZE 16
94 /**
95 * Something for filesystem access
96 */
97 struct NewBaseAddrBits /* 32 bits */
98 {
99 unsigned int q : 4; /* Highest index - 2log */
100 /* Strings are treated as 16 bit indexed */
101 /* variables with the number of characters in */
102 /* index 0, byte 0 */
103 unsigned int v : 3; /* Size in bits - 2log */
104 unsigned int unused : 25 ;
105 };
106
107 typedef struct NewVar
108 {
109 Uint32 * WA;
110 Uint32 nrr;
111 Uint32 ClusterSize; /* Real Cluster size */
112 NewBaseAddrBits bits;
113 } NewVARIABLE; /* 128 bits */
114
115 struct Block_context
116 {
Block_contextBlock_context117 Block_context(class Configuration& cfg, class Ndbd_mem_manager& mm)
118 : m_config(cfg), m_mm(mm) {}
119 class Configuration& m_config;
120 class Ndbd_mem_manager& m_mm;
121 };
122
123 struct PackedWordsContainer
124 {
125 BlockReference hostBlockRef;
126 Uint32 noOfPackedWords;
127 Uint32 packedWords[30];
128 }; // 128 bytes
129
130 /**
131 Description of NDB Software Architecture
132 ----------------------------------------
133
134 The NDB software architecture has two foundations, blocks and signals.
135 The base object for the blocks is the below SimulatedBlock class and
136 the signal object is the base class Signal defined in VMSignal.hpp.
137
138 Blocks are intended as software units that owns its own data and it
139 communicates with other blocks only through signals. Each block owns
140 its own set of data which it entirely controls. There has been some
141 optimisations where blocks always executing in the same thread can do
142 some shortcuts by calling functions in a different block directly.
143 There is even some code to call functions in a block in a different
144 thread, in this case however some mutex is required to protect the
145 data.
146
147 Blocks are gathered together in threads. Threads are gathered into nodes.
148 So when sending a signal you need to send it to an address. The address is
149 a 32-bit word. It is a bit similar to IPv4 addresses. The address is
150 setup in the following manner:
151
152 -- Bit 0-8 ------- Bit 9-15 ------ Bit 16-31 ------
153 | Block number | Thread id | NodeId |
154 ---------------------------------------------------
155
156 So when delivering a signal we start by checking the node id. If the node
157 id is our own node id, then we will continue checking thread id. If it
158 is destined to another node, then we move the signal sending to the module
159 that takes care of transporting the signal to another node in the cluster.
160
161 Each other node is found using a socket over TCP/IP. The architecture
162 supports also other ways to transport signals such as using some form
163 of shared memory between processes on the same or different machines.
164 It would also be possible to extend the architecture such that we
165 might use different sockets for different threads in the node.
166
167 If the signal is destined for a different thread then we transport the
168 signal to that thread, we use a separate memory buffer for each two
169 threads that communicate such that the communication between threads is
170 completely lock-free.
171
172 One block number can be used in several threads. So e.g. the LDM threads
173 all contain its own instance of the DBLQH block. The method instance()
174 gets the instance number of the currently executing block. The method
175 reference() gets the block reference of the currently executing block.
176
177 If we send to ourselves we put the signal in the memory buffer for
178 communication with our own thread.
179
180 The current limits of the architecture is a maximum of 512 block numbers.
181 We currently use less than 25 of those numbers. The maximum number of
182 threads are 128 threads. We currently can use at most 72 threads.
183 The current node limit is 255 nodes and node id 0 is a special case.
184
185 So there is still a lot of space in the addressing mechanism for growth
186 in terms of number of threads, blocks and nodes and even for introduction
187 of new addressable units like subthreads or similar things.
188
189 The software architecture also contains a structure for how signals are
190 structured. Each signal is sent at a certain priority level. Finally also
191 there is a concept of sending delayed signals to blocks within the same
192 thread.
193
194 Priority level on signals
195 -------------------------
196 So starting with priority level a signal can be sent on high priority
197 (JBA) and normal priority (JBB). The priority level can be used also when
198 sending to other nodes. The priority will however not be used to prioritise
199 the signal in sending it over the socket to the receiving node.
200
201 Each thread has its own buffer for A-priority signals. In the scheduler
202 we will always execute all signals in the A-priority buffer first. If
203 new A-priority signals are sent during these signals, then they will also
204 be executed until no more signals exist on A-priority level. So it's not
205 allowed to have a flow of signals all executing at A-level. We always have
206 to insert a signal in the flow that either goes down to B-level or use some
207 form of delayed signal.
208
209 If an A-level signal is sent from a B-level signal it will be handled
210 differently in the single threaded ndbd and the multi-threaded ndbmtd. In
211 ndbmtd it will be executed after executing up to 128 B-level signals. In
212 ndbd it will be executed as the next signal. So one cannot assume that an
213 A-level signal will be executed before a specific B-level signal. A B-level
214 signal can even be executed before an A-level signal although it was sent
215 after the A-level signal.
216
217 Delayed signals
218 ---------------
219 Delayed signals are used to create threads of activities that execute without
220 consuming too much CPU activity. Delayed signals can only be sent internally
221 within the same thread. When the signal has been delayed and is taken out of
222 its timer queue its inserted into the priority A buffer.
223
224 Bounded delay signals
225 ---------------------
226 A special form of delayed signal also exists, this is sent with delay equal to
227 the constant BOUNDED_DELAY. This means that the signal will be executed as a
228 priority A task as soon as the current set of B-level tasks are done. This is
229 similar to sending an A-level signal from a B-level job in ndbmtd. However for
230 ndbd it's not the same thing and also when sending an A-level signal from an
231 A-level signal it is also not the same thing.
232
233 So a delayed signal with delay BOUNDED_DELAY is a special type of signal
234 with a bounded delay. The bound is that no more than 100 B-level signals will
235 be executed before this signal is executed. Given our design requirements
236 a B-level signal should mostly be executed within at most 5-10 microseconds
237 or so, mostly much shorter than this even, so a normal execution time of
238 a signal would be below 1 microsecond. So 100 signals should almost never
239 execute for more than 1000 microseconds and rarely go beyond even 100
240 microseconds.
241
242 So these bounded delay signals are a good tool to ensure that activitites
243 such as backups, checkpoints, node recovery activities, altering of tables
244 and similar things gets executed at a certain rate. Without any possibility
245 of bounded delay signals it is very hard to implement an activity that gets
246 executed at a certain rate.
247
248 So in a sense we're using the bounded delay signals to implement a form of
249 time-sharing priority, certain activities are allowed to use a proportion
250 of the available CPU resources, not too much, but also not too little. If
251 an LCP gets bogged down by user transactions then the system will eventually
252 run out of REDO log space. If a node recovery activity gets bogged down by
253 user transactions then we will run for too long with only one replica in the
254 node group which is bad for system availability.
255
256 Execute direct signals
257 ----------------------
258 If the receiving block is within the same thread, then it is possible to
259 send the signal using the method EXECUTE_DIRECT. This execution will
260 happen immediately and won't be scheduled for later, it will be done in
261 the same fashion as a function call.
262
263 Signals
264 -------
265 Signals are carried with a certain structure:
266 1) Each signal has a signal number. This number also is mapped to a name.
267 When executing a signal with a certain number which e.g. has the name
268 TCKEYREQ, then this signal is implemented by a method called
269 execTCKEYREQ in the receiving block. More than one block could have
270 such a method since a signal is not tied to a certain block.
271
272 2) Each signal has 4 areas that can be sent in the signal. The first is
273 always sent in the signal, this is the fixed part. The fixed part
274 consists of at least 1 and at most 25 32-bit words. Many signals have
275 a class that defines this part of the signal. This is however not
276 absolutely necessary. Then there are up to 3 sections that can carry
277 longer information bits. So e.g. a TCKEYREQ has one section that contains
278 the primary key and another part that contains the attribute information.
279 The attribute information could be seen as a program sent to MySQL
280 Cluster data nodes to read, update the row specified in the key
281 section. The attribute information could also contain interpreted
282 programs that can do things like increment, decrement, conditional
283 update and so forth.
284
285 3) As mentioned above each signal carries a certain priority level to
286 execute it on. It is currently not possible to check the prio
287 level you're currently executing on, but it would be real simple
288 to add this capability if necessary.
289
290 4) When executing a certain signal it gets a signal id, this id is
291 local to the thread and is incremented by one each new signal that
292 is executed. This signal id is available in the Signal class and
293 can e.g. be used to deduce if the thread is currently at high load.
294
295 A signal is sent over the socket using a special protocol that is called
296 Protocol6. This is not discussed more here, it is a feature of the
297 transport mechanisms of the NDB Software Architecture.
298
299 CONTINUEB
300 ---------
301 CONTINUEB is a special signal used by almost all blocks. This signal is
302 used to handle background thread activities. Often the CONTINUEB signals
303 are used as part of implementing a more complex action. One example is
304 when DBDIH starts up a new LCP. It sends various forms of CONTINUEB
305 signals to itself to move ahead through the LCP actions it needs to do
306 as part of starting up a new LCP. The first word contains the type of
307 CONTINUEB signal, so this is in a sense a bit like a second level of
308 signal number. Based on this number the CONTINUEB data is treated
309 differently.
310
311 Common patterns of signals
312 --------------------------
313 There is no absolute patterns for how signal data looks like. But it is
314 very common that a signal at least contains the destination object id,
315 the senders object id and the senders block reference. The senders block
316 reference is actually also available in the Signal class when executing
317 a signal. But we can use various forms of software routing of the
318 signal, so the senders block reference is the originator of the signal,
319 not necessarily the same as the sender of the signal since it could be
320 routed through several blocks on the way.
321
322 The basic data type in the NDB signals are unsigned 32-bit integers. So
323 all addressing is using a special form of pointers. The pointers always
324 refers to a special class of objects and the pointer is the index in an
325 array of objects of this kind. So we can have up to 4 billion objects of
326 most kinds. If one needs to send strings and 64-bit integers one follows
327 various techniques to do this. Signals are sent in the endian order of
328 the machine they were generated, so machines in a cluster has to be
329 of the same type of endian.
330
331 ROUTE_SIGNAL
332 ------------
333 ROUTE_SIGNAL is a special signal that can be used to carry a signal
334 in a special path to ensure that it arrives in the correct order to
335 the receiving block.
336
337 Signal order guarantees
338 -----------------------
339 The following signal order guarantees are maintained.
340
341 1) Sending signals at the same priority level to the same block reference
342 from one block will arrive in the order they were sent.
343
344 It is not guaranteed if the priority level is different for the signals,
345 it is also not guaranteed if they are sent through different paths.
346 Not even sending in the following pattern has a guarantee on the
347 delivery order. Signal 1: Block A -> Block B, Signal 2: Block A ->
348 Block C -> Block B. Although the signal 2 uses a longer path and is
349 destined to the same block it can still arrive before signal 1 at
350 Block B. The reason is that we execute signals from one sender at a
351 time, so we might be executing in Block C very quickly whereas the
352 thread executing Block B might be stalled and then when Block C has
353 sent its signal the thread executing Block B wakes up and decides
354 to execute signals from Block C before signals from Block A.
355
356 So as can be seen there is very little support for signal orders in the
357 NDB software architecture and so most protocols have to take into
358 account that signals can arrive in many different orders.
359
360 Fragmented signals
361 ------------------
362 It is possible to send really long signals. These signals cannot be
363 sent as one signal though. They are sent as one signal, then they will
364 be split up into multiple signals. The fixed part is the same in all
365 signals. What mainly differs is that they each contain a part of each
366 segment.
367
368 When receiving such a signal one should always call assembleFragments()
369 at first to see if the entire signal has arrived first. The signal
370 executor method is executed once for each signal fragment that is sent.
371 When all fragments have arrived then they will contain the full signal
372 with up to 3 sections that can much longer than the normal sized signals
373 that have limitations on the size of the signals.
374
375 Tracing infrastructure
376 ----------------------
377 All signals are sent through memory buffers. At crashes these memory
378 buffers can be used to print the last executed signals in each thread.
379 This will aid in looking for reasons for the crash. There will be one
380 file generated for each thread in the ndbmtd, in the case of ndbd there
381 will be only one file since there is only one file.
382
383 Jams
384 ----
385 jam() and its cousins is a set of macros used for tracing what happened
386 at the point of a crash. Each jam call executes a set of instructions
387 that inserts the line number of the jam macro into an array kept per
388 thread. There is some overhead in the jams, but it helps quite a lot in
389 debugging crashes of the NDB data nodes. At crash time we can see a few
390 thousand of the last decisions made just before the crash. This together
391 with the signal logs makes for a powerful tool to root out bugs in NDB
392 data nodes.
393
394 Trace Id
395 --------
396 Each signal also carries a signal id, this id can be used to trace certain
397 activities that go on for a longer time. This tracing can happen even in a
398 live system.
399 */
400
401 class SimulatedBlock :
402 public SegmentUtils /* SimulatedBlock implements the Interface */
403 {
404 friend class TraceLCP;
405 friend class SafeCounter;
406 friend class SafeCounterManager;
407 friend class AsyncFile;
408 friend class PosixAsyncFile; // FIXME
409 friend class Win32AsyncFile;
410 friend class Pgman;
411 friend class Page_cache_client;
412 friend class Lgman;
413 friend class Logfile_client;
414 friend class Tablespace_client;
415 friend class Dbtup_client;
416 friend struct Pool_context;
417 friend struct SectionHandle;
418 friend class LockQueue;
419 friend class SimplePropertiesSectionWriter;
420 friend class SegmentedSectionGuard;
421 public:
422 friend class BlockComponent;
423 virtual ~SimulatedBlock();
424
425 static const Uint32 BOUNDED_DELAY = 0xFFFFFF00;
426 protected:
427 /**
428 * Constructor
429 */
430 SimulatedBlock(BlockNumber blockNumber,
431 struct Block_context & ctx,
432 Uint32 instanceNumber = 0);
433
434 /**********************************************************
435 * Handling of execFunctions
436 */
437 typedef void (SimulatedBlock::* ExecFunction)(Signal* signal);
438 void addRecSignalImpl(GlobalSignalNumber g, ExecFunction fun, bool f =false);
439 void installSimulatedBlockFunctions();
440 ExecFunction theExecArray[MAX_GSN+1];
441 void handle_execute_error(GlobalSignalNumber gsn);
442
443 void initCommon();
444
445 inline void executeFunction(GlobalSignalNumber gsn,
446 Signal* signal,
447 ExecFunction f);
448
449 inline void executeFunction(GlobalSignalNumber gsn,
450 Signal* signal,
451 ExecFunction f,
452 BlockReference ref,
453 Uint32 len);
454
455 public:
456 typedef void (SimulatedBlock::* CallbackFunction)(class Signal*,
457 Uint32 callbackData,
458 Uint32 returnCode);
459 struct Callback {
460 CallbackFunction m_callbackFunction;
461 Uint32 m_callbackData;
462 };
463
464 inline void executeFunction(GlobalSignalNumber gsn, Signal* signal);
465 inline void executeFunction_async(GlobalSignalNumber gsn, Signal* signal);
466
467 /* Multiple block instances */
instance() const468 Uint32 instance() const {
469 return theInstance;
470 }
471
getExecuteFunction(GlobalSignalNumber gsn)472 ExecFunction getExecuteFunction(GlobalSignalNumber gsn)
473 {
474 return theExecArray[gsn];
475 }
476
getInstance(Uint32 instanceNumber)477 SimulatedBlock* getInstance(Uint32 instanceNumber) {
478 ndbrequire(theInstance == 0); // valid only on main instance
479 if (instanceNumber == 0)
480 return this;
481 ndbrequire(instanceNumber < MaxInstances);
482 if (theInstanceList != 0)
483 return theInstanceList[instanceNumber];
484 return 0;
485 }
486 void addInstance(SimulatedBlock* b, Uint32 theInstanceNo);
loadWorkers()487 virtual void loadWorkers() {}
488
489 struct ThreadContext
490 {
491 Uint32 threadId;
492 EmulatedJamBuffer* jamBuffer;
493 Uint32 * watchDogCounter;
494 SectionSegmentPool::Cache * sectionPoolCache;
495 };
496 /* Setup state of a block object for executing in a particular thread. */
497 void assignToThread(ThreadContext ctx);
498 /* For multithreaded ndbd, get the id of owning thread. */
getThreadId() const499 uint32 getThreadId() const { return m_threadId; }
500 /**
501 * To call EXECUTE_DIRECT on THRMAN we need to get its instance number.
502 * Its instance number is always 1 higher than the thread id since 0
503 * is used for the proxy instance and then there is one instance per
504 * thread.
505 */
getThrmanInstance() const506 Uint32 getThrmanInstance() const
507 {
508 if (isNdbMt())
509 {
510 return m_threadId + 1;
511 }
512 else
513 {
514 return 0;
515 }
516 }
517 static bool isMultiThreaded();
518
519 /* Configuration based alternative. Applies only to this node */
isNdbMt()520 static bool isNdbMt() { return globalData.isNdbMt; }
isNdbMtLqh()521 static bool isNdbMtLqh() { return globalData.isNdbMtLqh; }
getLqhWorkers()522 static Uint32 getLqhWorkers() { return globalData.ndbMtLqhWorkers; }
523
524 /**
525 * Assert that thread calling this function is "owner" of block instance
526 */
527 #ifdef VM_TRACE
528 void assertOwnThread();
529 #else
assertOwnThread()530 void assertOwnThread(){ }
531 #endif
532
533 /*
534 * Instance key (1-4) is used only when sending a signal. Receiver
535 * maps it to actual instance (0, if receiver is not MT LQH).
536 *
537 * For performance reason, DBTC gets instance key directly from DBDIH
538 * via DI*GET*NODES*REQ signals.
539 */
540 static Uint32 getInstanceKey(Uint32 tabId, Uint32 fragId);
541 static Uint32 getInstanceFromKey(Uint32 instanceKey); // local use only
542
543 /**
544 * This method will make sure that when callback in called each
545 * thread running an instance any of the threads in blocks[]
546 * will have executed a signal
547 */
548 void synchronize_threads_for_blocks(Signal*, const Uint32 blocks[],
549 const Callback&, JobBufferLevel = JBB);
550
551 /**
552 * This method make sure that the path specified in blocks[]
553 * will be traversed before returning
554 */
555 void synchronize_path(Signal*, const Uint32 blocks[],
556 const Callback&, JobBufferLevel = JBB);
557
558 /**
559 * These methods are used to assist blocks to use the TIME_SIGNAL to
560 * generate drum beats with a regular delay. elapsed_time will report
561 * back the elapsed time since last call but will never report more
562 * than max delay. max_delay = 2 * delay here.
563 */
564 void init_elapsed_time(Signal *signal,
565 NDB_TICKS &latestTIME_SIGNAL);
566 void sendTIME_SIGNAL(Signal *signal,
567 const NDB_TICKS currentTime,
568 Uint32 delay);
569 Uint64 elapsed_time(Signal *signal,
570 const NDB_TICKS currentTime,
571 NDB_TICKS &latestTIME_SIGNAL,
572 Uint32 max_delay);
573
574 private:
575 struct SyncThreadRecord
576 {
577 Callback m_callback;
578 Uint32 m_cnt;
579 Uint32 nextPool;
580 };
581 ArrayPool<SyncThreadRecord> c_syncThreadPool;
582 void execSYNC_THREAD_REQ(Signal*);
583 void execSYNC_THREAD_CONF(Signal*);
584
585 void execSYNC_REQ(Signal*);
586
587 void execSYNC_PATH_REQ(Signal*);
588 void execSYNC_PATH_CONF(Signal*);
589 public:
get_filename(Uint32 fd) const590 virtual const char* get_filename(Uint32 fd) const { return "";}
591
592 void EXECUTE_DIRECT(ExecFunction f,
593 Signal *signal);
594 protected:
595 static Callback TheEmptyCallback;
596 void TheNULLCallbackFunction(class Signal*, Uint32, Uint32);
597 static Callback TheNULLCallback;
598 void execute(Signal* signal, Callback & c, Uint32 returnCode);
599
600
601 void getSendBufferLevel(NodeId node, SB_LevelType &level);
602 Uint32 getSignalsInJBB();
603
604 /**********************************************************
605 * Send signal - dialects
606 */
607
608 void sendSignal(BlockReference ref,
609 GlobalSignalNumber gsn,
610 Signal* signal,
611 Uint32 length,
612 JobBufferLevel jbuf ) const ;
613
614 void sendSignal(NodeReceiverGroup rg,
615 GlobalSignalNumber gsn,
616 Signal* signal,
617 Uint32 length,
618 JobBufferLevel jbuf ) const ;
619
620 void sendSignal(BlockReference ref,
621 GlobalSignalNumber gsn,
622 Signal* signal,
623 Uint32 length,
624 JobBufferLevel jbuf,
625 SectionHandle* sections) const;
626
627 void sendSignal(NodeReceiverGroup rg,
628 GlobalSignalNumber gsn,
629 Signal* signal,
630 Uint32 length,
631 JobBufferLevel jbuf,
632 SectionHandle* sections) const;
633
634 void sendSignal(BlockReference ref,
635 GlobalSignalNumber gsn,
636 Signal* signal,
637 Uint32 length,
638 JobBufferLevel jbuf,
639 LinearSectionPtr ptr[3],
640 Uint32 noOfSections) const ;
641
642 void sendSignal(NodeReceiverGroup rg,
643 GlobalSignalNumber gsn,
644 Signal* signal,
645 Uint32 length,
646 JobBufferLevel jbuf,
647 LinearSectionPtr ptr[3],
648 Uint32 noOfSections) const ;
649
650 /* NoRelease sendSignal variants do not release sections as
651 * a side-effect of sending. This requires extra
652 * copying for local sends
653 */
654 void sendSignalNoRelease(BlockReference ref,
655 GlobalSignalNumber gsn,
656 Signal* signal,
657 Uint32 length,
658 JobBufferLevel jbuf,
659 SectionHandle* sections) const;
660
661 void sendSignalNoRelease(NodeReceiverGroup rg,
662 GlobalSignalNumber gsn,
663 Signal* signal,
664 Uint32 length,
665 JobBufferLevel jbuf,
666 SectionHandle* sections) const;
667
668 // Send multiple signal with delay. In this VM the jobbufffer level has
669 // no effect on on delayed signals
670 //
671
672 void sendSignalWithDelay(BlockReference ref,
673 GlobalSignalNumber gsn,
674 Signal* signal,
675 Uint32 delayInMilliSeconds,
676 Uint32 length) const ;
677
678 void sendSignalWithDelay(BlockReference ref,
679 GlobalSignalNumber gsn,
680 Signal* signal,
681 Uint32 delayInMilliSeconds,
682 Uint32 length,
683 SectionHandle* sections) const;
684
685 /*
686 * Instance defaults to instance of sender. Using explicit
687 * instance argument asserts that the call is thread-safe.
688 */
689 void EXECUTE_DIRECT(Uint32 block,
690 Uint32 gsn,
691 Signal* signal,
692 Uint32 len,
693 Uint32 givenInstanceNo);
694 void EXECUTE_DIRECT(Uint32 block,
695 Uint32 gsn,
696 Signal* signal,
697 Uint32 len);
698
699 class SectionSegmentPool& getSectionSegmentPool();
700 void release(SegmentedSectionPtr & ptr);
release(SegmentedSectionPtrPOD & ptr)701 void release(SegmentedSectionPtrPOD & ptr) {
702 SegmentedSectionPtr tmp(ptr);
703 release(tmp);
704 ptr.setNull();
705 }
706 void releaseSection(Uint32 firstSegmentIVal);
707 void releaseSections(struct SectionHandle&);
708
709 bool import(Ptr<SectionSegment> & first, const Uint32 * src, Uint32 len);
710 bool import(SegmentedSectionPtr& ptr, const Uint32* src, Uint32 len);
711 bool import(SectionHandle * dst, LinearSectionPtr src[3],Uint32 cnt);
712
713 bool appendToSection(Uint32& firstSegmentIVal, const Uint32* src, Uint32 len);
714 bool dupSection(Uint32& copyFirstIVal, Uint32 srcFirstIVal);
715 bool writeToSection(Uint32 firstSegmentIVal, Uint32 offset, const Uint32* src, Uint32 len);
716
717 void handle_invalid_sections_in_send_signal(const Signal*) const;
718 void handle_lingering_sections_after_execute(const Signal*) const;
719 void handle_invalid_fragmentInfo(Signal*) const;
720 void handle_send_failed(SendStatus, Signal*) const;
721 void handle_out_of_longsignal_memory(Signal*) const;
722
723 /**
724 * Send routed signals (ONLY LOCALLY)
725 *
726 * NOTE: Only localhost is allowed!
727 */
728 struct RoutePath
729 {
730 Uint32 ref;
731 JobBufferLevel prio;
732 };
733 void sendRoutedSignal(RoutePath path[],
734 Uint32 pathcnt, // #hops
735 Uint32 dst[], // Final destination(s)
736 Uint32 dstcnt, // #final destination(s)
737 Uint32 gsn, // Final GSN
738 Signal*,
739 Uint32 len,
740 JobBufferLevel prio, // Final prio
741 SectionHandle * handle = 0);
742
743
744 /**
745 * Check that signal sent from remote node
746 * is guaranteed to be correctly serialized wrt to NODE_FAILREP
747 */
748 bool checkNodeFailSequence(Signal*);
749
750 /**********************************************************
751 * Fragmented signals
752 */
753
754 /**
755 * Assemble fragments
756 *
757 * @return true if all fragments has arrived
758 * false otherwise
759 */
760 bool assembleFragments(Signal * signal);
761
762 /**
763 * Assemble dropped fragments
764 *
765 * Should be called at the start of a Dropped Signal Report
766 * (GSN_DROPPED_SIGNAL_REP) handler when it is expected that
767 * the block could receive fragmented signals.
768 * No dropped signal handling should be done until this method
769 * returns true.
770 *
771 * @return true if all fragments has arrived and dropped signal
772 * handling can proceed.
773 * false otherwise
774 */
775 bool assembleDroppedFragments(Signal * signal);
776
777 /* If send size is > FRAGMENT_WORD_SIZE, fragments of this size
778 * will be sent by the sendFragmentedSignal variants
779 */
780 STATIC_CONST( FRAGMENT_WORD_SIZE = 240 );
781
782 void sendFragmentedSignal(BlockReference ref,
783 GlobalSignalNumber gsn,
784 Signal* signal,
785 Uint32 length,
786 JobBufferLevel jbuf,
787 SectionHandle * sections,
788 Callback & = TheEmptyCallback,
789 Uint32 messageSize = FRAGMENT_WORD_SIZE);
790
791 void sendFragmentedSignal(NodeReceiverGroup rg,
792 GlobalSignalNumber gsn,
793 Signal* signal,
794 Uint32 length,
795 JobBufferLevel jbuf,
796 SectionHandle * sections,
797 Callback & = TheEmptyCallback,
798 Uint32 messageSize = FRAGMENT_WORD_SIZE);
799
800 void sendFragmentedSignal(BlockReference ref,
801 GlobalSignalNumber gsn,
802 Signal* signal,
803 Uint32 length,
804 JobBufferLevel jbuf,
805 LinearSectionPtr ptr[3],
806 Uint32 noOfSections,
807 Callback & = TheEmptyCallback,
808 Uint32 messageSize = FRAGMENT_WORD_SIZE);
809
810 void sendFragmentedSignal(NodeReceiverGroup rg,
811 GlobalSignalNumber gsn,
812 Signal* signal,
813 Uint32 length,
814 JobBufferLevel jbuf,
815 LinearSectionPtr ptr[3],
816 Uint32 noOfSections,
817 Callback & = TheEmptyCallback,
818 Uint32 messageSize = FRAGMENT_WORD_SIZE);
819
820 /**
821 * simBlockNodeFailure
822 *
823 * Method must be called by blocks that send or receive
824 * remote Fragmented Signals when they detect a node
825 * (NDBD or API) failure.
826 * If the block needs to acknowledge or perform further
827 * processing after completing block-level node failure
828 * handling, it can supply a Callback which will be invoked
829 * when block-level node failure handling has completed.
830 * Otherwise TheEmptyCallback is used.
831 * If TheEmptyCallback is used, all failure handling is
832 * performed in the current timeslice, to avoid any
833 * races.
834 *
835 * Parameters
836 * signal : Current signal*
837 * failedNodeId : Node id of failed node
838 * cb : Callback to be executed when block-level
839 * node failure handling completed.
840 * TheEmptyCallback is passed if no further
841 * processing is required.
842 * Returns
843 * Number of 'resources' cleaned up in call.
844 * Callback return code is total resources cleaned up.
845 *
846 */
847 Uint32 simBlockNodeFailure(Signal* signal,
848 Uint32 failedNodeId,
849 Callback& cb = TheEmptyCallback);
850
851 /**********************************************************
852 * Fragmented signals structures
853 */
854
855 /**
856 * Struct used when assembling fragmented long signals at receiver side
857 */
858 struct FragmentInfo {
859 FragmentInfo(Uint32 fragId, Uint32 sender);
860
861 Uint32 m_senderRef;
862 Uint32 m_fragmentId;
863 Uint32 m_sectionPtrI[3];
864 union {
865 Uint32 nextPool;
866 Uint32 nextHash;
867 };
868 Uint32 prevHash;
869
equalSimulatedBlock::FragmentInfo870 inline bool equal(FragmentInfo const & p) const {
871 return m_senderRef == p.m_senderRef && m_fragmentId == p.m_fragmentId;
872 }
873
hashValueSimulatedBlock::FragmentInfo874 inline Uint32 hashValue() const {
875 return m_senderRef + m_fragmentId ;
876 }
877
isDroppedSimulatedBlock::FragmentInfo878 inline bool isDropped() const {
879 /* IsDropped when entry in hash, but no segments stored */
880 return (( m_sectionPtrI[0] == RNIL ) &&
881 ( m_sectionPtrI[1] == RNIL ) &&
882 ( m_sectionPtrI[2] == RNIL ) );
883 }
884 }; // sizeof() = 32 bytes
885
886 /**
887 * Struct used when sending fragmented signals
888 */
889 struct FragmentSendInfo {
890 FragmentSendInfo();
891
892 enum Status {
893 SendNotComplete = 0,
894 SendComplete = 1,
895 SendCancelled = 2
896 };
897 Uint8 m_status;
898 Uint8 m_prio;
899 Uint8 m_fragInfo;
900 enum Flags {
901 SendNoReleaseSeg = 0x1
902 };
903 Uint8 m_flags;
904 Uint16 m_gsn;
905 Uint16 m_messageSize; // Size of each fragment
906 Uint32 m_fragmentId;
907 union {
908 // Similar to Ptr<SectionSegment> but a POD, as needed in a union.
909 struct {
910 SectionSegment* p;
911 Uint32 i;
912 } m_segmented;
913 LinearSectionPtr m_linear;
914 } m_sectionPtr[3];
915 LinearSectionPtr m_theDataSection;
916 NodeReceiverGroup m_nodeReceiverGroup; // 3
917 Callback m_callback;
918 union {
919 Uint32 nextPool;
920 Uint32 nextList;
921 };
922 Uint32 prevList;
923 };
924
925 /**
926 * sendFirstFragment
927 * Used by sendFragmentedSignal
928 * noRelease can only be used if the caller can guarantee
929 * not to free the supplied sections until all fragments
930 * have been sent.
931 */
932 bool sendFirstFragment(FragmentSendInfo & info,
933 NodeReceiverGroup rg,
934 GlobalSignalNumber gsn,
935 Signal* signal,
936 Uint32 length,
937 JobBufferLevel jbuf,
938 SectionHandle * sections,
939 bool noRelease,
940 Uint32 messageSize = FRAGMENT_WORD_SIZE);
941
942 bool sendFirstFragment(FragmentSendInfo & info,
943 NodeReceiverGroup rg,
944 GlobalSignalNumber gsn,
945 Signal* signal,
946 Uint32 length,
947 JobBufferLevel jbuf,
948 LinearSectionPtr ptr[3],
949 Uint32 noOfSections,
950 Uint32 messageSize = FRAGMENT_WORD_SIZE);
951
952 /**
953 * Send signal fragment
954 *
955 * @see sendFragmentedSignal
956 */
957 void sendNextSegmentedFragment(Signal* signal, FragmentSendInfo & info);
958
959 /**
960 * Send signal fragment
961 *
962 * @see sendFragmentedSignal
963 */
964 void sendNextLinearFragment(Signal* signal, FragmentSendInfo & info);
965
966 BlockNumber number() const;
967 public:
968 /* Must be public so that we can jam() outside of block scope. */
969 EmulatedJamBuffer *jamBuffer() const;
970 protected:
971 BlockReference reference() const;
972 NodeId getOwnNodeId() const;
973
974 /**
975 * Refresh Watch Dog in initialising code
976 *
977 */
978 void refresh_watch_dog(Uint32 place = 1);
979 void update_watch_dog_timer(Uint32 interval);
980
981 /**
982 * Prog error
983 * This function should be called when this node should be shutdown
984 * If the cause of the shutdown is known use extradata to add an
985 * errormessage describing the problem
986 */
987 void progError(int line, int err_code, const char* extradata=NULL) const
988 ATTRIBUTE_NORETURN;
989 private:
990 void signal_error(Uint32, Uint32, Uint32, const char*, int) const
991 ATTRIBUTE_NORETURN;
992 const NodeId theNodeId;
993 const BlockNumber theNumber;
994 const Uint32 theInstance;
995 const BlockReference theReference;
996 /*
997 * Instance 0 is the main instance. It creates/owns other instances.
998 * In MT LQH main instance is the LQH proxy and the others ("workers")
999 * are real LQHs run by multiple threads.
1000 */
1001 protected:
1002 enum { MaxInstances = NDBMT_MAX_BLOCK_INSTANCES };
1003 private:
1004 SimulatedBlock** theInstanceList; // set in main, indexed by instance
1005 SimulatedBlock* theMainInstance; // set in all
1006 /*
1007 Thread id currently executing this block.
1008 Not used in singlethreaded ndbd.
1009 */
1010 Uint32 m_threadId;
1011 /*
1012 Jam buffer reference.
1013 In multithreaded ndbd, this is different in each thread, and must be
1014 updated if migrating the block to another thread.
1015 */
1016 EmulatedJamBuffer *m_jamBuffer;
1017 /* For multithreaded ndb, the thread-specific watchdog counter. */
1018 Uint32 *m_watchDogCounter;
1019
1020 SectionSegmentPool::Cache * m_sectionPoolCache;
1021
1022
1023 Uint32 doNodeFailureCleanup(Signal* signal,
1024 Uint32 failedNodeId,
1025 Uint32 resource,
1026 Uint32 cursor,
1027 Uint32 elementsCleaned,
1028 Callback& cb);
1029
1030 bool doCleanupFragInfo(Uint32 failedNodeId,
1031 Uint32& cursor,
1032 Uint32& rtUnitsUsed,
1033 Uint32& elementsCleaned);
1034
1035 bool doCleanupFragSend(Uint32 failedNodeId,
1036 Uint32& cursor,
1037 Uint32& rtUnitsUsed,
1038 Uint32& elementsCleaned);
1039
1040 protected:
1041 Block_context m_ctx;
1042 NewVARIABLE* allocateBat(int batSize);
1043 void freeBat();
1044 static const NewVARIABLE* getBat (BlockNumber blockNo,
1045 Uint32 instanceNo);
1046 static Uint16 getBatSize(BlockNumber blockNo,
1047 Uint32 instanceNo);
1048
1049 static BlockReference calcTcBlockRef (NodeId aNode);
1050 static BlockReference calcLqhBlockRef (NodeId aNode);
1051 static BlockReference calcAccBlockRef (NodeId aNode);
1052 static BlockReference calcTupBlockRef (NodeId aNode);
1053 static BlockReference calcTuxBlockRef (NodeId aNode);
1054 static BlockReference calcDihBlockRef (NodeId aNode);
1055 static BlockReference calcQmgrBlockRef (NodeId aNode);
1056 static BlockReference calcDictBlockRef (NodeId aNode);
1057 static BlockReference calcNdbCntrBlockRef (NodeId aNode);
1058 static BlockReference calcTrixBlockRef (NodeId aNode);
1059 static BlockReference calcBackupBlockRef (NodeId aNode);
1060 static BlockReference calcSumaBlockRef (NodeId aNode);
1061
1062 static BlockReference calcApiClusterMgrBlockRef (NodeId aNode);
1063
1064 // matching instance on same node e.g. LQH-ACC-TUP
1065 BlockReference calcInstanceBlockRef(BlockNumber aBlock);
1066
1067 // matching instance on another node e.g. LQH-LQH
1068 // valid only if receiver has same number of workers
1069 BlockReference calcInstanceBlockRef(BlockNumber aBlock, NodeId aNode);
1070
1071 /**
1072 * allocRecord
1073 * Allocates memory for the datastructures where ndb keeps the data
1074 *
1075 */
1076 void* allocRecord(const char * type, size_t s, size_t n, bool clear = true, Uint32 paramId = 0);
1077 void* allocRecordAligned(const char * type, size_t s, size_t n, void **unaligned_buffer, Uint32 align = NDB_O_DIRECT_WRITE_ALIGNMENT, bool clear = true, Uint32 paramId = 0);
1078
1079 /**
1080 * Deallocate record
1081 *
1082 * NOTE: Also resets pointer
1083 */
1084 void deallocRecord(void **, const char * type, size_t s, size_t n);
1085
1086 /**
1087 * Allocate memory from global pool,
1088 * returns #chunks used
1089 *
1090 * Typically used by part of code, not converted to use global pool
1091 * directly, but allocates everything during startup
1092 */
1093 struct AllocChunk
1094 {
1095 Uint32 ptrI;
1096 Uint32 cnt;
1097 };
1098 Uint32 allocChunks(AllocChunk dst[], Uint32 /* size of dst */ arraysize,
1099 Uint32 /* resource group */ rg,
1100 Uint32 /* no of pages to allocate */ pages,
1101 Uint32 paramId /* for error message if failing */);
1102
1103 static int sortchunks(const void*, const void*);
1104
1105 /**
1106 * General info event (sent to cluster log)
1107 */
1108 void infoEvent(const char * msg, ...) const
1109 ATTRIBUTE_FORMAT(printf, 2, 3);
1110 void warningEvent(const char * msg, ...) const
1111 ATTRIBUTE_FORMAT(printf, 2, 3);
1112
1113 /**
1114 * Get node state
1115 */
1116 const NodeState & getNodeState() const;
1117
1118 /**
1119 * Get node info
1120 */
1121 const NodeInfo & getNodeInfo(NodeId nodeId) const;
1122 NodeInfo & setNodeInfo(NodeId);
1123
1124 const NodeVersionInfo& getNodeVersionInfo() const;
1125 NodeVersionInfo& setNodeVersionInfo();
1126
1127 /**********************
1128 * Xfrm stuff
1129 */
1130
1131 /**
1132 * @return length
1133 */
1134 Uint32 xfrm_key(Uint32 tab, const Uint32* src,
1135 Uint32 *dst, Uint32 dstSize,
1136 Uint32 keyPartLen[MAX_ATTRIBUTES_IN_INDEX]) const;
1137
1138 Uint32 xfrm_attr(Uint32 attrDesc, CHARSET_INFO* cs,
1139 const Uint32* src, Uint32 & srcPos,
1140 Uint32* dst, Uint32 & dstPos, Uint32 dstSize) const;
1141
1142 /**
1143 *
1144 */
1145 Uint32 create_distr_key(Uint32 tableId,
1146 const Uint32* src,
1147 Uint32 *dst,
1148 const Uint32 keyPaLen[MAX_ATTRIBUTES_IN_INDEX])const;
1149
1150 /**
1151 * if ndbd,
1152 * wakeup main-loop if sleeping on IO
1153 * if ndbmtd
1154 * wakeup thread running block-instance
1155 */
1156 void wakeup();
1157
1158 /**
1159 * setup struct for wakeup
1160 */
1161 void setup_wakeup();
1162
1163 /**
1164 * Get receiver thread index for node
1165 * MAX_NODES == no receiver thread
1166 */
1167 Uint32 get_recv_thread_idx(NodeId nodeId);
1168
1169 private:
1170 NewVARIABLE* NewVarRef; /* New Base Address Table for block */
1171 Uint16 theBATSize; /* # entries in BAT */
1172
1173 protected:
1174 SafeArrayPool<GlobalPage>& m_global_page_pool;
1175 ArrayPool<GlobalPage>& m_shared_page_pool;
1176
1177 void execNDB_TAMPER(Signal * signal);
1178 void execNODE_STATE_REP(Signal* signal);
1179 void execCHANGE_NODE_STATE_REQ(Signal* signal);
1180
1181 void execSIGNAL_DROPPED_REP(Signal* signal);
1182 void execCONTINUE_FRAGMENTED(Signal* signal);
1183 void execSTOP_FOR_CRASH(Signal* signal);
1184 void execAPI_START_REP(Signal* signal);
1185 void execNODE_START_REP(Signal* signal);
1186 void execSEND_PACKED(Signal* signal);
1187 void execLOCAL_ROUTE_ORD(Signal*);
1188 private:
1189 /**
1190 * Node state
1191 */
1192 NodeState theNodeState;
1193
1194 Uint32 c_fragmentIdCounter;
1195 ArrayPool<FragmentInfo> c_fragmentInfoPool;
1196 DLHashTable<FragmentInfo> c_fragmentInfoHash;
1197
1198 bool c_fragSenderRunning;
1199 ArrayPool<FragmentSendInfo> c_fragmentSendPool;
1200 DLList<FragmentSendInfo> c_linearFragmentSendList;
1201 DLList<FragmentSendInfo> c_segmentedFragmentSendList;
1202
1203 protected:
1204 Uint32 debugPrintFragmentCounts();
1205
1206 public:
1207 class MutexManager {
1208 friend class Mutex;
1209 friend class SimulatedBlock;
1210 friend class DbUtil;
1211 public:
1212 MutexManager(class SimulatedBlock &);
1213
1214 bool setSize(Uint32 maxNoOfActiveMutexes);
1215 Uint32 getSize() const ; // Get maxNoOfActiveMutexes
1216
1217 private:
1218 /**
1219 * core interface
1220 */
1221 struct ActiveMutex {
ActiveMutexSimulatedBlock::MutexManager::ActiveMutex1222 ActiveMutex() {}
1223 Uint32 m_gsn; // state
1224 Uint32 m_mutexId;
1225 Callback m_callback;
1226 union {
1227 Uint32 nextPool;
1228 Uint32 nextList;
1229 };
1230 Uint32 prevList;
1231 };
1232 typedef Ptr<ActiveMutex> ActiveMutexPtr;
1233
1234 bool seize(ActiveMutexPtr& ptr);
1235 void release(Uint32 activeMutexPtrI);
1236
1237 void getPtr(ActiveMutexPtr& ptr);
1238
1239 void create(Signal*, ActiveMutexPtr&);
1240 void destroy(Signal*, ActiveMutexPtr&);
1241 void lock(Signal*, ActiveMutexPtr&, Uint32 flags);
1242 void unlock(Signal*, ActiveMutexPtr&);
1243
1244 private:
1245 void execUTIL_CREATE_LOCK_REF(Signal* signal);
1246 void execUTIL_CREATE_LOCK_CONF(Signal* signal);
1247 void execUTIL_DESTORY_LOCK_REF(Signal* signal);
1248 void execUTIL_DESTORY_LOCK_CONF(Signal* signal);
1249 void execUTIL_LOCK_REF(Signal* signal);
1250 void execUTIL_LOCK_CONF(Signal* signal);
1251 void execUTIL_UNLOCK_REF(Signal* signal);
1252 void execUTIL_UNLOCK_CONF(Signal* signal);
1253
1254 SimulatedBlock & m_block;
1255 ArrayPool<ActiveMutex> m_mutexPool;
1256 DLList<ActiveMutex> m_activeMutexes;
1257
1258 BlockReference reference() const;
1259 void progError(int line,
1260 int err_code,
1261 const char* extra = 0) ATTRIBUTE_NORETURN;
1262 };
1263
1264 friend class MutexManager;
1265 MutexManager c_mutexMgr;
1266
1267 void ignoreMutexUnlockCallback(Signal* signal, Uint32 ptrI, Uint32 retVal);
getParam(const char * param,Uint32 * retVal)1268 virtual bool getParam(const char * param, Uint32 * retVal) { return false;}
1269
1270 SafeCounterManager c_counterMgr;
1271 private:
1272 void execUTIL_CREATE_LOCK_REF(Signal* signal);
1273 void execUTIL_CREATE_LOCK_CONF(Signal* signal);
1274 void execUTIL_DESTORY_LOCK_REF(Signal* signal);
1275 void execUTIL_DESTORY_LOCK_CONF(Signal* signal);
1276 void execUTIL_LOCK_REF(Signal* signal);
1277 void execUTIL_LOCK_CONF(Signal* signal);
1278 void execUTIL_UNLOCK_REF(Signal* signal);
1279 void execUTIL_UNLOCK_CONF(Signal* signal);
1280
1281 void check_sections(Signal* signal,
1282 Uint32 oldSecCount,
1283 Uint32 newSecCount) const;
1284 protected:
1285
1286 void fsRefError(Signal* signal, Uint32 line, const char *msg);
1287 void execFSWRITEREF(Signal* signal);
1288 void execFSREADREF(Signal* signal);
1289 void execFSOPENREF(Signal* signal);
1290 void execFSCLOSEREF(Signal* signal);
1291 void execFSREMOVEREF(Signal* signal);
1292 void execFSSYNCREF(Signal* signal);
1293 void execFSAPPENDREF(Signal* signal);
1294
1295 // MT LQH callback CONF via signal
1296 public:
1297 struct CallbackPtr {
1298 Uint32 m_callbackIndex;
1299 Uint32 m_callbackData;
1300 };
1301 protected:
1302 enum CallbackFlags {
1303 CALLBACK_DIRECT = 0x0001, // use EXECUTE_DIRECT (assumed thread safe)
1304 CALLBACK_ACK = 0x0002 // send ack at the end of callback timeslice
1305 };
1306
1307 struct CallbackEntry {
1308 CallbackFunction m_function;
1309 Uint32 m_flags;
1310 };
1311
1312 struct CallbackTable {
1313 Uint32 m_count;
1314 CallbackEntry* m_entry; // array
1315 };
1316
1317 CallbackTable* m_callbackTableAddr; // set by block if used
1318
1319 enum {
1320 THE_NULL_CALLBACK = 0 // must assign TheNULLCallbackFunction
1321 };
1322
1323 void execute(Signal* signal, CallbackPtr & cptr, Uint32 returnCode);
1324 const CallbackEntry& getCallbackEntry(Uint32 ci);
1325 void sendCallbackConf(Signal* signal, Uint32 fullBlockNo,
1326 CallbackPtr& cptr,
1327 Uint32 senderData, Uint32 callbackInfo,
1328 Uint32 returnCode);
1329 void execCALLBACK_CONF(Signal* signal);
1330
1331 // Variable for storing inserted errors, see pc.H
1332 ERROR_INSERT_VARIABLE;
1333
1334 #ifdef VM_TRACE_TIME
1335 public:
1336 void clearTimes();
1337 void printTimes(FILE * output);
1338 void addTime(Uint32 gsn, Uint64 time);
1339 void subTime(Uint32 gsn, Uint64 time);
1340 struct TimeTrace {
1341 Uint32 cnt;
1342 Uint64 sum, sub;
1343 } m_timeTrace[MAX_GSN+1];
1344 Uint32 m_currentGsn;
1345 #endif
1346
1347 #ifdef VM_TRACE
1348 Ptr<void> **m_global_variables, **m_global_variables_save;
1349 void clear_global_variables();
1350 void init_globals_list(void ** tmp, size_t cnt);
1351 void disable_global_variables();
1352 void enable_global_variables();
1353 #endif
1354
1355 #ifdef VM_TRACE
1356 public:
1357 NdbOut debugOut;
debugOutStream()1358 NdbOut& debugOutStream() { return debugOut; };
1359 bool debugOutOn();
debugOutLock()1360 void debugOutLock() { globalSignalLoggers.lock(); }
debugOutUnlock()1361 void debugOutUnlock() { globalSignalLoggers.unlock(); }
1362 const char* debugOutTag(char* buf, int line);
1363 #endif
1364
1365 void ndbinfo_send_row(Signal* signal,
1366 const DbinfoScanReq& req,
1367 const Ndbinfo::Row& row,
1368 Ndbinfo::Ratelimit& rl) const;
1369
1370 void ndbinfo_send_scan_break(Signal* signal,
1371 DbinfoScanReq& req,
1372 const Ndbinfo::Ratelimit& rl,
1373 Uint32 data1, Uint32 data2 = 0,
1374 Uint32 data3 = 0, Uint32 data4 = 0) const;
1375
1376 void ndbinfo_send_scan_conf(Signal* signal,
1377 DbinfoScanReq& req,
1378 const Ndbinfo::Ratelimit& rl) const;
1379
1380
1381 protected:
1382 /**
1383 * SegmentUtils methods
1384 */
1385 virtual SectionSegment* getSegmentPtr(Uint32 iVal);
1386 virtual bool seizeSegment(Ptr<SectionSegment>& p);
1387 virtual void releaseSegment(Uint32 iVal);
1388
1389 virtual void releaseSegmentList(Uint32 firstSegmentIVal);
1390
1391 /** End of SegmentUtils methods */
1392 };
1393
1394 // outside blocks e.g. within a struct
1395 #ifdef VM_TRACE
1396 #define DEBUG_OUT_DEFINES(blockNo) \
1397 static SimulatedBlock* debugOutBlock() \
1398 { return globalData.getBlock(blockNo); } \
1399 static NdbOut& debugOutStream() \
1400 { return debugOutBlock()->debugOutStream(); } \
1401 static bool debugOutOn() \
1402 { return debugOutBlock()->debugOutOn(); } \
1403 static void debugOutLock() \
1404 { debugOutBlock()->debugOutLock(); } \
1405 static void debugOutUnlock() \
1406 { debugOutBlock()->debugOutUnlock(); } \
1407 static const char* debugOutTag(char* buf, int line) \
1408 { return debugOutBlock()->debugOutTag(buf, line); } \
1409 static void debugOutDefines()
1410 #else
1411 #define DEBUG_OUT_DEFINES(blockNo) \
1412 static void debugOutDefines()
1413 #endif
1414
1415 inline
1416 void
executeFunction(GlobalSignalNumber gsn,Signal * signal)1417 SimulatedBlock::executeFunction(GlobalSignalNumber gsn,
1418 Signal *signal)
1419 {
1420 ExecFunction f = theExecArray[gsn];
1421 if (unlikely(gsn > MAX_GSN))
1422 {
1423 handle_execute_error(gsn);
1424 return;
1425 }
1426 executeFunction(gsn, signal, f);
1427 }
1428
1429 inline
1430 void
executeFunction_async(GlobalSignalNumber gsn,Signal * signal)1431 SimulatedBlock::executeFunction_async(GlobalSignalNumber gsn,
1432 Signal *signal)
1433 {
1434 ExecFunction f = theExecArray[gsn];
1435 #ifdef VM_TRACE
1436 clear_global_variables();
1437 #endif
1438 if (unlikely(gsn > MAX_GSN))
1439 {
1440 handle_execute_error(gsn);
1441 return;
1442 }
1443 executeFunction(gsn, signal, f);
1444 }
1445
1446 inline
1447 void
executeFunction(GlobalSignalNumber gsn,Signal * signal,ExecFunction f,BlockReference ref,Uint32 len)1448 SimulatedBlock::executeFunction(GlobalSignalNumber gsn,
1449 Signal* signal,
1450 ExecFunction f,
1451 BlockReference ref,
1452 Uint32 len)
1453 {
1454 if (unlikely(gsn > MAX_GSN))
1455 {
1456 handle_execute_error(gsn);
1457 return;
1458 }
1459 signal->setLength(len);
1460 signal->header.theSendersBlockRef = ref;
1461 executeFunction(gsn, signal, f);
1462 }
1463
1464 inline
1465 void
executeFunction(GlobalSignalNumber gsn,Signal * signal,ExecFunction f)1466 SimulatedBlock::executeFunction(GlobalSignalNumber gsn,
1467 Signal* signal,
1468 ExecFunction f)
1469 {
1470 if (likely(f != 0))
1471 {
1472 (this->*f)(signal);
1473
1474 if (unlikely(signal->header.m_noOfSections))
1475 {
1476 handle_lingering_sections_after_execute(signal);
1477 }
1478 return;
1479 }
1480 /**
1481 * This point only passed if an error has occurred
1482 */
1483 handle_execute_error(gsn);
1484 }
1485
1486 inline
1487 void
execute(Signal * signal,Callback & c,Uint32 returnCode)1488 SimulatedBlock::execute(Signal* signal, Callback & c, Uint32 returnCode){
1489 CallbackFunction fun = c.m_callbackFunction;
1490 if (fun == TheNULLCallback.m_callbackFunction)
1491 return;
1492 ndbrequire(fun != 0);
1493 c.m_callbackFunction = NULL;
1494 (this->*fun)(signal, c.m_callbackData, returnCode);
1495 }
1496
1497 inline
1498 void
execute(Signal * signal,CallbackPtr & cptr,Uint32 returnCode)1499 SimulatedBlock::execute(Signal* signal, CallbackPtr & cptr, Uint32 returnCode){
1500 const CallbackEntry& ce = getCallbackEntry(cptr.m_callbackIndex);
1501 cptr.m_callbackIndex = ZNIL;
1502 Callback c;
1503 c.m_callbackFunction = ce.m_function;
1504 c.m_callbackData = cptr.m_callbackData;
1505 execute(signal, c, returnCode);
1506 }
1507
1508 inline
1509 BlockNumber
number() const1510 SimulatedBlock::number() const {
1511 return theNumber;
1512 }
1513
1514 inline
1515 EmulatedJamBuffer *
jamBuffer() const1516 SimulatedBlock::jamBuffer() const {
1517 return m_jamBuffer;
1518 }
1519
1520 inline
1521 BlockReference
reference() const1522 SimulatedBlock::reference() const {
1523 return theReference;
1524 }
1525
1526 inline
1527 NodeId
getOwnNodeId() const1528 SimulatedBlock::getOwnNodeId() const {
1529 return theNodeId;
1530 }
1531
1532 inline
1533 BlockReference
calcTcBlockRef(NodeId aNodeId)1534 SimulatedBlock::calcTcBlockRef (NodeId aNodeId){
1535 return numberToRef(DBTC, aNodeId);
1536 }
1537
1538 inline
1539 BlockReference
calcLqhBlockRef(NodeId aNodeId)1540 SimulatedBlock::calcLqhBlockRef (NodeId aNodeId){
1541 return numberToRef(DBLQH, aNodeId);
1542 }
1543
1544 inline
1545 BlockReference
calcAccBlockRef(NodeId aNodeId)1546 SimulatedBlock::calcAccBlockRef (NodeId aNodeId){
1547 return numberToRef(DBACC, aNodeId);
1548 }
1549
1550 inline
1551 BlockReference
calcTupBlockRef(NodeId aNodeId)1552 SimulatedBlock::calcTupBlockRef (NodeId aNodeId){
1553 return numberToRef(DBTUP, aNodeId);
1554 }
1555
1556 inline
1557 BlockReference
calcTuxBlockRef(NodeId aNodeId)1558 SimulatedBlock::calcTuxBlockRef (NodeId aNodeId){
1559 return numberToRef(DBTUX, aNodeId);
1560 }
1561
1562 inline
1563 BlockReference
calcDihBlockRef(NodeId aNodeId)1564 SimulatedBlock::calcDihBlockRef (NodeId aNodeId){
1565 return numberToRef(DBDIH, aNodeId);
1566 }
1567
1568 inline
1569 BlockReference
calcDictBlockRef(NodeId aNodeId)1570 SimulatedBlock::calcDictBlockRef (NodeId aNodeId){
1571 return numberToRef(DBDICT, aNodeId);
1572 }
1573
1574 inline
1575 BlockReference
calcQmgrBlockRef(NodeId aNodeId)1576 SimulatedBlock::calcQmgrBlockRef (NodeId aNodeId){
1577 return numberToRef(QMGR, aNodeId);
1578 }
1579
1580 inline
1581 BlockReference
calcNdbCntrBlockRef(NodeId aNodeId)1582 SimulatedBlock::calcNdbCntrBlockRef (NodeId aNodeId){
1583 return numberToRef(NDBCNTR, aNodeId);
1584 }
1585
1586 inline
1587 BlockReference
calcTrixBlockRef(NodeId aNodeId)1588 SimulatedBlock::calcTrixBlockRef (NodeId aNodeId){
1589 return numberToRef(TRIX, aNodeId);
1590 }
1591
1592 inline
1593 BlockReference
calcBackupBlockRef(NodeId aNodeId)1594 SimulatedBlock::calcBackupBlockRef (NodeId aNodeId){
1595 return numberToRef(BACKUP, aNodeId);
1596 }
1597
1598 inline
1599 BlockReference
calcSumaBlockRef(NodeId aNodeId)1600 SimulatedBlock::calcSumaBlockRef (NodeId aNodeId){
1601 return numberToRef(SUMA, aNodeId);
1602 }
1603
1604 inline
1605 BlockReference
calcApiClusterMgrBlockRef(NodeId aNodeId)1606 SimulatedBlock::calcApiClusterMgrBlockRef (NodeId aNodeId){
1607 return numberToRef(API_CLUSTERMGR, aNodeId);
1608 }
1609
1610 inline
1611 BlockReference
calcInstanceBlockRef(BlockNumber aBlock)1612 SimulatedBlock::calcInstanceBlockRef(BlockNumber aBlock){
1613 return numberToRef(aBlock, instance(), getOwnNodeId());
1614 }
1615
1616 inline
1617 BlockReference
calcInstanceBlockRef(BlockNumber aBlock,NodeId aNodeId)1618 SimulatedBlock::calcInstanceBlockRef(BlockNumber aBlock, NodeId aNodeId){
1619 return numberToRef(aBlock, instance(), aNodeId);
1620 }
1621
1622 inline
1623 const NodeState &
getNodeState() const1624 SimulatedBlock::getNodeState() const {
1625 return theNodeState;
1626 }
1627
1628 inline
1629 const NodeInfo &
getNodeInfo(NodeId nodeId) const1630 SimulatedBlock::getNodeInfo(NodeId nodeId) const {
1631 ndbrequire(nodeId > 0 && nodeId < MAX_NODES);
1632 return globalData.m_nodeInfo[nodeId];
1633 }
1634
1635 inline
1636 const NodeVersionInfo &
getNodeVersionInfo() const1637 SimulatedBlock::getNodeVersionInfo() const {
1638 return globalData.m_versionInfo;
1639 }
1640
1641 inline
1642 NodeVersionInfo &
setNodeVersionInfo()1643 SimulatedBlock::setNodeVersionInfo() {
1644 return globalData.m_versionInfo;
1645 }
1646
1647 #ifdef VM_TRACE_TIME
1648 inline
1649 void
addTime(Uint32 gsn,Uint64 time)1650 SimulatedBlock::addTime(Uint32 gsn, Uint64 time){
1651 m_timeTrace[gsn].cnt ++;
1652 m_timeTrace[gsn].sum += time;
1653 }
1654
1655 inline
1656 void
subTime(Uint32 gsn,Uint64 time)1657 SimulatedBlock::subTime(Uint32 gsn, Uint64 time){
1658 m_timeTrace[gsn].sub += time;
1659 }
1660 #endif
1661
1662 inline
1663 void
EXECUTE_DIRECT(ExecFunction f,Signal * signal)1664 SimulatedBlock::EXECUTE_DIRECT(ExecFunction f,
1665 Signal *signal)
1666 {
1667 (this->*f)(signal);
1668 }
1669
1670 inline
1671 void
EXECUTE_DIRECT(Uint32 block,Uint32 gsn,Signal * signal,Uint32 len,Uint32 instanceNo)1672 SimulatedBlock::EXECUTE_DIRECT(Uint32 block,
1673 Uint32 gsn,
1674 Signal* signal,
1675 Uint32 len,
1676 Uint32 instanceNo)
1677 {
1678 SimulatedBlock* rec_block;
1679 SimulatedBlock* main_block = globalData.getBlock(block);
1680 ndbassert(main_block != 0);
1681 /**
1682 * In multithreaded NDB, blocks run in different threads, and EXECUTE_DIRECT
1683 * (unlike sendSignal) is generally not thread-safe.
1684 * So only allow EXECUTE_DIRECT between blocks that run in the same thread,
1685 * unless caller explicitly marks it as being thread safe (eg NDBFS),
1686 * by using an explicit instance argument.
1687 * By default instance of sender is used. This is automatically thread-safe
1688 * for worker instances (instance != 0).
1689 *
1690 * We also need to use this function when calling blocks that don't belong
1691 * to the same module, so e.g. LDM blocks can all call each other without
1692 * using this method. But e.g. no block can call THRMAN using implicit
1693 * instance id since the instance numbers of the LDM blocks and the THRMAN
1694 * blocks are not the same. There is one THRMAN instance for each thread,
1695 * not only for the LDM threads.
1696 */
1697 signal->header.theSendersBlockRef = reference();
1698 signal->setLength(len);
1699 ndbassert(instanceNo < MaxInstances);
1700 rec_block = main_block->getInstance(instanceNo);
1701 ndbassert(rec_block != 0);
1702 #ifdef VM_TRACE
1703 if(globalData.testOn){
1704 signal->header.theVerId_signalNumber = gsn;
1705 signal->header.theReceiversBlockNumber = numberToBlock(block, instanceNo);
1706 globalSignalLoggers.executeDirect(signal->header,
1707 0, // in
1708 &signal->theData[0],
1709 globalData.ownId);
1710 }
1711 #endif
1712 #ifdef VM_TRACE_TIME
1713 const NDB_TICKS t1 = NdbTick_getCurrentTicks();
1714 Uint32 tGsn = m_currentGsn;
1715 rec_block->m_currentGsn = gsn;
1716 #endif
1717 rec_block->executeFunction(gsn, signal);
1718 #ifdef VM_TRACE_TIME
1719 const NDB_TICKS t2 = NdbTick_getCurrentTicks();
1720 const Uint64 diff = NdbTick_Elapsed(t1, t2).microSec();
1721 rec_block->addTime(gsn, diff);
1722 m_currentGsn = tGsn;
1723 subTime(tGsn, diff);
1724 #endif
1725 }
1726
1727 /**
1728 We implement the normal EXECUTE_DIRECT in a special function
1729 since this is performance-critical although it introduces a
1730 little bit of code duplication.
1731 */
1732 inline
1733 void
EXECUTE_DIRECT(Uint32 block,Uint32 gsn,Signal * signal,Uint32 len)1734 SimulatedBlock::EXECUTE_DIRECT(Uint32 block,
1735 Uint32 gsn,
1736 Signal* signal,
1737 Uint32 len)
1738 {
1739 /**
1740 globalData.getBlock(block) gives us the pointer to the block of
1741 the receiving class, it gives the pointer to instance 0. This
1742 instance has all the function pointers that all other instances
1743 also have, so we can reuse this block object to get the execute
1744 function. This means that we will use less cache lines over the
1745 system.
1746 */
1747 SimulatedBlock* main_block = globalData.getBlock(block);
1748 Uint32 instanceNo = instance();
1749 BlockReference ref = reference();
1750 SimulatedBlock* rec_block;
1751 signal->setLength(len);
1752 ndbassert(main_block != 0);
1753 ndbassert(main_block->theInstance == 0);
1754 ndbassert(instanceNo < MaxInstances);
1755 rec_block = main_block->theInstanceList[instanceNo];
1756 if (unlikely(gsn > MAX_GSN))
1757 {
1758 handle_execute_error(gsn);
1759 return;
1760 }
1761 ExecFunction f = rec_block->theExecArray[gsn];
1762 signal->header.theSendersBlockRef = ref;
1763 /**
1764 * In this function we only allow function calls within the same thread.
1765 *
1766 * No InstanceList leads to immediate Segmentation Fault,
1767 * so not necessary to check with ndbrequire for this.
1768 */
1769 ndbassert(rec_block != 0);
1770 ndbassert(rec_block->getThreadId() == getThreadId());
1771 #ifdef VM_TRACE
1772 if(globalData.testOn){
1773 signal->header.theVerId_signalNumber = gsn;
1774 signal->header.theReceiversBlockNumber = numberToBlock(block, instanceNo);
1775 globalSignalLoggers.executeDirect(signal->header,
1776 0, // in
1777 &signal->theData[0],
1778 globalData.ownId);
1779 }
1780 #endif
1781 #ifdef VM_TRACE_TIME
1782 const NDB_TICKS t1 = NdbTick_getCurrentTicks();
1783 Uint32 tGsn = m_currentGsn;
1784 rec_block->m_currentGsn = gsn;
1785 #endif
1786 rec_block->executeFunction(gsn, signal, f);
1787 #ifdef VM_TRACE_TIME
1788 const NDB_TICKS t2 = NdbTick_getCurrentTicks();
1789 const Uint64 diff = NdbTick_Elapsed(t1,t2).microSec();
1790 rec_block->addTime(gsn, diff);
1791 m_currentGsn = tGsn;
1792 subTime(tGsn, diff);
1793 #endif
1794 }
1795
1796 // Do a consictency check before reusing a signal.
1797 inline void
check_sections(Signal * signal,Uint32 oldSecCount,Uint32 newSecCount) const1798 SimulatedBlock::check_sections(Signal* signal,
1799 Uint32 oldSecCount,
1800 Uint32 newSecCount) const
1801 {
1802 // Sections from previous use should have been consumed by now.
1803 if (unlikely(oldSecCount != 0))
1804 {
1805 handle_invalid_sections_in_send_signal(signal);
1806 }
1807 else if (unlikely(newSecCount == 0 &&
1808 signal->header.m_fragmentInfo != 0 &&
1809 signal->header.m_fragmentInfo != 3))
1810 {
1811 handle_invalid_fragmentInfo(signal);
1812 }
1813 }
1814
1815 /**
1816 * Defines for backward compatiblility
1817 */
1818
1819 #define BLOCK_DEFINES(BLOCK) \
1820 typedef void (BLOCK::* ExecSignalLocal) (Signal* signal); \
1821 typedef void (BLOCK::* BlockCallback)(Signal*, Uint32 callb, Uint32 retCode); \
1822 inline CallbackFunction safe_cast(BlockCallback f){ \
1823 return static_cast<CallbackFunction>(f); \
1824 } \
1825 public:\
1826 private: \
1827 void addRecSignal(GlobalSignalNumber gsn, ExecSignalLocal f, bool force = false)
1828
1829 #define BLOCK_CONSTRUCTOR(BLOCK) do { SimulatedBlock::initCommon(); } while(0)
1830
1831 #define BLOCK_FUNCTIONS(BLOCK) \
1832 void \
1833 BLOCK::addRecSignal(GlobalSignalNumber gsn, ExecSignalLocal f, bool force){ \
1834 addRecSignalImpl(gsn, (ExecFunction)f, force);\
1835 }
1836
1837 #ifdef ERROR_INSERT
1838 #define RSS_AP_SNAPSHOT(x) Uint32 rss_##x
1839 #define RSS_AP_SNAPSHOT_SAVE(x) rss_##x = x.getNoOfFree()
1840 #define RSS_AP_SNAPSHOT_CHECK(x) ndbrequire(rss_##x == x.getNoOfFree())
1841 #define RSS_AP_SNAPSHOT_SAVE2(x,y) rss_##x = x.getNoOfFree()+(y)
1842 #define RSS_AP_SNAPSHOT_CHECK2(x,y) ndbrequire(rss_##x == x.getNoOfFree()+(y))
1843
1844 #define RSS_OP_COUNTER(x) Uint32 x
1845 #define RSS_OP_COUNTER_INIT(x) x = 0
1846 #define RSS_OP_ALLOC(x) x ++
1847 #define RSS_OP_FREE(x) x --
1848 #define RSS_OP_ALLOC_X(x,n) x += n
1849 #define RSS_OP_FREE_X(x,n) x -= n
1850
1851 #define RSS_OP_SNAPSHOT(x) Uint32 rss_##x
1852 #define RSS_OP_SNAPSHOT_SAVE(x) rss_##x = x
1853 #define RSS_OP_SNAPSHOT_CHECK(x) ndbrequire(rss_##x == x)
1854
1855 #define RSS_DA256_SNAPSHOT(x) Uint32 rss_##x
1856 #define RSS_DA256_SNAPSHOT_SAVE(x) rss_##x = x.m_high_pos
1857 #define RSS_DA256_SNAPSHOT_CHECK(x) ndbrequire(x.m_high_pos <= rss_##x)
1858 #else
1859 #define RSS_AP_SNAPSHOT(x) struct rss_dummy0_##x { int dummy; }
1860 #define RSS_AP_SNAPSHOT_SAVE(x)
1861 #define RSS_AP_SNAPSHOT_CHECK(x)
1862 #define RSS_AP_SNAPSHOT_SAVE2(x,y)
1863 #define RSS_AP_SNAPSHOT_CHECK2(x,y)
1864
1865 #define RSS_OP_COUNTER(x) struct rss_dummy1_##x { int dummy; }
1866 #define RSS_OP_COUNTER_INIT(x)
1867 #define RSS_OP_ALLOC(x)
1868 #define RSS_OP_FREE(x)
1869 #define RSS_OP_ALLOC_X(x,n)
1870 #define RSS_OP_FREE_X(x,n)
1871
1872 #define RSS_OP_SNAPSHOT(x) struct rss_dummy2_##x { int dummy; }
1873 #define RSS_OP_SNAPSHOT_SAVE(x)
1874 #define RSS_OP_SNAPSHOT_CHECK(x)
1875
1876 #define RSS_DA256_SNAPSHOT(x)
1877 #define RSS_DA256_SNAPSHOT_SAVE(x)
1878 #define RSS_DA256_SNAPSHOT_CHECK(x)
1879 #endif
1880
1881 struct Hash2FragmentMap
1882 {
1883 STATIC_CONST( MAX_MAP = NDB_MAX_HASHMAP_BUCKETS );
1884 Uint32 m_cnt;
1885 Uint32 m_fragments;
1886 Uint16 m_map[MAX_MAP];
1887 Uint32 nextPool;
1888 Uint32 m_object_id;
1889 };
1890
1891 extern ArrayPool<Hash2FragmentMap> g_hash_map;
1892
1893 /**
1894 * Guard class for auto release of segmentedsectionptr's
1895 */
1896 class SegmentedSectionGuard
1897 {
1898 Uint32 cnt;
1899 Uint32 ptr[3];
1900 SimulatedBlock * block;
1901
1902 public:
SegmentedSectionGuard(SimulatedBlock * b)1903 SegmentedSectionGuard(SimulatedBlock* b) : cnt(0), block(b) { }
SegmentedSectionGuard(SimulatedBlock * b,Uint32 ptrI)1904 SegmentedSectionGuard(SimulatedBlock* b, Uint32 ptrI) : cnt(1), block(b) {
1905 ptr[0] = ptrI;
1906 }
1907
add(Uint32 ptrI)1908 void add(Uint32 ptrI) {
1909 if (ptrI != RNIL)
1910 {
1911 assert(cnt < NDB_ARRAY_SIZE(ptr));
1912 ptr[cnt] = ptrI;
1913 cnt++;
1914 }
1915 }
1916
release()1917 void release() {
1918 for (Uint32 i = 0; i < cnt; i++) {
1919 if (ptr[i] != RNIL)
1920 block->releaseSection(ptr[i]);
1921 }
1922 cnt = 0;
1923 }
1924
clear()1925 void clear() {
1926 cnt = 0;
1927 }
1928
~SegmentedSectionGuard()1929 ~SegmentedSectionGuard() {
1930 release();
1931 }
1932 };
1933
1934 #undef JAM_FILE_ID
1935
1936 #endif
1937
1938