1 /*
2    Copyright (c) 2003, 2015, 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 #define DBLQH_C
26 #include "Dblqh.hpp"
27 #include <ndb_limits.h>
28 #include <md5_hash.hpp>
29 
30 #include <ndb_version.h>
31 #include <signaldata/NodeRecoveryStatusRep.hpp>
32 #include <signaldata/TuxBound.hpp>
33 #include <signaldata/AccScan.hpp>
34 #include <signaldata/CopyActive.hpp>
35 #include <signaldata/CopyFrag.hpp>
36 #include <signaldata/CreateTrigImpl.hpp>
37 #include <signaldata/DropTrigImpl.hpp>
38 #include <signaldata/EmptyLcp.hpp>
39 #include <signaldata/EventReport.hpp>
40 #include <signaldata/ExecFragReq.hpp>
41 #include <signaldata/GCP.hpp>
42 #include <signaldata/TcKeyRef.hpp>
43 #include <signaldata/LqhKey.hpp>
44 #include <signaldata/NextScan.hpp>
45 #include <signaldata/NFCompleteRep.hpp>
46 #include <signaldata/NodeFailRep.hpp>
47 #include <signaldata/ReadNodesConf.hpp>
48 #include <signaldata/RelTabMem.hpp>
49 #include <signaldata/ScanFrag.hpp>
50 #include <signaldata/SrFragidConf.hpp>
51 #include <signaldata/StartFragReq.hpp>
52 #include <signaldata/StartRec.hpp>
53 #include <signaldata/TupKey.hpp>
54 #include <signaldata/TupCommit.hpp>
55 #include <signaldata/LqhFrag.hpp>
56 #include <signaldata/AccFrag.hpp>
57 #include <signaldata/TupFrag.hpp>
58 #include <signaldata/DumpStateOrd.hpp>
59 #include <signaldata/PackedSignal.hpp>
60 #include <signaldata/LqhTransReq.hpp>
61 
62 #include <signaldata/CreateTab.hpp>
63 #include <signaldata/CreateTable.hpp>
64 #include <signaldata/PrepDropTab.hpp>
65 #include <signaldata/DropTab.hpp>
66 #include <signaldata/DropTable.hpp>
67 
68 #include <signaldata/AlterTab.hpp>
69 #include <signaldata/AlterTable.hpp>
70 #include <signaldata/DictTabInfo.hpp>
71 
72 #include <signaldata/LCP.hpp>
73 #include <DebuggerNames.hpp>
74 #include <signaldata/BackupImpl.hpp>
75 #include <signaldata/RestoreImpl.hpp>
76 #include <signaldata/KeyInfo.hpp>
77 #include <signaldata/AttrInfo.hpp>
78 #include <signaldata/TransIdAI.hpp>
79 #include <KeyDescriptor.hpp>
80 #include <signaldata/RouteOrd.hpp>
81 #include <signaldata/FsRef.hpp>
82 #include <SectionReader.hpp>
83 #include <signaldata/SignalDroppedRep.hpp>
84 #include <signaldata/FsReadWriteReq.hpp>
85 #include <signaldata/DbinfoScan.hpp>
86 #include <signaldata/SystemError.hpp>
87 #include <signaldata/FireTrigOrd.hpp>
88 #include <signaldata/IsolateOrd.hpp>
89 #include <NdbEnv.h>
90 #include <Checksum.hpp>
91 
92 #include "../suma/Suma.hpp"
93 #include "DblqhCommon.hpp"
94 
95 /**
96  * overload handling...
97  * TODO: cleanup...from all sorts of perspective
98  */
99 #include <TransporterRegistry.hpp>
100 
101 #include <EventLogger.hpp>
102 extern EventLogger * g_eventLogger;
103 
104 // Use DEBUG to print messages that should be
105 // seen only when we debug the product
106 #ifdef VM_TRACE
107 #define DEBUG(x) ndbout << "DBLQH: "<< x << endl;
108 static
109 NdbOut &
operator <<(NdbOut & out,Dblqh::TcConnectionrec::TransactionState state)110 operator<<(NdbOut& out, Dblqh::TcConnectionrec::TransactionState state){
111   out << (int)state;
112   return out;
113 }
114 
115 static
116 NdbOut &
operator <<(NdbOut & out,Dblqh::TcConnectionrec::LogWriteState state)117 operator<<(NdbOut& out, Dblqh::TcConnectionrec::LogWriteState state){
118   out << (int)state;
119   return out;
120 }
121 
122 static
123 NdbOut &
operator <<(NdbOut & out,Dblqh::TcConnectionrec::AbortState state)124 operator<<(NdbOut& out, Dblqh::TcConnectionrec::AbortState state){
125   out << (int)state;
126   return out;
127 }
128 
129 static
130 NdbOut &
operator <<(NdbOut & out,Dblqh::ScanRecord::ScanState state)131 operator<<(NdbOut& out, Dblqh::ScanRecord::ScanState state){
132   out << (int)state;
133   return out;
134 }
135 
136 static
137 NdbOut &
operator <<(NdbOut & out,Dblqh::LogFileOperationRecord::LfoState state)138 operator<<(NdbOut& out, Dblqh::LogFileOperationRecord::LfoState state){
139   out << (int)state;
140   return out;
141 }
142 
143 static
144 NdbOut &
operator <<(NdbOut & out,Dblqh::ScanRecord::ScanType state)145 operator<<(NdbOut& out, Dblqh::ScanRecord::ScanType state){
146   out << (int)state;
147   return out;
148 }
149 
150 static
151 NdbOut &
operator <<(NdbOut & out,Operation_t op)152 operator<<(NdbOut& out, Operation_t op)
153 {
154   switch(op){
155   case ZREAD: out << "READ"; break;
156   case ZREAD_EX: out << "READ-EX"; break;
157   case ZINSERT: out << "INSERT"; break;
158   case ZUPDATE: out << "UPDATE"; break;
159   case ZDELETE: out << "DELETE"; break;
160   case ZWRITE: out << "WRITE"; break;
161   case ZUNLOCK: out << "UNLOCK"; break;
162   case ZREFRESH: out << "REFRESH"; break;
163   }
164   return out;
165 }
166 
167 #else
168 #define DEBUG(x)
169 #endif
170 
171 //#define MARKER_TRACE 0
172 //#define TRACE_SCAN_TAKEOVER 1
173 
174 #ifdef VM_TRACE
175 #ifndef NDB_DEBUG_REDO
176 #define NDB_DEBUG_REDO
177 #endif
178 #endif
179 
180 #ifdef NDB_DEBUG_REDO
181 static int DEBUG_REDO = 0;
182 #else
183 #define DEBUG_REDO 0
184 #endif
185 
186 /**
187  * System reserved scan ids. Scan ids 0-11 are specific for ACC scans.
188  * Scan ids from 12 and up to a maximum of 133 (configurable) are used
189  * for TUX range scans and finally scan ids of from last TUX range scan
190  * id up to a maximum of 252 is used for TUP full table scans. Scan ids
191  * 253, 254 and 255 are reserved for LCP scans, Backup scans and NR scans.
192  */
193 const Uint32 NR_ScanNo = 253;
194 const Uint32 LCP_ScanNo = 254;
195 const Uint32 Backup_ScanNo = 255;
196 
197 #ifndef NDBD_TRACENR
198 #if defined VM_TRACE
199 #define NDBD_TRACENR
200 #endif
201 #endif
202 
203 #ifdef NDBD_TRACENR
204 #include <NdbConfig.h>
205 static NdbOut * tracenrout = 0;
206 static int TRACENR_FLAG = 0;
207 #define TRACENR(x) (* tracenrout) << x
208 #define SET_TRACENR_FLAG TRACENR_FLAG = 1
209 #define CLEAR_TRACENR_FLAG TRACENR_FLAG = 0
210 #else
211 #define TRACENR_FLAG 0
212 #define TRACENR(x) do { } while(0)
213 #define SET_TRACENR_FLAG
214 #define CLEAR_TRACENR_FLAG
215 #endif
216 
217 #define JAM_FILE_ID 451
218 
219 
220 #ifdef NDBD_TRACENR
221 static NdbOut * traceopout = 0;
222 #define TRACE_OP(regTcPtr, place) do { if (TRACE_OP_CHECK(regTcPtr)) TRACE_OP_DUMP(regTcPtr, place); } while(0)
223 #else
224 #define TRACE_OP(x, y) { (void)x;}
225 #endif
226 
227 struct LogPosition
228 {
229   Uint32 m_file_no;
230   Uint32 m_mbyte;
231 };
232 
233 int
cmp(const LogPosition & pos1,const LogPosition & pos2)234 cmp(const LogPosition& pos1, const LogPosition& pos2)
235 {
236   if (pos1.m_file_no > pos2.m_file_no)
237     return 1;
238   if (pos1.m_file_no < pos2.m_file_no)
239     return -1;
240   if (pos1.m_mbyte > pos2.m_mbyte)
241     return 1;
242   if (pos1.m_mbyte < pos2.m_mbyte)
243     return -1;
244 
245   return 0;
246 }
247 
248 /**
249  * head - tail
250  */
251 static
252 Uint64
free_log(const LogPosition & head,const LogPosition & tail,Uint32 cnt,Uint32 size)253 free_log(const LogPosition& head, const LogPosition& tail,
254          Uint32 cnt, Uint32 size)
255 {
256   Uint64 headmb = head.m_file_no*Uint64(size) + head.m_mbyte;
257   Uint64 tailmb = tail.m_file_no*Uint64(size) + tail.m_mbyte;
258   if (headmb >= tailmb)
259   {
260     return (cnt * Uint64(size)) - headmb + tailmb;
261   }
262   else
263   {
264     return tailmb - headmb;
265   }
266 }
267 
268 /* ------------------------------------------------------------------------- */
269 /* -------               SEND SYSTEM ERROR                           ------- */
270 /*                                                                           */
271 /* ------------------------------------------------------------------------- */
systemError(Signal * signal,int line)272 void Dblqh::systemError(Signal* signal, int line)
273 {
274   signal->theData[0] = 2304;
275   execDUMP_STATE_ORD(signal);
276   progError(line, NDBD_EXIT_NDBREQUIRE);
277 }//Dblqh::systemError()
278 
279 /* *************** */
280 /*  ACCSEIZEREF  > */
281 /* *************** */
execACCSEIZEREF(Signal * signal)282 void Dblqh::execACCSEIZEREF(Signal* signal)
283 {
284   jamEntry();
285   ndbrequire(false);
286 }//Dblqh::execACCSEIZEREF()
287 
288 /* ******************************************************>> */
289 /* THIS SIGNAL IS USED TO HANDLE REAL-TIME                  */
290 /* BREAKS THAT ARE NECESSARY TO ENSURE REAL-TIME            */
291 /* OPERATION OF LQH.                                        */
292 /* This signal is also used for signal loops, for example   */
293 /* the timeout handling for writing logs every second.      */
294 /* ******************************************************>> */
execCONTINUEB(Signal * signal)295 void Dblqh::execCONTINUEB(Signal* signal)
296 {
297   jamEntry();
298   Uint32 tcase = signal->theData[0];
299   Uint32 data0 = signal->theData[1];
300   Uint32 data1 = signal->theData[2];
301   Uint32 data2 = signal->theData[3];
302 #if 0
303   if (tcase == RNIL) {
304     tcConnectptr.i = data0;
305     ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
306     ndbout << "State = " << tcConnectptr.p->transactionState;
307     ndbout << " seqNoReplica = " << tcConnectptr.p->seqNoReplica;
308     ndbout << " tcNodeFailrec = " << tcConnectptr.p->tcNodeFailrec;
309     ndbout << " activeCreat = " << tcConnectptr.p->activeCreat;
310     ndbout << endl;
311     ndbout << "abortState = " << tcConnectptr.p->abortState;
312     ndbout << endl;
313     return;
314   }//if
315 #endif
316   LogPartRecordPtr save;
317   switch (tcase) {
318   case ZLOG_LQHKEYREQ:
319     if (cnoOfLogPages == 0) {
320       jam();
321   busywait:
322       sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 10, 2);
323       return;
324     }//if
325     logPartPtr.i = data0;
326     ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
327     save = logPartPtr;
328 
329     logPartPtr.p->LogLqhKeyReqSent = ZFALSE;
330 
331     if (logPartPtr.p->waitWriteGciLog == LogPartRecord::WWGL_TRUE)
332     {
333       jam();
334       goto startnext;
335     }
336     if (logPartPtr.p->m_log_complete_queue.isEmpty())
337     {
338       jam();
339       if (logPartPtr.p->m_log_prepare_queue.isEmpty())
340       {
341         /**
342          * We have already removed all entries from both queues (this can
343          * happen if aborts arrive and remove entries from the prepare
344          * queue). We stop checking the log queues until they fill up
345          * again.
346          */
347         jam();
348         return;
349       }
350       /**
351        * prepare is first in queue...check that it's ok to rock'n'roll
352        */
353       if (logPartPtr.p->m_log_problems != 0 ||
354           ERROR_INSERTED(5083))
355       {
356         /**
357          * It will be restarted when problems are cleared...
358          */
359         jam();
360         return;
361       }
362 
363       if (cnoOfLogPages < ZMIN_LOG_PAGES_OPERATION)
364       {
365         jam();
366         logPartPtr.p->LogLqhKeyReqSent = ZTRUE;
367         goto busywait;
368       }
369     }
370 
371     logFilePtr.i = logPartPtr.p->currentLogfile;
372     ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
373     logPagePtr.i = logFilePtr.p->currentLogpage;
374     ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
375 
376     getFirstInLogQueue(signal, tcConnectptr);
377     fragptr.i = tcConnectptr.p->fragmentptr;
378     c_fragment_pool.getPtr(fragptr);
379 
380     // so that operation can continue...
381     ndbrequire(logPartPtr.p->logPartState == LogPartRecord::ACTIVE);
382     logPartPtr.p->logPartState = LogPartRecord::IDLE;
383     switch (tcConnectptr.p->transactionState) {
384     case TcConnectionrec::LOG_QUEUED:
385       if (tcConnectptr.p->abortState != TcConnectionrec::ABORT_IDLE)
386       {
387         jam();
388         abortCommonLab(signal);
389       }
390       else
391       {
392         jam();
393         logLqhkeyreqLab(signal);
394       }
395       break;
396     case TcConnectionrec::LOG_ABORT_QUEUED:
397       jam();
398       writeAbortLog(signal);
399       removeLogTcrec(signal);
400       continueAfterLogAbortWriteLab(signal);
401       break;
402     case TcConnectionrec::LOG_COMMIT_QUEUED:
403     case TcConnectionrec::LOG_COMMIT_QUEUED_WAIT_SIGNAL:
404       jam();
405       writeCommitLog(signal, logPartPtr);
406       if (tcConnectptr.p->transactionState == TcConnectionrec::LOG_COMMIT_QUEUED) {
407         if (tcConnectptr.p->seqNoReplica == 0 ||
408 	    tcConnectptr.p->activeCreat == Fragrecord::AC_NR_COPY)
409         {
410           jam();
411           localCommitLab(signal);
412         }
413         else
414         {
415           jam();
416           commitReplyLab(signal);
417         }
418       }
419       else
420       {
421         jam();
422         tcConnectptr.p->transactionState = TcConnectionrec::LOG_COMMIT_WRITTEN_WAIT_SIGNAL;
423       }
424       break;
425     case TcConnectionrec::COMMIT_QUEUED:
426       jam();
427       localCommitLab(signal);
428       break;
429     case TcConnectionrec::ABORT_QUEUED:
430       jam();
431       abortCommonLab(signal);
432       break;
433     default:
434       ndbrequire(false);
435       break;
436     }//switch
437 
438     /**
439      * LogFile/LogPage could have altered due to above
440      */
441   startnext:
442     logPartPtr = save;
443     logFilePtr.i = logPartPtr.p->currentLogfile;
444     ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
445     logPagePtr.i = logFilePtr.p->currentLogpage;
446     ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
447     logNextStart(signal);
448     return;
449     break;
450   case ZSR_GCI_LIMITS:
451     jam();
452     signal->theData[0] = data0;
453     srGciLimits(signal);
454     return;
455     break;
456   case ZSR_LOG_LIMITS:
457     jam();
458     signal->theData[0] = data0;
459     signal->theData[1] = data1;
460     signal->theData[2] = data2;
461     srLogLimits(signal);
462     return;
463     break;
464   case ZSEND_EXEC_CONF:
465     jam();
466     signal->theData[0] = data0;
467     sendExecConf(signal);
468     return;
469     break;
470   case ZEXEC_SR:
471     jam();
472     signal->theData[0] = data0;
473     execSr(signal);
474     return;
475     break;
476   case ZSR_FOURTH_COMP:
477     jam();
478     signal->theData[0] = data0;
479     srFourthComp(signal);
480     return;
481     break;
482   case ZINIT_FOURTH:
483     jam();
484     signal->theData[0] = data0;
485     initFourth(signal);
486     return;
487     break;
488   case ZTIME_SUPERVISION:
489     jam();
490     signal->theData[0] = data0;
491     timeSup(signal);
492     return;
493     break;
494   case ZSR_PHASE3_START:
495     jam();
496     srPhase3Start(signal);
497     return;
498     break;
499   case ZLQH_TRANS_NEXT:
500   {
501     jam();
502     TcNodeFailRecordPtr tcNodeFailPtr;
503     tcNodeFailPtr.i = data0;
504     ptrCheckGuard(tcNodeFailPtr, ctcNodeFailrecFileSize, tcNodeFailRecord);
505     lqhTransNextLab(signal, tcNodeFailPtr);
506     return;
507     break;
508   }
509   case ZSCAN_TC_CONNECT:
510     jam();
511     tabptr.i = data1;
512     ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
513     scanTcConnectLab(signal, data0, data2);
514     return;
515     break;
516   case ZINITIALISE_RECORDS:
517     jam();
518     initialiseRecordsLab(signal, data0, data2, signal->theData[4]);
519     return;
520     break;
521   case ZINIT_GCP_REC:
522     jam();
523     gcpPtr.i = 0;
524     ptrAss(gcpPtr, gcpRecord);
525     initGcpRecLab(signal);
526     startTimeSupervision(signal);
527     return;
528     break;
529   case ZCHECK_LCP_STOP_BLOCKED:
530     jam();
531     c_scanRecordPool.getPtr(scanptr, data0);
532     tcConnectptr.i = scanptr.p->scanTcrec;
533     ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
534     fragptr.i = tcConnectptr.p->fragmentptr;
535     c_fragment_pool.getPtr(fragptr);
536     checkLcpStopBlockedLab(signal);
537     return;
538   case ZSCAN_MARKERS:
539     jam();
540     scanMarkers(signal, data0, data1, data2);
541     return;
542     break;
543 
544   case ZOPERATION_EVENT_REP:
545     jam();
546     /* Send counter event report */
547     {
548       const Uint32 len = c_Counters.build_event_rep(signal);
549       sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, len, JBB);
550     }
551 
552     {
553       const Uint32 report_interval = 5000;
554       const Uint32 len = c_Counters.build_continueB(signal);
555       signal->theData[0] = ZOPERATION_EVENT_REP;
556       sendSignalWithDelay(cownref, GSN_CONTINUEB, signal,
557                           report_interval, len);
558     }
559     break;
560   case ZDROP_TABLE_WAIT_USAGE:
561     jam();
562     dropTab_wait_usage(signal);
563     return;
564     break;
565   case ZENABLE_EXPAND_CHECK:
566   {
567     jam();
568     fragptr.i = signal->theData[1];
569     if (fragptr.i != RNIL)
570     {
571       jam();
572       c_lcp_complete_fragments.getPtr(fragptr);
573       Ptr<Fragrecord> save = fragptr;
574 
575       c_lcp_complete_fragments.next(fragptr);
576       signal->theData[0] = ZENABLE_EXPAND_CHECK;
577       signal->theData[1] = fragptr.i;
578       sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
579 
580       c_lcp_complete_fragments.remove(save);
581       return;
582     }
583     else
584     {
585       jam();
586       cstartRecReq = SRR_REDO_COMPLETE;
587       ndbrequire(c_lcp_complete_fragments.isEmpty());
588 
589       rebuildOrderedIndexes(signal, 0);
590       return;
591     }
592   }
593   case ZRETRY_TCKEYREF:
594   {
595     jam();
596     Uint32 cnt = signal->theData[1];
597     Uint32 ref = signal->theData[2];
598     if (cnt < (10 * 60 * 5))
599     {
600       jam();
601       /**
602        * Only retry for 5 minutes...then hope that API has handled it..somehow
603        */
604       memmove(signal->theData, signal->theData+3, 4*TcKeyRef::SignalLength);
605       sendTCKEYREF(signal, ref, 0, cnt);
606     }
607     return;
608   }
609   case ZWAIT_REORG_SUMA_FILTER_ENABLED:
610     jam();
611     wait_reorg_suma_filter_enabled(signal);
612     return;
613   case ZREBUILD_ORDERED_INDEXES:
614   {
615     Uint32 tableId = signal->theData[1];
616     rebuildOrderedIndexes(signal, tableId);
617     return;
618   }
619   case ZWAIT_READONLY:
620   {
621     jam();
622     wait_readonly(signal);
623     return;
624   }
625   case ZLCP_FRAG_WATCHDOG:
626   {
627     jam();
628     checkLcpFragWatchdog(signal);
629     return;
630   }
631   default:
632     ndbrequire(false);
633     break;
634   }//switch
635 }//Dblqh::execCONTINUEB()
636 
637 /* *********************************************************> */
638 /*  Request from DBDIH to include a new node in the node list */
639 /*  and so forth.                                             */
640 /* *********************************************************> */
execINCL_NODEREQ(Signal * signal)641 void Dblqh::execINCL_NODEREQ(Signal* signal)
642 {
643   jamEntry();
644   BlockReference retRef = signal->theData[0];
645   Uint32 nodeId = signal->theData[1];
646   cnewestGci = signal->theData[2];
647   cnewestCompletedGci = signal->theData[2] - 1;
648   ndbrequire(cnoOfNodes < MAX_NDB_NODES);
649   for (Uint32 i = 0; i < cnoOfNodes; i++) {
650     jam();
651     if (cnodeData[i] == nodeId) {
652       jam();
653       cnodeStatus[i] = ZNODE_UP;
654     }//if
655   }//for
656 
657   {
658     HostRecordPtr Thostptr;
659     Thostptr.i = nodeId;
660     ptrCheckGuard(Thostptr, chostFileSize, hostRecord);
661     Thostptr.p->nodestatus = ZNODE_UP;
662   }
663 
664   signal->theData[0] = nodeId;
665   signal->theData[1] = cownref;
666   sendSignal(retRef, GSN_INCL_NODECONF, signal, 2, JBB);
667   return;
668 }//Dblqh::execINCL_NODEREQ()
669 
execTUPSEIZEREF(Signal * signal)670 void Dblqh::execTUPSEIZEREF(Signal* signal)
671 {
672   jamEntry();
673   ndbrequire(false);
674 }//Dblqh::execTUPSEIZEREF()
675 
676 /* ########################################################################## */
677 /* #######                  START / RESTART MODULE                    ####### */
678 /* ########################################################################## */
679 /* ************************************************************************>> */
680 /*  This is first signal that arrives in a start / restart. Sender is NDBCNTR_REF. */
681 /* ************************************************************************>> */
execSTTOR(Signal * signal)682 void Dblqh::execSTTOR(Signal* signal)
683 {
684   UintR tstartPhase;
685 
686   jamEntry();
687                                                   /* START CASE */
688   tstartPhase = signal->theData[1];
689                                                   /* SYSTEM RESTART RANK */
690   csignalKey = signal->theData[6];
691 #if defined VM_TRACE || defined ERROR_INSERT || defined NDBD_TRACENR
692   char *name;
693   FILE *out = 0;
694 #endif
695   switch (tstartPhase) {
696   case ZSTART_PHASE1:
697     jam();
698     cstartPhase = tstartPhase;
699     c_tup = (Dbtup*)globalData.getBlock(DBTUP, instance());
700     c_tux = (Dbtux*)globalData.getBlock(DBTUX, instance());
701     c_acc = (Dbacc*)globalData.getBlock(DBACC, instance());
702     c_lgman = (Lgman*)globalData.getBlock(LGMAN);
703     ndbrequire(c_tup != 0 && c_tux != 0 && c_acc != 0 && c_lgman != 0);
704     sendsttorryLab(signal);
705 
706 #ifdef NDBD_TRACENR
707 #ifdef VM_TRACE
708     out = globalSignalLoggers.getOutputStream();
709 #endif
710     if (out == 0) {
711       name = NdbConfig_SignalLogFileName(getOwnNodeId());
712       out = fopen(name, "a");
713     }
714     tracenrout = new NdbOut(* new FileOutputStream(out));
715 #endif
716 
717 #ifdef NDBD_TRACENR
718     traceopout = &ndbout;
719 #endif
720 
721 #ifdef NDB_DEBUG_REDO
722     {
723       char buf[100];
724       if (NdbEnv_GetEnv("NDB_DEBUG_REDO", buf, sizeof(buf)))
725       {
726         DEBUG_REDO = 1;
727       }
728     }
729 #endif
730     return;
731     break;
732   case 4:
733     jam();
734     define_backup(signal);
735     break;
736   case 6:
737     c_elapsed_time_millis = 0;
738     init_elapsed_time(signal, c_latestTIME_SIGNAL);
739     sendsttorryLab(signal);
740     break;
741   default:
742     jam();
743     /*empty*/;
744     sendsttorryLab(signal);
745     return;
746     break;
747   }//switch
748 }//Dblqh::execSTTOR()
749 
750 void
define_backup(Signal * signal)751 Dblqh::define_backup(Signal* signal)
752 {
753   DefineBackupReq * req = (DefineBackupReq*)signal->getDataPtrSend();
754   req->backupId = 0;
755   req->clientRef = 0;
756   req->clientData = 0;
757   req->senderRef = reference();
758   req->backupPtr = 0;
759   req->backupKey[0] = 0;
760   req->backupKey[1] = 0;
761   req->nodes.clear();
762   req->nodes.set(getOwnNodeId());
763   req->backupDataLen = ~0;
764 
765   BlockReference backupRef = calcInstanceBlockRef(BACKUP);
766   sendSignal(backupRef, GSN_DEFINE_BACKUP_REQ, signal,
767 	     DefineBackupReq::SignalLength, JBB);
768 }
769 
770 void
execDEFINE_BACKUP_REF(Signal * signal)771 Dblqh::execDEFINE_BACKUP_REF(Signal* signal)
772 {
773   jamEntry();
774   m_backup_ptr = RNIL;
775   DefineBackupRef* ref = (DefineBackupRef*)signal->getDataPtrSend();
776   int err_code = 0;
777   char * extra_msg = NULL;
778 
779   switch(ref->errorCode){
780     case DefineBackupRef::Undefined:
781     case DefineBackupRef::FailedToSetupFsBuffers:
782     case DefineBackupRef::FailedToAllocateBuffers:
783     case DefineBackupRef::FailedToAllocateTables:
784     case DefineBackupRef::FailedAllocateTableMem:
785     case DefineBackupRef::FailedToAllocateFileRecord:
786     case DefineBackupRef::FailedToAllocateAttributeRecord:
787     case DefineBackupRef::FailedInsertFileHeader:
788     case DefineBackupRef::FailedInsertTableList:
789       jam();
790       err_code = NDBD_EXIT_INVALID_CONFIG;
791       extra_msg = (char*) "Probably Backup parameters configuration error, Please consult the manual";
792       progError(__LINE__, err_code, extra_msg);
793   }
794 
795   sendsttorryLab(signal);
796 }
797 
798 void
execDEFINE_BACKUP_CONF(Signal * signal)799 Dblqh::execDEFINE_BACKUP_CONF(Signal* signal)
800 {
801   jamEntry();
802   DefineBackupConf * conf = (DefineBackupConf*)signal->getDataPtrSend();
803   m_backup_ptr = conf->backupPtr;
804   sendsttorryLab(signal);
805 }
806 
807 /* ***************************************> */
808 /*  Restart phases 1 - 6, sender is Ndbcntr */
809 /* ***************************************> */
execNDB_STTOR(Signal * signal)810 void Dblqh::execNDB_STTOR(Signal* signal)
811 {
812   jamEntry();
813   Uint32 ownNodeId = signal->theData[1];   /* START PHASE*/
814   cstartPhase = signal->theData[2];  /* MY NODE ID */
815   cstartType = signal->theData[3];   /* START TYPE */
816 
817   switch (cstartPhase) {
818   case ZSTART_PHASE1:
819     jam();
820     preComputedRequestInfoMask = 0;
821     LqhKeyReq::setKeyLen(preComputedRequestInfoMask, RI_KEYLEN_MASK);
822     LqhKeyReq::setLastReplicaNo(preComputedRequestInfoMask, RI_LAST_REPL_MASK);
823     // Dont LqhKeyReq::setApplicationAddressFlag
824     LqhKeyReq::setDirtyFlag(preComputedRequestInfoMask, 1);
825     // Dont LqhKeyReq::setInterpretedFlag
826     LqhKeyReq::setSimpleFlag(preComputedRequestInfoMask, 1);
827     LqhKeyReq::setOperation(preComputedRequestInfoMask, RI_OPERATION_MASK);
828     LqhKeyReq::setGCIFlag(preComputedRequestInfoMask, 1);
829     LqhKeyReq::setNrCopyFlag(preComputedRequestInfoMask, 1);
830     // Dont setAIInLqhKeyReq
831     // Dont setSeqNoReplica
832     // Dont setSameClientAndTcFlag
833     // Dont setReturnedReadLenAIFlag
834     LqhKeyReq::setMarkerFlag(preComputedRequestInfoMask, 1);
835     LqhKeyReq::setQueueOnRedoProblemFlag(preComputedRequestInfoMask, 1);
836     //preComputedRequestInfoMask = 0x003d7fff;
837     startphase1Lab(signal, /* dummy */ ~0, ownNodeId);
838 
839     {
840       /* Start counter activity event reporting. */
841       const Uint32 len = c_Counters.build_continueB(signal);
842       signal->theData[0] = ZOPERATION_EVENT_REP;
843       sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 10, len);
844     }
845     return;
846     break;
847   case ZSTART_PHASE2:
848     jam();
849     startphase2Lab(signal, /* dummy */ ~0);
850     return;
851     break;
852   case ZSTART_PHASE3:
853     jam();
854     startphase3Lab(signal);
855     return;
856     break;
857   case ZSTART_PHASE4:
858     jam();
859     /*empty*/;
860     sendNdbSttorryLab(signal);
861     return;
862     break;
863   case ZSTART_PHASE6:
864     jam();
865     startphase6Lab(signal);
866     return;
867     break;
868   default:
869     jam();
870     /*empty*/;
871     sendNdbSttorryLab(signal);
872     return;
873     break;
874   }//switch
875 }//Dblqh::execNDB_STTOR()
876 
877 /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
878 /* +++++++                         START PHASE 2                    +++++++ */
879 /*                                                                          */
880 /*             INITIATE ALL RECORDS WITHIN THE BLOCK                        */
881 /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
startphase1Lab(Signal * signal,Uint32 _dummy,Uint32 ownNodeId)882 void Dblqh::startphase1Lab(Signal* signal, Uint32 _dummy, Uint32 ownNodeId)
883 {
884   UintR Ti, Tj;
885   HostRecordPtr ThostPtr;
886 
887 /* ------- INITIATE ALL RECORDS ------- */
888   cownNodeid    = ownNodeId;
889   caccBlockref  = calcInstanceBlockRef(DBACC);
890   ctupBlockref  = calcInstanceBlockRef(DBTUP);
891   ctuxBlockref  = calcInstanceBlockRef(DBTUX);
892   cownref       = calcInstanceBlockRef(DBLQH);
893   ndbassert(cownref == reference());
894   for (Ti = 0; Ti < chostFileSize; Ti++) {
895     ThostPtr.i = Ti;
896     ptrCheckGuard(ThostPtr, chostFileSize, hostRecord);
897     /*
898      * Valid only if receiver has same number of LQH workers.
899      * In general full instance key of fragment must be used.
900      */
901     ThostPtr.p->inPackedList = false;
902     for (Tj = 0; Tj < NDB_ARRAY_SIZE(ThostPtr.p->lqh_pack); Tj++)
903     {
904       ThostPtr.p->lqh_pack[Tj].noOfPackedWords = 0;
905       ThostPtr.p->lqh_pack[Tj].hostBlockRef =
906         numberToRef(DBLQH, Tj, ThostPtr.i);
907     }
908     for (Tj = 0; Tj < NDB_ARRAY_SIZE(ThostPtr.p->tc_pack); Tj++)
909     {
910       ThostPtr.p->tc_pack[Tj].noOfPackedWords = 0;
911       ThostPtr.p->tc_pack[Tj].hostBlockRef =
912         numberToRef(DBTC, Tj, ThostPtr.i);
913     }
914     ThostPtr.p->nodestatus = ZNODE_DOWN;
915   }//for
916   cpackedListIndex = 0;
917 
918   bool do_init =
919     (cstartType == NodeState::ST_INITIAL_START) ||
920     (cstartType == NodeState::ST_INITIAL_NODE_RESTART);
921 
922   LogFileRecordPtr prevLogFilePtr;
923   LogFileRecordPtr zeroLogFilePtr;
924 
925   if (do_init)
926   {
927     g_eventLogger->info("LDM(%u): Starting REDO log initialisation",
928                         instance());
929   }
930   ndbrequire(cnoLogFiles != 0);
931   for (logPartPtr.i = 0; logPartPtr.i < clogPartFileSize; logPartPtr.i++)
932   {
933     jam();
934     ptrAss(logPartPtr, logPartRecord);
935     initLogpart(signal);
936     for (Uint32 fileNo = 0; fileNo < cnoLogFiles; fileNo++)
937     {
938       seizeLogfile(signal);
939       if (fileNo != 0)
940       {
941         jam();
942         prevLogFilePtr.p->nextLogFile = logFilePtr.i;
943         logFilePtr.p->prevLogFile = prevLogFilePtr.i;
944       }
945       else
946       {
947         jam();
948         logPartPtr.p->firstLogfile = logFilePtr.i;
949         logPartPtr.p->currentLogfile = logFilePtr.i;
950         zeroLogFilePtr.i = logFilePtr.i;
951         zeroLogFilePtr.p = logFilePtr.p;
952       }//if
953       prevLogFilePtr.i = logFilePtr.i;
954       prevLogFilePtr.p = logFilePtr.p;
955       initLogfile(signal, fileNo);
956       if (do_init)
957       {
958         jam();
959         if (logFilePtr.i == zeroLogFilePtr.i)
960         {
961           jam();
962 /* ------------------------------------------------------------------------- */
963 /*IN AN INITIAL START WE START BY CREATING ALL LOG FILES AND SETTING THEIR   */
964 /*PROPER SIZE AND INITIALISING PAGE ZERO IN ALL FILES.                       */
965 /*WE START BY CREATING FILE ZERO IN EACH LOG PART AND THEN PROCEED           */
966 /*SEQUENTIALLY THROUGH ALL LOG FILES IN THE LOG PART.                        */
967 /* ------------------------------------------------------------------------- */
968           if (m_use_om_init == 0 || logPartPtr.i == 0)
969           {
970             /**
971              * initialize one file at a time if using OM_INIT
972              */
973             jam();
974 #ifdef VM_TRACE
975             if (m_use_om_init)
976             {
977               jam();
978               /**
979                * FSWRITEREQ does cross-thread execute-direct
980                *   which makes the clear_global_variables "unsafe"
981                *   disable it until we're finished with init log-files
982                */
983               disable_global_variables();
984             }
985 #endif
986             openLogfileInit(signal);
987           }
988         }//if
989       }//if
990     }//for
991     zeroLogFilePtr.p->prevLogFile = logFilePtr.i;
992     logFilePtr.p->nextLogFile = zeroLogFilePtr.i;
993   }
994 
995   initReportStatus(signal);
996   if (!do_init)
997   {
998     jam();
999     g_eventLogger->info("LDM(%u): Started LDM restart phase 1"
1000                         " (read REDO log page headers to init"
1001                         " REDO log data)",
1002                         instance());
1003     sendNdbSttorryLab(signal);
1004   }
1005   else
1006   {
1007     reportStatus(signal);
1008   }
1009 
1010   return;
1011 }//Dblqh::startphase1Lab()
1012 
1013 /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1014 /* +++++++                           START PHASE 2                    +++++++ */
1015 /*                                                                            */
1016 /* CONNECT LQH WITH ACC AND TUP.                                              */
1017 /* EVERY CONNECTION RECORD IN LQH IS ASSIGNED TO ONE ACC CONNECTION RECORD    */
1018 /*       AND ONE TUP CONNECTION RECORD.                                       */
1019 /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
startphase2Lab(Signal * signal,Uint32 _dummy)1020 void Dblqh::startphase2Lab(Signal* signal, Uint32 _dummy)
1021 {
1022   cmaxWordsAtNodeRec = MAX_NO_WORDS_OUTSTANDING_COPY_FRAGMENT;
1023 /* -- ACC AND TUP CONNECTION PROCESS -- */
1024   tcConnectptr.i = 0;
1025   ptrAss(tcConnectptr, tcConnectionrec);
1026   moreconnectionsLab(signal);
1027   return;
1028 }//Dblqh::startphase2Lab()
1029 
moreconnectionsLab(Signal * signal)1030 void Dblqh::moreconnectionsLab(Signal* signal)
1031 {
1032   tcConnectptr.p->tcAccBlockref = caccBlockref;
1033   // set TUX block here (no operation is seized in TUX)
1034   tcConnectptr.p->tcTuxBlockref = ctuxBlockref;
1035 /* NO STATE CHECKING IS PERFORMED, ASSUMED TO WORK */
1036 /* *************** */
1037 /*  ACCSEIZEREQ  < */
1038 /* *************** */
1039   signal->theData[0] = tcConnectptr.i;
1040   signal->theData[1] = cownref;
1041   sendSignal(caccBlockref, GSN_ACCSEIZEREQ, signal, 2, JBB);
1042   return;
1043 }//Dblqh::moreconnectionsLab()
1044 
1045 /* ***************> */
1046 /*  ACCSEIZECONF  > */
1047 /* ***************> */
execACCSEIZECONF(Signal * signal)1048 void Dblqh::execACCSEIZECONF(Signal* signal)
1049 {
1050   jamEntry();
1051   tcConnectptr.i = signal->theData[0];
1052   ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
1053   tcConnectptr.p->accConnectrec = signal->theData[1];
1054 /* *************** */
1055 /*  TUPSEIZEREQ  < */
1056 /* *************** */
1057   tcConnectptr.p->tcTupBlockref = ctupBlockref;
1058   signal->theData[0] = tcConnectptr.i;
1059   signal->theData[1] = cownref;
1060   sendSignal(ctupBlockref, GSN_TUPSEIZEREQ, signal, 2, JBB);
1061   return;
1062 }//Dblqh::execACCSEIZECONF()
1063 
1064 /* ***************> */
1065 /*  TUPSEIZECONF  > */
1066 /* ***************> */
execTUPSEIZECONF(Signal * signal)1067 void Dblqh::execTUPSEIZECONF(Signal* signal)
1068 {
1069   jamEntry();
1070   tcConnectptr.i = signal->theData[0];
1071   ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
1072   tcConnectptr.p->tupConnectrec = signal->theData[1];
1073 /* ------- CHECK IF THERE ARE MORE CONNECTIONS TO BE CONNECTED ------- */
1074   tcConnectptr.i = tcConnectptr.p->nextTcConnectrec;
1075   if (tcConnectptr.i != RNIL) {
1076     jam();
1077     ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
1078     moreconnectionsLab(signal);
1079     return;
1080   }//if
1081 /* ALL LQH_CONNECT RECORDS ARE CONNECTED TO ACC AND TUP ---- */
1082   sendNdbSttorryLab(signal);
1083   return;
1084 }//Dblqh::execTUPSEIZECONF()
1085 
1086 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1087 /* +++++++                    START PHASE 4                          +++++++ */
1088 /*                                                                           */
1089 /*       CONNECT LQH WITH LQH.                                               */
1090 /*       CONNECT EACH LQH WITH EVERY LQH IN THE DATABASE SYSTEM.             */
1091 /*       IF INITIAL START THEN CREATE THE FRAGMENT LOG FILES                 */
1092 /*IF SYSTEM RESTART OR NODE RESTART THEN OPEN THE FRAGMENT LOG FILES AND     */
1093 /*FIND THE END OF THE LOG FILES.                                             */
1094 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1095 /*        WAIT UNTIL ADD NODE PROCESSES ARE COMPLETED                        */
1096 /*        IF INITIAL START ALSO WAIT FOR LOG FILES TO INITIALISED            */
1097 /*START TIME SUPERVISION OF LOG FILES. WE HAVE TO WRITE LOG PAGES TO DISK    */
1098 /*EVEN IF THE PAGES ARE NOT FULL TO ENSURE THAT THEY COME TO DISK ASAP.      */
1099 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
startphase3Lab(Signal * signal)1100 void Dblqh::startphase3Lab(Signal* signal)
1101 {
1102   caddNodeState = ZTRUE;
1103 /* ***************<< */
1104 /*  READ_NODESREQ  < */
1105 /* ***************<< */
1106   cinitialStartOngoing = ZTRUE;
1107 
1108   switch(cstartType){
1109   case NodeState::ST_NODE_RESTART:
1110   case NodeState::ST_SYSTEM_RESTART:
1111     jam();
1112     for (logPartPtr.i = 0; logPartPtr.i < clogPartFileSize; logPartPtr.i++)
1113     {
1114       jam();
1115       LogFileRecordPtr locLogFilePtr;
1116       ptrAss(logPartPtr, logPartRecord);
1117       locLogFilePtr.i = logPartPtr.p->firstLogfile;
1118       ptrCheckGuard(locLogFilePtr, clogFileFileSize, logFileRecord);
1119       locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_FRONTPAGE;
1120       openFileRw(signal, locLogFilePtr);
1121     }//for
1122     break;
1123   case NodeState::ST_INITIAL_START:
1124   case NodeState::ST_INITIAL_NODE_RESTART:
1125     jam();
1126     for (logPartPtr.i = 0; logPartPtr.i < clogPartFileSize; logPartPtr.i++)
1127     {
1128       jam();
1129       signal->theData[0] = ZINIT_FOURTH;
1130       signal->theData[1] = logPartPtr.i;
1131       sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
1132     }
1133     break;
1134   }
1135 
1136   signal->theData[0] = cownref;
1137   sendSignal(NDBCNTR_REF, GSN_READ_NODESREQ, signal, 1, JBB);
1138   return;
1139 }//Dblqh::startphase3Lab()
1140 
1141 /* ****************** */
1142 /*  READ_NODESCONF  > */
1143 /* ****************** */
execREAD_NODESCONF(Signal * signal)1144 void Dblqh::execREAD_NODESCONF(Signal* signal)
1145 {
1146   jamEntry();
1147 
1148   ReadNodesConf * const readNodes = (ReadNodesConf *)&signal->theData[0];
1149   cnoOfNodes = readNodes->noOfNodes;
1150 
1151   unsigned ind = 0;
1152   unsigned i = 0;
1153   for (i = 1; i < MAX_NDB_NODES; i++) {
1154     jam();
1155     if (NdbNodeBitmask::get(readNodes->allNodes, i)) {
1156       jam();
1157       cnodeData[ind]    = i;
1158       cnodeStatus[ind]  = NdbNodeBitmask::get(readNodes->inactiveNodes, i);
1159 
1160       {
1161         HostRecordPtr Thostptr;
1162         Thostptr.i = i;
1163         ptrCheckGuard(Thostptr, chostFileSize, hostRecord);
1164         Thostptr.p->nodestatus = cnodeStatus[ind];
1165       }
1166 
1167       //readNodes->getVersionId(i, readNodes->theVersionIds) not used
1168       if (!NodeBitmask::get(readNodes->inactiveNodes, i))
1169       {
1170 	jam();
1171 	m_sr_nodes.set(i);
1172       }
1173       ind++;
1174     }//if
1175   }//for
1176   ndbrequire(ind == cnoOfNodes);
1177   ndbrequire(cnoOfNodes >= 1 && cnoOfNodes < MAX_NDB_NODES);
1178   ndbrequire(!(cnoOfNodes == 1 && cstartType == NodeState::ST_NODE_RESTART));
1179 
1180 #ifdef ERROR_INSERT
1181   c_master_node_id = readNodes->masterNodeId;
1182 #endif
1183 
1184   caddNodeState = ZFALSE;
1185   if (cstartType == NodeState::ST_SYSTEM_RESTART)
1186   {
1187     jam();
1188     sendNdbSttorryLab(signal);
1189     return;
1190   }
1191   else if (cstartType == NodeState::ST_NODE_RESTART)
1192   {
1193     jam();
1194     SET_TRACENR_FLAG;
1195     m_sr_nodes.clear();
1196     m_sr_nodes.set(getOwnNodeId());
1197     sendNdbSttorryLab(signal);
1198     return;
1199   }
1200   SET_TRACENR_FLAG;
1201 
1202   checkStartCompletedLab(signal);
1203   return;
1204 }//Dblqh::execREAD_NODESCONF()
1205 
checkStartCompletedLab(Signal * signal)1206 void Dblqh::checkStartCompletedLab(Signal* signal)
1207 {
1208   if (caddNodeState == ZFALSE) {
1209     if (cinitialStartOngoing == ZFALSE) {
1210       jam();
1211       sendNdbSttorryLab(signal);
1212       return;
1213     }//if
1214   }//if
1215   return;
1216 }//Dblqh::checkStartCompletedLab()
1217 
1218 /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1219 /* SET CONCURRENCY OF LOCAL CHECKPOINTS TO BE USED AFTER SYSTEM RESTART.      */
1220 /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
startphase6Lab(Signal * signal)1221 void Dblqh::startphase6Lab(Signal* signal)
1222 {
1223   cstartPhase = ZNIL;
1224   cstartType = ZNIL;
1225   CLEAR_TRACENR_FLAG;
1226   sendNdbSttorryLab(signal);
1227   return;
1228 }//Dblqh::startphase6Lab()
1229 
sendNdbSttorryLab(Signal * signal)1230 void Dblqh::sendNdbSttorryLab(Signal* signal)
1231 {
1232   signal->theData[0] = cownref;
1233   BlockReference cntrRef = !isNdbMtLqh() ? NDBCNTR_REF : DBLQH_REF;
1234   sendSignal(cntrRef, GSN_NDB_STTORRY, signal, 1, JBB);
1235   return;
1236 }//Dblqh::sendNdbSttorryLab()
1237 
sendsttorryLab(Signal * signal)1238 void Dblqh::sendsttorryLab(Signal* signal)
1239 {
1240 /* *********<< */
1241 /*  STTORRY  < */
1242 /* *********<< */
1243   signal->theData[0] = csignalKey; /* SIGNAL KEY */
1244   signal->theData[1] = 3;          /* BLOCK CATEGORY */
1245   signal->theData[2] = 2;          /* SIGNAL VERSION NUMBER */
1246   signal->theData[3] = ZSTART_PHASE1;
1247   signal->theData[4] = 4;
1248   signal->theData[5] = 6;
1249   signal->theData[6] = 255;
1250   BlockReference cntrRef = !isNdbMtLqh() ? NDBCNTR_REF : DBLQH_REF;
1251   sendSignal(cntrRef, GSN_STTORRY, signal, 7, JBB);
1252   return;
1253 }//Dblqh::sendsttorryLab()
1254 
1255 /* ***************>> */
1256 /*  READ_NODESREF  > */
1257 /* ***************>> */
execREAD_NODESREF(Signal * signal)1258 void Dblqh::execREAD_NODESREF(Signal* signal)
1259 {
1260   jamEntry();
1261   ndbrequire(false);
1262 }//Dblqh::execREAD_NODESREF()
1263 
1264 /* ****************** */
1265 /*  READ_CONFIG_REQ > */
1266 /* ****************** */
execREAD_CONFIG_REQ(Signal * signal)1267 void Dblqh::execREAD_CONFIG_REQ(Signal* signal)
1268 {
1269   const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr();
1270   Uint32 ref = req->senderRef;
1271   Uint32 senderData = req->senderData;
1272   ndbrequire(req->noOfParameters == 0);
1273 
1274   jamEntry();
1275 
1276   const ndb_mgm_configuration_iterator * p =
1277     m_ctx.m_config.getOwnConfigIterator();
1278   ndbrequire(p != 0);
1279 
1280 
1281   /**
1282    * TODO move check of log-parts vs. ndbMtLqhWorkers to better place
1283    * (Configuration.cpp ??)
1284    */
1285   ndbrequire(globalData.ndbLogParts <= NDB_MAX_LOG_PARTS);
1286   if (globalData.ndbMtLqhWorkers > globalData.ndbLogParts)
1287   {
1288     char buf[255];
1289     BaseString::snprintf(buf, sizeof(buf),
1290       "Trying to start %d LQH workers with only %d log parts, try initial"
1291       " node restart to be able to use more LQH workers.",
1292       globalData.ndbMtLqhWorkers, globalData.ndbLogParts);
1293     progError(__LINE__, NDBD_EXIT_INVALID_CONFIG, buf);
1294   }
1295 
1296   if (globalData.ndbLogParts != 4 &&
1297       globalData.ndbLogParts != 6 &&
1298       globalData.ndbLogParts != 8 &&
1299       globalData.ndbLogParts != 10 &&
1300       globalData.ndbLogParts != 12 &&
1301       globalData.ndbLogParts != 16 &&
1302       globalData.ndbLogParts != 20 &&
1303       globalData.ndbLogParts != 24 &&
1304       globalData.ndbLogParts != 32)
1305   {
1306     char buf[255];
1307     BaseString::snprintf(buf, sizeof(buf),
1308       "Trying to start with %d log parts, number of log parts can"
1309       " only be set to 4, 6, 8, 10, 12, 16, 20, 24 or 32.",
1310       globalData.ndbLogParts);
1311     progError(__LINE__, NDBD_EXIT_INVALID_CONFIG, buf);
1312   }
1313 
1314   cnoLogFiles = 8;
1315   ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_NO_REDOLOG_FILES,
1316 					&cnoLogFiles));
1317   ndbrequire(cnoLogFiles > 0);
1318 
1319   Uint32 log_page_size= 0;
1320   ndb_mgm_get_int_parameter(p, CFG_DB_REDO_BUFFER,
1321 			    &log_page_size);
1322 
1323   /**
1324    * Always set page size in half MBytes
1325    */
1326   clogPageFileSize= (log_page_size / sizeof(LogPageRecord));
1327   Uint32 mega_byte_part= clogPageFileSize & 15;
1328   if (mega_byte_part != 0) {
1329     jam();
1330     clogPageFileSize+= (16 - mega_byte_part);
1331   }
1332 
1333   /* maximum number of log file operations */
1334   clfoFileSize = clogPageFileSize;
1335   if (clfoFileSize < ZLFO_MIN_FILE_SIZE)
1336     clfoFileSize = ZLFO_MIN_FILE_SIZE;
1337 
1338   ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_LQH_TABLE, &ctabrecFileSize));
1339   ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_LQH_TC_CONNECT,
1340 					&ctcConnectrecFileSize));
1341   clogFileFileSize = clogPartFileSize * cnoLogFiles;
1342   ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_LQH_SCAN, &cscanrecFileSize));
1343 
1344   ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_DISCLESS, &c_diskless));
1345   c_o_direct = true;
1346   ndb_mgm_get_int_parameter(p, CFG_DB_O_DIRECT, &c_o_direct);
1347 
1348   m_use_om_init = 0;
1349   {
1350     const char * conf = 0;
1351     if (!ndb_mgm_get_string_parameter(p, CFG_DB_INIT_REDO, &conf) && conf)
1352     {
1353       jam();
1354       if (native_strcasecmp(conf, "sparse") == 0)
1355       {
1356         jam();
1357         m_use_om_init = 0;
1358       }
1359       else if (native_strcasecmp(conf, "full") == 0)
1360       {
1361         jam();
1362         m_use_om_init = 1;
1363       }
1364     }
1365   }
1366 
1367   Uint32 tmp= 0;
1368   ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_LQH_FRAG, &tmp));
1369   c_fragment_pool.setSize(tmp);
1370 
1371   if (!ndb_mgm_get_int_parameter(p, CFG_DB_REDOLOG_FILE_SIZE,
1372                                  &clogFileSize))
1373   {
1374     // convert to mbyte
1375     clogFileSize = (clogFileSize + 1024*1024 - 1) / (1024 * 1024);
1376     ndbrequire(clogFileSize >= 4 && clogFileSize <= 1024);
1377   }
1378 
1379   m_startup_report_frequency = 0;
1380   ndb_mgm_get_int_parameter(p,CFG_DB_STARTUP_REPORT_FREQUENCY,
1381                             &m_startup_report_frequency);
1382   totalLogFiles = 4 * cnoLogFiles;
1383   totallogMBytes = totalLogFiles * clogFileSize;
1384 
1385   cmaxLogFilesInPageZero = (ZPAGE_SIZE - ZPAGE_HEADER_SIZE - 128) /
1386     (ZFD_MBYTE_SIZE * clogFileSize);
1387 
1388   /**
1389    * "Old" cmaxLogFilesInPageZero was 40
1390    * Each FD need 3 words per mb, require that they can fit into 1 page
1391    *   (atleast 1 FD)
1392    * Is also checked in ConfigInfo.cpp (max FragmentLogFileSize = 1Gb)
1393    *   1Gb = 1024Mb => 3(ZFD_MBYTE_SIZE) * 1024 < 8192 (ZPAGE_SIZE)
1394    */
1395   if (cmaxLogFilesInPageZero > 40)
1396   {
1397     jam();
1398     cmaxLogFilesInPageZero = 40;
1399   }
1400   else
1401   {
1402     ndbrequire(cmaxLogFilesInPageZero);
1403   }
1404 
1405 #if defined VM_TRACE || defined ERROR_INSERT
1406   if (cmaxLogFilesInPageZero_DUMP != 0)
1407   {
1408     ndbout << "LQH DUMP 2396 " << cmaxLogFilesInPageZero_DUMP;
1409     if (cmaxLogFilesInPageZero_DUMP > cmaxLogFilesInPageZero)
1410     {
1411       ndbout << ": max allowed is " << cmaxLogFilesInPageZero << endl;
1412       // do not continue with useless test
1413       ndbrequire(false);
1414     }
1415     cmaxLogFilesInPageZero = cmaxLogFilesInPageZero_DUMP;
1416     ndbout << endl;
1417   }
1418 #endif
1419 
1420   /* How many file's worth of info is actually valid? */
1421   cmaxValidLogFilesInPageZero = cmaxLogFilesInPageZero - 1;
1422 
1423   /* Must be at least 1 */
1424   ndbrequire(cmaxValidLogFilesInPageZero > 0);
1425 
1426    {
1427     Uint32 config_val = 20;
1428     ndb_mgm_get_int_parameter(p, CFG_DB_LCP_INTERVAL, &config_val);
1429     config_val = config_val > 31 ? 31 : config_val;
1430 
1431     const Uint32 mb = 1024 * 1024;
1432 
1433     // perform LCP after this amout of mbytes written
1434     const Uint64 config_mbytes = ((Uint64(4) << config_val) + mb - 1) / mb;
1435     const Uint64 totalmb = Uint64(cnoLogFiles) * Uint64(clogFileSize);
1436     if (totalmb > config_mbytes)
1437     {
1438       c_free_mb_force_lcp_limit = Uint32(totalmb - config_mbytes);
1439     }
1440     else
1441     {
1442       c_free_mb_force_lcp_limit = 0;
1443     }
1444 
1445     // No less than 33%
1446     Uint32 limit = Uint32(totalmb / 3);
1447     if (c_free_mb_force_lcp_limit < limit)
1448     {
1449       c_free_mb_force_lcp_limit = limit;
1450     }
1451   }
1452   c_free_mb_tail_problem_limit = 4;  // If less than 4Mb set TAIL_PROBLEM
1453 
1454   ndb_mgm_get_int_parameter(p, CFG_DB_TRANSACTION_DEADLOCK_TIMEOUT,
1455                             &cTransactionDeadlockDetectionTimeout);
1456 
1457   initRecords();
1458   initialiseRecordsLab(signal, 0, ref, senderData);
1459 
1460   c_max_redo_lag = 30;
1461   ndb_mgm_get_int_parameter(p, CFG_DB_REDO_OVERCOMMIT_LIMIT,
1462                             &c_max_redo_lag);
1463 
1464   c_max_redo_lag_counter = 3;
1465   ndb_mgm_get_int_parameter(p, CFG_DB_REDO_OVERCOMMIT_COUNTER,
1466                             &c_max_redo_lag_counter);
1467 
1468   c_max_parallel_scans_per_frag = 32;
1469   ndb_mgm_get_int_parameter(p, CFG_DB_PARALLEL_SCANS_PER_FRAG,
1470                             &c_max_parallel_scans_per_frag);
1471 
1472   if (c_max_parallel_scans_per_frag > (256 - MAX_PARALLEL_SCANS_PER_FRAG) / 2)
1473   {
1474     jam();
1475     c_max_parallel_scans_per_frag = (256 - MAX_PARALLEL_SCANS_PER_FRAG) / 2;
1476   }
1477 
1478   {
1479     Uint32 param = 60;
1480     ndb_mgm_get_int_parameter(p, CFG_DB_LCP_SCAN_WATCHDOG_LIMIT,
1481                               &param);
1482 
1483     /* LCP fail when LCP_SCAN_WATCHDOG_LIMIT exceeded */
1484     param *= 1000;  // Convert to milliseconds
1485     c_lcpFragWatchdog.MaxElapsedWithNoProgressMillis = param;
1486 
1487     /* Warn when stalled for roughly 1/3 time, */
1488     c_lcpFragWatchdog.WarnElapsedWithNoProgressMillis = (param + 2)/3;
1489 
1490     ndbrequire(c_lcpFragWatchdog.MaxElapsedWithNoProgressMillis >=
1491                c_lcpFragWatchdog.WarnElapsedWithNoProgressMillis);
1492 
1493     /* Dump LCPFragWatchdog parameter values */
1494     signal->theData[0] = 2395;
1495     execDUMP_STATE_ORD(signal);
1496    }
1497 
1498   return;
1499 }
1500 
1501 /* ########################################################################## */
1502 /* #######                          ADD/DELETE FRAGMENT MODULE        ####### */
1503 /*       THIS MODULE IS USED BY DICTIONARY TO CREATE NEW FRAGMENTS AND DELETE */
1504 /*       OLD FRAGMENTS.                                                       */
1505 /*                                                                            */
1506 /* ########################################################################## */
1507 /* -------------------------------------------------------------- */
1508 /*            FRAG REQ                                            */
1509 /* -------------------------------------------------------------- */
1510 /* *********************************************************> */
1511 /*  LQHFRAGREQ: Create new fragments for a table. Sender DICT */
1512 /* *********************************************************> */
1513 
1514 // this unbelievable mess could be replaced by one signal to LQH
1515 // and execute direct to local DICT to get everything at once
1516 void
execCREATE_TAB_REQ(Signal * signal)1517 Dblqh::execCREATE_TAB_REQ(Signal* signal)
1518 {
1519   CreateTabReq* req = (CreateTabReq*)signal->getDataPtr();
1520   tabptr.i = req->tableId;
1521   ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
1522 
1523   Uint32 senderRef = req->senderRef;
1524   Uint32 senderData = req->senderData;
1525 
1526   if (tabptr.p->tableStatus != Tablerec::NOT_DEFINED)
1527   {
1528     jam();
1529     CreateTabRef* ref = (CreateTabRef*)signal->getDataPtrSend();
1530     ref->senderData = senderData;
1531     ref->senderRef = reference();
1532     ref->errorCode = CreateTableRef::TableAlreadyExist;
1533     sendSignal(senderRef, GSN_CREATE_TAB_REF, signal,
1534                CreateTabRef::SignalLength, JBB);
1535     return;
1536   }
1537 
1538   seizeAddfragrec(signal);
1539   addfragptr.p->m_createTabReq = *req;
1540   req = &addfragptr.p->m_createTabReq;
1541 
1542   tabptr.p->tableStatus = Tablerec::ADD_TABLE_ONGOING;
1543   tabptr.p->tableType = req->tableType;
1544   tabptr.p->primaryTableId = (req->primaryTableId == RNIL ? tabptr.i :
1545                               req->primaryTableId);
1546   tabptr.p->schemaVersion = req->tableVersion;
1547   tabptr.p->m_disk_table= 0;
1548 
1549   addfragptr.p->addfragStatus = AddFragRecord::WAIT_TUP;
1550   sendCreateTabReq(signal, addfragptr);
1551 }
1552 
1553 void
sendCreateTabReq(Signal * signal,AddFragRecordPtr addfragptr)1554 Dblqh::sendCreateTabReq(Signal* signal, AddFragRecordPtr addfragptr)
1555 {
1556   TablerecPtr tabPtr;
1557   tabPtr.i = addfragptr.p->m_createTabReq.tableId;
1558   ptrCheckGuard(tabPtr, ctabrecFileSize, tablerec);
1559 
1560   CreateTabReq* req = (CreateTabReq*)signal->getDataPtrSend();
1561   * req = addfragptr.p->m_createTabReq;
1562 
1563   req->senderRef = reference();
1564   req->senderData = addfragptr.i;
1565 
1566   Uint32 ref = calcInstanceBlockRef(DBTUP);
1567   switch(addfragptr.p->addfragStatus){
1568   case AddFragRecord::WAIT_TUP:
1569     if (DictTabInfo::isOrderedIndex(tabPtr.p->tableType))
1570     {
1571       jam();
1572       req->noOfAttributes = 1;
1573       req->noOfKeyAttr = 1;
1574       req->noOfNullAttributes = 0;
1575     }
1576     break;
1577   case AddFragRecord::WAIT_TUX:
1578     jam();
1579     ndbrequire(req->noOfAttributes >= 2);
1580     req->noOfAttributes--;
1581     ref = calcInstanceBlockRef(DBTUX);
1582     break;
1583   default:
1584     jamLine(addfragptr.p->addfragStatus);
1585     ndbrequire(false);
1586   }
1587 
1588   sendSignal(ref, GSN_CREATE_TAB_REQ, signal,
1589              CreateTabReq::SignalLengthLDM, JBB);
1590 }
1591 
1592 void
execCREATE_TAB_REF(Signal * signal)1593 Dblqh::execCREATE_TAB_REF(Signal* signal)
1594 {
1595   jamEntry();
1596 
1597   CreateTabRef * ref = (CreateTabRef*)signal->getDataPtr();
1598   addfragptr.i = ref->senderData;
1599   ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord);
1600 
1601   abortAddFragOps(signal);
1602 
1603   ref->senderRef = reference();
1604   ref->senderData = addfragptr.p->m_createTabReq.senderData;
1605   sendSignal(addfragptr.p->m_createTabReq.senderRef,
1606              GSN_CREATE_TAB_REF, signal, CreateTabConf::SignalLength, JBB);
1607 
1608   releaseAddfragrec(signal);
1609 }
1610 
1611 void
execCREATE_TAB_CONF(Signal * signal)1612 Dblqh::execCREATE_TAB_CONF(Signal* signal)
1613 {
1614   jamEntry();
1615   CreateTabConf* conf = (CreateTabConf*)signal->getDataPtr();
1616   addfragptr.i = conf->senderData;
1617   ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord);
1618 
1619   TablerecPtr tabPtr;
1620   tabPtr.i = addfragptr.p->m_createTabReq.tableId;
1621   ptrCheckGuard(tabPtr, ctabrecFileSize, tablerec);
1622 
1623   switch(addfragptr.p->addfragStatus){
1624   case AddFragRecord::WAIT_TUP:
1625     jam();
1626     addfragptr.p->tupConnectptr = conf->tupConnectPtr;
1627     if (DictTabInfo::isOrderedIndex(tabPtr.p->tableType))
1628     {
1629       jam();
1630       addfragptr.p->addfragStatus = AddFragRecord::WAIT_TUX;
1631       sendCreateTabReq(signal, addfragptr);
1632       return;
1633     }
1634     break;
1635   case AddFragRecord::WAIT_TUX:
1636     jam();
1637     addfragptr.p->tuxConnectptr = conf->tuxConnectPtr;
1638     break;
1639   default:
1640     jamLine(addfragptr.p->addfragStatus);
1641     ndbrequire(false);
1642   }
1643 
1644   addfragptr.p->addfragStatus = AddFragRecord::WAIT_ADD_ATTR;
1645 
1646   conf->senderRef = reference();
1647   conf->senderData = addfragptr.p->m_createTabReq.senderData;
1648   conf->lqhConnectPtr = addfragptr.i;
1649   sendSignal(addfragptr.p->m_createTabReq.senderRef,
1650              GSN_CREATE_TAB_CONF, signal, CreateTabConf::SignalLength, JBB);
1651 }
1652 
1653 /* ************************************************************************> */
1654 /*  LQHADDATTRREQ: Request from DICT to create attributes for the new table. */
1655 /* ************************************************************************> */
execLQHADDATTREQ(Signal * signal)1656 void Dblqh::execLQHADDATTREQ(Signal* signal)
1657 {
1658   jamEntry();
1659   LqhAddAttrReq * req = (LqhAddAttrReq*)signal->getDataPtr();
1660 
1661   addfragptr.i = req->lqhFragPtr;
1662   ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord);
1663 
1664   addfragptr.p->m_addAttrReq = * req;
1665 
1666   const Uint32 tnoOfAttr = req->noOfAttributes;
1667   const Uint32 numSections = signal->getNoOfSections();
1668   bool isLongReq= ( numSections != 0 );
1669   addfragptr.p->defValSectionI = RNIL;
1670   addfragptr.p->defValNextPos = 0;
1671 
1672   if (isLongReq)
1673   {
1674     SectionHandle handle(this, signal);
1675     SegmentedSectionPtr defValSection;
1676     handle.getSection(defValSection, LqhAddAttrReq::DEFAULT_VALUE_SECTION_NUM);
1677     addfragptr.p->defValSectionI = defValSection.i;
1678     addfragptr.p->defValNextPos = 0;
1679     //Don't free Section here. Section is freed after default values are trasfered to TUP
1680     handle.clear();
1681   }
1682 
1683   ndbrequire(addfragptr.p->addfragStatus == AddFragRecord::WAIT_ADD_ATTR);
1684   ndbrequire((tnoOfAttr != 0) && (tnoOfAttr <= LqhAddAttrReq::MAX_ATTRIBUTES));
1685   addfragptr.p->totalAttrReceived += tnoOfAttr;
1686   ndbrequire(addfragptr.p->totalAttrReceived <=
1687              addfragptr.p->m_createTabReq.noOfAttributes);
1688 
1689   addfragptr.p->attrReceived = tnoOfAttr;
1690 
1691   TablerecPtr tabPtr;
1692   tabPtr.i = addfragptr.p->m_createTabReq.tableId;
1693   ptrCheckGuard(tabPtr, ctabrecFileSize, tablerec);
1694 
1695   for (Uint32 i = 0; i < tnoOfAttr; i++)
1696   {
1697     if(AttributeDescriptor::getDiskBased(req->attributes[i].attrDescriptor))
1698     {
1699       jam();
1700       tabPtr.p->m_disk_table = 1;
1701     }
1702   }//for
1703 
1704   addfragptr.p->attrSentToTup = 0;
1705   addfragptr.p->addfragStatus = AddFragRecord::TUP_ATTR_WAIT;
1706   sendAddAttrReq(signal);
1707 }//Dblqh::execLQHADDATTREQ()
1708 
1709 /* *********************>> */
1710 /*  TUP_ADD_ATTCONF      > */
1711 /* *********************>> */
execTUP_ADD_ATTCONF(Signal * signal)1712 void Dblqh::execTUP_ADD_ATTCONF(Signal* signal)
1713 {
1714   jamEntry();
1715   addfragptr.i = signal->theData[0];
1716   // implies that operation was released on the other side
1717   const bool lastAttr = signal->theData[1];
1718   ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord);
1719 
1720   tabptr.i = addfragptr.p->m_createTabReq.tableId;
1721   ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
1722 
1723   Uint32 noOfAttr = addfragptr.p->m_createTabReq.noOfAttributes;
1724 
1725   switch (addfragptr.p->addfragStatus) {
1726   case AddFragRecord::TUP_ATTR_WAIT:
1727     if (DictTabInfo::isOrderedIndex(tabptr.p->tableType))
1728     {
1729       addfragptr.p->addfragStatus = AddFragRecord::TUX_ATTR_WAIT;
1730       sendAddAttrReq(signal);
1731       break;
1732     }
1733     goto done_with_attr;
1734     break;
1735   case AddFragRecord::TUX_ATTR_WAIT:
1736     jam();
1737     if (lastAttr)
1738       addfragptr.p->tuxConnectptr = RNIL;
1739     goto done_with_attr;
1740     break;
1741   done_with_attr:
1742     addfragptr.p->attrSentToTup = addfragptr.p->attrSentToTup + 1;
1743     ndbrequire(addfragptr.p->attrSentToTup <= addfragptr.p->attrReceived);
1744     ndbrequire(addfragptr.p->totalAttrReceived <= noOfAttr);
1745     if (addfragptr.p->attrSentToTup < addfragptr.p->attrReceived)
1746     {
1747       // more in this batch
1748       jam();
1749       addfragptr.p->addfragStatus = AddFragRecord::TUP_ATTR_WAIT;
1750       sendAddAttrReq(signal);
1751       return;
1752     }
1753 
1754     if (addfragptr.p->defValSectionI != RNIL)
1755     {
1756       releaseSection(addfragptr.p->defValSectionI);
1757       addfragptr.p->defValNextPos = 0;
1758       addfragptr.p->defValSectionI = RNIL;
1759     }
1760 
1761     { // Reply
1762       LqhAddAttrConf *const conf = (LqhAddAttrConf*)signal->getDataPtrSend();
1763       conf->senderData = addfragptr.p->m_addAttrReq.senderData;
1764       conf->senderAttrPtr = addfragptr.p->m_addAttrReq.senderAttrPtr;
1765       sendSignal(addfragptr.p->m_createTabReq.senderRef,
1766                  GSN_LQHADDATTCONF, signal, LqhAddAttrConf::SignalLength, JBB);
1767     }
1768     if (addfragptr.p->totalAttrReceived < noOfAttr)
1769     {
1770       jam();
1771       addfragptr.p->addfragStatus = AddFragRecord::WAIT_ADD_ATTR;
1772     }
1773     else
1774     {
1775       jam();
1776       releaseAddfragrec(signal);
1777     }
1778     break;
1779   default:
1780     ndbrequire(false);
1781     break;
1782   }
1783 }
1784 
1785 /* **********************>> */
1786 /*  TUX_ADD_ATTRCONF      > */
1787 /* **********************>> */
execTUX_ADD_ATTRCONF(Signal * signal)1788 void Dblqh::execTUX_ADD_ATTRCONF(Signal* signal)
1789 {
1790   jamEntry();
1791   execTUP_ADD_ATTCONF(signal);
1792 }//Dblqh::execTUX_ADD_ATTRCONF
1793 
1794 /* *********************> */
1795 /*  TUP_ADD_ATTREF      > */
1796 /* *********************> */
execTUP_ADD_ATTRREF(Signal * signal)1797 void Dblqh::execTUP_ADD_ATTRREF(Signal* signal)
1798 {
1799   jamEntry();
1800   addfragptr.i = signal->theData[0];
1801   ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord);
1802   const Uint32 errorCode = terrorCode = signal->theData[1];
1803 
1804   abortAddFragOps(signal);
1805 
1806   // operation was released on the other side
1807   switch (addfragptr.p->addfragStatus) {
1808   case AddFragRecord::TUP_ATTR_WAIT:
1809     jam();
1810     break;
1811   case AddFragRecord::TUX_ATTR_WAIT:
1812     jam();
1813     break;
1814   default:
1815     ndbrequire(false);
1816     break;
1817   }
1818 
1819   if (addfragptr.p->defValSectionI != RNIL)
1820   {
1821     releaseSection(addfragptr.p->defValSectionI);
1822     addfragptr.p->defValNextPos = 0;
1823     addfragptr.p->defValSectionI = RNIL;
1824   }
1825 
1826   const Uint32 Ref = addfragptr.p->m_createTabReq.senderRef;
1827   const Uint32 senderData = addfragptr.p->m_addAttrReq.senderData;
1828 
1829   releaseAddfragrec(signal);
1830 
1831   LqhAddAttrRef *const ref = (LqhAddAttrRef*)signal->getDataPtrSend();
1832   ref->senderData = senderData;
1833   ref->errorCode = errorCode;
1834   sendSignal(Ref, GSN_LQHADDATTREF, signal,
1835 	     LqhAddAttrRef::SignalLength, JBB);
1836 }//Dblqh::execTUP_ADD_ATTRREF()
1837 
1838 /* **********************> */
1839 /*  TUX_ADD_ATTRREF      > */
1840 /* **********************> */
execTUX_ADD_ATTRREF(Signal * signal)1841 void Dblqh::execTUX_ADD_ATTRREF(Signal* signal)
1842 {
1843   jamEntry();
1844   execTUP_ADD_ATTRREF(signal);
1845 }//Dblqh::execTUX_ADD_ATTRREF
1846 
1847 /*
1848  * Add attribute in TUP or TUX.  Called up to 4 times.
1849  */
1850 void
sendAddAttrReq(Signal * signal)1851 Dblqh::sendAddAttrReq(Signal* signal)
1852 {
1853   arrGuard(addfragptr.p->attrSentToTup, LqhAddAttrReq::MAX_ATTRIBUTES);
1854   LqhAddAttrReq::Entry& entry =
1855     addfragptr.p->m_addAttrReq.attributes[addfragptr.p->attrSentToTup];
1856 
1857   const Uint32 attrId = entry.attrId & 0xffff;
1858   const Uint32 primaryAttrId = entry.attrId >> 16;
1859 
1860   tabptr.i = addfragptr.p->m_createTabReq.tableId;
1861   ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
1862 
1863   if (addfragptr.p->addfragStatus == AddFragRecord::TUP_ATTR_WAIT)
1864   {
1865     if (DictTabInfo::isTable(tabptr.p->tableType) ||
1866         DictTabInfo::isHashIndex(tabptr.p->tableType) ||
1867         (DictTabInfo::isOrderedIndex(tabptr.p->tableType) &&
1868          primaryAttrId == ZNIL)) {
1869       jam();
1870       TupAddAttrReq* const tupreq = (TupAddAttrReq*)signal->getDataPtrSend();
1871       tupreq->tupConnectPtr = addfragptr.p->tupConnectptr;
1872       tupreq->attrId = attrId;
1873       tupreq->attrDescriptor = entry.attrDescriptor;
1874       tupreq->extTypeInfo = entry.extTypeInfo;
1875       BlockReference tupRef = calcInstanceBlockRef(DBTUP);
1876 
1877       Uint32 sectionLen = 0;
1878       Uint32 startIndex = TupAddAttrReq::SignalLength;
1879       if (addfragptr.p->defValSectionI != RNIL)
1880       {
1881         SegmentedSectionPtr defValSection;
1882         getSection(defValSection, addfragptr.p->defValSectionI);
1883 
1884         SectionReader defValueReader(defValSection, getSectionSegmentPool());
1885 
1886         ndbrequire(defValueReader.step(addfragptr.p->defValNextPos));
1887 
1888         Uint32 defValueHeader;
1889         ndbrequire(defValueReader.peekWord(&defValueHeader));
1890 
1891         AttributeHeader ah(defValueHeader);
1892         Uint32 defValueLen = ah.getByteSize();
1893         Uint32 defValueWords = ((defValueLen +3)/4) + 1;
1894         Uint32 *dst = &signal->theData[startIndex];
1895         ndbrequire(defValueReader.getWords(dst, defValueWords));
1896         addfragptr.p->defValNextPos += defValueWords;
1897         sectionLen = defValueWords;
1898       }
1899 
1900       //A long section is attached when a default value is sent.
1901       if (sectionLen != 0)
1902       {
1903         LinearSectionPtr ptr[3];
1904         ptr[0].p= &signal->theData[startIndex];
1905         ptr[0].sz= sectionLen;
1906         sendSignal(tupRef, GSN_TUP_ADD_ATTRREQ,
1907                    signal, TupAddAttrReq::SignalLength, JBB, ptr, 1);
1908       }
1909       else
1910         sendSignal(tupRef, GSN_TUP_ADD_ATTRREQ,
1911                    signal, TupAddAttrReq::SignalLength, JBB);
1912 
1913       return;
1914     }
1915     if (DictTabInfo::isOrderedIndex(tabptr.p->tableType) &&
1916         primaryAttrId != ZNIL) {
1917       // this attribute is not for TUP
1918       jam();
1919       TupAddAttrConf* tupconf = (TupAddAttrConf*)signal->getDataPtrSend();
1920       tupconf->userPtr = addfragptr.i;
1921       tupconf->lastAttr = false;
1922       sendSignal(reference(), GSN_TUP_ADD_ATTCONF,
1923 		 signal, TupAddAttrConf::SignalLength, JBB);
1924       return;
1925     }
1926   }
1927 
1928   if (addfragptr.p->addfragStatus == AddFragRecord::TUX_ATTR_WAIT)
1929   {
1930     jam();
1931     if (DictTabInfo::isOrderedIndex(tabptr.p->tableType) &&
1932         primaryAttrId != ZNIL) {
1933       jam();
1934       TuxAddAttrReq* const tuxreq = (TuxAddAttrReq*)signal->getDataPtrSend();
1935       tuxreq->tuxConnectPtr = addfragptr.p->tuxConnectptr;
1936       tuxreq->notused1 = 0;
1937       tuxreq->attrId = attrId;
1938       tuxreq->attrDescriptor = entry.attrDescriptor;
1939       tuxreq->extTypeInfo = entry.extTypeInfo;
1940       tuxreq->primaryAttrId = primaryAttrId;
1941       BlockReference tuxRef = calcInstanceBlockRef(DBTUX);
1942       sendSignal(tuxRef, GSN_TUX_ADD_ATTRREQ,
1943 		 signal, TuxAddAttrReq::SignalLength, JBB);
1944       return;
1945     }
1946     if (DictTabInfo::isOrderedIndex(tabptr.p->tableType) &&
1947         primaryAttrId == ZNIL) {
1948       // this attribute is not for TUX
1949       jam();
1950       TuxAddAttrConf* tuxconf = (TuxAddAttrConf*)signal->getDataPtrSend();
1951       tuxconf->userPtr = addfragptr.i;
1952       tuxconf->lastAttr = false;
1953       sendSignal(reference(), GSN_TUX_ADD_ATTRCONF,
1954 		 signal, TuxAddAttrConf::SignalLength, JBB);
1955       return;
1956     }
1957   }
1958   ndbrequire(false);
1959 }//Dblqh::sendAddAttrReq
1960 
execLQHFRAGREQ(Signal * signal)1961 void Dblqh::execLQHFRAGREQ(Signal* signal)
1962 {
1963   jamEntry();
1964   LqhFragReq copy = *(LqhFragReq*)signal->getDataPtr();
1965   LqhFragReq * req = &copy;
1966 
1967   tabptr.i = req->tableId;
1968   ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
1969 
1970   if (tabptr.p->tableStatus != Tablerec::ADD_TABLE_ONGOING &&
1971       (AlterTableReq::getAddFragFlag(req->changeMask) == 0))
1972   {
1973     jam();
1974     fragrefLab(signal, ZTAB_STATE_ERROR, req);
1975     return;
1976   }//if
1977 
1978   if (getFragmentrec(signal, req->fragId))
1979   {
1980     jam();
1981     fragrefLab(signal, terrorCode, req);
1982     return;
1983   }//if
1984 
1985   if (!insertFragrec(signal, req->fragId))
1986   {
1987     jam();
1988     fragrefLab(signal, terrorCode, req);
1989     return;
1990   }//if
1991 
1992   Uint32 copyType = req->requestInfo & 3;
1993   bool tempTable = ((req->requestInfo & LqhFragReq::TemporaryTable) != 0);
1994   initFragrec(signal, tabptr.i, req->fragId, copyType);
1995   fragptr.p->startGci = req->startGci;
1996   fragptr.p->newestGci = req->startGci;
1997   ndbrequire(tabptr.p->tableType < 256);
1998   fragptr.p->tableType = (Uint8)tabptr.p->tableType;
1999 
2000   {
2001     NdbLogPartInfo lpinfo(instance());
2002     Uint32 logPartNo = lpinfo.partNoFromId(req->logPartId);
2003     ndbrequire(lpinfo.partNoOwner(logPartNo));
2004 
2005     LogPartRecordPtr ptr;
2006     ptr.i = lpinfo.partNoIndex(logPartNo);
2007     ptrCheckGuard(ptr, clogPartFileSize, logPartRecord);
2008     ndbrequire(ptr.p->logPartNo == logPartNo);
2009 
2010     fragptr.p->m_log_part_ptr_i = ptr.i;
2011     fragptr.p->lqhInstanceKey = getInstanceKey(tabptr.i, req->fragId);
2012   }
2013 
2014   /* Init per-frag op counters */
2015   fragptr.p->m_useStat.init();
2016 
2017   if (DictTabInfo::isOrderedIndex(tabptr.p->tableType)) {
2018     jam();
2019     // find corresponding primary table fragment
2020     TablerecPtr tTablePtr;
2021     tTablePtr.i = tabptr.p->primaryTableId;
2022     ptrCheckGuard(tTablePtr, ctabrecFileSize, tablerec);
2023     FragrecordPtr tFragPtr;
2024     tFragPtr.i = RNIL;
2025     for (Uint32 i = 0; i < NDB_ARRAY_SIZE(tTablePtr.p->fragid); i++) {
2026       if (tTablePtr.p->fragid[i] == fragptr.p->fragId) {
2027         jam();
2028         tFragPtr.i = tTablePtr.p->fragrec[i];
2029         break;
2030       }
2031     }
2032     ndbrequire(tFragPtr.i != RNIL);
2033     // store it
2034     fragptr.p->tableFragptr = tFragPtr.i;
2035   }
2036   else
2037   {
2038     jam();
2039     fragptr.p->tableFragptr = fragptr.i;
2040   }
2041 
2042   if (tempTable)
2043   {
2044 //--------------------------------------------
2045 // reqinfo bit 3-4 = 2 means temporary table
2046 // without logging or checkpointing.
2047 //--------------------------------------------
2048     jam();
2049     fragptr.p->logFlag = Fragrecord::STATE_FALSE;
2050     fragptr.p->lcpFlag = Fragrecord::LCP_STATE_FALSE;
2051   }//if
2052 
2053   seizeAddfragrec(signal);
2054   addfragptr.p->m_lqhFragReq = * req;
2055   addfragptr.p->fragmentPtr = fragptr.i;
2056 
2057   if (DictTabInfo::isTable(tabptr.p->tableType) ||
2058       DictTabInfo::isHashIndex(tabptr.p->tableType)) {
2059     jam();
2060     AccFragReq* const accreq = (AccFragReq*)signal->getDataPtrSend();
2061     accreq->userPtr = addfragptr.i;
2062     accreq->userRef = cownref;
2063     accreq->tableId = tabptr.i;
2064     accreq->reqInfo = 0;
2065     accreq->fragId = req->fragId;
2066     accreq->localKeyLen = addfragptr.p->m_lqhFragReq.localKeyLength;
2067     accreq->maxLoadFactor = addfragptr.p->m_lqhFragReq.maxLoadFactor;
2068     accreq->minLoadFactor = addfragptr.p->m_lqhFragReq.minLoadFactor;
2069     accreq->kValue = addfragptr.p->m_lqhFragReq.kValue;
2070     accreq->lhFragBits = addfragptr.p->m_lqhFragReq.lh3DistrBits;
2071     accreq->lhDirBits = addfragptr.p->m_lqhFragReq.lh3PageBits;
2072     accreq->keyLength = addfragptr.p->m_lqhFragReq.keyLength;
2073     /* --------------------------------------------------------------------- */
2074     /* Send ACCFRAGREQ, when confirmation is received send 2 * TUPFRAGREQ to */
2075     /* create 2 tuple fragments on this node.                                */
2076     /* --------------------------------------------------------------------- */
2077     addfragptr.p->addfragStatus = AddFragRecord::ACC_ADDFRAG;
2078     sendSignal(fragptr.p->accBlockref, GSN_ACCFRAGREQ,
2079 	       signal, AccFragReq::SignalLength, JBB);
2080     return;
2081   }
2082   if (DictTabInfo::isOrderedIndex(tabptr.p->tableType)) {
2083     jam();
2084     addfragptr.p->addfragStatus = AddFragRecord::WAIT_TUP;
2085     sendAddFragReq(signal);
2086     return;
2087   }
2088   ndbrequire(false);
2089 }//Dblqh::execLQHFRAGREQ()
2090 
2091 /* *************** */
2092 /*  ACCFRAGCONF  > */
2093 /* *************** */
execACCFRAGCONF(Signal * signal)2094 void Dblqh::execACCFRAGCONF(Signal* signal)
2095 {
2096   jamEntry();
2097   addfragptr.i = signal->theData[0];
2098   Uint32 taccConnectptr = signal->theData[1];
2099   //Uint32 fragId1 = signal->theData[2];
2100   Uint32 accFragPtr1 = signal->theData[4];
2101   ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord);
2102   ndbrequire(addfragptr.p->addfragStatus == AddFragRecord::ACC_ADDFRAG);
2103 
2104   addfragptr.p->accConnectptr = taccConnectptr;
2105   fragptr.i = addfragptr.p->fragmentPtr;
2106   c_fragment_pool.getPtr(fragptr);
2107   fragptr.p->accFragptr = accFragPtr1;
2108 
2109   addfragptr.p->addfragStatus = AddFragRecord::WAIT_TUP;
2110   sendAddFragReq(signal);
2111 }//Dblqh::execACCFRAGCONF()
2112 
2113 /* *************** */
2114 /*  TUPFRAGCONF  > */
2115 /* *************** */
execTUPFRAGCONF(Signal * signal)2116 void Dblqh::execTUPFRAGCONF(Signal* signal)
2117 {
2118   jamEntry();
2119   addfragptr.i = signal->theData[0];
2120   Uint32 tupConnectptr = signal->theData[1];
2121   Uint32 tupFragPtr = signal->theData[2];  /* TUP FRAGMENT POINTER */
2122   //Uint32 localFragId = signal->theData[3];  /* LOCAL FRAGMENT ID    */
2123   ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord);
2124   fragptr.i = addfragptr.p->fragmentPtr;
2125   c_fragment_pool.getPtr(fragptr);
2126   tabptr.i = fragptr.p->tabRef;
2127   ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
2128 
2129   switch (addfragptr.p->addfragStatus) {
2130   case AddFragRecord::WAIT_TUP:
2131     jam();
2132     fragptr.p->tupFragptr = tupFragPtr;
2133     addfragptr.p->tupConnectptr = tupConnectptr;
2134     if (DictTabInfo::isOrderedIndex(tabptr.p->tableType))
2135     {
2136       addfragptr.p->addfragStatus = AddFragRecord::WAIT_TUX;
2137       sendAddFragReq(signal);
2138       break;
2139     }
2140     c_acc->set_tup_fragptr(fragptr.p->accFragptr, tupFragPtr);
2141     goto done_with_frag;
2142     break;
2143   case AddFragRecord::WAIT_TUX:
2144     jam();
2145     fragptr.p->tuxFragptr = tupFragPtr;
2146     addfragptr.p->tuxConnectptr = tupConnectptr;
2147     goto done_with_frag;
2148     break;
2149   done_with_frag:
2150     /* ---------------------------------------------------------------- */
2151     /* Finished create of fragments. Now ready for creating attributes. */
2152     /* ---------------------------------------------------------------- */
2153     fragptr.p->fragStatus = Fragrecord::FSACTIVE;
2154     {
2155       LqhFragConf* conf = (LqhFragConf*)signal->getDataPtrSend();
2156       conf->senderData = addfragptr.p->m_lqhFragReq.senderData;
2157       conf->lqhFragPtr = RNIL;
2158       conf->tableId = addfragptr.p->m_lqhFragReq.tableId;
2159       conf->fragId = fragptr.p->fragId;
2160       conf->changeMask = addfragptr.p->m_lqhFragReq.changeMask;
2161       sendSignal(addfragptr.p->m_lqhFragReq.senderRef, GSN_LQHFRAGCONF,
2162 		 signal, LqhFragConf::SignalLength, JBB);
2163     }
2164     releaseAddfragrec(signal);
2165     break;
2166   default:
2167     ndbrequire(false);
2168     break;
2169   }
2170 }//Dblqh::execTUPFRAGCONF()
2171 
2172 /* *************** */
2173 /*  TUXFRAGCONF  > */
2174 /* *************** */
execTUXFRAGCONF(Signal * signal)2175 void Dblqh::execTUXFRAGCONF(Signal* signal)
2176 {
2177   jamEntry();
2178   execTUPFRAGCONF(signal);
2179 }//Dblqh::execTUXFRAGCONF
2180 
2181 /*
2182  * Add fragment in TUP or TUX.  Called up to 4 times.
2183  */
2184 void
sendAddFragReq(Signal * signal)2185 Dblqh::sendAddFragReq(Signal* signal)
2186 {
2187   fragptr.i = addfragptr.p->fragmentPtr;
2188   c_fragment_pool.getPtr(fragptr);
2189   tabptr.i = fragptr.p->tabRef;
2190   ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
2191   if (addfragptr.p->addfragStatus == AddFragRecord::WAIT_TUP)
2192   {
2193     TupFragReq* const tupFragReq = (TupFragReq*)signal->getDataPtrSend();
2194     tupFragReq->userPtr = addfragptr.i;
2195     tupFragReq->userRef = cownref;
2196     tupFragReq->reqInfo = 0; /* ADD TABLE */
2197     tupFragReq->tableId = tabptr.i;
2198     tupFragReq->fragId = addfragptr.p->m_lqhFragReq.fragId;
2199     tupFragReq->tablespaceid = addfragptr.p->m_lqhFragReq.tablespace_id;
2200     tupFragReq->maxRowsHigh = addfragptr.p->m_lqhFragReq.maxRowsHigh;
2201     tupFragReq->maxRowsLow = addfragptr.p->m_lqhFragReq.maxRowsLow;
2202     tupFragReq->minRowsHigh = addfragptr.p->m_lqhFragReq.minRowsHigh;
2203     tupFragReq->minRowsLow = addfragptr.p->m_lqhFragReq.minRowsLow;
2204     tupFragReq->changeMask = addfragptr.p->m_lqhFragReq.changeMask;
2205     sendSignal(fragptr.p->tupBlockref, GSN_TUPFRAGREQ,
2206                signal, TupFragReq::SignalLength, JBB);
2207     return;
2208   }
2209   if (addfragptr.p->addfragStatus == AddFragRecord::WAIT_TUX)
2210   {
2211     jam();
2212     ndbrequire(DictTabInfo::isOrderedIndex(tabptr.p->tableType));
2213     TuxFragReq* const tuxreq = (TuxFragReq*)signal->getDataPtrSend();
2214     tuxreq->userPtr = addfragptr.i;
2215     tuxreq->userRef = cownref;
2216     tuxreq->reqInfo = 0; /* ADD TABLE */
2217     tuxreq->tableId = tabptr.i;
2218     tuxreq->fragId = addfragptr.p->m_lqhFragReq.fragId;
2219     tuxreq->primaryTableId = tabptr.p->primaryTableId;
2220     // pointer to index fragment in TUP
2221     tuxreq->tupIndexFragPtrI = fragptr.p->tupFragptr;
2222     // pointers to table fragments in TUP and ACC
2223     FragrecordPtr tFragPtr;
2224     tFragPtr.i = fragptr.p->tableFragptr;
2225     c_fragment_pool.getPtr(tFragPtr);
2226     tuxreq->tupTableFragPtrI = tFragPtr.p->tupFragptr;
2227     tuxreq->accTableFragPtrI = tFragPtr.p->accFragptr;
2228     sendSignal(fragptr.p->tuxBlockref, GSN_TUXFRAGREQ,
2229                signal, TuxFragReq::SignalLength, JBB);
2230     return;
2231   }
2232 }//Dblqh::sendAddFragReq
2233 
2234 
2235 /* ************************************************************************>> */
2236 /*  TAB_COMMITREQ: Commit the new table for use in transactions. Sender DICT. */
2237 /* ************************************************************************>> */
execTAB_COMMITREQ(Signal * signal)2238 void Dblqh::execTAB_COMMITREQ(Signal* signal)
2239 {
2240   jamEntry();
2241   Uint32 dihPtr = signal->theData[0];
2242   BlockReference dihBlockref = signal->theData[1];
2243   tabptr.i = signal->theData[2];
2244 
2245   if (tabptr.i >= ctabrecFileSize) {
2246     jam();
2247     terrorCode = ZTAB_FILE_SIZE;
2248     signal->theData[0] = dihPtr;
2249     signal->theData[1] = cownNodeid;
2250     signal->theData[2] = tabptr.i;
2251     signal->theData[3] = terrorCode;
2252     sendSignal(dihBlockref, GSN_TAB_COMMITREF, signal, 4, JBB);
2253     return;
2254   }//if
2255   ptrAss(tabptr, tablerec);
2256   if (tabptr.p->tableStatus != Tablerec::ADD_TABLE_ONGOING) {
2257     jam();
2258     terrorCode = ZTAB_STATE_ERROR;
2259     signal->theData[0] = dihPtr;
2260     signal->theData[1] = cownNodeid;
2261     signal->theData[2] = tabptr.i;
2262     signal->theData[3] = terrorCode;
2263     signal->theData[4] = tabptr.p->tableStatus;
2264     sendSignal(dihBlockref, GSN_TAB_COMMITREF, signal, 5, JBB);
2265     ndbrequire(false);
2266     return;
2267   }//if
2268   tabptr.p->usageCountR = 0;
2269   tabptr.p->usageCountW = 0;
2270   tabptr.p->tableStatus = Tablerec::TABLE_DEFINED;
2271   signal->theData[0] = dihPtr;
2272   signal->theData[1] = cownNodeid;
2273   signal->theData[2] = tabptr.i;
2274   sendSignal(dihBlockref, GSN_TAB_COMMITCONF, signal, 3, JBB);
2275 
2276   return;
2277 }//Dblqh::execTAB_COMMITREQ()
2278 
2279 
fragrefLab(Signal * signal,Uint32 errorCode,const LqhFragReq * req)2280 void Dblqh::fragrefLab(Signal* signal,
2281                        Uint32 errorCode,
2282                        const LqhFragReq* req)
2283 {
2284   LqhFragRef * ref = (LqhFragRef*)signal->getDataPtrSend();
2285   ref->senderData = req->senderData;
2286   ref->errorCode = errorCode;
2287   ref->requestInfo = req->requestInfo;
2288   ref->tableId = req->tableId;
2289   ref->fragId = req->fragId;
2290   ref->changeMask = req->changeMask;
2291   sendSignal(req->senderRef, GSN_LQHFRAGREF, signal,
2292 	     LqhFragRef::SignalLength, JBB);
2293   return;
2294 }//Dblqh::fragrefLab()
2295 
2296 /*
2297  * Abort on-going ops.
2298  */
abortAddFragOps(Signal * signal)2299 void Dblqh::abortAddFragOps(Signal* signal)
2300 {
2301   if (addfragptr.p->tupConnectptr != RNIL) {
2302     jam();
2303     TupFragReq* const tupFragReq = (TupFragReq*)signal->getDataPtrSend();
2304     tupFragReq->userPtr = (Uint32)-1;
2305     tupFragReq->userRef = addfragptr.p->tupConnectptr;
2306     sendSignal(ctupBlockref, GSN_TUPFRAGREQ, signal, 2, JBB);
2307     addfragptr.p->tupConnectptr = RNIL;
2308   }
2309   if (addfragptr.p->tuxConnectptr != RNIL) {
2310     jam();
2311     TuxFragReq* const tuxFragReq = (TuxFragReq*)signal->getDataPtrSend();
2312     tuxFragReq->userPtr = (Uint32)-1;
2313     tuxFragReq->userRef = addfragptr.p->tuxConnectptr;
2314     sendSignal(ctuxBlockref, GSN_TUXFRAGREQ, signal, 2, JBB);
2315     addfragptr.p->tuxConnectptr = RNIL;
2316   }
2317 }
2318 
2319 /* ************>> */
2320 /*  ACCFRAGREF  > */
2321 /* ************>> */
execACCFRAGREF(Signal * signal)2322 void Dblqh::execACCFRAGREF(Signal* signal)
2323 {
2324   jamEntry();
2325   addfragptr.i = signal->theData[0];
2326   ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord);
2327   Uint32 errorCode = terrorCode = signal->theData[1];
2328   ndbrequire(addfragptr.p->addfragStatus == AddFragRecord::ACC_ADDFRAG);
2329 
2330   fragrefLab(signal, errorCode, &addfragptr.p->m_lqhFragReq);
2331   releaseAddfragrec(signal);
2332 
2333   return;
2334 }//Dblqh::execACCFRAGREF()
2335 
2336 /* ************>> */
2337 /*  TUPFRAGREF  > */
2338 /* ************>> */
execTUPFRAGREF(Signal * signal)2339 void Dblqh::execTUPFRAGREF(Signal* signal)
2340 {
2341   jamEntry();
2342   addfragptr.i = signal->theData[0];
2343   ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord);
2344   Uint32 errorCode = terrorCode = signal->theData[1];
2345   fragptr.i = addfragptr.p->fragmentPtr;
2346   c_fragment_pool.getPtr(fragptr);
2347 
2348   // no operation to release, just add some jams
2349   switch (addfragptr.p->addfragStatus) {
2350   case AddFragRecord::WAIT_TUP:
2351     jam();
2352     break;
2353   case AddFragRecord::WAIT_TUX:
2354     jam();
2355     break;
2356   default:
2357     ndbrequire(false);
2358     break;
2359   }
2360 
2361   fragrefLab(signal, errorCode, &addfragptr.p->m_lqhFragReq);
2362   releaseAddfragrec(signal);
2363 
2364 }//Dblqh::execTUPFRAGREF()
2365 
2366 void
execDROP_FRAG_REQ(Signal * signal)2367 Dblqh::execDROP_FRAG_REQ(Signal* signal)
2368 {
2369   DropFragReq *req = (DropFragReq*)signal->getDataPtr();
2370   seizeAddfragrec(signal);
2371   addfragptr.p->m_dropFragReq = *req;
2372 
2373   /**
2374    * 1 - self
2375    * 2 - acc
2376    * 3 - tup
2377    * 4 - tux (optional)
2378    */
2379   tabptr.i = req->tableId;
2380   ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
2381 
2382   deleteFragrec(req->fragId);
2383 
2384   Uint32 ref = calcInstanceBlockRef(DBACC);
2385   if (DictTabInfo::isOrderedIndex(tabptr.p->tableType))
2386   {
2387     jam();
2388     ref = calcInstanceBlockRef(DBTUP);
2389   }
2390 
2391   req->senderRef = reference();
2392   req->senderData = addfragptr.i;
2393   sendSignal(ref, GSN_DROP_FRAG_REQ, signal, DropFragReq::SignalLength, JBB);
2394 }
2395 
2396 void
execDROP_FRAG_REF(Signal * signal)2397 Dblqh::execDROP_FRAG_REF(Signal* signal)
2398 {
2399   ndbrequire(false);
2400 }
2401 
2402 void
execDROP_FRAG_CONF(Signal * signal)2403 Dblqh::execDROP_FRAG_CONF(Signal* signal)
2404 {
2405   DropFragConf* conf = (DropFragConf*)signal->getDataPtr();
2406   addfragptr.i = conf->senderData;
2407   ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord);
2408 
2409   Uint32 ref = RNIL;
2410   switch(refToMain(conf->senderRef)){
2411   case DBACC:
2412     jam();
2413     ref = calcInstanceBlockRef(DBTUP);
2414     break;
2415   case DBTUP:
2416   {
2417     tabptr.i = addfragptr.p->m_dropFragReq.tableId;
2418     ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
2419     if (DictTabInfo::isOrderedIndex(tabptr.p->tableType))
2420     {
2421       jam();
2422       ref = calcInstanceBlockRef(DBTUX);
2423     }
2424     break;
2425   }
2426   case DBTUX:
2427     break;
2428   default:
2429     ndbrequire(false);
2430   }
2431 
2432   if (ref != RNIL)
2433   {
2434     DropFragReq* req = (DropFragReq*)signal->getDataPtrSend();
2435     * req = addfragptr.p->m_dropFragReq;
2436     req->senderRef = reference();
2437     req->senderData = addfragptr.i;
2438     sendSignal(ref, GSN_DROP_FRAG_REQ, signal, DropFragReq::SignalLength,
2439                JBB);
2440     return;
2441   }
2442 
2443   conf->senderRef = reference();
2444   conf->senderData = addfragptr.p->m_dropFragReq.senderData;
2445   conf->tableId = addfragptr.p->m_dropFragReq.tableId;
2446   conf->fragId = addfragptr.p->m_dropFragReq.fragId;
2447   sendSignal(addfragptr.p->m_dropFragReq.senderRef, GSN_DROP_FRAG_CONF,
2448              signal, DropFragConf::SignalLength, JBB);
2449 
2450   releaseAddfragrec(signal);
2451 }
2452 
2453 /* ************>> */
2454 /*  TUXFRAGREF  > */
2455 /* ************>> */
execTUXFRAGREF(Signal * signal)2456 void Dblqh::execTUXFRAGREF(Signal* signal)
2457 {
2458   jamEntry();
2459   execTUPFRAGREF(signal);
2460 }//Dblqh::execTUXFRAGREF
2461 
2462 void
execPREP_DROP_TAB_REQ(Signal * signal)2463 Dblqh::execPREP_DROP_TAB_REQ(Signal* signal){
2464   jamEntry();
2465 
2466   PrepDropTabReq* req = (PrepDropTabReq*)signal->getDataPtr();
2467 
2468   Uint32 senderRef = req->senderRef;
2469   Uint32 senderData = req->senderData;
2470 
2471   TablerecPtr tabPtr;
2472   tabPtr.i = req->tableId;
2473   ptrCheckGuard(tabPtr, ctabrecFileSize, tablerec);
2474 
2475   Uint32 errCode = 0;
2476   switch(tabPtr.p->tableStatus) {
2477   case Tablerec::TABLE_DEFINED:
2478     jam();
2479     break;
2480   case Tablerec::NOT_DEFINED:
2481     jam();
2482     // Fall through
2483   case Tablerec::ADD_TABLE_ONGOING:
2484     jam();
2485     errCode = PrepDropTabRef::NoSuchTable;
2486     break;
2487   case Tablerec::PREP_DROP_TABLE_DONE:
2488     jam();
2489     errCode = PrepDropTabRef::DropInProgress;
2490     break;
2491   case Tablerec::DROP_TABLE_WAIT_USAGE:
2492   case Tablerec::DROP_TABLE_WAIT_DONE:
2493   case Tablerec::DROP_TABLE_ACC:
2494   case Tablerec::DROP_TABLE_TUP:
2495   case Tablerec::DROP_TABLE_TUX:
2496     jam();
2497     errCode = PrepDropTabRef::DropInProgress;
2498   case Tablerec::TABLE_READ_ONLY:
2499     jam();
2500     errCode = PrepDropTabRef::InvalidTableState;
2501     break;
2502   }
2503 
2504   if(errCode != 0)
2505   {
2506     jam();
2507 
2508     PrepDropTabRef* ref = (PrepDropTabRef*)signal->getDataPtrSend();
2509     ref->senderRef = reference();
2510     ref->senderData = senderData;
2511     ref->tableId = tabPtr.i;
2512     ref->errorCode = errCode;
2513     sendSignal(senderRef, GSN_PREP_DROP_TAB_REF, signal,
2514 	       PrepDropTabRef::SignalLength, JBB);
2515     return;
2516   }
2517 
2518   tabPtr.p->tableStatus = Tablerec::PREP_DROP_TABLE_DONE;
2519 
2520   PrepDropTabConf * conf = (PrepDropTabConf*)signal->getDataPtrSend();
2521   conf->tableId = tabPtr.i;
2522   conf->senderRef = reference();
2523   conf->senderData = senderData;
2524   sendSignal(senderRef, GSN_PREP_DROP_TAB_CONF, signal,
2525 	     PrepDropTabConf::SignalLength, JBB);
2526 }
2527 
2528 void
dropTab_wait_usage(Signal * signal)2529 Dblqh::dropTab_wait_usage(Signal* signal){
2530 
2531   TablerecPtr tabPtr;
2532   FragrecordPtr loc_fragptr;
2533   tabPtr.i = signal->theData[1];
2534   ptrCheckGuard(tabPtr, ctabrecFileSize, tablerec);
2535 
2536   Uint32 senderRef = signal->theData[2];
2537   Uint32 senderData = signal->theData[3];
2538 
2539   ndbrequire(tabPtr.p->tableStatus == Tablerec::DROP_TABLE_WAIT_USAGE);
2540 
2541   if (tabPtr.p->usageCountR > 0 || tabPtr.p->usageCountW > 0)
2542   {
2543     jam();
2544     sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 10, 4);
2545     return;
2546   }
2547 
2548   bool lcpDone = true;
2549   lcpPtr.i = 0;
2550   ptrAss(lcpPtr, lcpRecord);
2551   if(lcpPtr.p->lcpState != LcpRecord::LCP_IDLE)
2552   {
2553     jam();
2554 
2555     for (Uint32 i = 0; i < NDB_ARRAY_SIZE(tabPtr.p->fragrec); i++)
2556     {
2557       jam();
2558       loc_fragptr.i = tabPtr.p->fragrec[i];
2559       if (loc_fragptr.i != RNIL)
2560       {
2561         jam();
2562         c_fragment_pool.getPtr(loc_fragptr);
2563         if ((loc_fragptr.p->lcp_frag_ord_state == Fragrecord::LCP_QUEUED) &&
2564             (!ERROR_INSERTED(5089)))
2565         {
2566           /**
2567            * The fragment is queued up for an LCP scan, but it hasn't
2568            * started yet. In this case the LCP scan will be faked anyways,
2569            * so we will remove it from the queue immediately and fake its
2570            * completion. The only reason to send this signal is to ensure
2571            * that DIH and other blocks that wait for this REP signal can
2572            * keep track of the outstanding number of outstanding signals.
2573            * It will be dropped immediately after that when received in
2574            * DIH since the table is being dropped.
2575            */
2576           LcpRecord::FragOrd fragOrd;
2577           jam();
2578           CLEAR_ERROR_INSERT_VALUE;
2579           c_queued_lcp_frag_ord.remove(loc_fragptr);
2580 
2581           fragOrd.lcpFragOrd.lcpNo = loc_fragptr.p->lcp_frag_ord_lcp_no;
2582           fragOrd.lcpFragOrd.lcpId = loc_fragptr.p->lcp_frag_ord_lcp_id;
2583           fragOrd.lcpFragOrd.fragmentId = loc_fragptr.p->fragId;
2584           fragOrd.lcpFragOrd.tableId = loc_fragptr.p->tabRef;
2585 
2586           loc_fragptr.p->lcp_frag_ord_state = Fragrecord::LCP_EXECUTED;
2587 
2588           sendLCP_FRAG_REP(signal, fragOrd, loc_fragptr.p);
2589         }
2590         else if (loc_fragptr.p->lcp_frag_ord_state ==
2591                  Fragrecord::LCP_EXECUTING)
2592         {
2593           /**
2594            * The LCP scan is ongoing, we need to make sure it has completed
2595            * before we can drop the table. Thus we need to continue the
2596            * wait for a while longer.
2597            */
2598           jam();
2599           CLEAR_ERROR_INSERT_VALUE;
2600           lcpDone = false;
2601         }
2602         else if (ERROR_INSERTED(5088) || ERROR_INSERTED(5089))
2603         {
2604           /**
2605            * Delay drop table until we reach either LCP_QUEUED or
2606            * LCP_EXECUTING.
2607            */
2608           jam();
2609           lcpDone = false;
2610         }
2611       }
2612     }
2613   }
2614   else if (ERROR_INSERTED(5088) || ERROR_INSERTED(5089))
2615   {
2616     jam();
2617     CLEAR_ERROR_INSERT_VALUE;
2618   }
2619 
2620   if(!lcpDone)
2621   {
2622     jam();
2623     signal->theData[0] = ZDROP_TABLE_WAIT_USAGE;
2624     signal->theData[1] = tabPtr.i;
2625     signal->theData[2] = senderRef;
2626     signal->theData[3] = senderData;
2627     sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 10, 4);
2628     return;
2629   }
2630   tabPtr.p->tableStatus = Tablerec::DROP_TABLE_WAIT_DONE;
2631 
2632   DropTabConf * conf = (DropTabConf*)signal->getDataPtrSend();
2633   conf->tableId = tabPtr.i;
2634   conf->senderRef = reference();
2635   conf->senderData = senderData;
2636   sendSignal(senderRef, GSN_DROP_TAB_CONF, signal,
2637 	     DropTabConf::SignalLength, JBB);
2638 }
2639 
2640 void
execDROP_TAB_REQ(Signal * signal)2641 Dblqh::execDROP_TAB_REQ(Signal* signal){
2642   jamEntry();
2643   if (ERROR_INSERTED(5076))
2644   {
2645     /**
2646      * This error insert simulates a situation where it takes a long time
2647      * to execute DROP_TAB_REQ, such that we can crash the (dict) master
2648      * while there is an outstanding DROP_TAB_REQ.
2649      */
2650     jam();
2651     CLEAR_ERROR_INSERT_VALUE;
2652     sendSignalWithDelay(reference(), GSN_DROP_TAB_REQ, signal, 10000,
2653                         signal->getLength());
2654     return;
2655   }
2656   if (ERROR_INSERTED(5077))
2657   {
2658     jam();
2659     CLEAR_ERROR_INSERT_VALUE;
2660     /**
2661      * Kill this node 2 seconds from now. We wait for two seconds to make sure
2662      * that DROP_TAB_REQ messages have reached other nodes before this one
2663      * dies.
2664      */
2665     signal->theData[0] = 9999;
2666     sendSignalWithDelay(CMVMI_REF, GSN_NDB_TAMPER, signal, 2000, 1);
2667     return;
2668   }
2669   DropTabReq reqCopy = * (DropTabReq*)signal->getDataPtr();
2670   DropTabReq* req = &reqCopy;
2671 
2672   TablerecPtr tabPtr;
2673   tabPtr.i = req->tableId;
2674   ptrCheckGuard(tabPtr, ctabrecFileSize, tablerec);
2675 
2676   Uint32 errCode = 0;
2677   switch((DropTabReq::RequestType)req->requestType) {
2678   case DropTabReq::RestartDropTab:
2679     jam();
2680     tabPtr.p->tableStatus = Tablerec::DROP_TABLE_WAIT_DONE;
2681     break;
2682   case DropTabReq::CreateTabDrop:
2683     jam();
2684     tabPtr.p->tableStatus = Tablerec::DROP_TABLE_WAIT_DONE;
2685     break;
2686   case DropTabReq::OnlineDropTab:
2687     jam();
2688     switch(tabPtr.p->tableStatus) {
2689     case Tablerec::TABLE_DEFINED:
2690       jam();
2691       errCode = DropTabRef::DropWoPrep;
2692       break;
2693     case Tablerec::NOT_DEFINED:
2694       jam();
2695       errCode = DropTabRef::NoSuchTable;
2696       break;
2697     case Tablerec::ADD_TABLE_ONGOING:
2698       jam();
2699       ndbassert(false);
2700     case Tablerec::PREP_DROP_TABLE_DONE:
2701       jam();
2702       tabPtr.p->tableStatus = Tablerec::DROP_TABLE_WAIT_USAGE;
2703       signal->theData[0] = ZDROP_TABLE_WAIT_USAGE;
2704       signal->theData[1] = tabPtr.i;
2705       signal->theData[2] = req->senderRef;
2706       signal->theData[3] = req->senderData;
2707       dropTab_wait_usage(signal);
2708       return;
2709       break;
2710     case Tablerec::DROP_TABLE_WAIT_USAGE:
2711     case Tablerec::DROP_TABLE_ACC:
2712     case Tablerec::DROP_TABLE_TUP:
2713     case Tablerec::DROP_TABLE_TUX:
2714       ndbrequire(false);
2715     case Tablerec::DROP_TABLE_WAIT_DONE:
2716       jam();
2717       break;
2718     case Tablerec::TABLE_READ_ONLY:
2719       jam();
2720       errCode = DropTabRef::InvalidTableState;
2721       break;
2722     }
2723   }
2724 
2725   if (errCode)
2726   {
2727     jam();
2728     DropTabRef * ref = (DropTabRef*)signal->getDataPtrSend();
2729     ref->tableId = tabPtr.i;
2730     ref->senderRef = reference();
2731     ref->senderData = req->senderData;
2732     ref->errorCode = errCode;
2733     sendSignal(req->senderRef, GSN_DROP_TAB_REF, signal,
2734                DropTabRef::SignalLength, JBB);
2735     return;
2736   }
2737 
2738   ndbrequire(tabPtr.p->usageCountR == 0 && tabPtr.p->usageCountW == 0);
2739   seizeAddfragrec(signal);
2740   addfragptr.p->m_dropTabReq = * req;
2741   dropTable_nextStep(signal, addfragptr);
2742 }
2743 
2744 void
execDROP_TAB_REF(Signal * signal)2745 Dblqh::execDROP_TAB_REF(Signal* signal)
2746 {
2747   jamEntry();
2748   DropTabRef * ref = (DropTabRef*)signal->getDataPtr();
2749 
2750 #if defined ERROR_INSERT || defined VM_TRACE
2751   jamLine(ref->errorCode);
2752   ndbrequire(false);
2753 #endif
2754 
2755   Ptr<AddFragRecord> addFragPtr;
2756   addFragPtr.i = ref->senderData;
2757   ptrCheckGuard(addFragPtr, caddfragrecFileSize, addFragRecord);
2758   dropTable_nextStep(signal, addFragPtr);
2759 }
2760 
2761 void
execDROP_TAB_CONF(Signal * signal)2762 Dblqh::execDROP_TAB_CONF(Signal* signal)
2763 {
2764   jamEntry();
2765   DropTabConf * conf = (DropTabConf*)signal->getDataPtr();
2766 
2767   Ptr<AddFragRecord> addFragPtr;
2768   addFragPtr.i = conf->senderData;
2769   ptrCheckGuard(addFragPtr, caddfragrecFileSize, addFragRecord);
2770   dropTable_nextStep(signal, addFragPtr);
2771 }
2772 
2773 void
dropTable_nextStep(Signal * signal,Ptr<AddFragRecord> addFragPtr)2774 Dblqh::dropTable_nextStep(Signal* signal, Ptr<AddFragRecord> addFragPtr)
2775 {
2776   jam();
2777 
2778   TablerecPtr tabPtr;
2779   tabPtr.i = addFragPtr.p->m_dropTabReq.tableId;
2780   ptrCheckGuard(tabPtr, ctabrecFileSize, tablerec);
2781 
2782   Uint32 ref = 0;
2783   if (tabPtr.p->tableStatus == Tablerec::DROP_TABLE_WAIT_DONE)
2784   {
2785     jam();
2786     if (DictTabInfo::isTable(tabPtr.p->tableType) ||
2787         DictTabInfo::isHashIndex(tabPtr.p->tableType))
2788     {
2789       jam();
2790       ref = calcInstanceBlockRef(DBACC);
2791       tabPtr.p->tableStatus = Tablerec::DROP_TABLE_ACC;
2792     }
2793     else
2794     {
2795       jam();
2796       ref = calcInstanceBlockRef(DBTUP);
2797       tabPtr.p->tableStatus = Tablerec::DROP_TABLE_TUP;
2798     }
2799   }
2800   else if (tabPtr.p->tableStatus == Tablerec::DROP_TABLE_ACC)
2801   {
2802     jam();
2803     ref = calcInstanceBlockRef(DBTUP);
2804     tabPtr.p->tableStatus = Tablerec::DROP_TABLE_TUP;
2805   }
2806   else if (tabPtr.p->tableStatus == Tablerec::DROP_TABLE_TUP)
2807   {
2808     jam();
2809     if (DictTabInfo::isOrderedIndex(tabPtr.p->tableType))
2810     {
2811       jam();
2812       ref = calcInstanceBlockRef(DBTUX);
2813       tabPtr.p->tableStatus = Tablerec::DROP_TABLE_TUX;
2814     }
2815   }
2816 
2817   if (ref)
2818   {
2819     jam();
2820     DropTabReq* req = (DropTabReq*)signal->getDataPtrSend();
2821     req->senderData = addFragPtr.i;
2822     req->senderRef = reference();
2823     req->tableId = tabPtr.i;
2824     req->tableVersion = tabPtr.p->schemaVersion;
2825     req->requestType = addFragPtr.p->m_dropTabReq.requestType;
2826     sendSignal(ref, GSN_DROP_TAB_REQ, signal,
2827                DropTabReq::SignalLength, JBB);
2828     return;
2829   }
2830 
2831   removeTable(tabPtr.i);
2832   tabPtr.p->tableStatus = Tablerec::NOT_DEFINED;
2833 
2834   DropTabConf* conf = (DropTabConf*)signal->getDataPtrSend();
2835   conf->senderRef = reference();
2836   conf->senderData = addFragPtr.p->m_dropTabReq.senderData;
2837   conf->tableId = tabPtr.i;
2838   sendSignal(addFragPtr.p->m_dropTabReq.senderRef, GSN_DROP_TAB_CONF, signal,
2839              DropTabConf::SignalLength, JBB);
2840 
2841   addfragptr = addFragPtr;
2842   releaseAddfragrec(signal);
2843 }
2844 
removeTable(Uint32 tableId)2845 void Dblqh::removeTable(Uint32 tableId)
2846 {
2847   tabptr.i = tableId;
2848   ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
2849 
2850   for (Uint32 i = 0; i < NDB_ARRAY_SIZE(tabptr.p->fragid); i++) {
2851     jam();
2852     if (tabptr.p->fragid[i] != ZNIL) {
2853       jam();
2854       deleteFragrec(tabptr.p->fragid[i]);
2855     }//if
2856   }//for
2857 }//Dblqh::removeTable()
2858 
2859 void
execALTER_TAB_REQ(Signal * signal)2860 Dblqh::execALTER_TAB_REQ(Signal* signal)
2861 {
2862   jamEntry();
2863 
2864   if(!assembleFragments(signal))
2865     return;
2866 
2867   AlterTabReq copy = *(AlterTabReq*)signal->getDataPtr();
2868   const AlterTabReq* req = &copy;
2869   const Uint32 senderRef = req->senderRef;
2870   const Uint32 senderData = req->senderData;
2871   const Uint32 tableId = req->tableId;
2872   const Uint32 tableVersion = req->tableVersion;
2873   const Uint32 newTableVersion = req->newTableVersion;
2874   AlterTabReq::RequestType requestType =
2875     (AlterTabReq::RequestType) req->requestType;
2876 
2877   TablerecPtr tablePtr;
2878   tablePtr.i = tableId;
2879   ptrCheckGuard(tablePtr, ctabrecFileSize, tablerec);
2880 
2881   Uint32 len = signal->getLength();
2882   switch (requestType) {
2883   case AlterTabReq::AlterTablePrepare:
2884     jam();
2885     break;
2886   case AlterTabReq::AlterTableRevert:
2887     jam();
2888     tablePtr.p->schemaVersion = tableVersion;
2889     break;
2890   case AlterTabReq::AlterTableCommit:
2891     jam();
2892     tablePtr.p->schemaVersion = newTableVersion;
2893     if (AlterTableReq::getReorgFragFlag(req->changeMask))
2894     {
2895       jam();
2896       commit_reorg(tablePtr);
2897     }
2898     break;
2899   case AlterTabReq::AlterTableComplete:
2900     jam();
2901     break;
2902   case AlterTabReq::AlterTableSumaEnable:
2903     jam();
2904     break;
2905   case AlterTabReq::AlterTableSumaFilter:
2906     jam();
2907     signal->theData[len++] = cnewestGci + 3;
2908     break;
2909   case AlterTabReq::AlterTableReadOnly:
2910     jam();
2911     ndbrequire(tablePtr.p->tableStatus == Tablerec::TABLE_DEFINED);
2912     tablePtr.p->tableStatus = Tablerec::TABLE_READ_ONLY;
2913     signal->theData[0] = ZWAIT_READONLY;
2914     signal->theData[1] = tablePtr.i;
2915     signal->theData[2] = senderRef;
2916     signal->theData[3] = senderData;
2917     sendSignal(reference(), GSN_CONTINUEB, signal, 4, JBB);
2918     return;
2919   case AlterTabReq::AlterTableReadWrite:
2920     jam();
2921     ndbrequire(tablePtr.p->tableStatus == Tablerec::TABLE_READ_ONLY);
2922     tablePtr.p->tableStatus = Tablerec::TABLE_DEFINED;
2923     break;
2924   default:
2925     ndbrequire(false);
2926     break;
2927   }
2928 
2929   EXECUTE_DIRECT(DBTUP, GSN_ALTER_TAB_REQ, signal, len);
2930   jamEntry();
2931 
2932   Uint32 errCode = signal->theData[0];
2933   Uint32 connectPtr = signal->theData[1];
2934   if (errCode == 0)
2935   {
2936     // Request handled successfully
2937     AlterTabConf* conf = (AlterTabConf*)signal->getDataPtrSend();
2938     conf->senderRef = reference();
2939     conf->senderData = senderData;
2940     conf->connectPtr = connectPtr;
2941     sendSignal(senderRef, GSN_ALTER_TAB_CONF, signal,
2942                AlterTabConf::SignalLength, JBB);
2943   }
2944   else if (errCode == ~Uint32(0))
2945   {
2946     /**
2947      * Wait
2948      */
2949     ndbrequire(requestType == AlterTabReq::AlterTableSumaFilter);
2950     signal->theData[0] = ZWAIT_REORG_SUMA_FILTER_ENABLED;
2951     signal->theData[1] = cnewestGci + 3;
2952     signal->theData[2] = senderData;
2953     signal->theData[3] = connectPtr;
2954     signal->theData[4] = senderRef;
2955     wait_reorg_suma_filter_enabled(signal);
2956     return;
2957   }
2958   else
2959   {
2960     jam();
2961     AlterTabRef* ref = (AlterTabRef*)signal->getDataPtrSend();
2962     ref->senderRef = reference();
2963     ref->senderData = senderData;
2964     ref->connectPtr = connectPtr;
2965     ref->errorCode = errCode;
2966     sendSignal(senderRef, GSN_ALTER_TAB_REF, signal,
2967                AlterTabRef::SignalLength, JBB);
2968   }
2969 }
2970 
2971 void
wait_reorg_suma_filter_enabled(Signal * signal)2972 Dblqh::wait_reorg_suma_filter_enabled(Signal* signal)
2973 {
2974   if (cnewestCompletedGci >= signal->theData[1])
2975   {
2976     jam();
2977     Uint32 senderData = signal->theData[2];
2978     Uint32 connectPtr = signal->theData[3];
2979     Uint32 senderRef = signal->theData[4];
2980 
2981     AlterTabConf* conf = (AlterTabConf*)signal->getDataPtrSend();
2982     conf->senderRef = reference();
2983     conf->senderData = senderData;
2984     conf->connectPtr = connectPtr;
2985     sendSignal(senderRef, GSN_ALTER_TAB_CONF, signal,
2986                AlterTabConf::SignalLength, JBB);
2987     return;
2988   }
2989   sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 500, 5);
2990 }
2991 
2992 void
commit_reorg(TablerecPtr tablePtr)2993 Dblqh::commit_reorg(TablerecPtr tablePtr)
2994 {
2995   for (Uint32 i = 0; i < NDB_ARRAY_SIZE(tablePtr.p->fragrec); i++)
2996   {
2997     jam();
2998     Ptr<Fragrecord> fragPtr;
2999     if ((fragPtr.i = tablePtr.p->fragrec[i]) != RNIL)
3000     {
3001       jam();
3002       c_fragment_pool.getPtr(fragPtr);
3003       fragPtr.p->fragDistributionKey = (fragPtr.p->fragDistributionKey+1)&0xFF;
3004     }
3005   }
3006 }
3007 
3008 void
wait_readonly(Signal * signal)3009 Dblqh::wait_readonly(Signal* signal)
3010 {
3011   jam();
3012 
3013   Uint32 tableId = signal->theData[1];
3014 
3015   TablerecPtr tablePtr;
3016   tablePtr.i = tableId;
3017   ptrCheckGuard(tablePtr, ctabrecFileSize, tablerec);
3018   ndbrequire(tablePtr.p->tableStatus == Tablerec::TABLE_READ_ONLY);
3019 
3020   if (tablePtr.p->usageCountW > 0)
3021   {
3022     jam();
3023     sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 3000,
3024                         signal->getLength());
3025     return;
3026   }
3027 
3028   Uint32 senderRef = signal->theData[2];
3029   Uint32 senderData = signal->theData[3];
3030 
3031   // Request handled successfully
3032   AlterTabConf * conf = (AlterTabConf*)signal->getDataPtrSend();
3033   conf->senderRef = reference();
3034   conf->senderData = senderData;
3035   sendSignal(senderRef, GSN_ALTER_TAB_CONF, signal,
3036 	     AlterTabConf::SignalLength, JBB);
3037 }
3038 
3039 /* ************************************************************************>>
3040  * TIME_SIGNAL: Handles time-out of local operations. This is a clean-up
3041  * handler. If no other measure has succeeded in cleaning up after time-outs
3042  * or else then this routine will remove the transaction after 120 seconds of
3043  * inactivity. The check is performed once per 40 milliseconds.
3044  * ************************************************************************>> */
3045 #define LQH_TIME_SIGNAL_DELAY 40
execTIME_SIGNAL(Signal * signal)3046 void Dblqh::execTIME_SIGNAL(Signal* signal)
3047 {
3048   jamEntry();
3049 
3050   const NDB_TICKS currentTime = NdbTick_getCurrentTicks();
3051   Uint64 num_ms_elapsed = elapsed_time(signal,
3052                                        currentTime,
3053                                        c_latestTIME_SIGNAL,
3054                                        Uint32(LQH_TIME_SIGNAL_DELAY));
3055   sendTIME_SIGNAL(signal, currentTime, Uint32(LQH_TIME_SIGNAL_DELAY));
3056 
3057   /**
3058    * timer_handling will effectively call tick in the IOTracker and
3059    * this in turn will only do something every 128ms, so this means
3060    * that with a maximum of 8 runs per execTIME_SIGNAL we can at most
3061    * have one call to tick that actually does something useful.
3062    * We avoid using the same delay as in DBTC to avoid running the
3063    * delay handling code at the same time.
3064    *
3065    * The idea of calling timer_handling logically once per 10ms is
3066    * a remnant from when TIME_SIGNAL was generated by QMGR, this could
3067    * be changed in the future.
3068    */
3069   c_elapsed_time_millis += num_ms_elapsed;
3070   while (c_elapsed_time_millis > Uint64(10))
3071   {
3072     jam();
3073     c_elapsed_time_millis -= Uint64(10);
3074     timer_handling(signal);
3075   }
3076 }
3077 
timer_handling(Signal * signal)3078 void Dblqh::timer_handling(Signal *signal)
3079 {
3080   cLqhTimeOutCount++;
3081   cLqhTimeOutCheckCount++;
3082 
3083   for (logPartPtr.i = 0; logPartPtr.i < clogPartFileSize; logPartPtr.i++)
3084   {
3085     jam();
3086     ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
3087     int ret = logPartPtr.p->m_io_tracker.tick(10 * cLqhTimeOutCount,
3088                                               c_max_redo_lag,
3089                                               c_max_redo_lag_counter);
3090     if (ret < 0)
3091     {
3092       /**
3093        * set problem
3094        */
3095       update_log_problem(signal, logPartPtr,
3096                          LogPartRecord::P_REDO_IO_PROBLEM, true);
3097     }
3098     else if (ret > 0)
3099     {
3100       /**
3101        * clear
3102        */
3103       update_log_problem(signal, logPartPtr,
3104                          LogPartRecord::P_REDO_IO_PROBLEM, false);
3105     }
3106   }
3107 
3108   if (cLqhTimeOutCheckCount < 1000) {
3109     jam();
3110     return;
3111   }//if
3112 
3113   cLqhTimeOutCheckCount = 0;
3114 #ifdef VM_TRACE
3115   TcConnectionrecPtr tTcConptr;
3116 
3117   for (tTcConptr.i = 0; tTcConptr.i < ctcConnectrecFileSize;
3118        tTcConptr.i++) {
3119     jam();
3120     ptrAss(tTcConptr, tcConnectionrec);
3121     if ((tTcConptr.p->tcTimer != 0) &&
3122 	((tTcConptr.p->tcTimer + 12000) < cLqhTimeOutCount)) {
3123       ndbout << "Dblqh::execTIME_SIGNAL"<<endl
3124 	     << "Timeout found in tcConnectRecord " <<tTcConptr.i<<endl
3125 	     << " cLqhTimeOutCount = " << cLqhTimeOutCount << endl
3126 	     << " tcTimer="<<tTcConptr.p->tcTimer<<endl
3127 	     << " tcTimer+12000="<<tTcConptr.p->tcTimer + 12000<<endl;
3128 
3129       signal->theData[0] = 2307;
3130       signal->theData[1] = tTcConptr.i;
3131       execDUMP_STATE_ORD(signal);
3132 
3133       // Reset the timer
3134       tTcConptr.p->tcTimer = 0;
3135     }//if
3136   }//for
3137 #endif
3138 #ifdef VM_TRACE
3139   for (lfoPtr.i = 0; lfoPtr.i < clfoFileSize; lfoPtr.i++) {
3140     ptrAss(lfoPtr, logFileOperationRecord);
3141     if ((lfoPtr.p->lfoTimer != 0) &&
3142         ((lfoPtr.p->lfoTimer + 12000) < cLqhTimeOutCount)) {
3143       ndbout << "We have lost LFO record" << endl;
3144       ndbout << "index = " << lfoPtr.i;
3145       ndbout << "State = " << lfoPtr.p->lfoState;
3146       ndbout << " Page No = " << lfoPtr.p->lfoPageNo;
3147       ndbout << " noPagesRw = " << lfoPtr.p->noPagesRw;
3148       ndbout << "lfoWordWritten = " << lfoPtr.p->lfoWordWritten << endl;
3149       lfoPtr.p->lfoTimer = cLqhTimeOutCount;
3150     }//if
3151   }//for
3152 
3153 #endif
3154 
3155 #if 0
3156   LcpRecordPtr TlcpPtr;
3157   // Print information about the current local checkpoint
3158   TlcpPtr.i = 0;
3159   ptrAss(TlcpPtr, lcpRecord);
3160   ndbout << "Information about LCP in this LQH" << endl
3161 	 << "  lcpState=" << TlcpPtr.p->lcpState << endl
3162 	 << "   firstLcpLocAcc=" << TlcpPtr.p->firstLcpLocAcc << endl
3163 	 << "   firstLcpLocTup=" << TlcpPtr.p->firstLcpLocTup << endl
3164 	 << "   lcpAccptr=" << TlcpPtr.p->lcpAccptr << endl
3165 	 << "   lastFragmentFlag=" << TlcpPtr.p->lastFragmentFlag << endl
3166 	 << "   reportEmptyref=" << TlcpPtr.p->reportEmptyRef << endl
3167 	 << "   reportEmpty=" << TlcpPtr.p->reportEmpty << endl;
3168 #endif
3169 }//Dblqh::execTIME_SIGNAL()
3170 
3171 /* ######################################################################### */
3172 /* #######                  EXECUTION MODULE                         ####### */
3173 /* THIS MODULE HANDLES THE RECEPTION OF LQHKEYREQ AND ALL PROCESSING         */
3174 /* OF OPERATIONS ON BEHALF OF THIS REQUEST. THIS DOES ALSO INVOLVE           */
3175 /* RECEPTION OF VARIOUS TYPES OF ATTRINFO AND KEYINFO. IT DOES ALSO          */
3176 /* INVOLVE COMMUNICATION WITH ACC AND TUP.                                   */
3177 /* ######################################################################### */
3178 
3179 /**
3180  * earlyKeyReqAbort
3181  *
3182  * Exit early from handling an LQHKEYREQ request.
3183  * Method determines which resources (if any) need freed, then
3184  * signals requestor with error response.
3185  * * Verify all required resources are freed if adding new callers *
3186  */
earlyKeyReqAbort(Signal * signal,const LqhKeyReq * lqhKeyReq,bool isLongReq,Uint32 errCode)3187 void Dblqh::earlyKeyReqAbort(Signal* signal,
3188                              const LqhKeyReq * lqhKeyReq,
3189                              bool isLongReq,
3190                              Uint32 errCode)
3191 {
3192   jamEntry();
3193   const Uint32 transid1  = lqhKeyReq->transId1;
3194   const Uint32 transid2  = lqhKeyReq->transId2;
3195   Uint32 treqInfo        = lqhKeyReq->requestInfo;
3196 
3197   if (!isLongReq)
3198   {
3199     jam();
3200     /* The inlined AI length does not matter here.  Zero it to avoid
3201      * interpretation as 7.x bits (getNormalProtocolFlag).
3202      * bug#14702377
3203      */
3204     LqhKeyReq::clearAIInLqhKeyReq(treqInfo);
3205   }
3206   const Uint32 reqInfo   = treqInfo;
3207 
3208   bool tcConnectRecAllocated = (tcConnectptr.i != RNIL);
3209 
3210   if (tcConnectRecAllocated)
3211   {
3212     jam();
3213 
3214     /* Could have a commit-ack marker allocated. */
3215     remove_commit_marker(tcConnectptr.p);
3216 
3217     /* Could have long key/attr sections linked */
3218     ndbrequire(tcConnectptr.p->m_dealloc == 0);
3219     releaseOprec(signal);
3220 
3221 
3222     /*
3223      * Free the TcConnectRecord, ensuring that the
3224      * table reference counts have not been incremented and
3225      * so will not be decremented.
3226      * Also verify that we're not present in the transid
3227      * hash
3228      */
3229     ndbrequire(tcConnectptr.p->tableref == RNIL);
3230     /* Following is not 100% check, but a reasonable guard */
3231     ndbrequire(tcConnectptr.p->nextHashRec == RNIL);
3232     ndbrequire(tcConnectptr.p->prevHashRec == RNIL);
3233     releaseTcrec(signal, tcConnectptr);
3234   }
3235 
3236   /* Now perform signalling */
3237 
3238   if (LqhKeyReq::getDirtyFlag(reqInfo) &&
3239       LqhKeyReq::getOperation(reqInfo) == ZREAD &&
3240       !LqhKeyReq::getNormalProtocolFlag(reqInfo)){
3241     jam();
3242     /* Dirty read sends TCKEYREF direct to client, and nothing to TC */
3243     ndbrequire(LqhKeyReq::getApplicationAddressFlag(reqInfo));
3244     const Uint32 apiRef   = lqhKeyReq->variableData[0];
3245     const Uint32 apiOpRec = lqhKeyReq->variableData[1];
3246 
3247     TcKeyRef * const tcKeyRef = (TcKeyRef *) signal->getDataPtrSend();
3248 
3249     tcKeyRef->connectPtr = apiOpRec;
3250     tcKeyRef->transId[0] = transid1;
3251     tcKeyRef->transId[1] = transid2;
3252     tcKeyRef->errorCode = errCode;
3253     sendTCKEYREF(signal, apiRef, lqhKeyReq->tcBlockref, 0);
3254   } else {
3255     jam();
3256     /* All ops apart from dirty read send LQHKEYREF to TC
3257      * (This includes simple read)
3258      */
3259 
3260     const Uint32 clientPtr = lqhKeyReq->clientConnectPtr;
3261     Uint32 TcOprec = clientPtr;
3262     if(LqhKeyReq::getSameClientAndTcFlag(reqInfo) == 1){
3263       if(LqhKeyReq::getApplicationAddressFlag(reqInfo))
3264 	TcOprec = lqhKeyReq->variableData[2];
3265       else
3266 	TcOprec = lqhKeyReq->variableData[0];
3267     }
3268 
3269     LqhKeyRef * const ref = (LqhKeyRef*)signal->getDataPtrSend();
3270     ref->userRef = clientPtr;
3271     ref->connectPtr = TcOprec;
3272     ref->errorCode = errCode;
3273     ref->transId1 = transid1;
3274     ref->transId2 = transid2;
3275     sendSignal(signal->senderBlockRef(), GSN_LQHKEYREF, signal,
3276 	       LqhKeyRef::SignalLength, JBB);
3277   }//if
3278   return;
3279 }//Dblqh::earlyKeyReqAbort()
3280 
3281 Uint32
get_table_state_error(Ptr<Tablerec> tabPtr) const3282 Dblqh::get_table_state_error(Ptr<Tablerec> tabPtr) const
3283 {
3284   switch(tabPtr.p->tableStatus){
3285   case Tablerec::NOT_DEFINED:
3286     jam();
3287     return ZTABLE_NOT_DEFINED;
3288     break;
3289   case Tablerec::ADD_TABLE_ONGOING:
3290     jam();
3291   case Tablerec::PREP_DROP_TABLE_DONE:
3292     jam();
3293   case Tablerec::DROP_TABLE_WAIT_USAGE:
3294     jam();
3295   case Tablerec::DROP_TABLE_WAIT_DONE:
3296     jam();
3297   case Tablerec::DROP_TABLE_ACC:
3298     jam();
3299   case Tablerec::DROP_TABLE_TUP:
3300     jam();
3301   case Tablerec::DROP_TABLE_TUX:
3302     jam();
3303     return ZDROP_TABLE_IN_PROGRESS;
3304     break;
3305   case Tablerec::TABLE_DEFINED:
3306   case Tablerec::TABLE_READ_ONLY:
3307     ndbrequire(0);
3308     return ZTABLE_NOT_DEFINED;
3309     break;
3310   }
3311   ndbrequire(0);
3312   return ~Uint32(0);
3313 }
3314 
3315 int
check_tabstate(Signal * signal,const Tablerec * tablePtrP,Uint32 op)3316 Dblqh::check_tabstate(Signal * signal, const Tablerec * tablePtrP, Uint32 op)
3317 {
3318   if (tabptr.p->tableStatus == Tablerec::TABLE_READ_ONLY)
3319   {
3320     jam();
3321     if (op == ZREAD || op == ZREAD_EX || op == ZUNLOCK)
3322     {
3323       jam();
3324       return 0;
3325     }
3326     terrorCode = ZTABLE_READ_ONLY;
3327   }
3328   else
3329   {
3330     jam();
3331     terrorCode = get_table_state_error(tabptr);
3332   }
3333   abortErrorLab(signal);
3334   return 1;
3335 }
3336 
LQHKEY_abort(Signal * signal,int errortype)3337 void Dblqh::LQHKEY_abort(Signal* signal, int errortype)
3338 {
3339   switch (errortype) {
3340   case 0:
3341     jam();
3342     terrorCode = ZCOPY_NODE_ERROR;
3343     break;
3344   case 1:
3345     jam();
3346     terrorCode = ZNO_FREE_LQH_CONNECTION;
3347     break;
3348   case 2:
3349     jam();
3350     terrorCode = signal->theData[1];
3351     break;
3352   case 3:
3353     jam();
3354     ndbrequire((tcConnectptr.p->transactionState == TcConnectionrec::WAIT_ACC_ABORT) ||
3355                (tcConnectptr.p->transactionState == TcConnectionrec::ABORT_QUEUED));
3356     return;
3357     break;
3358   case 4:
3359     jam();
3360     terrorCode = get_table_state_error(tabptr);
3361     break;
3362   case 5:
3363     jam();
3364     terrorCode = ZINVALID_SCHEMA_VERSION;
3365     break;
3366   default:
3367     ndbrequire(false);
3368     break;
3369   }//switch
3370   abortErrorLab(signal);
3371 }//Dblqh::LQHKEY_abort()
3372 
LQHKEY_error(Signal * signal,int errortype)3373 void Dblqh::LQHKEY_error(Signal* signal, int errortype)
3374 {
3375   switch (errortype) {
3376   case 0:
3377     jam();
3378     break;
3379   case 1:
3380     jam();
3381     break;
3382   case 2:
3383     jam();
3384     break;
3385   case 3:
3386     jam();
3387     break;
3388   case 4:
3389     jam();
3390     break;
3391   case 5:
3392     jam();
3393     break;
3394   case 6:
3395     jam();
3396     break;
3397   default:
3398     jam();
3399     break;
3400   }//switch
3401   ndbrequire(false);
3402 }//Dblqh::LQHKEY_error()
3403 
execLQHKEYREF(Signal * signal)3404 void Dblqh::execLQHKEYREF(Signal* signal)
3405 {
3406   jamEntry();
3407   tcConnectptr.i = signal->theData[0];
3408   Uint32 tcOprec  = signal->theData[1];
3409   terrorCode = signal->theData[2];
3410   Uint32 transid1 = signal->theData[3];
3411   Uint32 transid2 = signal->theData[4];
3412   if (tcConnectptr.i >= ctcConnectrecFileSize) {
3413     errorReport(signal, 3);
3414     return;
3415   }//if
3416 
3417   ptrAss(tcConnectptr, tcConnectionrec);
3418   TcConnectionrec * const regTcPtr = tcConnectptr.p;
3419 
3420   if (likely(! ((regTcPtr->connectState == TcConnectionrec::LOG_CONNECTED) ||
3421                 (regTcPtr->connectState == TcConnectionrec::COPY_CONNECTED))))
3422   {
3423     /**
3424      * This...is unpleasant...
3425      *   LOG_CONNECTED and COPY_CONNECTED will not release there tcConnectptr
3426      *   before all outstanding is finished.
3427      *
3428      *   CONNECTED on the other hand can, (in ::execABORT)
3429      *     which means that findTransaction *should* be used
3430      *     to make sure that correct tcConnectptr is accessed.
3431      *
3432      *   However, as LOG_CONNECTED & COPY_CONNECTED only uses 1 tcConnectptr
3433      *     (and fiddles) with transid and other stuff, I could
3434      *     not find an easy way to modify the code so that findTransaction
3435      *     is usable also for them
3436      */
3437     if (findTransaction(transid1, transid2, tcOprec, 0) != ZOK)
3438     {
3439       jam();
3440       warningReport(signal, 14);
3441       return;
3442     }
3443   }
3444 
3445   switch (regTcPtr->connectState) {
3446   case TcConnectionrec::CONNECTED:
3447     jam();
3448     if (regTcPtr->abortState != TcConnectionrec::ABORT_IDLE) {
3449       warningReport(signal, 15);
3450       return;
3451     }//if
3452     abortErrorLab(signal);
3453     return;
3454     break;
3455   case TcConnectionrec::LOG_CONNECTED:
3456     jam();
3457     logLqhkeyrefLab(signal);
3458     return;
3459     break;
3460   case TcConnectionrec::COPY_CONNECTED:
3461     jam();
3462     copyLqhKeyRefLab(signal);
3463     return;
3464     break;
3465   default:
3466     warningReport(signal, 16);
3467     return;
3468     break;
3469   }//switch
3470 }//Dblqh::execLQHKEYREF()
3471 
3472 /* -------------------------------------------------------------------------- */
3473 /* -------                       ENTER PACKED_SIGNAL                  ------- */
3474 /* Execution of packed signal. The packed signal can contain COMMIT, COMPLETE */
3475 /* or LQHKEYCONF signals. These signals will be executed by their resp. exec  */
3476 /* functions.                                                                 */
3477 /* -------------------------------------------------------------------------- */
execPACKED_SIGNAL(Signal * signal)3478 void Dblqh::execPACKED_SIGNAL(Signal* signal)
3479 {
3480   Uint32 Tstep = 0;
3481   Uint32 Tlength;
3482   Uint32 TpackedData[28];
3483   Uint32 sig0, sig1, sig2, sig3 ,sig4, sig5, sig6;
3484 
3485   jamEntry();
3486   Tlength = signal->length();
3487   Uint32 TsenderRef = signal->getSendersBlockRef();
3488   Uint32 TcommitLen = 5;
3489   Uint32 Tgci_lo_mask = ~(Uint32)0;
3490 
3491   if (unlikely(!ndb_check_micro_gcp(getNodeInfo(refToNode(signal->getSendersBlockRef())).m_version)))
3492   {
3493     jam();
3494     TcommitLen = 4;
3495     Tgci_lo_mask = 0;
3496   }
3497 
3498 #ifdef ERROR_INSERT
3499   Uint32 senderBlockRef = signal->getSendersBlockRef();
3500 #endif
3501 
3502   ndbrequire(Tlength <= 25);
3503   MEMCOPY_NO_WORDS(&TpackedData[0], &signal->theData[0], Tlength);
3504 
3505   if (VERIFY_PACKED_RECEIVE)
3506   {
3507     ndbrequire(PackedSignal::verify(&TpackedData[0],
3508                                     Tlength,
3509                                     cownref,
3510                                     LQH_RECEIVE_TYPES,
3511                                     TcommitLen));
3512   }
3513 
3514   while (Tlength > Tstep) {
3515     switch (TpackedData[Tstep] >> 28) {
3516     case ZCOMMIT:
3517       jam();
3518       sig0 = TpackedData[Tstep + 0] & 0x0FFFFFFF;
3519       sig1 = TpackedData[Tstep + 1];
3520       sig2 = TpackedData[Tstep + 2];
3521       sig3 = TpackedData[Tstep + 3];
3522       sig4 = TpackedData[Tstep + 4];
3523       signal->theData[0] = sig0;
3524       signal->theData[1] = sig1;
3525       signal->theData[2] = sig2;
3526       signal->theData[3] = sig3;
3527       signal->theData[4] = sig4 & Tgci_lo_mask;
3528       signal->header.theLength = TcommitLen;
3529       jamBuffer()->markEndOfSigExec();
3530       execCOMMIT(signal);
3531       Tstep += TcommitLen;
3532       break;
3533     case ZCOMPLETE:
3534       jam();
3535       sig0 = TpackedData[Tstep + 0] & 0x0FFFFFFF;
3536       sig1 = TpackedData[Tstep + 1];
3537       sig2 = TpackedData[Tstep + 2];
3538       signal->theData[0] = sig0;
3539       signal->theData[1] = sig1;
3540       signal->theData[2] = sig2;
3541       signal->header.theLength = 3;
3542       jamBuffer()->markEndOfSigExec();
3543       execCOMPLETE(signal);
3544       Tstep += 3;
3545       break;
3546     case ZLQHKEYCONF: {
3547       jam();
3548       LqhKeyConf * lqhKeyConf = CAST_PTR(LqhKeyConf, signal->theData);
3549       sig0 = TpackedData[Tstep + 0] & 0x0FFFFFFF;
3550       sig1 = TpackedData[Tstep + 1];
3551       sig2 = TpackedData[Tstep + 2];
3552       sig3 = TpackedData[Tstep + 3];
3553       sig4 = TpackedData[Tstep + 4];
3554       sig5 = TpackedData[Tstep + 5];
3555       sig6 = TpackedData[Tstep + 6];
3556       lqhKeyConf->connectPtr = sig0;
3557       lqhKeyConf->opPtr = sig1;
3558       lqhKeyConf->userRef = sig2;
3559       lqhKeyConf->readLen = sig3;
3560       lqhKeyConf->transId1 = sig4;
3561       lqhKeyConf->transId2 = sig5;
3562       lqhKeyConf->numFiredTriggers = sig6;
3563       jamBuffer()->markEndOfSigExec();
3564       execLQHKEYCONF(signal);
3565       Tstep += LqhKeyConf::SignalLength;
3566       break;
3567     }
3568     case ZREMOVE_MARKER:
3569       jam();
3570       sig0 = TpackedData[Tstep + 1];
3571       sig1 = TpackedData[Tstep + 2];
3572       signal->theData[0] = sig0;
3573       signal->theData[1] = sig1;
3574       if ((TpackedData[Tstep] & 1) == 0)
3575       {
3576         /**
3577          * This is the normal path where we remove a marker
3578          * after commit.
3579          */
3580         signal->header.theLength = 2;
3581       }
3582       else
3583       {
3584         /**
3585          * This is a new path that is used when removing a marker
3586          * after an API node failure. We indicate this in packed
3587          * signal by setting one of the 28 unused bits in the
3588          * packed signal (the first word only uses the last 4 bits
3589          * in the first 32-bit word.
3590          *
3591          * We indicate this to the execREMOVE_MARKER_ORD method
3592          * by setting the Length of the signal to 3 (we cannot
3593          * add an extra parameter since the signal can be sent
3594          * directly and not through the packed signal interface.
3595          */
3596         signal->header.theLength = 3;
3597       }
3598       jamBuffer()->markEndOfSigExec();
3599       execREMOVE_MARKER_ORD(signal);
3600       Tstep += 3;
3601       break;
3602     case ZFIRE_TRIG_REQ:
3603       jam();
3604       ndbassert(FireTrigReq::SignalLength == 4);
3605       sig0 = TpackedData[Tstep + 0] & 0x0FFFFFFF;
3606       sig1 = TpackedData[Tstep + 1];
3607       sig2 = TpackedData[Tstep + 2];
3608       sig3 = TpackedData[Tstep + 3];
3609       signal->theData[0] = sig0;
3610       signal->theData[1] = sig1;
3611       signal->theData[2] = sig2;
3612       signal->theData[3] = sig3;
3613       signal->header.theLength = FireTrigReq::SignalLength;
3614       signal->header.theSendersBlockRef = TsenderRef;
3615       jamBuffer()->markEndOfSigExec();
3616       execFIRE_TRIG_REQ(signal);
3617       Tstep += FireTrigReq::SignalLength;
3618       break;
3619     default:
3620       ndbrequire(false);
3621       return;
3622     }//switch
3623 #ifdef ERROR_INSERT
3624     signal->header.theSendersBlockRef = senderBlockRef;
3625 #endif
3626   }//while
3627   ndbrequire(Tlength == Tstep);
3628   return;
3629 }//Dblqh::execPACKED_SIGNAL()
3630 
3631 void
execREMOVE_MARKER_ORD(Signal * signal)3632 Dblqh::execREMOVE_MARKER_ORD(Signal* signal)
3633 {
3634   CommitAckMarker key;
3635   key.transid1 = signal->theData[0];
3636   key.transid2 = signal->theData[1];
3637   bool removed_by_fail_api = (signal->header.theLength == 3);
3638   jamEntry();
3639 
3640   CommitAckMarkerPtr removedPtr;
3641   m_commitAckMarkerHash.remove(removedPtr, key);
3642   if (removedPtr.i != RNIL)
3643   {
3644     jam();
3645     ndbrequire(removedPtr.p->in_hash);
3646     removedPtr.p->in_hash = false;
3647     removedPtr.p->reference_count = 0;
3648     removedPtr.p->removed_by_fail_api = removed_by_fail_api;
3649     m_commitAckMarkerPool.releaseLast(removedPtr);
3650   }
3651   else
3652   {
3653     /**
3654      * This can happen in a special situation. This is when a large transaction
3655      * commits. As it decides to commit it sends of the commit decision to the
3656      * API. As soon as the API receives this it will send a TC_COMMIT_ACK
3657      * message back to DBTC. This message could arrive before the transaction
3658      * is fully completed. When the TC_COMMIT_ACK it is received it is
3659      * immediately transferred to the DBLQH's of the transaction owning the
3660      * commit ack markers. Next if the node where DBTC resides fails after
3661      * completing the sending of the TC_COMMIT_ACK, but before the transaction
3662      * is completed. This can happen in cases with a large transaction doing a
3663      * commit.
3664      *
3665      * Next step that happens is that a new DBTC takes over the transaction to
3666      * complete it. It will complete the parts remaining and since all parts
3667      * heard of were in the Committed state, the transaction will be committed
3668      * and a TCKEY_FAILCONF will be sent to the API. This TCKEY_FAILCONF will
3669      * trigger a new TC_COMMIT_ACK which will be passed through the new DBTC
3670      * and sent onwards to the participating DBLQH's. The REMOVE_MARKER_ORD
3671      * signal is received from DBTC here in DBLQH can thus in some cases be
3672      * received when multiple times, possibly even more than twice since there
3673      * could be multiple failures serially. The second and further times will
3674      * end up in this else-branch. There is no longer any record in DBLQH
3675      * with the received transaction id.
3676      *
3677      * This only happens as part of normal TC_COMMIT_ACK reception, so not when
3678      * the flag removed_by_fail_api is set.
3679      *
3680      * It can also happen in a situation where we are performing a TC takeover.
3681      * If an LQH instance reports having a marker, then the new TC inserts all
3682      * LQH instances as having the marker. So this means that a lot of LQH
3683      * instances will receive this message even when they haven't claimed to
3684      * have the marker. This is so since the protocol in LQH_TRANSCONF doesn't
3685      * specify which LQH instances that sent the LQH_TRANSCONF. Actually this
3686      * isn't entirely true since the senders block reference is always received
3687      * as part of Protocol6, thus we can actually find the LQH instance from
3688      * this. But for now we take this safe approach and send too many signals.
3689      * These signals will also end up in this branch.
3690      */
3691 #if (defined VM_TRACE || defined ERROR_INSERT) && defined(wl4391_todo)
3692     ndbout_c("%u Rem marker failed[%.8x %.8x] remove_by_fail_api = %u", instance(),
3693              key.transid1, key.transid2, removed_by_fail_api);
3694 #endif
3695   }
3696 #ifdef MARKER_TRACE
3697   ndbout_c("%u Rem marker[%.8x %.8x]", instance(), key.transid1, key.transid2);
3698 #endif
3699 }
3700 
3701 
3702 /* -------------------------------------------------------------------------- */
3703 /* -------                 ENTER SEND_PACKED                          ------- */
3704 /* Used to force a packed signal to be sent if local signal buffer is not     */
3705 /* empty.                                                                     */
3706 /* -------------------------------------------------------------------------- */
execSEND_PACKED(Signal * signal)3707 void Dblqh::execSEND_PACKED(Signal* signal)
3708 {
3709   HostRecordPtr Thostptr;
3710   UintR i;
3711   UintR j;
3712   UintR TpackedListIndex = cpackedListIndex;
3713   jamEntry();
3714   for (i = 0; i < TpackedListIndex; i++) {
3715     Thostptr.i = cpackedList[i];
3716     ptrAss(Thostptr, hostRecord);
3717     jam();
3718     ndbrequire(Thostptr.i - 1 < MAX_NDB_NODES - 1);
3719     for (j = 0; j < NDB_ARRAY_SIZE(Thostptr.p->lqh_pack); j++)
3720     {
3721       struct PackedWordsContainer * container = &Thostptr.p->lqh_pack[j];
3722       if (container->noOfPackedWords > 0) {
3723         jam();
3724         sendPackedSignal(signal, container);
3725       }
3726     }
3727     for (j = 0; j < NDB_ARRAY_SIZE(Thostptr.p->tc_pack); j++)
3728     {
3729       struct PackedWordsContainer * container = &Thostptr.p->tc_pack[j];
3730       if (container->noOfPackedWords > 0) {
3731         jam();
3732         sendPackedSignal(signal, container);
3733       }
3734     }
3735     Thostptr.p->inPackedList = false;
3736   }//for
3737   cpackedListIndex = 0;
3738   return;
3739 }//Dblqh::execSEND_PACKED()
3740 
3741 void
updatePackedList(Signal * signal,HostRecord * ahostptr,Uint16 hostId)3742 Dblqh::updatePackedList(Signal* signal, HostRecord * ahostptr, Uint16 hostId)
3743 {
3744   Uint32 TpackedListIndex = cpackedListIndex;
3745   if (ahostptr->inPackedList == false) {
3746     jam();
3747     ahostptr->inPackedList = true;
3748     cpackedList[TpackedListIndex] = hostId;
3749     cpackedListIndex = TpackedListIndex + 1;
3750   }//if
3751 }//Dblqh::updatePackedList()
3752 
3753 void
execREAD_PSEUDO_REQ(Signal * signal)3754 Dblqh::execREAD_PSEUDO_REQ(Signal* signal){
3755   jamEntry();
3756   TcConnectionrecPtr regTcPtr;
3757   regTcPtr.i = signal->theData[0];
3758   ptrCheckGuard(regTcPtr, ctcConnectrecFileSize, tcConnectionrec);
3759 
3760   switch(signal->theData[1])
3761   {
3762   case AttributeHeader::RANGE_NO:
3763     signal->theData[0] = regTcPtr.p->m_scan_curr_range_no;
3764     break;
3765   case AttributeHeader::ROW_COUNT:
3766   case AttributeHeader::COMMIT_COUNT:
3767   {
3768     jam();
3769     FragrecordPtr regFragptr;
3770     regFragptr.i = regTcPtr.p->fragmentptr;
3771     c_fragment_pool.getPtr(regFragptr);
3772 
3773     signal->theData[0] = regFragptr.p->accFragptr;
3774     c_acc->execREAD_PSEUDO_REQ(signal);
3775     break;
3776   }
3777   case AttributeHeader::RECORDS_IN_RANGE:
3778   case AttributeHeader::INDEX_STAT_KEY:
3779   case AttributeHeader::INDEX_STAT_VALUE:
3780   {
3781     jam();
3782     // scanptr gets reset somewhere within the timeslice
3783     ScanRecordPtr tmp;
3784     tmp.i = regTcPtr.p->tcScanRec;
3785     c_scanRecordPool.getPtr(tmp);
3786     signal->theData[0] = tmp.p->scanAccPtr;
3787     c_tux->execREAD_PSEUDO_REQ(signal);
3788     break;
3789   }
3790   case AttributeHeader::LOCK_REF:
3791   {
3792     /* Return 3x 32-bit words
3793      *  - LQH instance info
3794      *  - TC operation index
3795      *  - Bottom 32-bits of LQH-local key-request id (for uniqueness)
3796      */
3797     jam();
3798     signal->theData[0] = (getOwnNodeId() << 16) | regTcPtr.p->fragmentid;
3799     signal->theData[1] = regTcPtr.p->tcOprec;
3800     signal->theData[2] = (Uint32) regTcPtr.p->lqhKeyReqId;
3801     break;
3802   }
3803   case AttributeHeader::OP_ID:
3804   {
3805     jam();
3806     memcpy(signal->theData, &regTcPtr.p->lqhKeyReqId, 8);
3807     break;
3808   }
3809   case AttributeHeader::CORR_FACTOR64:
3810   {
3811     Uint32 add = 0;
3812     ScanRecordPtr tmp;
3813     tmp.i = regTcPtr.p->tcScanRec;
3814     if (tmp.i != RNIL)
3815     {
3816       c_scanRecordPool.getPtr(tmp);
3817       add = tmp.p->m_curr_batch_size_rows;
3818     }
3819 
3820     signal->theData[0] = regTcPtr.p->m_corrFactorLo + add;
3821     signal->theData[1] = regTcPtr.p->m_corrFactorHi;
3822     break;
3823   }
3824   default:
3825     ndbrequire(false);
3826   }
3827 }
3828 
3829 /* ************>> */
3830 /*  TUPKEYCONF  > */
3831 /* ************>> */
execTUPKEYCONF(Signal * signal)3832 void Dblqh::execTUPKEYCONF(Signal* signal)
3833 {
3834   TcConnectionrecPtr regTcPtr;
3835   const TupKeyConf * const tupKeyConf = (TupKeyConf *)signal->getDataPtr();
3836   regTcPtr.i = tupKeyConf->userPtr;
3837   TcConnectionrec *regTcConnectionrec = tcConnectionrec;
3838   Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize;
3839   jamEntry();
3840   ptrCheckGuard(regTcPtr, ttcConnectrecFileSize, regTcConnectionrec);
3841   Uint32 activeCreat = regTcPtr.p->activeCreat;
3842 
3843   FragrecordPtr regFragptr;
3844   regFragptr.i = regTcPtr.p->fragmentptr;
3845   c_fragment_pool.getPtr(regFragptr);
3846 
3847   fragptr = regFragptr;
3848   tcConnectptr = regTcPtr;
3849 
3850   switch (regTcPtr.p->transactionState) {
3851   case TcConnectionrec::WAIT_TUP:
3852     {
3853       jam();
3854       if (regTcPtr.p->seqNoReplica == 0) // Primary replica
3855         regTcPtr.p->numFiredTriggers = tupKeyConf->numFiredTriggers;
3856 
3857       Fragrecord::UsageStat& useStat = regFragptr.p->m_useStat;
3858       useStat.m_keyReqWordsReturned += tupKeyConf->readLength;
3859       useStat.m_keyInstructionCount += tupKeyConf->noExecInstructions;
3860 
3861       tupkeyConfLab(signal, regTcPtr.p);
3862     }
3863     break;
3864   case TcConnectionrec::COPY_TUPKEY:
3865     jam();
3866     copyTupkeyConfLab(signal);
3867     break;
3868   case TcConnectionrec::SCAN_TUPKEY:
3869     jam();
3870     scanTupkeyConfLab(signal);
3871     break;
3872   case TcConnectionrec::WAIT_TUP_TO_ABORT:
3873     jam();
3874 /* ------------------------------------------------------------------------- */
3875 // Abort was not ready to start until this signal came back. Now we are ready
3876 // to start the abort.
3877 /* ------------------------------------------------------------------------- */
3878     if (unlikely(activeCreat == Fragrecord::AC_NR_COPY))
3879     {
3880       jam();
3881       ndbrequire(regTcPtr.p->m_nr_delete.m_cnt);
3882       regTcPtr.p->m_nr_delete.m_cnt--;
3883       if (regTcPtr.p->m_nr_delete.m_cnt)
3884       {
3885 	jam();
3886 	/**
3887 	 * Let operation wait for pending NR operations
3888 	 *   even for before writing log...(as it's simpler)
3889 	 */
3890 
3891 #ifdef VM_TRACE
3892 	/**
3893 	 * Only disk table can have pending ops...
3894 	 */
3895 	TablerecPtr tablePtr;
3896 	tablePtr.i = regTcPtr.p->tableref;
3897 	ptrCheckGuard(tablePtr, ctabrecFileSize, tablerec);
3898 	ndbrequire(tablePtr.p->m_disk_table);
3899 #endif
3900 	return;
3901       }
3902     }
3903 
3904     abortCommonLab(signal);
3905     break;
3906   case TcConnectionrec::WAIT_ACC_ABORT:
3907   case TcConnectionrec::ABORT_QUEUED:
3908     jam();
3909 /* ------------------------------------------------------------------------- */
3910 /*      IGNORE SINCE ABORT OF THIS OPERATION IS ONGOING ALREADY.             */
3911 /* ------------------------------------------------------------------------- */
3912     break;
3913   default:
3914     ndbrequire(false);
3915     break;
3916   }//switch
3917 }//Dblqh::execTUPKEYCONF()
3918 
3919 /* ************> */
3920 /*  TUPKEYREF  > */
3921 /* ************> */
execTUPKEYREF(Signal * signal)3922 void Dblqh::execTUPKEYREF(Signal* signal)
3923 {
3924   const TupKeyRef * const tupKeyRef = (TupKeyRef *)signal->getDataPtr();
3925 
3926   jamEntry();
3927   tcConnectptr.i = tupKeyRef->userRef;
3928   terrorCode = tupKeyRef->errorCode;
3929   ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
3930   TcConnectionrec* regTcPtr = tcConnectptr.p;
3931   Uint32 activeCreat = regTcPtr->activeCreat;
3932 
3933   FragrecordPtr regFragptr;
3934   regFragptr.i = regTcPtr->fragmentptr;
3935   c_fragment_pool.getPtr(regFragptr);
3936   fragptr = regFragptr;
3937 
3938   TRACE_OP(regTcPtr, "TUPKEYREF");
3939 
3940   if (unlikely(activeCreat == Fragrecord::AC_NR_COPY))
3941   {
3942     jam();
3943     ndbrequire(regTcPtr->m_nr_delete.m_cnt);
3944     regTcPtr->m_nr_delete.m_cnt--;
3945     ndbassert(regTcPtr->transactionState == TcConnectionrec::WAIT_TUP ||
3946 	      regTcPtr->transactionState ==TcConnectionrec::WAIT_TUP_TO_ABORT);
3947   }
3948 
3949   switch (tcConnectptr.p->transactionState) {
3950   case TcConnectionrec::WAIT_TUP:
3951     {
3952       jam();
3953       Fragrecord::UsageStat& useStat = regFragptr.p->m_useStat;
3954       useStat.m_keyRefCount++;
3955       useStat.m_keyInstructionCount += tupKeyRef->noExecInstructions;
3956       abortErrorLab(signal);
3957     }
3958     break;
3959   case TcConnectionrec::COPY_TUPKEY:
3960     copyTupkeyRefLab(signal);
3961     break;
3962   case TcConnectionrec::SCAN_TUPKEY:
3963     jam();
3964     scanTupkeyRefLab(signal);
3965     break;
3966   case TcConnectionrec::WAIT_TUP_TO_ABORT:
3967     jam();
3968 /* ------------------------------------------------------------------------- */
3969 // Abort was not ready to start until this signal came back. Now we are ready
3970 // to start the abort.
3971 /* ------------------------------------------------------------------------- */
3972     abortCommonLab(signal);
3973     break;
3974   case TcConnectionrec::WAIT_ACC_ABORT:
3975   case TcConnectionrec::ABORT_QUEUED:
3976     jam();
3977 /* ------------------------------------------------------------------------- */
3978 /*       IGNORE SINCE ABORT OF THIS OPERATION IS ONGOING ALREADY.            */
3979 /* ------------------------------------------------------------------------- */
3980     break;
3981   default:
3982     jamLine(tcConnectptr.p->transactionState);
3983     ndbrequire(false);
3984     break;
3985   }//switch
3986 }//Dblqh::execTUPKEYREF()
3987 
sendPackedSignal(Signal * signal,struct PackedWordsContainer * container)3988 void Dblqh::sendPackedSignal(Signal* signal,
3989                              struct PackedWordsContainer * container)
3990 {
3991   Uint32 noOfWords = container->noOfPackedWords;
3992   BlockReference hostRef = container->hostBlockRef;
3993   container->noOfPackedWords = 0;
3994   MEMCOPY_NO_WORDS(&signal->theData[0],
3995                    &container->packedWords[0],
3996                    noOfWords);
3997   if (VERIFY_PACKED_SEND)
3998   {
3999     int receiveTypes = (refToMain(hostRef) == DBLQH)?
4000       LQH_RECEIVE_TYPES:
4001       TC_RECEIVE_TYPES;
4002     ndbrequire(PackedSignal::verify(&signal->theData[0],
4003                                     noOfWords,
4004                                     hostRef,
4005                                     receiveTypes,
4006                                     5)); /* Commit signal length */
4007   }
4008   sendSignal(hostRef, GSN_PACKED_SIGNAL, signal, noOfWords, JBB);
4009 }
4010 
sendCommitLqh(Signal * signal,BlockReference alqhBlockref)4011 void Dblqh::sendCommitLqh(Signal* signal, BlockReference alqhBlockref)
4012 {
4013   Uint32 instanceKey = refToInstance(alqhBlockref);
4014   ndbassert(refToMain(alqhBlockref) == DBLQH);
4015 
4016   if (instanceKey > MAX_NDBMT_LQH_THREADS)
4017   {
4018     /* No send packed support in these cases */
4019     jam();
4020     signal->theData[0] = tcConnectptr.p->clientConnectrec;
4021     signal->theData[1] = tcConnectptr.p->transid[0];
4022     signal->theData[2] = tcConnectptr.p->transid[1];
4023     sendSignal(alqhBlockref, GSN_COMMIT, signal, 3, JBB);
4024     return;
4025   }
4026 
4027   HostRecordPtr Thostptr;
4028 
4029   Thostptr.i = refToNode(alqhBlockref);
4030   ptrCheckGuard(Thostptr, chostFileSize, hostRecord);
4031   struct PackedWordsContainer * container = &Thostptr.p->lqh_pack[instanceKey];
4032 
4033   Uint32 Tdata[5];
4034   Tdata[0] = tcConnectptr.p->clientConnectrec;
4035   Tdata[1] = tcConnectptr.p->gci_hi;
4036   Tdata[2] = tcConnectptr.p->transid[0];
4037   Tdata[3] = tcConnectptr.p->transid[1];
4038   Tdata[4] = tcConnectptr.p->gci_lo;
4039   Uint32 len = 5;
4040 
4041   if (unlikely(!ndb_check_micro_gcp(getNodeInfo(Thostptr.i).m_version)))
4042   {
4043     jam();
4044     ndbassert(Tdata[4] == 0 || getNodeInfo(Thostptr.i).m_version == 0);
4045     len = 4;
4046   }
4047 
4048   if (container->noOfPackedWords > 25 - len) {
4049     jam();
4050     sendPackedSignal(signal, container);
4051   } else {
4052     jam();
4053     updatePackedList(signal, Thostptr.p, Thostptr.i);
4054   }
4055 
4056   Tdata[0] |= (ZCOMMIT << 28);
4057   Uint32 pos = container->noOfPackedWords;
4058   container->noOfPackedWords = pos + len;
4059   memcpy(&container->packedWords[pos], &Tdata[0], len << 2);
4060 }
4061 
sendCompleteLqh(Signal * signal,BlockReference alqhBlockref)4062 void Dblqh::sendCompleteLqh(Signal* signal, BlockReference alqhBlockref)
4063 {
4064   Uint32 instanceKey = refToInstance(alqhBlockref);
4065   ndbassert(refToMain(alqhBlockref) == DBLQH);
4066 
4067   if (instanceKey > MAX_NDBMT_LQH_THREADS)
4068   {
4069     /* No send packed support in these cases */
4070     jam();
4071     signal->theData[0] = tcConnectptr.p->clientConnectrec;
4072     signal->theData[1] = tcConnectptr.p->transid[0];
4073     signal->theData[2] = tcConnectptr.p->transid[1];
4074     sendSignal(alqhBlockref, GSN_COMPLETE, signal, 3, JBB);
4075     return;
4076   }
4077 
4078   HostRecordPtr Thostptr;
4079 
4080   Thostptr.i = refToNode(alqhBlockref);
4081   ptrCheckGuard(Thostptr, chostFileSize, hostRecord);
4082   struct PackedWordsContainer * container = &Thostptr.p->lqh_pack[instanceKey];
4083 
4084   Uint32 Tdata[3];
4085   Tdata[0] = tcConnectptr.p->clientConnectrec;
4086   Tdata[1] = tcConnectptr.p->transid[0];
4087   Tdata[2] = tcConnectptr.p->transid[1];
4088   Uint32 len = 3;
4089 
4090   if (container->noOfPackedWords > 22) {
4091     jam();
4092     sendPackedSignal(signal, container);
4093   } else {
4094     jam();
4095     updatePackedList(signal, Thostptr.p, Thostptr.i);
4096   }
4097 
4098   Tdata[0] |= (ZCOMPLETE << 28);
4099   Uint32 pos = container->noOfPackedWords;
4100   container->noOfPackedWords = pos + len;
4101   memcpy(&container->packedWords[pos], &Tdata[0], len << 2);
4102 }
4103 
sendCommittedTc(Signal * signal,BlockReference atcBlockref)4104 void Dblqh::sendCommittedTc(Signal* signal, BlockReference atcBlockref)
4105 {
4106   Uint32 instanceKey = refToInstance(atcBlockref);
4107 
4108   ndbassert(refToMain(atcBlockref) == DBTC);
4109   if (instanceKey > MAX_NDBMT_TC_THREADS)
4110   {
4111     /* No send packed support in these cases */
4112     jam();
4113     signal->theData[0] = tcConnectptr.p->clientConnectrec;
4114     signal->theData[1] = tcConnectptr.p->transid[0];
4115     signal->theData[2] = tcConnectptr.p->transid[1];
4116     sendSignal(atcBlockref, GSN_COMMITTED, signal, 3, JBB);
4117     return;
4118   }
4119 
4120   HostRecordPtr Thostptr;
4121   Thostptr.i = refToNode(atcBlockref);
4122   ptrCheckGuard(Thostptr, chostFileSize, hostRecord);
4123   struct PackedWordsContainer * container = &Thostptr.p->tc_pack[instanceKey];
4124 
4125   Uint32 Tdata[3];
4126   Tdata[0] = tcConnectptr.p->clientConnectrec;
4127   Tdata[1] = tcConnectptr.p->transid[0];
4128   Tdata[2] = tcConnectptr.p->transid[1];
4129   Uint32 len = 3;
4130 
4131   if (container->noOfPackedWords > 22) {
4132     jam();
4133     sendPackedSignal(signal, container);
4134   } else {
4135     jam();
4136     updatePackedList(signal, Thostptr.p, Thostptr.i);
4137   }
4138 
4139   Tdata[0] |= (ZCOMMITTED << 28);
4140   Uint32 pos = container->noOfPackedWords;
4141   container->noOfPackedWords = pos + len;
4142   memcpy(&container->packedWords[pos], &Tdata[0], len << 2);
4143 }
4144 
sendCompletedTc(Signal * signal,BlockReference atcBlockref)4145 void Dblqh::sendCompletedTc(Signal* signal, BlockReference atcBlockref)
4146 {
4147   Uint32 instanceKey = refToInstance(atcBlockref);
4148 
4149   ndbassert(refToMain(atcBlockref) == DBTC);
4150   if (instanceKey > MAX_NDBMT_TC_THREADS)
4151   {
4152     /* No handling of send packed in those cases */
4153     jam();
4154     signal->theData[0] = tcConnectptr.p->clientConnectrec;
4155     signal->theData[1] = tcConnectptr.p->transid[0];
4156     signal->theData[2] = tcConnectptr.p->transid[1];
4157     sendSignal(atcBlockref, GSN_COMPLETED, signal, 3, JBB);
4158     return;
4159   }
4160 
4161   HostRecordPtr Thostptr;
4162   Thostptr.i = refToNode(atcBlockref);
4163   ptrCheckGuard(Thostptr, chostFileSize, hostRecord);
4164   struct PackedWordsContainer * container = &Thostptr.p->tc_pack[instanceKey];
4165 
4166   Uint32 Tdata[3];
4167   Tdata[0] = tcConnectptr.p->clientConnectrec;
4168   Tdata[1] = tcConnectptr.p->transid[0];
4169   Tdata[2] = tcConnectptr.p->transid[1];
4170   Uint32 len = 3;
4171 
4172   if (container->noOfPackedWords > 22) {
4173     jam();
4174     sendPackedSignal(signal, container);
4175   } else {
4176     jam();
4177     updatePackedList(signal, Thostptr.p, Thostptr.i);
4178   }
4179 
4180   Tdata[0] |= (ZCOMPLETED << 28);
4181   Uint32 pos = container->noOfPackedWords;
4182   container->noOfPackedWords = pos + len;
4183   memcpy(&container->packedWords[pos], &Tdata[0], len << 2);
4184 }
4185 
sendLqhkeyconfTc(Signal * signal,BlockReference atcBlockref)4186 void Dblqh::sendLqhkeyconfTc(Signal* signal, BlockReference atcBlockref)
4187 {
4188   LqhKeyConf* lqhKeyConf;
4189   struct PackedWordsContainer * container;
4190   bool send_packed = true;
4191   HostRecordPtr Thostptr;
4192   Thostptr.i = refToNode(atcBlockref);
4193   Uint32 instanceKey = refToInstance(atcBlockref);
4194   ptrCheckGuard(Thostptr, chostFileSize, hostRecord);
4195   Uint32 block = refToMain(atcBlockref);
4196 
4197   if (block == DBLQH)
4198   {
4199     if (instanceKey <= MAX_NDBMT_LQH_THREADS)
4200     {
4201       container = &Thostptr.p->lqh_pack[instanceKey];
4202     }
4203     else
4204     {
4205       send_packed = false;
4206     }
4207   }
4208   else if (block == DBTC)
4209   {
4210     if (instanceKey <= MAX_NDBMT_TC_THREADS)
4211     {
4212       container = &Thostptr.p->tc_pack[instanceKey];
4213     }
4214     else
4215     {
4216       send_packed = false;
4217     }
4218   }
4219   else
4220   {
4221     send_packed = false;
4222   }
4223 
4224 /*******************************************************************
4225 // Normal path
4226 // This signal was intended for DBTC as part of the normal transaction
4227 // execution.
4228 // More unusual path
4229 // This signal was intended for DBLQH as part of log execution or
4230 // node recovery.
4231 // Yet another path
4232 // Intended for DBSPJ as part of join processing
4233 ********************************************************************/
4234   if (send_packed)
4235   {
4236     if (container->noOfPackedWords > (25 - LqhKeyConf::SignalLength)) {
4237       jam();
4238       sendPackedSignal(signal, container);
4239     } else {
4240       jam();
4241       updatePackedList(signal, Thostptr.p, Thostptr.i);
4242     }//if
4243     lqhKeyConf = (LqhKeyConf *)
4244       &container->packedWords[container->noOfPackedWords];
4245     container->noOfPackedWords += LqhKeyConf::SignalLength;
4246   }
4247   else
4248   {
4249     lqhKeyConf = (LqhKeyConf *)&signal->theData[0];
4250   }
4251 
4252   Uint32 ptrAndType = tcConnectptr.i | (ZLQHKEYCONF << 28);
4253   Uint32 tcOprec = tcConnectptr.p->tcOprec;
4254   Uint32 ownRef = cownref;
4255   lqhKeyConf->connectPtr = ptrAndType;
4256   lqhKeyConf->opPtr = tcOprec;
4257   lqhKeyConf->userRef = ownRef;
4258 
4259   Uint32 readlenAi = tcConnectptr.p->readlenAi;
4260   Uint32 transid1 = tcConnectptr.p->transid[0];
4261   Uint32 transid2 = tcConnectptr.p->transid[1];
4262   Uint32 numFiredTriggers = tcConnectptr.p->numFiredTriggers;
4263   lqhKeyConf->readLen = readlenAi;
4264   lqhKeyConf->transId1 = transid1;
4265   lqhKeyConf->transId2 = transid2;
4266   lqhKeyConf->numFiredTriggers = numFiredTriggers;
4267 
4268   if (!send_packed)
4269   {
4270     lqhKeyConf->connectPtr = tcConnectptr.i;
4271     sendSignal(atcBlockref, GSN_LQHKEYCONF,
4272                signal, LqhKeyConf::SignalLength, JBB);
4273   }
4274 }//Dblqh::sendLqhkeyconfTc()
4275 
4276 /* ************************************************************************>>
4277  * KEYINFO: Get tuple request from DBTC. Next step is to contact DBACC to get
4278  * key to tuple if all key/attrinfo has been received, else for more attrinfo
4279  * signals.
4280  * ************************************************************************>> */
execKEYINFO(Signal * signal)4281 void Dblqh::execKEYINFO(Signal* signal)
4282 {
4283   Uint32 tcOprec = signal->theData[0];
4284   Uint32 transid1 = signal->theData[1];
4285   Uint32 transid2 = signal->theData[2];
4286   jamEntry();
4287   if (findTransaction(transid1, transid2, tcOprec, 0) != ZOK) {
4288     jam();
4289     return;
4290   }//if
4291 
4292   receive_keyinfo(signal,
4293 		  signal->theData+KeyInfo::HeaderLength,
4294 		  signal->getLength()-KeyInfo::HeaderLength);
4295 }
4296 
4297 void
receive_keyinfo(Signal * signal,Uint32 * data,Uint32 len)4298 Dblqh::receive_keyinfo(Signal* signal,
4299 		       Uint32 * data, Uint32 len)
4300 {
4301   TcConnectionrec * const regTcPtr = tcConnectptr.p;
4302   TcConnectionrec::TransactionState state = regTcPtr->transactionState;
4303   if (state != TcConnectionrec::WAIT_TUPKEYINFO &&
4304       state != TcConnectionrec::WAIT_SCAN_AI)
4305   {
4306     jam();
4307 /*****************************************************************************/
4308 /* TRANSACTION WAS ABORTED, THIS IS MOST LIKELY A SIGNAL BELONGING TO THE    */
4309 /* ABORTED TRANSACTION. THUS IGNORE THE SIGNAL.                              */
4310 /*****************************************************************************/
4311     return;
4312   }//if
4313 
4314   Uint32 errorCode =
4315     handleLongTupKey(signal, data, len);
4316 
4317   if (errorCode != 0) {
4318     if (errorCode == 1) {
4319       jam();
4320       return;
4321     }//if
4322     jam();
4323     terrorCode = errorCode;
4324     if(state == TcConnectionrec::WAIT_TUPKEYINFO)
4325       abortErrorLab(signal);
4326     else
4327       abort_scan(signal, regTcPtr->tcScanRec, errorCode);
4328     return;
4329   }//if
4330   if(state == TcConnectionrec::WAIT_TUPKEYINFO)
4331   {
4332     FragrecordPtr regFragptr;
4333     regFragptr.i = regTcPtr->fragmentptr;
4334     c_fragment_pool.getPtr(regFragptr);
4335     fragptr = regFragptr;
4336     endgettupkeyLab(signal);
4337   }
4338   return;
4339 }//Dblqh::execKEYINFO()
4340 
4341 /* ------------------------------------------------------------------------- */
4342 /* FILL IN KEY DATA INTO DATA BUFFERS.                                       */
4343 /* ------------------------------------------------------------------------- */
handleLongTupKey(Signal * signal,Uint32 * dataPtr,Uint32 len)4344 Uint32 Dblqh::handleLongTupKey(Signal* signal,
4345 			       Uint32* dataPtr,
4346 			       Uint32 len)
4347 {
4348   TcConnectionrec * const regTcPtr = tcConnectptr.p;
4349   Uint32 total = regTcPtr->save1 + len;
4350   Uint32 primKeyLen = regTcPtr->primKeyLen;
4351 
4352   if (unlikely(total > primKeyLen))
4353   {
4354     /**
4355      * DBLQH 6.3 has the bad taste to send more KEYINFO than what is
4356      *  really in the key...up to 3 words extra
4357      */
4358     Uint32 extra = total - primKeyLen;
4359     ndbrequire(extra <= 3);
4360     ndbrequire(len > extra);
4361     len -= extra;
4362   }
4363 
4364   bool ok= appendToSection(regTcPtr->keyInfoIVal,
4365                            dataPtr,
4366                            len);
4367   if (unlikely(!ok))
4368   {
4369     jam();
4370     return ZGET_DATAREC_ERROR;
4371   }
4372 
4373   regTcPtr->save1 = total;
4374   return (total >= primKeyLen ? 0 : 1);
4375 }//Dblqh::handleLongTupKey()
4376 
4377 /* ------------------------------------------------------------------------- */
4378 /* -------                HANDLE ATTRINFO SIGNALS                    ------- */
4379 /*                                                                           */
4380 /* ------------------------------------------------------------------------- */
4381 /* ************************************************************************>> */
4382 /*  ATTRINFO: Continuation of KEYINFO signal (except for scans that do not use*/
4383 /*  any KEYINFO). When all key and attribute info is received we contact DBACC*/
4384 /*  for index handling.                                                       */
4385 /* ************************************************************************>> */
execATTRINFO(Signal * signal)4386 void Dblqh::execATTRINFO(Signal* signal)
4387 {
4388   Uint32 tcOprec = signal->theData[0];
4389   Uint32 transid1 = signal->theData[1];
4390   Uint32 transid2 = signal->theData[2];
4391   jamEntry();
4392   if (findTransaction(transid1,
4393                       transid2,
4394                       tcOprec, 0) != ZOK) {
4395     jam();
4396     return;
4397   }//if
4398 
4399   receive_attrinfo(signal,
4400 		   signal->getDataPtrSend()+AttrInfo::HeaderLength,
4401 		   signal->getLength()-AttrInfo::HeaderLength);
4402 }//Dblqh::execATTRINFO()
4403 
4404 void
receive_attrinfo(Signal * signal,Uint32 * dataPtr,Uint32 length)4405 Dblqh::receive_attrinfo(Signal* signal, Uint32 * dataPtr, Uint32 length)
4406 {
4407   TcConnectionrec * const regTcPtr = tcConnectptr.p;
4408   Uint32 totReclenAi = regTcPtr->totReclenAi;
4409   Uint32 currReclenAi = regTcPtr->currReclenAi + length;
4410   regTcPtr->currReclenAi = currReclenAi;
4411   if (totReclenAi == currReclenAi) {
4412     switch (regTcPtr->transactionState) {
4413     case TcConnectionrec::WAIT_ATTR:
4414     {
4415       jam();
4416       fragptr.i = regTcPtr->fragmentptr;
4417       c_fragment_pool.getPtr(fragptr);
4418       lqhAttrinfoLab(signal, dataPtr, length);
4419       endgettupkeyLab(signal);
4420       return;
4421       break;
4422     }
4423     case TcConnectionrec::WAIT_SCAN_AI:
4424       jam();
4425       scanAttrinfoLab(signal, dataPtr, length);
4426       return;
4427       break;
4428     case TcConnectionrec::WAIT_TUP_TO_ABORT:
4429     case TcConnectionrec::LOG_ABORT_QUEUED:
4430     case TcConnectionrec::ABORT_QUEUED:
4431     case TcConnectionrec::WAIT_ACC_ABORT:
4432     case TcConnectionrec::WAIT_AI_AFTER_ABORT:
4433       jam();
4434       aiStateErrorCheckLab(signal, dataPtr,length);
4435       return;
4436       break;
4437     default:
4438       jam();
4439       ndbrequire(regTcPtr->abortState != TcConnectionrec::ABORT_IDLE);
4440       break;
4441     }//switch
4442   } else if (currReclenAi < totReclenAi) {
4443     jam();
4444     switch (regTcPtr->transactionState) {
4445     case TcConnectionrec::WAIT_ATTR:
4446       jam();
4447       lqhAttrinfoLab(signal, dataPtr, length);
4448       return;
4449       break;
4450     case TcConnectionrec::WAIT_SCAN_AI:
4451       jam();
4452       scanAttrinfoLab(signal, dataPtr, length);
4453       return;
4454       break;
4455     case TcConnectionrec::WAIT_TUP_TO_ABORT:
4456     case TcConnectionrec::LOG_ABORT_QUEUED:
4457     case TcConnectionrec::ABORT_QUEUED:
4458     case TcConnectionrec::WAIT_ACC_ABORT:
4459     case TcConnectionrec::WAIT_AI_AFTER_ABORT:
4460       jam();
4461       aiStateErrorCheckLab(signal, dataPtr, length);
4462       return;
4463       break;
4464     default:
4465       jam();
4466       ndbrequire(regTcPtr->abortState != TcConnectionrec::ABORT_IDLE);
4467       break;
4468     }//switch
4469   } else {
4470     switch (regTcPtr->transactionState) {
4471     case TcConnectionrec::WAIT_SCAN_AI:
4472       jam();
4473       scanAttrinfoLab(signal, dataPtr, length);
4474       return;
4475       break;
4476     default:
4477       ndbout_c("%d", regTcPtr->transactionState);
4478       ndbrequire(false);
4479       break;
4480     }//switch
4481   }//if
4482   return;
4483 }
4484 
4485 /* ************************************************************************>> */
4486 /*  TUP_ATTRINFO: Interpreted execution in DBTUP generates redo-log info      */
4487 /*  which is sent back to DBLQH for logging. This is because the decision     */
4488 /*  to execute or not is made in DBTUP and thus we cannot start logging until */
4489 /*  DBTUP part has been run.                                                  */
4490 /* ************************************************************************>> */
execTUP_ATTRINFO(Signal * signal)4491 void Dblqh::execTUP_ATTRINFO(Signal* signal)
4492 {
4493   TcConnectionrec *regTcConnectionrec = tcConnectionrec;
4494   Uint32 tcIndex = signal->theData[0];
4495   Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize;
4496   jamEntry();
4497   tcConnectptr.i = tcIndex;
4498   ptrCheckGuard(tcConnectptr, ttcConnectrecFileSize, regTcConnectionrec);
4499   TcConnectionrec * const regTcPtr = tcConnectptr.p;
4500 
4501   ndbrequire(regTcPtr->transactionState == TcConnectionrec::WAIT_TUP);
4502 
4503   /* TUP_ATTRINFO signal is unrelated to ATTRINFO
4504    * It just transports a section IVAL from TUP back to
4505    * LQH
4506    */
4507   ndbrequire(signal->header.theLength == 3);
4508   Uint32 tupAttrInfoWords= signal->theData[1];
4509   Uint32 tupAttrInfoIVal= signal->theData[2];
4510 
4511   ndbassert(tupAttrInfoWords > 0);
4512   ndbassert(tupAttrInfoIVal != RNIL);
4513 
4514   /* If we have stored ATTRINFO that we sent to TUP,
4515    * free it now
4516    */
4517   if (regTcPtr->attrInfoIVal != RNIL)
4518   {
4519     /* We should be expecting to receive attrInfo back */
4520     ndbassert( !(regTcPtr->m_flags &
4521                  TcConnectionrec::OP_SAVEATTRINFO) );
4522     releaseSection( regTcPtr->attrInfoIVal );
4523     regTcPtr->attrInfoIVal= RNIL;
4524   }
4525 
4526   /* Store reference to ATTRINFO from TUP */
4527   regTcPtr->attrInfoIVal= tupAttrInfoIVal;
4528   regTcPtr->currTupAiLen= tupAttrInfoWords;
4529 
4530 }//Dblqh::execTUP_ATTRINFO()
4531 
4532 /* ------------------------------------------------------------------------- */
4533 /* -------                HANDLE ATTRINFO FROM LQH                   ------- */
4534 /*                                                                           */
4535 /* ------------------------------------------------------------------------- */
lqhAttrinfoLab(Signal * signal,Uint32 * dataPtr,Uint32 length)4536 void Dblqh::lqhAttrinfoLab(Signal* signal, Uint32* dataPtr, Uint32 length)
4537 {
4538   /* Store received AttrInfo in a long section */
4539   jam();
4540   if (saveAttrInfoInSection(dataPtr, length) == ZOK) {
4541     ;
4542   } else {
4543     jam();
4544 /* ------------------------------------------------------------------------- */
4545 /* WE MIGHT BE WAITING FOR RESPONSE FROM SOME BLOCK HERE. THUS WE NEED TO    */
4546 /* GO THROUGH THE STATE MACHINE FOR THE OPERATION.                           */
4547 /* ------------------------------------------------------------------------- */
4548     localAbortStateHandlerLab(signal);
4549     return;
4550   }//if
4551 }//Dblqh::lqhAttrinfoLab()
4552 
4553 /* ------------------------------------------------------------------------- */
4554 /* ------         FIND TRANSACTION BY USING HASH TABLE               ------- */
4555 /*                                                                           */
4556 /* We keep a hash structure of TcConnectionrec which are identified by:      */
4557 /*  - Id of Transaction owning this TcConnectionrec.                         */
4558 /*  - A 'tcOpRec' id which uniquely(*below) identify this TcConnectionRec    */
4559 /*    within this specific transaction.                                      */
4560 /*  - An optional 'hashHi' id used for SCANREQs in cases where 'tcOpRec'     */
4561 /*    on its own cant provide uniqueness.                                    */
4562 /*    This is required in cases where there are multiple (internal) clients  */
4563 /*    producing REQs where the uniqueness is only guaranteed within          */
4564 /*    each client. Currently the only such client is the SPJ block.          */
4565 /*                                                                           */
4566 /* Hash lookup of TcConnectionrecPtr might be required for TcConnectionRecs  */
4567 /* having a lifetime beyond the initial REQ. That is:                        */
4568 /*  - Short requests awaiting for a later ATTR- or KEYINFO.                  */
4569 /*  - SCANREQ which may need a later NEXTREQ to fetch more or close scan     */
4570 /*  - Transactional (non-DirtyOp) REQs which need a later abort, commit      */
4571 /*    or unlock request.                                                     */
4572 /*                                                                           */
4573 /* TcConnectionrec's identified as not requiring hash lookup are not         */
4574 /* inserted in the hash table!                                               */
4575 /*                                                                           */
4576 /* 'tcOpRec' ids comes from TC. Where TC has released the record (dirtyOp),  */
4577 /* the id can be reused. Therefore it cannot be considered 'unique' beyond   */
4578 /* the reception of the request signal (train). For non dirty operations it  */
4579 /* is unique for the lifecycle of the operation at TC.                       */
4580 /*                                                                           */
4581 /* NOTE:                                                                     */
4582 /*   The internal clients of NDB does *not* guarantee hash uniqueness        */
4583 /*   for LQHKEYREQs as described above (SPJ, node restart ..). However,      */
4584 /*   these requests are all 'long', 'dirtyOp'-requests and thus neither      */
4585 /*   inserted nor searched after in the hash table.                          */
4586 /*                                                                           */
4587 /* ------------------------------------------------------------------------- */
findTransaction(UintR Transid1,UintR Transid2,UintR TcOprec,Uint32 hi)4588 int Dblqh::findTransaction(UintR Transid1, UintR Transid2, UintR TcOprec,
4589                            Uint32 hi)
4590 {
4591   TcConnectionrec *regTcConnectionrec = tcConnectionrec;
4592   Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize;
4593   TcConnectionrecPtr locTcConnectptr;
4594 
4595   Uint32 ThashIndex = (Transid1 ^ TcOprec) & 1023;
4596   locTcConnectptr.i = ctransidHash[ThashIndex];
4597   while (locTcConnectptr.i != RNIL) {
4598     ptrCheckGuard(locTcConnectptr, ttcConnectrecFileSize, regTcConnectionrec);
4599     if ((locTcConnectptr.p->transid[0] == Transid1) &&
4600         (locTcConnectptr.p->transid[1] == Transid2) &&
4601         (locTcConnectptr.p->tcOprec == TcOprec) &&
4602         (locTcConnectptr.p->tcHashKeyHi == hi)) {
4603 /* FIRST PART OF TRANSACTION CORRECT */
4604 /* SECOND PART ALSO CORRECT */
4605 /* THE OPERATION RECORD POINTER IN TC WAS ALSO CORRECT */
4606       jam();
4607       tcConnectptr.i = locTcConnectptr.i;
4608       tcConnectptr.p = locTcConnectptr.p;
4609       ndbassert(tcConnectptr.p->hashIndex == ThashIndex);
4610       return (int)ZOK;
4611     }//if
4612     jam();
4613 /* THIS WAS NOT THE TRANSACTION WHICH WAS SOUGHT */
4614     locTcConnectptr.i = locTcConnectptr.p->nextHashRec;
4615   }//while
4616 /* WE DID NOT FIND THE TRANSACTION, REPORT NOT FOUND */
4617   return (int)ZNOT_FOUND;
4618 }//Dblqh::findTransaction()
4619 
4620 /* ------------------------------------------------------------------------- */
4621 /* -------           SAVE ATTRINFO INTO ATTR SECTION                 ------- */
4622 /*                                                                           */
4623 /* ------------------------------------------------------------------------- */
saveAttrInfoInSection(const Uint32 * dataPtr,Uint32 len)4624 int Dblqh::saveAttrInfoInSection(const Uint32* dataPtr, Uint32 len)
4625 {
4626   TcConnectionrec * const regTcPtr = tcConnectptr.p;
4627 
4628   bool ok= appendToSection(regTcPtr->attrInfoIVal,
4629                            dataPtr,
4630                            len);
4631 
4632   if (unlikely(!ok))
4633   {
4634     jam();
4635     terrorCode = ZGET_ATTRINBUF_ERROR;
4636     return ZGET_ATTRINBUF_ERROR;
4637   }//if
4638 
4639   if (regTcPtr->m_flags & TcConnectionrec::OP_SAVEATTRINFO)
4640     regTcPtr->currTupAiLen += len;
4641 
4642   return ZOK;
4643 } // saveAttrInfoInSection
4644 
4645 
4646 /* ==========================================================================
4647  * =======                        SEIZE TC CONNECT RECORD             =======
4648  *
4649  *       GETS A NEW TC CONNECT RECORD FROM FREELIST.
4650  * ========================================================================= */
seizeTcrec()4651 void Dblqh::seizeTcrec()
4652 {
4653   TcConnectionrecPtr locTcConnectptr;
4654 
4655   locTcConnectptr.i = cfirstfreeTcConrec;
4656 
4657   Uint32 numFree = ctcNumFree;
4658   Uint32 timeOutCount = cLqhTimeOutCount;
4659 
4660   ptrCheckGuard(locTcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
4661 
4662   Uint32 nextTc = locTcConnectptr.p->nextTcConnectrec;
4663 
4664   locTcConnectptr.p->nextTcConnectrec = RNIL;
4665   locTcConnectptr.p->clientConnectrec = RNIL;
4666   locTcConnectptr.p->clientBlockref = RNIL;
4667   locTcConnectptr.p->tableref = RNIL;
4668   locTcConnectptr.p->hashIndex = RNIL;
4669 
4670   ctcNumFree = numFree - 1;
4671   cfirstfreeTcConrec = nextTc;
4672 
4673   locTcConnectptr.p->tcTimer = timeOutCount;
4674   locTcConnectptr.p->abortState = TcConnectionrec::ABORT_IDLE;
4675   locTcConnectptr.p->connectState = TcConnectionrec::CONNECTED;
4676   locTcConnectptr.p->savePointId = 0;
4677   locTcConnectptr.p->gci_hi = 0;
4678   locTcConnectptr.p->gci_lo = 0;
4679 
4680   tcConnectptr = locTcConnectptr;
4681 }//Dblqh::seizeTcrec()
4682 
4683 bool
checkTransporterOverloaded(Signal * signal,const NodeBitmask & all,const LqhKeyReq * req)4684 Dblqh::checkTransporterOverloaded(Signal* signal,
4685                                   const NodeBitmask& all,
4686                                   const LqhKeyReq* req)
4687 {
4688   /* FC : Quick exit if the mask is clear? */
4689   // nodes likely to be affected by this op
4690   NodeBitmask mask;
4691   // tc
4692   Uint32 tc_node = refToNode(req->tcBlockref);
4693   if (tc_node < MAX_NODES) // not worth to crash here
4694     mask.set(tc_node);
4695   const Uint8 op = LqhKeyReq::getOperation(req->requestInfo);
4696   if (op == ZREAD || op == ZREAD_EX || op == ZUNLOCK) {
4697     // the receiver
4698     Uint32 api_node = refToNode(req->variableData[0]);
4699     if (api_node < MAX_NODES) // not worth to crash here
4700       mask.set(api_node);
4701   } else {
4702     // next replica
4703     Uint32 replica_node = LqhKeyReq::getNextReplicaNodeId(req->fragmentData);
4704     if (replica_node < MAX_NODES) // could be ZNIL
4705       mask.set(replica_node);
4706     // event subscribers
4707     const Suma* suma = (Suma*)globalData.getBlock(SUMA);
4708     mask.bitOR(suma->getSubscriberNodes());
4709   }
4710   mask.bitAND(all);
4711   if (likely(mask.isclear()))
4712   {
4713     return false;
4714   }
4715 
4716   jam();
4717   /* Overloaded, do some accounting */
4718   c_keyOverloads++;
4719 
4720   if (tc_node < MAX_NODES && all.get(tc_node))
4721   {
4722     jam();
4723     c_keyOverloadsTcNode++;
4724   }
4725 
4726   if (op == ZREAD || op == ZREAD_EX || op == ZUNLOCK)
4727   {
4728     jam();
4729     // the receiver
4730     Uint32 api_node = refToNode(req->variableData[0]);
4731     if ((api_node < MAX_NODES) && // not worth to crash here
4732         (all.get(api_node)))
4733     {
4734       jam();
4735       c_keyOverloadsReaderApi++;
4736     }
4737   }
4738   else
4739   {
4740     jam();
4741     // write
4742     // next replica
4743     Uint32 replica_node = LqhKeyReq::getNextReplicaNodeId(req->fragmentData);
4744     if ((replica_node < MAX_NODES) &&
4745         (all.get(replica_node)))
4746     {
4747       jam();
4748       c_keyOverloadsPeerNode++;
4749     }
4750 
4751     // event subscribers
4752     const Suma* suma = (Suma*)globalData.getBlock(SUMA);
4753     NodeBitmask subscribers = suma->getSubscriberNodes();
4754     subscribers.bitAND(all);
4755     if (!subscribers.isclear())
4756     {
4757       jam();
4758       c_keyOverloadsSubscriber++;
4759     }
4760   }
4761 
4762   return true;
4763 }
4764 
execSIGNAL_DROPPED_REP(Signal * signal)4765 void Dblqh::execSIGNAL_DROPPED_REP(Signal* signal)
4766 {
4767   /* An incoming signal was dropped, handle it
4768    * Dropped signal really means that we ran out of
4769    * long signal buffering to store its sections
4770    */
4771   jamEntry();
4772 
4773   if (!assembleDroppedFragments(signal))
4774   {
4775     jam();
4776     return;
4777   }
4778 
4779   const SignalDroppedRep* rep = (SignalDroppedRep*) &signal->theData[0];
4780   Uint32 originalGSN= rep->originalGsn;
4781   const bool isLongReq = (rep->originalSectionCount > 0);
4782 
4783   DEBUG("SignalDroppedRep received for GSN " << originalGSN);
4784 
4785   switch(originalGSN) {
4786   case GSN_LQHKEYREQ:
4787   {
4788     jam();
4789     /* Get original signal data - unfortunately it may
4790      * have been truncated.  We must not read beyond
4791      * word # 22
4792      * We will notify the client that their LQHKEYREQ
4793      * failed
4794      */
4795     tcConnectptr.i = RNIL;
4796     const LqhKeyReq * const truncatedLqhKeyReq =
4797       (LqhKeyReq *) &rep->originalData[0];
4798 
4799     earlyKeyReqAbort(signal, truncatedLqhKeyReq, isLongReq, ZGET_DATAREC_ERROR);
4800 
4801     break;
4802   }
4803   case GSN_SCAN_FRAGREQ:
4804   {
4805     jam();
4806     /* Get original signal data - unfortunately it may
4807      * have been truncated.  We must not read beyond
4808      * word # 22
4809      * We will notify the client that their SCAN_FRAGREQ
4810      * failed
4811      */
4812     // TODO : Handle fragmented failure
4813     const ScanFragReq* const truncatedScanFragReq =
4814       (ScanFragReq*) &rep->originalData[0];
4815     const Uint32 senderData= truncatedScanFragReq->senderData;
4816     const Uint32 transid1= truncatedScanFragReq->transId1;
4817     const Uint32 transid2= truncatedScanFragReq->transId2;
4818 
4819     /* Send SCAN_FRAGREF back to the client */
4820     ScanFragRef* ref= (ScanFragRef*)&signal->theData[0];
4821     ref->senderData= senderData;
4822     ref->transId1= transid1;
4823     ref->transId2= transid2;
4824     ref->errorCode= ZGET_ATTRINBUF_ERROR;
4825 
4826     sendSignal(signal->senderBlockRef(), GSN_SCAN_FRAGREF, signal,
4827                ScanFragRef::SignalLength, JBB);
4828     break;
4829   }
4830   default:
4831     jam();
4832     /* Don't expect dropped signals for other GSNs,
4833      * default handling
4834      */
4835     SimulatedBlock::execSIGNAL_DROPPED_REP(signal);
4836   };
4837 
4838   return;
4839 }
4840 
4841 // Get size of interpreted program, in words.
getProgramWordCount(SegmentedSectionPtr attrInfo)4842 static inline Uint32 getProgramWordCount(SegmentedSectionPtr attrInfo)
4843 {
4844   /*
4845     The second word of 'attrinfo' contains the length of the interpreted
4846     program, and the fifth contains the length of associated subroutines.
4847     (There should be a header of 5 length fields at the start of
4848     'attrinfo'.)
4849   */
4850   assert(attrInfo.sz>=5);
4851   SectionReader aiReader(attrInfo, g_sectionSegmentPool);
4852   Uint32 header[5];
4853   const bool ok =
4854     aiReader.getWords(header, sizeof(header)/sizeof(header[0]));
4855   assert(ok);
4856   (void) ok; // Prevent compiler warning.
4857   return header[1]+header[4];
4858 }
4859 
4860 /* ------------------------------------------------------------------------- */
4861 /* -------                TAKE CARE OF LQHKEYREQ                     ------- */
4862 /* LQHKEYREQ IS THE SIGNAL THAT STARTS ALL OPERATIONS IN THE LQH BLOCK       */
4863 /* THIS SIGNAL CONTAINS A LOT OF INFORMATION ABOUT WHAT TYPE OF OPERATION,   */
4864 /* KEY INFORMATION, ATTRIBUTE INFORMATION, NODE INFORMATION AND A LOT MORE   */
4865 /* ------------------------------------------------------------------------- */
execLQHKEYREQ(Signal * signal)4866 void Dblqh::execLQHKEYREQ(Signal* signal)
4867 {
4868   UintR sig0, sig1, sig2, sig3, sig4, sig5;
4869   Uint8 tfragDistKey;
4870 
4871   const LqhKeyReq * const lqhKeyReq = (LqhKeyReq *)signal->getDataPtr();
4872   SectionHandle handle(this, signal);
4873   const bool isLongReq = (handle.m_cnt > 0);
4874   tcConnectptr.i = RNIL;
4875 
4876   {
4877     const NodeBitmask& all = globalTransporterRegistry.get_status_overloaded();
4878     if (unlikely(!all.isclear()))
4879     {
4880       if (checkTransporterOverloaded(signal, all, lqhKeyReq))
4881       {
4882         /* Overloaded, reject new work */
4883         jam();
4884         releaseSections(handle);
4885         earlyKeyReqAbort(signal, lqhKeyReq, isLongReq,
4886                          ZTRANSPORTER_OVERLOADED_ERROR);
4887         return;
4888       }
4889     }
4890   }
4891 
4892   const UintR Treqinfo = lqhKeyReq->requestInfo;
4893 
4894   if (ERROR_INSERTED(5078) &&
4895       refToMain(signal->header.theSendersBlockRef) == DBSPJ &&
4896       LqhKeyReq::getDirtyFlag(Treqinfo) &&
4897       !LqhKeyReq::getNormalProtocolFlag(Treqinfo))
4898   {
4899     /**
4900      * This is used to trigger Bug#16187976 "NDBD NODE FAILS TO START WITH
4901      * ILLEGAL SIGNAL RECEIVED (GSN 121 NOT ADDED)". This bug occurs if a
4902      * ROUTE_ORD signal carrying a TCKEYREC signal is sent via the SPJ block.
4903      * ROUTE_ORD signals should always be sent via TC, which unlike SPJ should
4904      * be connected to the API. (Otherwise, the API will initiate its own
4905      * error handling which will compensate for TCKEYREC and other missing
4906      * signals.) The tests above check that we use the short-circuited protocol,
4907      * meaning that LQH wants to send TCKEYREC directly to the API, instead
4908      * of sending LQHKEYREC to SPJ (or TC).
4909      * Here we enable a different error insert (5079) which we test for in
4910      * Dblqh::sendTCKEYREF() below. It is done this way since in
4911      * sendTCKEYREF() we would otherwise not have sufficient context to tell
4912      * when to send the ROUTE_ORD signal.
4913      */
4914     SET_ERROR_INSERT_VALUE(5079);
4915   }
4916 
4917   if (ERROR_INSERTED_CLEAR(5047) ||
4918       ERROR_INSERTED(5079))
4919   {
4920     jam();
4921     releaseSections(handle);
4922     earlyKeyReqAbort(signal, lqhKeyReq, isLongReq,
4923                      ZTRANSPORTER_OVERLOADED_ERROR);
4924     return;
4925   }
4926 
4927   sig0 = lqhKeyReq->clientConnectPtr;
4928   if (ctcNumFree > ZNUM_RESERVED_TC_CONNECT_RECORDS &&
4929       !ERROR_INSERTED_CLEAR(5031)) {
4930     jamEntry();
4931     seizeTcrec();
4932   } else {
4933 /* ------------------------------------------------------------------------- */
4934 /* NO FREE TC RECORD AVAILABLE, THUS WE CANNOT HANDLE THE REQUEST.           */
4935 /* ------------------------------------------------------------------------- */
4936     releaseSections(handle);
4937     earlyKeyReqAbort(signal, lqhKeyReq, isLongReq, ZNO_TC_CONNECT_ERROR);
4938     return;
4939   }//if
4940 
4941   if(ERROR_INSERTED(5038) &&
4942      refToNode(signal->getSendersBlockRef()) != getOwnNodeId()){
4943     jam();
4944     releaseSections(handle);
4945     SET_ERROR_INSERT_VALUE(5039);
4946     return;
4947   }
4948 
4949   Uint32 tot_lqh_key_req_count = cTotalLqhKeyReqCount;
4950   Uint32 num_operations = c_Counters.operations;
4951 
4952   TcConnectionrec * const regTcPtr = tcConnectptr.p;
4953   jamLine(tcConnectptr.i & 0xFFFF);
4954   c_Counters.operations = num_operations + 1;
4955   cTotalLqhKeyReqCount = tot_lqh_key_req_count + 1;
4956 
4957   Uint32 senderRef = regTcPtr->clientBlockref = signal->senderBlockRef();
4958   regTcPtr->clientConnectrec = sig0;
4959   regTcPtr->tcOprec = sig0;
4960   regTcPtr->tcHashKeyHi = 0;
4961   regTcPtr->storedProcId = ZNIL;
4962   regTcPtr->lqhKeyReqId = cTotalLqhKeyReqCount;
4963   regTcPtr->commitAckMarker = RNIL;
4964   regTcPtr->m_flags= 0;
4965   if (isLongReq)
4966   {
4967     regTcPtr->m_flags|= TcConnectionrec::OP_ISLONGREQ;
4968   }
4969 
4970   UintR attrLenFlags = lqhKeyReq->attrLen;
4971   sig1 = lqhKeyReq->savePointId;
4972   sig2 = lqhKeyReq->hashValue;
4973   sig4 = lqhKeyReq->tableSchemaVersion;
4974   sig5 = lqhKeyReq->tcBlockref;
4975   // Ensure that ROUTE_ORD (carrying TCKEYREF) will not be sent to SPJ.
4976   ndbassert(refToNode(signal->getSendersBlockRef()) == getOwnNodeId() ||
4977             !LqhKeyReq::getDirtyFlag(lqhKeyReq->requestInfo) ||
4978             LqhKeyReq::getNormalProtocolFlag(lqhKeyReq->requestInfo) ||
4979             LqhKeyReq::getOperation(lqhKeyReq->requestInfo) != ZREAD ||
4980             refToMain(lqhKeyReq->tcBlockref) == DBTC);
4981 
4982   regTcPtr->savePointId = sig1;
4983   regTcPtr->hashValue = sig2;
4984   const Uint32 schemaVersion = regTcPtr->schemaVersion = LqhKeyReq::getSchemaVersion(sig4);
4985   tabptr.i = LqhKeyReq::getTableId(sig4);
4986   regTcPtr->tcBlockref = sig5;
4987 
4988   const Uint8 op = LqhKeyReq::getOperation(Treqinfo);
4989   if (ERROR_INSERTED(5080) ||
4990       ((op == ZREAD || op == ZREAD_EX) && !getAllowRead()))
4991   {
4992     releaseSections(handle);
4993     earlyKeyReqAbort(signal, lqhKeyReq, isLongReq, ZNODE_SHUTDOWN_IN_PROGRESS);
4994     return;
4995   }
4996 
4997   if (ERROR_INSERTED(5081) ||
4998       unlikely(get_node_status(refToNode(sig5)) != ZNODE_UP))
4999   {
5000     releaseSections(handle);
5001     earlyKeyReqAbort(signal, lqhKeyReq, isLongReq, ZNODE_SHUTDOWN_IN_PROGRESS);
5002     return;
5003   }
5004 
5005   Uint32 senderVersion = getNodeInfo(refToNode(senderRef)).m_version;
5006 
5007   regTcPtr->tcScanInfo  = lqhKeyReq->scanInfo;
5008   regTcPtr->indTakeOver = LqhKeyReq::getScanTakeOverFlag(attrLenFlags);
5009   regTcPtr->m_reorg     = LqhKeyReq::getReorgFlag(attrLenFlags);
5010 
5011   regTcPtr->readlenAi = 0;
5012   regTcPtr->currTupAiLen = 0;
5013   regTcPtr->logWriteState = TcConnectionrec::NOT_STARTED;
5014   regTcPtr->fragmentptr = RNIL;
5015 
5016   sig0 = lqhKeyReq->fragmentData;
5017   sig1 = lqhKeyReq->transId1;
5018   sig2 = lqhKeyReq->transId2;
5019   sig3 = lqhKeyReq->variableData[0];
5020   sig4 = lqhKeyReq->variableData[1];
5021 
5022   regTcPtr->fragmentid = LqhKeyReq::getFragmentId(sig0);
5023   regTcPtr->nextReplica = LqhKeyReq::getNextReplicaNodeId(sig0);
5024   regTcPtr->transid[0] = sig1;
5025   regTcPtr->transid[1] = sig2;
5026   regTcPtr->applRef = sig3;
5027   regTcPtr->applOprec = sig4;
5028 
5029   if (LqhKeyReq::getMarkerFlag(Treqinfo))
5030   {
5031     struct CommitAckMarker check;
5032     CommitAckMarkerPtr markerPtr;
5033     jam();
5034     check.transid1 = regTcPtr->transid[0];
5035     check.transid2 = regTcPtr->transid[1];
5036 
5037     if (m_commitAckMarkerHash.find(markerPtr, check))
5038     {
5039       /*
5040         A commit ack marker was already placed here for this transaction.
5041         We increase the reference count to ensure we don't remove the
5042         commit ack marker prematurely.
5043       */
5044       ndbrequire(markerPtr.p->in_hash == true);
5045       ndbrequire(markerPtr.p->reference_count > 0);
5046       markerPtr.p->reference_count++;
5047 #ifdef MARKER_TRACE
5048       ndbout_c("Inc marker[%.8x %.8x] op: %u ref: %u",
5049                markerPtr.p->transid1, markerPtr.p->transid2,
5050                tcConnectptr.i, markerPtr.p->reference_count);
5051 #endif
5052     }
5053     else
5054     {
5055       if (ERROR_INSERTED(5082) ||
5056           unlikely(!m_commitAckMarkerHash.seize(markerPtr)))
5057       {
5058         releaseSections(handle);
5059         earlyKeyReqAbort(signal, lqhKeyReq, isLongReq,
5060                          ZNO_FREE_MARKER_RECORDS_ERROR);
5061         return;
5062       }
5063       markerPtr.p->transid1 = sig1;
5064       markerPtr.p->transid2 = sig2;
5065       markerPtr.p->apiRef   = sig3;
5066       markerPtr.p->apiOprec = sig4;
5067       markerPtr.p->tcRef = sig5;
5068       markerPtr.p->reference_count = 1;
5069       markerPtr.p->in_hash = true;
5070       m_commitAckMarkerHash.add(markerPtr);
5071 
5072 #ifdef MARKER_TRACE
5073       ndbout_c("%u Add marker[%.8x %.8x] op: %u", instance(), markerPtr.p->transid1, markerPtr.p->transid2, tcConnectptr.i);
5074 #endif
5075     }
5076     regTcPtr->commitAckMarker = markerPtr.i;
5077   }
5078 
5079   regTcPtr->reqinfo = Treqinfo;
5080   regTcPtr->lastReplicaNo = LqhKeyReq::getLastReplicaNo(Treqinfo);
5081   regTcPtr->dirtyOp       = LqhKeyReq::getDirtyFlag(Treqinfo);
5082   regTcPtr->opExec        = LqhKeyReq::getInterpretedFlag(Treqinfo);
5083   regTcPtr->opSimple      = LqhKeyReq::getSimpleFlag(Treqinfo);
5084   regTcPtr->seqNoReplica  = LqhKeyReq::getSeqNoReplica(Treqinfo);
5085   regTcPtr->m_use_rowid   = LqhKeyReq::getRowidFlag(Treqinfo);
5086   regTcPtr->m_dealloc     = 0;
5087   if (unlikely(senderVersion < NDBD_ROWID_VERSION))
5088   {
5089     regTcPtr->operation = op;
5090     regTcPtr->lockType = LqhKeyReq::getLockType(Treqinfo);
5091   }
5092   else
5093   {
5094     regTcPtr->operation = (Operation_t) op == ZREAD_EX ? ZREAD : (Operation_t) op;
5095     regTcPtr->lockType =
5096       op == ZREAD_EX ? ZUPDATE :
5097       (Operation_t) op == ZWRITE ? ZINSERT :
5098       (Operation_t) op == ZREFRESH ? ZINSERT :
5099       (Operation_t) op == ZUNLOCK ? ZREAD : // lockType not relevant for unlock req
5100       (Operation_t) op;
5101   }
5102 
5103   if (regTcPtr->dirtyOp)
5104   {
5105     ndbrequire(regTcPtr->opSimple);
5106   }
5107 
5108   CRASH_INSERTION2(5041, (op == ZREAD &&
5109                           (regTcPtr->opSimple || regTcPtr->dirtyOp) &&
5110                           refToNode(signal->senderBlockRef()) != cownNodeid));
5111 
5112   regTcPtr->numFiredTriggers = lqhKeyReq->numFiredTriggers;
5113 
5114   UintR TapplAddressInd = LqhKeyReq::getApplicationAddressFlag(Treqinfo);
5115   UintR nextPos = (TapplAddressInd << 1);
5116   UintR TsameClientAndTcOprec = LqhKeyReq::getSameClientAndTcFlag(Treqinfo);
5117   if (TsameClientAndTcOprec == 1) {
5118     regTcPtr->tcOprec = lqhKeyReq->variableData[nextPos];
5119     nextPos++;
5120   }//if
5121   UintR TnextReplicasIndicator = regTcPtr->lastReplicaNo -
5122                                  regTcPtr->seqNoReplica;
5123   if (TnextReplicasIndicator > 1) {
5124     regTcPtr->nodeAfterNext[0] = lqhKeyReq->variableData[nextPos] & 0xFFFF;
5125     regTcPtr->nodeAfterNext[1] = lqhKeyReq->variableData[nextPos] >> 16;
5126     nextPos++;
5127   }//if
5128   UintR TstoredProcIndicator = LqhKeyReq::getStoredProcFlag(attrLenFlags);
5129   if (TstoredProcIndicator == 1) {
5130     regTcPtr->storedProcId = lqhKeyReq->variableData[nextPos] & ZNIL;
5131     nextPos++;
5132   }//if
5133   UintR TreadLenAiIndicator = LqhKeyReq::getReturnedReadLenAIFlag(Treqinfo);
5134   if (TreadLenAiIndicator == 1) {
5135     regTcPtr->readlenAi = lqhKeyReq->variableData[nextPos] & ZNIL;
5136     nextPos++;
5137   }//if
5138 
5139   Uint32 TanyValueFlag = LqhKeyReq::getCorrFactorFlag(Treqinfo);
5140   if (isLongReq && TanyValueFlag == 1)
5141   {
5142     /**
5143      * For short lqhkeyreq, ai-length in-signal is stored in same pos...
5144      */
5145     regTcPtr->m_corrFactorLo = lqhKeyReq->variableData[nextPos + 0];
5146     regTcPtr->m_corrFactorHi = lqhKeyReq->variableData[nextPos + 1];
5147     nextPos += 2;
5148   }
5149 
5150   regTcPtr->m_fire_trig_pass = 0;
5151   Uint32 Tdeferred = LqhKeyReq::getDeferredConstraints(Treqinfo);
5152   if (isLongReq && Tdeferred)
5153   {
5154     regTcPtr->m_flags |= TcConnectionrec::OP_DEFERRED_CONSTRAINTS;
5155   }
5156 
5157   Uint32 TdisableFk = LqhKeyReq::getDisableFkConstraints(Treqinfo);
5158   if (isLongReq && TdisableFk)
5159   {
5160     regTcPtr->m_flags |= TcConnectionrec::OP_DISABLE_FK;
5161   }
5162 
5163   Uint32 TnormalProtocolFlag = LqhKeyReq::getNormalProtocolFlag(Treqinfo);
5164   if (isLongReq && TnormalProtocolFlag)
5165   {
5166     /**
5167      * Only set normal protocol flag if long request.
5168      * As above, short lqhKeyReq ai-length in-signal overlaps the bit.
5169      * bug#14702377
5170      */
5171     regTcPtr->m_flags |= TcConnectionrec::OP_NORMAL_PROTOCOL;
5172   }
5173 
5174   UintR TitcKeyLen = 0;
5175   Uint32 keyLenWithLQHReq = 0;
5176   UintR TreclenAiLqhkey   = 0;
5177 
5178   if (isLongReq)
5179   {
5180     /* Long LQHKEYREQ indicates Key and AttrInfo presence and
5181      * size via section lengths
5182      */
5183     SegmentedSectionPtr keyInfoSection, attrInfoSection;
5184 
5185     handle.getSection(keyInfoSection,
5186                       LqhKeyReq::KeyInfoSectionNum);
5187 
5188     ndbassert(keyInfoSection.i != RNIL);
5189 
5190     regTcPtr->keyInfoIVal= keyInfoSection.i;
5191     TitcKeyLen= keyInfoSection.sz;
5192     keyLenWithLQHReq= TitcKeyLen;
5193 
5194     Uint32 totalAttrInfoLen= 0;
5195     if (handle.getSection(attrInfoSection,
5196                           LqhKeyReq::AttrInfoSectionNum))
5197     {
5198       regTcPtr->attrInfoIVal= attrInfoSection.i;
5199       totalAttrInfoLen= attrInfoSection.sz;
5200     }
5201 
5202     regTcPtr->reclenAiLqhkey = 0;
5203     regTcPtr->currReclenAi = totalAttrInfoLen;
5204     regTcPtr->totReclenAi = totalAttrInfoLen;
5205 
5206     /* Detach sections from the handle, we are now responsible
5207      * for freeing them when appropriate
5208      */
5209     handle.clear();
5210   }
5211   else
5212   {
5213     /* Short LQHKEYREQ, Key and Attr sizes are in
5214      * signal, along with some data
5215      */
5216     TreclenAiLqhkey= LqhKeyReq::getAIInLqhKeyReq(Treqinfo);
5217     regTcPtr->reclenAiLqhkey = TreclenAiLqhkey;
5218     regTcPtr->currReclenAi = TreclenAiLqhkey;
5219     TitcKeyLen = LqhKeyReq::getKeyLen(Treqinfo);
5220     regTcPtr->totReclenAi = LqhKeyReq::getAttrLen(attrLenFlags);
5221 
5222     /* Note key can be length zero for NR when Rowid used */
5223     keyLenWithLQHReq= MIN(TitcKeyLen, LqhKeyReq::MaxKeyInfo);
5224 
5225     bool ok= appendToSection(regTcPtr->keyInfoIVal,
5226                              &lqhKeyReq->variableData[ nextPos ],
5227                              keyLenWithLQHReq);
5228     if (unlikely(!ok))
5229     {
5230       jam();
5231       earlyKeyReqAbort(signal, lqhKeyReq, isLongReq, ZGET_DATAREC_ERROR);
5232       return;
5233     }
5234 
5235     nextPos+= keyLenWithLQHReq;
5236   }
5237 
5238   regTcPtr->primKeyLen = TitcKeyLen;
5239 
5240   /* Only node restart copy allowed to send no KeyInfo */
5241   if (unlikely(keyLenWithLQHReq == 0))
5242   {
5243     if (refToMain(senderRef) == DBSPJ)
5244     {
5245       jam();
5246       ndbassert(! LqhKeyReq::getNrCopyFlag(Treqinfo));
5247 
5248       /* Reply with NO_TUPLE_FOUND */
5249       earlyKeyReqAbort(signal, lqhKeyReq, isLongReq, ZNO_TUPLE_FOUND);
5250       return;
5251     }
5252 
5253     if (! LqhKeyReq::getNrCopyFlag(Treqinfo))
5254     {
5255       LQHKEY_error(signal, 3);
5256       return;
5257     }//if
5258   }
5259 
5260   sig0 = lqhKeyReq->variableData[nextPos + 0];
5261   sig1 = lqhKeyReq->variableData[nextPos + 1];
5262   regTcPtr->m_row_id.m_page_no = sig0;
5263   regTcPtr->m_row_id.m_page_idx = sig1;
5264   nextPos += 2 * LqhKeyReq::getRowidFlag(Treqinfo);
5265 
5266   sig2 = lqhKeyReq->variableData[nextPos + 0];
5267   sig3 = cnewestGci;
5268   /* If gci_hi provided, take it and set gci_lo to max value
5269    * Otherwise, it will be decided by TUP at commit time as normal
5270    */
5271   regTcPtr->gci_hi = LqhKeyReq::getGCIFlag(Treqinfo) ? sig2 : sig3;
5272   regTcPtr->gci_lo = LqhKeyReq::getGCIFlag(Treqinfo) ? ~Uint32(0) : 0;
5273   nextPos += LqhKeyReq::getGCIFlag(Treqinfo);
5274 
5275   if (LqhKeyReq::getRowidFlag(Treqinfo))
5276   {
5277     ndbassert(refToMain(senderRef) != DBTC);
5278   }
5279   else if(op == ZINSERT)
5280   {
5281     ndbassert(refToMain(senderRef) == DBTC);
5282   }
5283 
5284   if ((LqhKeyReq::FixedSignalLength + nextPos + TreclenAiLqhkey) !=
5285       signal->length()) {
5286     LQHKEY_error(signal, 2);
5287     return;
5288   }//if
5289   UintR TseqNoReplica = regTcPtr->seqNoReplica;
5290   UintR TlastReplicaNo = regTcPtr->lastReplicaNo;
5291   if (TseqNoReplica == TlastReplicaNo) {
5292     jam();
5293     regTcPtr->nextReplica = ZNIL;
5294   } else {
5295     if (TseqNoReplica < TlastReplicaNo) {
5296       jam();
5297       regTcPtr->nextSeqNoReplica = TseqNoReplica + 1;
5298       if ((regTcPtr->nextReplica == 0) ||
5299           (regTcPtr->nextReplica == cownNodeid)) {
5300         LQHKEY_error(signal, 0);
5301       }//if
5302     } else {
5303       LQHKEY_error(signal, 4);
5304       return;
5305     }//if
5306   }//if
5307 
5308   /**
5309    * If this is a 'dirtyOp' we dont care about transaction semantics.
5310    * There will then be no further abort, commit or unlock requests for
5311    * this operation. Thus, we will never have to find this operation
5312    * in the hashlist by calling findTransaction().
5313    * If also all ATTR- and KEYINFOs has been received, there will be no
5314    * ::execKEY- or ATTRINFO. (Long request, or all INFO fit in the REQ.)
5315    *
5316    * Thus we skip insertion in hashlist whenever not required.
5317    */
5318   if (regTcPtr->dirtyOp == ZFALSE ||                  //Transactional operation
5319       regTcPtr->primKeyLen > keyLenWithLQHReq ||      //Await more KEYINFO
5320       regTcPtr->totReclenAi > regTcPtr->currReclenAi) //Await more ATTRINFO
5321   {
5322     jam();
5323     /* Check that no equal element exists */
5324     ndbassert(findTransaction(regTcPtr->transid[0], regTcPtr->transid[1],
5325                               regTcPtr->tcOprec, regTcPtr->tcHashKeyHi) == ZNOT_FOUND);
5326 
5327     TcConnectionrecPtr localNextTcConnectptr;
5328     Uint32 hashIndex = (regTcPtr->transid[0] ^ regTcPtr->tcOprec) & 1023;
5329     localNextTcConnectptr.i = ctransidHash[hashIndex];
5330     ctransidHash[hashIndex] = tcConnectptr.i;
5331     regTcPtr->prevHashRec = RNIL;
5332     regTcPtr->nextHashRec = localNextTcConnectptr.i;
5333     regTcPtr->hashIndex = hashIndex;
5334     if (localNextTcConnectptr.i != RNIL) {
5335       ptrCheckGuard(localNextTcConnectptr,
5336                     ctcConnectrecFileSize, tcConnectionrec);
5337       jam();
5338       ndbassert(localNextTcConnectptr.p->prevHashRec == RNIL);
5339       localNextTcConnectptr.p->prevHashRec = tcConnectptr.i;
5340     }//if
5341   }//if
5342   if (tabptr.i >= ctabrecFileSize) {
5343     LQHKEY_error(signal, 5);
5344     return;
5345   }//if
5346   ptrAss(tabptr, tablerec);
5347   if(table_version_major_lqhkeyreq(tabptr.p->schemaVersion) !=
5348      table_version_major_lqhkeyreq(schemaVersion)){
5349     LQHKEY_abort(signal, 5);
5350     return;
5351   }
5352 
5353   if (unlikely(tabptr.p->tableStatus != Tablerec::TABLE_DEFINED))
5354   {
5355     if (check_tabstate(signal, tabptr.p, op))
5356       return;
5357   }
5358 
5359   regTcPtr->tableref = tabptr.i;
5360   regTcPtr->m_disk_table = tabptr.p->m_disk_table;
5361   if(refToMain(signal->senderBlockRef()) == RESTORE)
5362     regTcPtr->m_disk_table &= !LqhKeyReq::getNoDiskFlag(Treqinfo);
5363   else if(op == ZREAD || op == ZREAD_EX || op == ZUPDATE)
5364     regTcPtr->m_disk_table &= !LqhKeyReq::getNoDiskFlag(Treqinfo);
5365 
5366   if (op == ZREAD || op == ZREAD_EX || op == ZUNLOCK)
5367     tabptr.p->usageCountR++;
5368   else
5369     tabptr.p->usageCountW++;
5370 
5371   if (!getFragmentrec(signal, regTcPtr->fragmentid)) {
5372     LQHKEY_error(signal, 6);
5373     return;
5374   }//if
5375 
5376   if (LqhKeyReq::getNrCopyFlag(Treqinfo))
5377   {
5378     ndbassert(refToMain(senderRef) == DBLQH);
5379     ndbassert(LqhKeyReq::getRowidFlag(Treqinfo));
5380     if (! (fragptr.p->fragStatus == Fragrecord::ACTIVE_CREATION))
5381     {
5382       ndbout_c("fragptr.p->fragStatus: %d",
5383 	       fragptr.p->fragStatus);
5384       CRASH_INSERTION(5046);
5385     }
5386     ndbassert(fragptr.p->fragStatus == Fragrecord::ACTIVE_CREATION);
5387     fragptr.p->m_copy_started_state = Fragrecord::AC_NR_COPY;
5388 
5389     if (op == ZDELETE)
5390       c_fragCopyRowsDel++;
5391     else
5392       c_fragCopyRowsIns++;
5393 
5394     c_fragBytesCopied+= (signal->length() << 2);
5395   }
5396   else
5397   {
5398     Fragrecord::UsageStat& useStat = fragptr.p->m_useStat;
5399     /* Don't count for NR fragcopy, just 'normal' operation */
5400     switch (op)
5401     {
5402     case ZREAD:
5403     case ZREAD_EX:
5404     case ZUNLOCK:
5405       useStat.m_readKeyReqCount++;
5406       break;
5407 
5408     case ZUPDATE:
5409       useStat.m_updKeyReqCount++;
5410       break;
5411 
5412     case ZINSERT:
5413       useStat.m_insKeyReqCount++;
5414       break;
5415 
5416     case ZWRITE:
5417       useStat.m_writeKeyReqCount++;
5418       break;
5419 
5420     case ZDELETE:
5421       useStat.m_delKeyReqCount++;
5422       break;
5423 
5424     default:
5425       // ZREFRESH is not counted.
5426       break;
5427     }
5428     useStat.m_keyReqAttrWords += regTcPtr->totReclenAi;
5429     useStat.m_keyReqKeyWords += TitcKeyLen;
5430     if (unlikely(LqhKeyReq::getInterpretedFlag(Treqinfo) && isLongReq))
5431     {
5432       /*
5433         Complete attrinfo may not have been received yet for short-signal
5434         lookups. We ignore these, since they only happen during online
5435         upgrade.
5436       */
5437       ndbassert(regTcPtr->attrInfoIVal != RNIL);
5438       SegmentedSectionPtr attrInfo;
5439       getSection(attrInfo, regTcPtr->attrInfoIVal);
5440       useStat.m_keyProgramWords += getProgramWordCount(attrInfo);
5441     }
5442   }
5443 
5444   Uint8 TcopyType = fragptr.p->fragCopy;
5445   Uint32 logPart = fragptr.p->m_log_part_ptr_i;
5446   tfragDistKey = fragptr.p->fragDistributionKey;
5447   if (fragptr.p->fragStatus == Fragrecord::ACTIVE_CREATION) {
5448     jam();
5449     regTcPtr->activeCreat = fragptr.p->m_copy_started_state;
5450     CRASH_INSERTION(5002);
5451     CRASH_INSERTION2(5042, tabptr.i == c_error_insert_table_id);
5452   } else {
5453     regTcPtr->activeCreat = Fragrecord::AC_NORMAL;
5454   }//if
5455   regTcPtr->replicaType = TcopyType;
5456   regTcPtr->fragmentptr = fragptr.i;
5457   regTcPtr->m_log_part_ptr_i = logPart;
5458   Uint8 TdistKey = LqhKeyReq::getDistributionKey(attrLenFlags);
5459   if ((tfragDistKey != TdistKey) &&
5460       (regTcPtr->seqNoReplica == 0) &&
5461       (regTcPtr->dirtyOp == ZFALSE))
5462   {
5463     /* ----------------------------------------------------------------------
5464      * WE HAVE DIFFERENT OPINION THAN THE DIH THAT STARTED THE TRANSACTION.
5465      * THE REASON COULD BE THAT THIS IS AN OLD DISTRIBUTION WHICH IS NO LONGER
5466      * VALID TO USE. THIS MUST BE CHECKED.
5467      * ONE IS ADDED TO THE DISTRIBUTION KEY EVERY TIME WE ADD A NEW REPLICA.
5468      * FAILED REPLICAS DO NOT AFFECT THE DISTRIBUTION KEY. THIS MEANS THAT THE
5469      * MAXIMUM DEVIATION CAN BE ONE BETWEEN THOSE TWO VALUES.
5470      * --------------------------------------------------------------------- */
5471     Int8 tmp = (TdistKey - tfragDistKey);
5472     tmp = (tmp < 0 ? - tmp : tmp);
5473     if ((tmp <= 1) || (tfragDistKey == 0)) {
5474       LQHKEY_abort(signal, 0);
5475       return;
5476     }//if
5477     LQHKEY_error(signal, 1);
5478     // Never get here
5479   }//if
5480 
5481   /*
5482    * Interpreted updates and deletes may require different AttrInfo in
5483    * different replicas, as only the primary executes the interpreted
5484    * program, and the effect of the program rather than the program
5485    * should be logged.
5486    * Non interpreted inserts, updates, writes and deletes use the same
5487    * AttrInfo in all replicas.
5488    * All reads only run on one replica, and are not logged.
5489    * The AttrInfo section is passed to TUP attached to the TUPKEYREQ
5490    * signal below.
5491    *
5492    * Normal processing :
5493    *   - LQH passes ATTRINFO section to TUP attached to direct TUPKEYREQ
5494    *     signal
5495    *   - TUP processes request and sends direct TUPKEYCONF back to LQH
5496    *   - LQH continues processing (logging, forwarding LQHKEYREQ to other
5497    *     replicas as necessary)
5498    *   - LQH frees ATTRINFO section
5499    *   Note that TUP is not responsible for freeing the passed ATTRINFO
5500    *   section, LQH is.
5501    *
5502    * Interpreted Update / Delete processing
5503    *   - LQH passes ATTRINFO section to TUP attached to direct TUPKEYREQ
5504    *     signal
5505    *   - TUP processes request, generating new ATTRINFO data
5506    *   - If new AttrInfo data is > 0 words, TUP sends it back to LQH as
5507    *     a long section attached to a single ATTRINFO signal.
5508    *     - LQH frees the original AttrInfo section and stores a ref to
5509    *       the new section
5510    *   - TUP sends direct TUPKEYCONF back to LQH with new ATTRINFO length
5511    *   - If the new ATTRINFO is > 0 words,
5512    *       - LQH continues processing with it (logging, forwarding
5513    *         LQHKEYREQ to other replicas as necessary)
5514    *       - LQH frees the new ATTRINFO section
5515    *   - If the new ATTRINFO is 0 words, LQH frees the original ATTRINFO
5516    *     section and continues processing (logging, forwarding LQHKEYREQ
5517    *     to other replicas as necessary)
5518    *
5519    */
5520   bool attrInfoToPropagate=
5521     (regTcPtr->totReclenAi != 0) &&
5522     (regTcPtr->operation != ZREAD) &&
5523     (regTcPtr->operation != ZDELETE) &&
5524     (regTcPtr->operation != ZUNLOCK);
5525   bool tupCanChangePropagatedAttrInfo= (regTcPtr->opExec == 1);
5526 
5527   bool saveAttrInfo=
5528     attrInfoToPropagate &&
5529     (! tupCanChangePropagatedAttrInfo);
5530 
5531   if (saveAttrInfo)
5532     regTcPtr->m_flags|= TcConnectionrec::OP_SAVEATTRINFO;
5533 
5534   /* Handle any AttrInfo we received with the LQHKEYREQ */
5535   if (regTcPtr->currReclenAi != 0)
5536   {
5537     jam();
5538     if (isLongReq)
5539     {
5540       /* Long LQHKEYREQ */
5541       jam();
5542 
5543       regTcPtr->currTupAiLen= saveAttrInfo ?
5544         regTcPtr->totReclenAi :
5545         0;
5546     }
5547     else
5548     {
5549       /* Short LQHKEYREQ */
5550       jam();
5551 
5552       /* Lets put the AttrInfo into a segmented section */
5553       bool ok= appendToSection(regTcPtr->attrInfoIVal,
5554                                lqhKeyReq->variableData + nextPos,
5555                                TreclenAiLqhkey);
5556       if (unlikely(!ok))
5557       {
5558         jam();
5559         terrorCode= ZGET_DATAREC_ERROR;
5560         abortErrorLab(signal);
5561         return;
5562       }
5563 
5564       if (saveAttrInfo)
5565         regTcPtr->currTupAiLen= TreclenAiLqhkey;
5566     }
5567   }//if
5568 
5569   /* If we've received all KeyInfo, proceed with processing,
5570    * otherwise wait for discrete KeyInfo signals
5571    */
5572   if (regTcPtr->primKeyLen == keyLenWithLQHReq) {
5573     endgettupkeyLab(signal);
5574     return;
5575   } else {
5576     jam();
5577     ndbassert(!isLongReq);
5578     /* Wait for remaining KeyInfo */
5579     regTcPtr->save1 = keyLenWithLQHReq;
5580     regTcPtr->transactionState = TcConnectionrec::WAIT_TUPKEYINFO;
5581     return;
5582   }//if
5583   return;
5584 }//Dblqh::execLQHKEYREQ()
5585 
5586 
5587 
5588 /**
5589  * endgettupkeyLab
5590  * Invoked when all KeyInfo and/or all AttrInfo has been
5591  * received
5592  */
endgettupkeyLab(Signal * signal)5593 void Dblqh::endgettupkeyLab(Signal* signal)
5594 {
5595   TcConnectionrec * const regTcPtr = tcConnectptr.p;
5596   if (regTcPtr->totReclenAi == regTcPtr->currReclenAi) {
5597     ;
5598   } else {
5599     jam();
5600     /* Wait for discrete AttrInfo signals */
5601     ndbrequire(regTcPtr->currReclenAi < regTcPtr->totReclenAi);
5602     ndbassert( !(regTcPtr->m_flags &
5603                  TcConnectionrec::OP_ISLONGREQ) );
5604     regTcPtr->transactionState = TcConnectionrec::WAIT_ATTR;
5605     return;
5606   }//if
5607 
5608 /* ---------------------------------------------------------------------- */
5609 /*       NOW RECEPTION OF LQHKEYREQ IS COMPLETED THE NEXT STEP IS TO START*/
5610 /*       PROCESSING THE MESSAGE. IF THE MESSAGE IS TO A STAND-BY NODE     */
5611 /*       WITHOUT NETWORK REDUNDANCY OR PREPARE-TO-COMMIT ACTIVATED THE    */
5612 /*       PREPARATION TO SEND TO THE NEXT NODE WILL START IMMEDIATELY.     */
5613 /*                                                                        */
5614 /*       OTHERWISE THE PROCESSING WILL START AFTER SETTING THE PROPER     */
5615 /*       STATE. HOWEVER BEFORE PROCESSING THE MESSAGE                     */
5616 /*       IT IS NECESSARY TO CHECK THAT THE FRAGMENT IS NOT PERFORMING     */
5617 /*       A CHECKPOINT. THE OPERATION SHALL ALSO BE LINKED INTO THE        */
5618 /*       FRAGMENT QUEUE OR LIST OF ACTIVE OPERATIONS.                     */
5619 /*                                                                        */
5620 /*       THE FIRST STEP IN PROCESSING THE MESSAGE IS TO CONTACT DBACC.    */
5621 /*------------------------------------------------------------------------*/
5622   switch (fragptr.p->fragStatus) {
5623   case Fragrecord::FSACTIVE:
5624   case Fragrecord::CRASH_RECOVERING:
5625   case Fragrecord::ACTIVE_CREATION:
5626     prepareContinueAfterBlockedLab(signal);
5627     return;
5628     break;
5629   case Fragrecord::FREE:
5630     jam();
5631   case Fragrecord::DEFINED:
5632     jam();
5633   case Fragrecord::REMOVING:
5634     jam();
5635   default:
5636     ndbrequire(false);
5637     break;
5638   }//switch
5639   return;
5640 }//Dblqh::endgettupkeyLab()
5641 
prepareContinueAfterBlockedLab(Signal * signal)5642 void Dblqh::prepareContinueAfterBlockedLab(Signal* signal)
5643 {
5644   UintR ttcScanOp;
5645 
5646 /* -------------------------------------------------------------------------- */
5647 /*       INPUT:          TC_CONNECTPTR           ACTIVE CONNECTION RECORD     */
5648 /*                       FRAGPTR                 FRAGMENT RECORD              */
5649 /* -------------------------------------------------------------------------- */
5650 /* -------------------------------------------------------------------------- */
5651 /*  CONTINUE HERE AFTER BEING BLOCKED FOR A WHILE DURING LOCAL CHECKPOINT.    */
5652 /* -------------------------------------------------------------------------- */
5653 /*       ALSO AFTER NORMAL PROCEDURE WE CONTINUE HERE                         */
5654 /* -------------------------------------------------------------------------- */
5655   Uint32 tc_ptr_i = tcConnectptr.i;
5656   TcConnectionrec * const regTcPtr = tcConnectptr.p;
5657   Uint32 activeCreat = regTcPtr->activeCreat;
5658   if (regTcPtr->operation == ZUNLOCK)
5659   {
5660     jam();
5661     handleUserUnlockRequest(signal);
5662     return;
5663   }
5664 
5665   if (regTcPtr->indTakeOver == ZTRUE) {
5666     jam();
5667     ttcScanOp = KeyInfo20::getScanOp(regTcPtr->tcScanInfo);
5668     scanptr.i = RNIL;
5669     {
5670       ScanRecord key;
5671       key.scanNumber = KeyInfo20::getScanNo(regTcPtr->tcScanInfo);
5672       key.fragPtrI = fragptr.i;
5673       c_scanTakeOverHash.find(scanptr, key);
5674 #ifdef TRACE_SCAN_TAKEOVER
5675       if(scanptr.i == RNIL)
5676 	ndbout_c("not finding (%d %d)", key.scanNumber, key.fragPtrI);
5677 #endif
5678     }
5679     if (scanptr.i == RNIL) {
5680       jam();
5681       takeOverErrorLab(signal);
5682       return;
5683     }//if
5684     Uint32 accOpPtr= get_acc_ptr_from_scan_record(scanptr.p,
5685                                                   ttcScanOp,
5686                                                   true);
5687     BlockReference blockRef = regTcPtr->tcAccBlockref;
5688     if (accOpPtr == RNIL) {
5689       jam();
5690       takeOverErrorLab(signal);
5691       return;
5692     }//if
5693     signal->theData[1] = accOpPtr;
5694     signal->theData[2] = regTcPtr->transid[0];
5695     signal->theData[3] = regTcPtr->transid[1];
5696     EXECUTE_DIRECT(refToMain(blockRef), GSN_ACC_TO_REQ, signal, 4);
5697     if (signal->theData[0] == (UintR)-1) {
5698       execACC_TO_REF(signal);
5699       return;
5700     }//if
5701     jamEntry();
5702   }//if
5703 /*-------------------------------------------------------------------*/
5704 /*       IT IS NOW TIME TO CONTACT ACC. THE TUPLE KEY WILL BE SENT   */
5705 /*       AND THIS WILL BE TRANSLATED INTO A LOCAL KEY BY USING THE   */
5706 /*       LOCAL PART OF THE LH3-ALGORITHM. ALSO PROPER LOCKS ON THE   */
5707 /*       TUPLE WILL BE SET. FOR INSERTS AND DELETES THE MESSAGE WILL */
5708 /*       START AN INSERT/DELETE INTO THE HASH TABLE.                 */
5709 /*                                                                   */
5710 /*       BEFORE SENDING THE MESSAGE THE REQUEST INFORMATION IS SET   */
5711 /*       PROPERLY.                                                   */
5712 /* ----------------------------------------------------------------- */
5713   if (TRACENR_FLAG)
5714   {
5715     TRACE_OP(regTcPtr, "RECEIVED");
5716     switch (regTcPtr->operation) {
5717     case ZREAD: TRACENR("READ"); break;
5718     case ZUPDATE: TRACENR("UPDATE"); break;
5719     case ZWRITE: TRACENR("WRITE"); break;
5720     case ZINSERT: TRACENR("INSERT"); break;
5721     case ZDELETE: TRACENR("DELETE"); break;
5722     case ZUNLOCK: TRACENR("UNLOCK"); break;
5723     case ZREFRESH: TRACENR("REFRESH"); break;
5724     default: TRACENR("<Unknown: " << regTcPtr->operation << ">"); break;
5725     }
5726 
5727     TRACENR(" tab: " << regTcPtr->tableref
5728 	   << " frag: " << regTcPtr->fragmentid
5729 	   << " activeCreat: " << (Uint32)activeCreat);
5730     if (LqhKeyReq::getNrCopyFlag(regTcPtr->reqinfo))
5731       TRACENR(" NrCopy");
5732     if (LqhKeyReq::getRowidFlag(regTcPtr->reqinfo))
5733       TRACENR(" rowid: " << regTcPtr->m_row_id);
5734     TRACENR(" key: " << getKeyInfoWordOrZero(regTcPtr, 0));
5735   }
5736 
5737   if (likely(activeCreat == Fragrecord::AC_NORMAL))
5738   {
5739     if (TRACENR_FLAG)
5740       TRACENR(endl);
5741     ndbassert(!LqhKeyReq::getNrCopyFlag(regTcPtr->reqinfo));
5742     exec_acckeyreq(signal, tcConnectptr);
5743   }
5744   else if (activeCreat == Fragrecord::AC_NR_COPY)
5745   {
5746     regTcPtr->totSendlenAi = regTcPtr->totReclenAi;
5747     handle_nr_copy(signal, tcConnectptr);
5748   }
5749   else
5750   {
5751     ndbassert(activeCreat == Fragrecord::AC_IGNORED);
5752     if (TRACENR_FLAG)
5753       TRACENR(" IGNORING (activeCreat == 2)" << endl);
5754 
5755     signal->theData[0] = tc_ptr_i;
5756     regTcPtr->transactionState = TcConnectionrec::WAIT_ACC_ABORT;
5757 
5758     signal->theData[0] = regTcPtr->tupConnectrec;
5759     EXECUTE_DIRECT(DBTUP, GSN_TUP_ABORTREQ, signal, 1);
5760     jamEntry();
5761 
5762     regTcPtr->totSendlenAi = regTcPtr->totReclenAi;
5763     packLqhkeyreqLab(signal);
5764   }
5765 }
5766 
5767 void
exec_acckeyreq(Signal * signal,TcConnectionrecPtr regTcPtr)5768 Dblqh::exec_acckeyreq(Signal* signal, TcConnectionrecPtr regTcPtr)
5769 {
5770   Uint32 taccreq;
5771   taccreq = regTcPtr.p->operation;
5772   taccreq = taccreq + (regTcPtr.p->lockType << 4);
5773   taccreq = taccreq + (regTcPtr.p->dirtyOp << 6);
5774   taccreq = taccreq + (regTcPtr.p->replicaType << 7);
5775 /* ************ */
5776 /*  ACCKEYREQ < */
5777 /* ************ */
5778   const Uint32 sig0 = regTcPtr.p->accConnectrec;
5779   const Uint32 sig1 = fragptr.p->accFragptr;
5780   const Uint32 sig3 = regTcPtr.p->hashValue;
5781   const Uint32 sig4 = regTcPtr.p->primKeyLen;
5782   const Uint32 sig5 = regTcPtr.p->transid[0];
5783   const Uint32 sig6 = regTcPtr.p->transid[1];
5784   signal->theData[0] = sig0;
5785   signal->theData[1] = sig1;
5786   signal->theData[2] = taccreq;
5787   signal->theData[3] = sig3;
5788   signal->theData[4] = sig4;
5789   signal->theData[5] = sig5;
5790   signal->theData[6] = sig6;
5791   regTcPtr.p->transactionState = TcConnectionrec::WAIT_ACC;
5792 
5793   const BlockReference blockRef = regTcPtr.p->tcAccBlockref;
5794   /* Copy KeyInfo to end of ACCKEYREQ signal, starting at offset 7 */
5795   copy(&signal->theData[7], regTcPtr.p->keyInfoIVal);
5796 
5797   TRACE_OP(regTcPtr.p, "ACC");
5798 
5799   EXECUTE_DIRECT(refToMain(blockRef), GSN_ACCKEYREQ,
5800 		 signal, 7 + regTcPtr.p->primKeyLen);
5801   if (signal->theData[0] < RNIL) {
5802     jamEntry();
5803     continueACCKEYCONF(signal,
5804                        regTcPtr.p,
5805                        signal->theData[3],
5806                        signal->theData[4]);
5807     return;
5808   } else if (signal->theData[0] == RNIL) {
5809     ;
5810   } else {
5811     ndbrequire(signal->theData[0] == (UintR)-1);
5812     signal->theData[0] = regTcPtr.i;
5813     execACCKEYREF(signal);
5814   }//if
5815   return;
5816 }//Dblqh::prepareContinueAfterBlockedLab()
5817 
5818 void
handle_nr_copy(Signal * signal,Ptr<TcConnectionrec> regTcPtr)5819 Dblqh::handle_nr_copy(Signal* signal, Ptr<TcConnectionrec> regTcPtr)
5820 {
5821   jam();
5822   Uint32 fragPtr = fragptr.p->tupFragptr;
5823   Uint32 op = regTcPtr.p->operation;
5824 
5825   const bool copy = LqhKeyReq::getNrCopyFlag(regTcPtr.p->reqinfo);
5826 
5827   if (!LqhKeyReq::getRowidFlag(regTcPtr.p->reqinfo))
5828   {
5829     /**
5830      * Rowid not set, that mean that primary has finished copying...
5831      */
5832     jam();
5833     if (TRACENR_FLAG)
5834       TRACENR(" Waiting for COPY_ACTIVEREQ" << endl);
5835     ndbassert(!LqhKeyReq::getNrCopyFlag(regTcPtr.p->reqinfo));
5836     regTcPtr.p->activeCreat = Fragrecord::AC_NORMAL;
5837     exec_acckeyreq(signal, regTcPtr);
5838     return;
5839   }
5840 
5841   /* Signal header was counted for when receiving LQHKEYREQ */
5842   c_fragBytesCopied += ((regTcPtr.p->primKeyLen +
5843                          ((regTcPtr.p->attrInfoIVal == RNIL)? 0 :
5844                           getSectionSz(regTcPtr.p->attrInfoIVal))) << 2);
5845 
5846   regTcPtr.p->m_nr_delete.m_cnt = 1; // Wait for real op aswell
5847   Uint32* dst = signal->theData+24;
5848   bool uncommitted;
5849   const int len = c_tup->nr_read_pk(fragPtr, &regTcPtr.p->m_row_id, dst,
5850 				    uncommitted);
5851   const bool match = (len>0) ? compare_key(regTcPtr.p, dst, len) == 0 : false;
5852 
5853   if (TRACENR_FLAG)
5854     TRACENR(" len: " << len << " match: " << match
5855 	   << " uncommitted: " << uncommitted);
5856 
5857   if (copy)
5858   {
5859     ndbassert(LqhKeyReq::getGCIFlag(regTcPtr.p->reqinfo));
5860     if (match)
5861     {
5862       /**
5863        * Case 1
5864        */
5865       jam();
5866       ndbassert(op == ZINSERT);
5867       if (TRACENR_FLAG)
5868 	TRACENR(" Changing from INSERT to ZUPDATE" << endl);
5869       regTcPtr.p->operation = ZUPDATE;
5870       goto run;
5871     }
5872     else if (len > 0 && op == ZDELETE)
5873     {
5874       /**
5875        * Case 4
5876        *   Perform delete using rowid
5877        *     primKeyLen == 0
5878        *     key[0] == rowid
5879        */
5880       jam();
5881       ndbassert(regTcPtr.p->primKeyLen == 0);
5882       if (TRACENR_FLAG)
5883 	TRACENR(" performing DELETE key: "
5884 	       << dst[0] << endl);
5885 
5886       nr_copy_delete_row(signal, regTcPtr, &regTcPtr.p->m_row_id, len);
5887       ndbassert(regTcPtr.p->m_nr_delete.m_cnt);
5888       regTcPtr.p->m_nr_delete.m_cnt--; // No real op is run
5889       if (regTcPtr.p->m_nr_delete.m_cnt)
5890       {
5891 	jam();
5892 	return;
5893       }
5894       packLqhkeyreqLab(signal);
5895       return;
5896     }
5897     else if (len == 0 && op == ZDELETE)
5898     {
5899       /**
5900        * Case 7
5901        */
5902       jam();
5903       if (TRACENR_FLAG)
5904 	TRACENR(" UPDATE_GCI" << endl);
5905       c_tup->nr_update_gci(fragPtr, &regTcPtr.p->m_row_id, regTcPtr.p->gci_hi);
5906       goto update_gci_ignore;
5907     }
5908 
5909     /**
5910      * 1) Delete row at specified rowid (if len > 0)
5911      * 2) Delete specified row at different rowid (if exists)
5912      * 3) Run insert
5913      */
5914     if (len > 0)
5915     {
5916       /**
5917        * 1) Delete row at specified rowid (if len > 0)
5918        */
5919       jam();
5920       nr_copy_delete_row(signal, regTcPtr, &regTcPtr.p->m_row_id, len);
5921     }
5922     /**
5923      * 2) Delete specified row at different rowid (if exists)
5924      */
5925     jam();
5926     nr_copy_delete_row(signal, regTcPtr, 0, 0);
5927     if (TRACENR_FLAG)
5928       TRACENR(" RUN INSERT" << endl);
5929     goto run;
5930   }
5931   else
5932   {
5933     if (!match && op != ZINSERT)
5934     {
5935       jam();
5936       if (TRACENR_FLAG)
5937 	TRACENR(" IGNORE " << endl);
5938       goto ignore;
5939     }
5940     if (match)
5941     {
5942       jam();
5943       if (op != ZDELETE && op != ZREFRESH)
5944       {
5945 	if (TRACENR_FLAG)
5946 	  TRACENR(" Changing from INSERT/UPDATE to ZWRITE" << endl);
5947 	regTcPtr.p->operation = ZWRITE;
5948       }
5949       goto run;
5950     }
5951 
5952     ndbassert(!match && op == ZINSERT);
5953 
5954     /**
5955      * 1) Delete row at specified rowid (if len > 0)
5956      * 2) Delete specified row at different rowid (if exists)
5957      * 3) Run insert
5958      */
5959     if (len > 0)
5960     {
5961       /**
5962        * 1) Delete row at specified rowid (if len > 0)
5963        */
5964       jam();
5965       nr_copy_delete_row(signal, regTcPtr, &regTcPtr.p->m_row_id, len);
5966     }
5967 
5968     /**
5969      * 2) Delete specified row at different rowid (if exists)
5970      */
5971     jam();
5972     nr_copy_delete_row(signal, regTcPtr, 0, 0);
5973     if (TRACENR_FLAG)
5974       TRACENR(" RUN op: " << op << endl);
5975     goto run;
5976   }
5977 
5978 run:
5979   jam();
5980   exec_acckeyreq(signal, regTcPtr);
5981   return;
5982 
5983 ignore:
5984   jam();
5985   ndbassert(!LqhKeyReq::getNrCopyFlag(regTcPtr.p->reqinfo));
5986 update_gci_ignore:
5987   regTcPtr.p->activeCreat = Fragrecord::AC_IGNORED;
5988   signal->theData[0] = regTcPtr.p->tupConnectrec;
5989   EXECUTE_DIRECT(DBTUP, GSN_TUP_ABORTREQ, signal, 1);
5990 
5991   packLqhkeyreqLab(signal);
5992 }
5993 
5994 /**
5995  * Compare received key data with the data supplied
5996  * returning 0 if they are the same, 1 otherwise
5997  */
5998 int
compare_key(const TcConnectionrec * regTcPtr,const Uint32 * ptr,Uint32 len)5999 Dblqh::compare_key(const TcConnectionrec* regTcPtr,
6000 		   const Uint32 * ptr, Uint32 len)
6001 {
6002   if (regTcPtr->primKeyLen != len)
6003     return 1;
6004 
6005   ndbassert( regTcPtr->keyInfoIVal != RNIL );
6006 
6007   SectionReader keyInfoReader(regTcPtr->keyInfoIVal,
6008                               getSectionSegmentPool());
6009 
6010   ndbassert(regTcPtr->primKeyLen == keyInfoReader.getSize());
6011 
6012   while (len != 0)
6013   {
6014     const Uint32* keyChunk= NULL;
6015     Uint32 chunkSize= 0;
6016 
6017     /* Get a ptr to a chunk of contiguous words to compare */
6018     bool ok= keyInfoReader.getWordsPtr(len, keyChunk, chunkSize);
6019 
6020     ndbrequire(ok);
6021 
6022     if ( memcmp(ptr, keyChunk, chunkSize << 2))
6023       return 1;
6024 
6025     ptr+= chunkSize;
6026     len-= chunkSize;
6027   }
6028 
6029   return 0;
6030 }
6031 
6032 void
nr_copy_delete_row(Signal * signal,Ptr<TcConnectionrec> regTcPtr,Local_key * rowid,Uint32 len)6033 Dblqh::nr_copy_delete_row(Signal* signal,
6034 			  Ptr<TcConnectionrec> regTcPtr,
6035 			  Local_key* rowid, Uint32 len)
6036 {
6037   Ptr<Fragrecord> fragPtr = fragptr;
6038 
6039   Uint32 keylen;
6040   Uint32 tableId = regTcPtr.p->tableref;
6041   Uint32 accPtr = regTcPtr.p->accConnectrec;
6042 
6043   signal->theData[0] = accPtr;
6044   signal->theData[1] = fragptr.p->accFragptr;
6045   signal->theData[2] = ZDELETE + (ZDELETE << 4);
6046   signal->theData[5] = regTcPtr.p->transid[0];
6047   signal->theData[6] = regTcPtr.p->transid[1];
6048 
6049   if (rowid)
6050   {
6051     jam();
6052     keylen = 2;
6053     if (g_key_descriptor_pool.getPtr(tableId)->hasCharAttr)
6054     {
6055       signal->theData[3] = calculateHash(tableId, signal->theData+24);
6056     }
6057     else
6058     {
6059       signal->theData[3] = md5_hash((Uint64*)(signal->theData+24), len);
6060     }
6061     signal->theData[4] = 0; // seach by local key
6062     signal->theData[7] = rowid->m_page_no;
6063     signal->theData[8] = rowid->m_page_idx;
6064   }
6065   else
6066   {
6067     jam();
6068     keylen = regTcPtr.p->primKeyLen;
6069     signal->theData[3] = regTcPtr.p->hashValue;
6070     signal->theData[4] = keylen;
6071 
6072     /* Copy KeyInfo inline into the ACCKEYREQ signal,
6073      * starting at word 7
6074      */
6075     copy(&signal->theData[7], regTcPtr.p->keyInfoIVal);
6076   }
6077   const Uint32 ref = refToMain(regTcPtr.p->tcAccBlockref);
6078   EXECUTE_DIRECT(ref, GSN_ACCKEYREQ, signal, 7 + keylen);
6079   jamEntry();
6080 
6081   Uint32 retValue = signal->theData[0];
6082   ndbrequire(retValue != RNIL); // This should never block...
6083 
6084   if (retValue == (Uint32)-1)
6085   {
6086     /**
6087      * Only delete by pk, may fail
6088      */
6089     jam();
6090     ndbrequire(rowid == 0);
6091     signal->theData[0] = accPtr;
6092     signal->theData[1] = 0;
6093     EXECUTE_DIRECT(ref, GSN_ACC_ABORTREQ, signal, 2);
6094     jamEntry();
6095     return;
6096   }
6097 
6098   /**
6099    * We found row (and have it locked in ACC)
6100    */
6101   ndbrequire(regTcPtr.p->m_dealloc == 0);
6102   Local_key save = regTcPtr.p->m_row_id;
6103 
6104   c_acc->execACCKEY_ORD(signal, accPtr);
6105   signal->theData[0] = accPtr;
6106   EXECUTE_DIRECT(ref, GSN_ACC_COMMITREQ, signal, 1);
6107   jamEntry();
6108 
6109   ndbrequire(regTcPtr.p->m_dealloc == 1);
6110   int ret = c_tup->nr_delete(signal, regTcPtr.i,
6111 			     fragPtr.p->tupFragptr, &regTcPtr.p->m_row_id,
6112 			     regTcPtr.p->gci_hi);
6113   jamEntry();
6114 
6115   if (ret)
6116   {
6117     ndbassert(ret == 1);
6118     Uint32 pos = regTcPtr.p->m_nr_delete.m_cnt - 1;
6119     memcpy(regTcPtr.p->m_nr_delete.m_disk_ref + pos,
6120 	   signal->theData, sizeof(Local_key));
6121     regTcPtr.p->m_nr_delete.m_page_id[pos] = RNIL;
6122     regTcPtr.p->m_nr_delete.m_cnt = pos + 2;
6123     if (0) ndbout << "PENDING DISK DELETE: " <<
6124       regTcPtr.p->m_nr_delete.m_disk_ref[pos] << endl;
6125   }
6126 
6127   TRACENR("DELETED: " << regTcPtr.p->m_row_id << endl);
6128 
6129   regTcPtr.p->m_dealloc = 0;
6130   regTcPtr.p->m_row_id = save;
6131   fragptr = fragPtr;
6132   tcConnectptr = regTcPtr;
6133 }
6134 
6135 void
get_nr_op_info(Nr_op_info * op,Uint32 page_id)6136 Dblqh::get_nr_op_info(Nr_op_info* op, Uint32 page_id)
6137 {
6138   Ptr<TcConnectionrec> tcPtr;
6139   tcPtr.i = op->m_ptr_i;
6140   ptrCheckGuard(tcPtr, ctcConnectrecFileSize, tcConnectionrec);
6141 
6142   Ptr<Fragrecord> fragPtr;
6143   c_fragment_pool.getPtr(fragPtr, tcPtr.p->fragmentptr);
6144 
6145   op->m_gci_hi = tcPtr.p->gci_hi;
6146   op->m_gci_lo = tcPtr.p->gci_lo;
6147   op->m_tup_frag_ptr_i = fragPtr.p->tupFragptr;
6148 
6149   ndbrequire(tcPtr.p->activeCreat == Fragrecord::AC_NR_COPY);
6150   ndbrequire(tcPtr.p->m_nr_delete.m_cnt);
6151 
6152 
6153   if (page_id == RNIL)
6154   {
6155     // get log buffer callback
6156     for (Uint32 i = 0; i<2; i++)
6157     {
6158       if (tcPtr.p->m_nr_delete.m_page_id[i] != RNIL)
6159       {
6160 	op->m_page_id = tcPtr.p->m_nr_delete.m_page_id[i];
6161 	op->m_disk_ref = tcPtr.p->m_nr_delete.m_disk_ref[i];
6162 	return;
6163       }
6164     }
6165   }
6166   else
6167   {
6168     // get page callback
6169     for (Uint32 i = 0; i<2; i++)
6170     {
6171       Local_key key = tcPtr.p->m_nr_delete.m_disk_ref[i];
6172       if (op->m_disk_ref.m_page_no == key.m_page_no &&
6173 	  op->m_disk_ref.m_file_no == key.m_file_no &&
6174 	  tcPtr.p->m_nr_delete.m_page_id[i] == RNIL)
6175       {
6176 	op->m_disk_ref = key;
6177 	tcPtr.p->m_nr_delete.m_page_id[i] = page_id;
6178 	return;
6179       }
6180     }
6181   }
6182   ndbrequire(false);
6183 }
6184 
6185 void
nr_delete_complete(Signal * signal,Nr_op_info * op)6186 Dblqh::nr_delete_complete(Signal* signal, Nr_op_info* op)
6187 {
6188   jamEntry();
6189   Ptr<TcConnectionrec> tcPtr;
6190   tcPtr.i = op->m_ptr_i;
6191   ptrCheckGuard(tcPtr, ctcConnectrecFileSize, tcConnectionrec);
6192 
6193   ndbrequire(tcPtr.p->activeCreat == Fragrecord::AC_NR_COPY);
6194   ndbrequire(tcPtr.p->m_nr_delete.m_cnt);
6195 
6196   tcPtr.p->m_nr_delete.m_cnt--;
6197   if (tcPtr.p->m_nr_delete.m_cnt == 0)
6198   {
6199     jam();
6200     tcConnectptr = tcPtr;
6201     c_fragment_pool.getPtr(fragptr, tcPtr.p->fragmentptr);
6202 
6203     if (tcPtr.p->abortState != TcConnectionrec::ABORT_IDLE)
6204     {
6205       jam();
6206       tcPtr.p->activeCreat = Fragrecord::AC_NORMAL;
6207       abortCommonLab(signal);
6208     }
6209     else if (tcPtr.p->operation == ZDELETE &&
6210 	     LqhKeyReq::getNrCopyFlag(tcPtr.p->reqinfo))
6211     {
6212       /**
6213        * This is run directly in handle_nr_copy
6214        */
6215       jam();
6216       packLqhkeyreqLab(signal);
6217     }
6218     else
6219     {
6220       jam();
6221       rwConcludedLab(signal);
6222     }
6223     return;
6224   }
6225 
6226   if (memcmp(&tcPtr.p->m_nr_delete.m_disk_ref[0],
6227 	     &op->m_disk_ref, sizeof(Local_key)) == 0)
6228   {
6229     jam();
6230     ndbassert(tcPtr.p->m_nr_delete.m_page_id[0] != RNIL);
6231     tcPtr.p->m_nr_delete.m_page_id[0] = tcPtr.p->m_nr_delete.m_page_id[1];
6232     tcPtr.p->m_nr_delete.m_disk_ref[0] = tcPtr.p->m_nr_delete.m_disk_ref[1];
6233   }
6234 }
6235 
6236 Uint32
readPrimaryKeys(Uint32 opPtrI,Uint32 * dst,bool xfrm)6237 Dblqh::readPrimaryKeys(Uint32 opPtrI, Uint32 * dst, bool xfrm)
6238 {
6239   TcConnectionrecPtr regTcPtr;
6240   Uint64 Tmp[MAX_KEY_SIZE_IN_WORDS >> 1];
6241 
6242   jamEntry();
6243   regTcPtr.i = opPtrI;
6244   ptrCheckGuard(regTcPtr, ctcConnectrecFileSize, tcConnectionrec);
6245 
6246   Uint32 tableId = regTcPtr.p->tableref;
6247   Uint32 keyLen = regTcPtr.p->primKeyLen;
6248   Uint32 * tmp = xfrm ? (Uint32*)Tmp : dst;
6249 
6250   copy(tmp, regTcPtr.p->keyInfoIVal);
6251 
6252   if (xfrm)
6253   {
6254     jam();
6255     Uint32 keyPartLen[MAX_ATTRIBUTES_IN_INDEX];
6256     return xfrm_key(tableId, (Uint32*)Tmp, dst, ~0, keyPartLen);
6257   }
6258 
6259   return keyLen;
6260 }
6261 
6262 /**
6263  * getKeyInfoWordOrZero
6264  * Get given word of KeyInfo, or zero if it's not available
6265  * Used for tracing
6266  */
6267 Uint32
getKeyInfoWordOrZero(const TcConnectionrec * regTcPtr,Uint32 offset)6268 Dblqh::getKeyInfoWordOrZero(const TcConnectionrec* regTcPtr,
6269                             Uint32 offset)
6270 {
6271   if (regTcPtr->keyInfoIVal != RNIL)
6272   {
6273     SectionReader keyInfoReader(regTcPtr->keyInfoIVal,
6274                                 g_sectionSegmentPool);
6275 
6276     if (keyInfoReader.getSize() > offset)
6277     {
6278       if (offset)
6279         keyInfoReader.step(offset);
6280 
6281       Uint32 word;
6282       keyInfoReader.getWord(&word);
6283       return word;
6284     }
6285   }
6286   return 0;
6287 }
6288 
unlockError(Signal * signal,Uint32 error)6289 void Dblqh::unlockError(Signal* signal, Uint32 error)
6290 {
6291   terrorCode = error;
6292   abortErrorLab(signal);
6293 }
6294 
6295 /**
6296  * handleUserUnlockRequest
6297  *
6298  * This method handles an LQHKEYREQ unlock request from
6299  * TC.
6300  */
handleUserUnlockRequest(Signal * signal)6301 void Dblqh::handleUserUnlockRequest(Signal* signal)
6302 {
6303   jam();
6304   TcConnectionrec * const regTcPtr = tcConnectptr.p;
6305   Uint32 tcPtrI = tcConnectptr.i;
6306 
6307   /* Request to unlock (abort) an existing read operation
6308    *
6309    * 1) Get user's LOCK_REF from KeyInfo
6310    *
6311    * 2) Lookup TC_OP_REF in hash
6312    *
6313    * 3) Check state of found op : TransId, state, type, lock
6314    *
6315    * 4) Check op_id portion
6316    *
6317    * 5) Abort locking op in ACC
6318    *
6319    * 6) Clean up locking op in LQH
6320    *
6321    * 7) Send LQHKEYCONF to TC for user unlock op
6322    *
6323    * 8) Clean up user unlock op
6324    */
6325   if (unlikely( regTcPtr->primKeyLen != LqhKeyReq::UnlockKeyLen ))
6326   {
6327     jam();
6328     unlockError(signal, 4109); /* Faulty primary key attribute length */
6329     return;
6330   }
6331 
6332   SectionReader keyInfoReader(regTcPtr->keyInfoIVal,
6333                               getSectionSegmentPool());
6334 
6335   ndbrequire( keyInfoReader.getSize() == regTcPtr->primKeyLen );
6336 
6337   /* Extract components of user lock reference */
6338   Uint32 tcOpRecIndex;
6339   Uint32 lqhOpIdWord;
6340   ndbrequire( keyInfoReader.getWord( &tcOpRecIndex ) ); // Locking op TC index
6341   ndbrequire( keyInfoReader.getWord( &lqhOpIdWord ) );  // Part of Locking op LQH id
6342 
6343   /* Use TC operation record index to find the operation record
6344    * This requires that this operation and the referenced
6345    * operation are part of the same transaction.
6346    * On success this sets tcConnectptr.i and .p to the
6347    * operation-to-unlock's record.
6348    */
6349   if (unlikely( findTransaction(regTcPtr->transid[0],
6350                                 regTcPtr->transid[1],
6351                                 tcOpRecIndex,
6352                                 0) != ZOK))
6353   {
6354     jam();
6355     unlockError(signal, ZBAD_OP_REF);
6356     return;
6357   }
6358 
6359   TcConnectionrec * const regLockTcPtr = tcConnectptr.p;
6360 
6361   /* Validate that the bottom 32-bits of the operation id reference
6362    * we were given are in alignment
6363    */
6364   Uint32 lockOpKeyReqId = (Uint32) regLockTcPtr->lqhKeyReqId;
6365   if (unlikely( lockOpKeyReqId != lqhOpIdWord ))
6366   {
6367     jam();
6368     unlockError(signal, ZBAD_OP_REF);
6369     return;
6370   }
6371 
6372   /* Validate the state of the locking operation */
6373   bool lockingOpValid =
6374     (( regLockTcPtr->operation == ZREAD ) &&
6375        // ZREAD_EX mapped to ZREAD above
6376      ( ! regLockTcPtr->dirtyOp ) &&
6377      ( ! regLockTcPtr->opSimple ) &&
6378      ( (regLockTcPtr->lockType == ZREAD) ||  // LM_Read
6379        (regLockTcPtr->lockType == ZUPDATE) ) // LM_Exclusive
6380      &&
6381      ( regLockTcPtr->transactionState == TcConnectionrec::PREPARED ) &&
6382      ( regLockTcPtr->commitAckMarker == RNIL ) &&
6383        // No commit ack marker
6384      ( regLockTcPtr->logWriteState ==
6385        TcConnectionrec::NOT_STARTED )); // No log written
6386 
6387   if (unlikely(! lockingOpValid))
6388   {
6389     jam();
6390     unlockError(signal, ZBAD_UNLOCK_STATE);
6391     return;
6392   }
6393 
6394   /* Ok, now we're ready to start 'aborting' this operation, to get the
6395    * effect of unlocking it
6396    */
6397   signal->theData[0] = regLockTcPtr->accConnectrec;
6398   signal->theData[1] = 0; // For Execute_Direct
6399   EXECUTE_DIRECT(refToMain(regLockTcPtr->tcAccBlockref),
6400                  GSN_ACC_ABORTREQ,
6401                  signal,
6402                  2);
6403   jamEntry();
6404 
6405   /* Would be nice to handle non-success case somehow */
6406   ndbrequire(signal->theData[1] == 0);
6407 
6408   /* Now we want to release LQH resources associated with the
6409    * locking operation
6410    */
6411   cleanUp(signal);
6412 
6413   /* Now that the locking operation has been 'disappeared', we need to
6414    * send an LQHKEYCONF for the unlock operation and then 'disappear' it
6415    * as well
6416    */
6417   tcConnectptr.i = tcPtrI;
6418   ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
6419 
6420   ndbrequire( regTcPtr == tcConnectptr.p );
6421 
6422   /* Set readlenAi to the unlocked operation's TC operation ref */
6423   regTcPtr->readlenAi = tcOpRecIndex;
6424 
6425   /* Clear number of fired triggers */
6426   regTcPtr->numFiredTriggers = 0;
6427 
6428   /* Now send the LQHKEYCONF to TC */
6429   sendLqhkeyconfTc(signal, regTcPtr->tcBlockref);
6430 
6431   /* Finally, clean up the unlock operation itself */
6432   cleanUp(signal);
6433 
6434   return;
6435 }
6436 
execTUP_DEALLOCREQ(Signal * signal)6437 void Dblqh::execTUP_DEALLOCREQ(Signal* signal)
6438 {
6439   TcConnectionrecPtr regTcPtr;
6440 
6441   jamEntry();
6442   regTcPtr.i = signal->theData[4];
6443 
6444   if (TRACENR_FLAG)
6445   {
6446     Local_key tmp;
6447     tmp.m_page_no = signal->theData[2];
6448     tmp.m_page_idx = signal->theData[3];
6449     TRACENR("TUP_DEALLOC: " << tmp <<
6450       (signal->theData[5] ? " DIRECT " : " DELAYED") << endl);
6451   }
6452 
6453   if (signal->theData[5])
6454   {
6455     jam();
6456     Local_key tmp;
6457 
6458     tmp.m_page_no = signal->theData[2];
6459     tmp.m_page_idx = signal->theData[3];
6460 
6461     if (ERROR_INSERTED(5712))
6462     {
6463       ndbout << "TUP_DEALLOC: " << tmp << endl;
6464     }
6465 
6466     EXECUTE_DIRECT(DBTUP, GSN_TUP_DEALLOCREQ, signal, signal->getLength());
6467     return;
6468   }
6469   else
6470   {
6471     jam();
6472     ptrCheckGuard(regTcPtr, ctcConnectrecFileSize, tcConnectionrec);
6473     regTcPtr.p->m_row_id.m_page_no = signal->theData[2];
6474     regTcPtr.p->m_row_id.m_page_idx = signal->theData[3];
6475 
6476     TRACE_OP(regTcPtr.p, "SET DEALLOC");
6477 
6478     ndbrequire(regTcPtr.p->m_dealloc == 0);
6479     regTcPtr.p->m_dealloc = 1;
6480   }
6481 }//Dblqh::execTUP_DEALLOCREQ()
6482 
6483 /* ************>> */
6484 /*  ACCKEYCONF  > */
6485 /* ************>> */
execACCKEYCONF(Signal * signal)6486 void Dblqh::execACCKEYCONF(Signal* signal)
6487 {
6488   TcConnectionrec *regTcConnectionrec = tcConnectionrec;
6489   Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize;
6490   Uint32 tcIndex = signal->theData[0];
6491   Uint32 localKey1 = signal->theData[3];
6492   Uint32 localKey2 = signal->theData[4];
6493   jamEntry();
6494 
6495   tcConnectptr.i = tcIndex;
6496   ptrCheckGuard(tcConnectptr, ttcConnectrecFileSize, regTcConnectionrec);
6497   TcConnectionrec * const regTcPtr = tcConnectptr.p;
6498   if (regTcPtr->transactionState != TcConnectionrec::WAIT_ACC) {
6499     LQHKEY_abort(signal, 3);
6500     return;
6501   }//if
6502 
6503   FragrecordPtr fragPtr;
6504   c_fragment_pool.getPtr(fragPtr, regTcPtr->fragmentptr);
6505   c_tup->prepareTUPKEYREQ(localKey1, localKey2, fragPtr.p->tupFragptr);
6506   continueACCKEYCONF(signal, regTcPtr, localKey1, localKey2);
6507 }
6508 
6509 void
continueACCKEYCONF(Signal * signal,TcConnectionrec * const regTcPtr,Uint32 localKey1,Uint32 localKey2)6510 Dblqh::continueACCKEYCONF(Signal * signal,
6511                           TcConnectionrec * const regTcPtr,
6512                           Uint32 localKey1,
6513                           Uint32 localKey2)
6514 {
6515   /* ------------------------------------------------------------------------
6516    * IT IS NOW TIME TO CONTACT THE TUPLE MANAGER. THE TUPLE MANAGER NEEDS THE
6517    * INFORMATION ON WHICH TABLE AND FRAGMENT, THE LOCAL KEY AND IT NEEDS TO
6518    * KNOW THE TYPE OF OPERATION TO PERFORM. TUP CAN SEND THE ATTRINFO DATA
6519    * EITHER TO THE TC BLOCK OR DIRECTLY TO THE APPLICATION. THE SCHEMA VERSION
6520    * IS NEEDED SINCE TWO SCHEMA VERSIONS CAN BE ACTIVE SIMULTANEOUSLY ON A
6521    * TABLE.
6522    * ----------------------------------------------------------------------- */
6523   if (regTcPtr->operation == ZWRITE)
6524   {
6525     ndbassert(regTcPtr->seqNoReplica == 0 ||
6526 	      regTcPtr->activeCreat == Fragrecord::AC_NR_COPY);
6527     Uint32 op= signal->theData[1];
6528     Uint32 requestInfo = regTcPtr->reqinfo;
6529     if(likely(op == ZINSERT || op == ZUPDATE))
6530     {
6531       jam();
6532       regTcPtr->operation = op;
6533     }
6534     else
6535     {
6536       jam();
6537       warningEvent("Convering %d to ZUPDATE", op);
6538       op = regTcPtr->operation = ZUPDATE;
6539     }
6540     if (regTcPtr->seqNoReplica == 0)
6541     {
6542       jam();
6543       requestInfo &= ~(RI_OPERATION_MASK <<  RI_OPERATION_SHIFT);
6544       LqhKeyReq::setOperation(requestInfo, op);
6545       regTcPtr->reqinfo = requestInfo;
6546     }
6547   }//if
6548 
6549   /* ------------------------------------------------------------------------
6550    * IT IS NOW TIME TO CONTACT THE TUPLE MANAGER. THE TUPLE MANAGER NEEDS THE
6551    * INFORMATION ON WHICH TABLE AND FRAGMENT, THE LOCAL KEY AND IT NEEDS TO
6552    * KNOW THE TYPE OF OPERATION TO PERFORM. TUP CAN SEND THE ATTRINFO DATA
6553    * EITHER TO THE TC BLOCK OR DIRECTLY TO THE APPLICATION. THE SCHEMA VERSION
6554    * IS NEEDED SINCE TWO SCHEMA VERSIONS CAN BE ACTIVE SIMULTANEOUSLY ON A
6555    * TABLE.
6556    * ----------------------------------------------------------------------- */
6557   FragrecordPtr regFragptr;
6558   regFragptr.i = regTcPtr->fragmentptr;
6559   c_fragment_pool.getPtr(regFragptr);
6560 
6561   if(!regTcPtr->m_disk_table)
6562     acckeyconf_tupkeyreq(signal, regTcPtr, regFragptr.p,
6563                          localKey1, localKey2, RNIL);
6564   else
6565     acckeyconf_load_diskpage(signal, tcConnectptr, regFragptr.p,
6566                              localKey1, localKey2);
6567 }
6568 
6569 void
acckeyconf_tupkeyreq(Signal * signal,TcConnectionrec * regTcPtr,Fragrecord * regFragptrP,Uint32 lkey1,Uint32 lkey2,Uint32 disk_page)6570 Dblqh::acckeyconf_tupkeyreq(Signal* signal, TcConnectionrec* regTcPtr,
6571 			    Fragrecord* regFragptrP,
6572 			    Uint32 lkey1, Uint32 lkey2,
6573 			    Uint32 disk_page)
6574 {
6575   Uint32 op = regTcPtr->operation;
6576   regTcPtr->transactionState = TcConnectionrec::WAIT_TUP;
6577   /* ------------------------------------------------------------------------
6578    * IT IS NOW TIME TO CONTACT THE TUPLE MANAGER. THE TUPLE MANAGER NEEDS THE
6579    * INFORMATION ON WHICH TABLE AND FRAGMENT, THE LOCAL KEY AND IT NEEDS TO
6580    * KNOW THE TYPE OF OPERATION TO PERFORM. TUP CAN SEND THE ATTRINFO DATA
6581    * EITHER TO THE TC BLOCK OR DIRECTLY TO THE APPLICATION. THE SCHEMA VERSION
6582    * IS NEEDED SINCE TWO SCHEMA VERSIONS CAN BE ACTIVE SIMULTANEOUSLY ON A
6583    * TABLE.
6584    * ----------------------------------------------------------------------- */
6585   Uint32 page_idx = lkey2;
6586   Uint32 page_no = lkey1;
6587   Uint32 Ttupreq = 0;
6588   Uint32 flags = regTcPtr->m_flags;
6589   TupKeyReq::setDirtyFlag(Ttupreq, regTcPtr->dirtyOp);
6590   TupKeyReq::setSimpleFlag(Ttupreq, regTcPtr->opSimple);
6591   TupKeyReq::setOperation(Ttupreq, op);
6592   TupKeyReq::setInterpretedFlag(Ttupreq, regTcPtr->opExec);
6593   TupKeyReq::setRowidFlag(Ttupreq, regTcPtr->m_use_rowid);
6594   TupKeyReq::setReorgFlag(Ttupreq, regTcPtr->m_reorg);
6595 
6596   /* ---------------------------------------------------------------------
6597    * Clear interpreted mode bit since we do not want the next replica to
6598    * use interpreted mode. The next replica will receive a normal write.
6599    * --------------------------------------------------------------------- */
6600   regTcPtr->opExec = 0;
6601   /* ************< */
6602   /*  TUPKEYREQ  < */
6603   /* ************< */
6604   Uint32 sig0, sig1, sig2, sig3;
6605   sig0 = regTcPtr->tupConnectrec;
6606 
6607   TupKeyReq * const tupKeyReq = (TupKeyReq *)signal->getDataPtrSend();
6608   tupKeyReq->connectPtr = sig0;
6609   tupKeyReq->request = Ttupreq;
6610   tupKeyReq->keyRef1 = page_no;
6611   tupKeyReq->keyRef2 = page_idx;
6612 
6613   sig0 = regTcPtr->totReclenAi;
6614   sig1 = regTcPtr->applOprec;
6615   sig2 = regTcPtr->applRef;
6616 
6617   tupKeyReq->attrBufLen = sig0;
6618   tupKeyReq->opRef = sig1;
6619   tupKeyReq->applRef = sig2;
6620 
6621   sig0 = regTcPtr->storedProcId;
6622   sig1 = regTcPtr->transid[0];
6623   sig2 = regTcPtr->transid[1];
6624   sig3 = regFragptrP->tupFragptr;
6625 
6626   tupKeyReq->storedProcedure = sig0;
6627   tupKeyReq->transId1 = sig1;
6628   tupKeyReq->transId2 = sig2;
6629   tupKeyReq->fragPtr = sig3;
6630 
6631   sig0 = regTcPtr->m_row_id.m_page_no;
6632   sig1 = regTcPtr->m_row_id.m_page_idx;
6633 
6634   tupKeyReq->primaryReplica = (tcConnectptr.p->seqNoReplica == 0)?true:false;
6635   tupKeyReq->coordinatorTC = tcConnectptr.p->tcBlockref;
6636   tupKeyReq->tcOpIndex = tcConnectptr.p->tcOprec;
6637   tupKeyReq->savePointId = tcConnectptr.p->savePointId;
6638   tupKeyReq->disk_page= disk_page;
6639 
6640   tupKeyReq->m_row_id_page_no = sig0;
6641   tupKeyReq->m_row_id_page_idx = sig1;
6642 
6643   TRACE_OP(regTcPtr, "TUPKEYREQ");
6644 
6645   regTcPtr->m_use_rowid |= (op == ZINSERT || op == ZREFRESH);
6646   regTcPtr->m_row_id.m_page_no = page_no;
6647   regTcPtr->m_row_id.m_page_idx = page_idx;
6648 
6649   tupKeyReq->attrInfoIVal= RNIL;
6650   tupKeyReq->deferred_constraints =
6651     (flags & TcConnectionrec::OP_DEFERRED_CONSTRAINTS) != 0;
6652   tupKeyReq->disable_fk_checks =
6653     (flags & TcConnectionrec::OP_DISABLE_FK) != 0;
6654 
6655 
6656   /* Pass AttrInfo section if available in the TupKeyReq signal
6657    * We are still responsible for releasing it, TUP is just
6658    * borrowing it
6659    */
6660   if (tupKeyReq->attrBufLen > 0)
6661   {
6662     ndbassert( regTcPtr->attrInfoIVal != RNIL );
6663     tupKeyReq->attrInfoIVal= regTcPtr->attrInfoIVal;
6664   }
6665 
6666   if (c_tup->execTUPKEYREQ(signal))
6667   {
6668     execTUPKEYCONF(signal);
6669   }
6670   else
6671   {
6672     execTUPKEYREF(signal);
6673   }
6674 }
6675 
6676 void
acckeyconf_load_diskpage(Signal * signal,TcConnectionrecPtr regTcPtr,Fragrecord * regFragptrP,Uint32 lkey1,Uint32 lkey2)6677 Dblqh::acckeyconf_load_diskpage(Signal* signal, TcConnectionrecPtr regTcPtr,
6678 				Fragrecord* regFragptrP,
6679                                 Uint32 lkey1, Uint32 lkey2)
6680 {
6681   int res;
6682   if((res= c_tup->load_diskpage(signal,
6683 				regTcPtr.p->tupConnectrec,
6684 				regFragptrP->tupFragptr,
6685 				lkey1, lkey2,
6686 				regTcPtr.p->operation)) > 0)
6687   {
6688     acckeyconf_tupkeyreq(signal, regTcPtr.p, regFragptrP, lkey1, lkey2, res);
6689   }
6690   else if(res == 0)
6691   {
6692     regTcPtr.p->transactionState = TcConnectionrec::WAIT_TUP;
6693     regTcPtr.p->m_row_id.m_page_no = lkey1;
6694     regTcPtr.p->m_row_id.m_page_idx = lkey2;
6695   }
6696   else
6697   {
6698     regTcPtr.p->transactionState = TcConnectionrec::WAIT_TUP;
6699     TupKeyRef * ref = (TupKeyRef *)signal->getDataPtr();
6700     ref->userRef= regTcPtr.i;
6701     ref->errorCode= ~0;
6702     execTUPKEYREF(signal);
6703   }
6704 }
6705 
6706 void
acckeyconf_load_diskpage_callback(Signal * signal,Uint32 callbackData,Uint32 disk_page)6707 Dblqh::acckeyconf_load_diskpage_callback(Signal* signal,
6708 					 Uint32 callbackData,
6709 					 Uint32 disk_page)
6710 {
6711   jamEntry();
6712   tcConnectptr.i = callbackData;
6713   ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
6714   TcConnectionrec * const regTcPtr = tcConnectptr.p;
6715 
6716   TcConnectionrec::TransactionState state = regTcPtr->transactionState;
6717   if (likely(disk_page > 0 && state == TcConnectionrec::WAIT_TUP))
6718   {
6719     FragrecordPtr fragPtr;
6720     c_fragment_pool.getPtr(fragPtr, regTcPtr->fragmentptr);
6721 
6722     c_tup->prepareTUPKEYREQ(regTcPtr->m_row_id.m_page_no,
6723                             regTcPtr->m_row_id.m_page_idx,
6724                             fragPtr.p->tupFragptr);
6725     acckeyconf_tupkeyreq(signal, regTcPtr, fragPtr.p,
6726 			 regTcPtr->m_row_id.m_page_no,
6727 			 regTcPtr->m_row_id.m_page_idx,
6728 			 disk_page);
6729   }
6730   else if (state != TcConnectionrec::WAIT_TUP)
6731   {
6732     ndbrequire(state == TcConnectionrec::WAIT_TUP_TO_ABORT);
6733     abortCommonLab(signal);
6734     return;
6735   }
6736   else
6737   {
6738     regTcPtr->transactionState = TcConnectionrec::WAIT_TUP;
6739     TupKeyRef * ref = (TupKeyRef *)signal->getDataPtr();
6740     ref->userRef= callbackData;
6741     ref->errorCode= disk_page;
6742     execTUPKEYREF(signal);
6743   }
6744 }
6745 
6746 /* --------------------------------------------------------------------------
6747  * -------                       ENTER TUP...                         -------
6748  * ENTER TUPKEYCONF WITH
6749  *           TC_CONNECTPTR,
6750  *           TDATA2,     LOCAL KEY REFERENCE 1, ONLY INTERESTING AFTER INSERT
6751  *           TDATA3,     LOCAL KEY REFERENCE 1, ONLY INTERESTING AFTER INSERT
6752  *           TDATA4,     TOTAL LENGTH OF READ DATA SENT TO TC/APPLICATION
6753  *           TDATA5      TOTAL LENGTH OF UPDATE DATA SENT TO/FROM TUP
6754  *        GOTO TUPKEY_CONF
6755  *
6756  *  TAKE CARE OF RESPONSES FROM TUPLE MANAGER.
6757  * -------------------------------------------------------------------------- */
tupkeyConfLab(Signal * signal,TcConnectionrec * const regTcPtr)6758 void Dblqh::tupkeyConfLab(Signal* signal,
6759                           TcConnectionrec * const regTcPtr)
6760 {
6761 /* ---- GET OPERATION TYPE AND CHECK WHAT KIND OF OPERATION IS REQUESTED --- */
6762   const TupKeyConf * const tupKeyConf = (TupKeyConf *)&signal->theData[0];
6763   Uint32 activeCreat = regTcPtr->activeCreat;
6764   Uint32 readLen = tupKeyConf->readLength;
6765   Uint32 writeLen = tupKeyConf->writeLength;
6766 
6767   TRACE_OP(regTcPtr, "TUPKEYCONF");
6768 
6769   Uint32 accOp = regTcPtr->accConnectrec;
6770   c_acc->execACCKEY_ORD(signal, accOp);
6771 
6772   jamEntry();
6773   if (readLen != 0)
6774   {
6775     jam();
6776 
6777     /* SET BIT 15 IN REQINFO */
6778     LqhKeyReq::setApplicationAddressFlag(regTcPtr->reqinfo, 1);
6779     regTcPtr->readlenAi = readLen;
6780   }//if
6781 
6782   if (regTcPtr->operation == ZREAD &&
6783       (regTcPtr->opSimple || regTcPtr->dirtyOp))
6784   {
6785     jam();
6786     /* ----------------------------------------------------------------------
6787      * THE OPERATION IS A SIMPLE READ.
6788      * WE WILL IMMEDIATELY COMMIT THE OPERATION.
6789      * SINCE WE HAVE NOT RELEASED THE FRAGMENT LOCK
6790      * (FOR LOCAL CHECKPOINTS) YET
6791      * WE CAN GO IMMEDIATELY TO COMMIT_CONTINUE_AFTER_BLOCKED.
6792      * WE HAVE ALREADY SENT THE RESPONSE SO WE ARE NOT INTERESTED IN
6793      * READ LENGTH
6794      * --------------------------------------------------------------------- */
6795     commitContinueAfterBlockedLab(signal);
6796     return;
6797   }//if
6798 
6799   regTcPtr->totSendlenAi = writeLen;
6800   /* We will propagate / log writeLen words
6801    * Check that that is how many we have available to
6802    * propagate
6803    */
6804   ndbrequire(regTcPtr->totSendlenAi == regTcPtr->currTupAiLen);
6805 
6806   if (unlikely(activeCreat == Fragrecord::AC_NR_COPY))
6807   {
6808     jam();
6809     ndbrequire(regTcPtr->m_nr_delete.m_cnt);
6810     regTcPtr->m_nr_delete.m_cnt--;
6811     if (regTcPtr->m_nr_delete.m_cnt)
6812     {
6813       jam();
6814       /**
6815        * Let operation wait for pending NR operations
6816        *   even for before writing log...(as it's simpler)
6817        */
6818 
6819 #ifdef VM_TRACE
6820       /**
6821        * Only disk table can have pending ops...
6822        */
6823       TablerecPtr tablePtr;
6824       tablePtr.i = regTcPtr->tableref;
6825       ptrCheckGuard(tablePtr, ctabrecFileSize, tablerec);
6826       ndbrequire(tablePtr.p->m_disk_table);
6827 #endif
6828 
6829       return;
6830     }
6831   }
6832 
6833   rwConcludedLab(signal);
6834   return;
6835 }//Dblqh::tupkeyConfLab()
6836 
6837 /* --------------------------------------------------------------------------
6838  *     THE CODE IS FOUND IN THE SIGNAL RECEPTION PART OF LQH
6839  * -------------------------------------------------------------------------- */
rwConcludedLab(Signal * signal)6840 void Dblqh::rwConcludedLab(Signal* signal)
6841 {
6842   TcConnectionrec * const regTcPtr = tcConnectptr.p;
6843   /* ------------------------------------------------------------------------
6844    *  WE HAVE NOW CONCLUDED READING/WRITING IN ACC AND TUP FOR THIS OPERATION.
6845    *  IT IS NOW TIME TO LOG THE OPERATION, SEND REQUEST TO NEXT NODE OR TC AND
6846    *  FOR SOME TYPES OF OPERATIONS IT IS EVEN TIME TO COMMIT THE OPERATION.
6847    * ------------------------------------------------------------------------ */
6848   if (regTcPtr->operation == ZREAD) {
6849     jam();
6850     /* ----------------------------------------------------------------------
6851      * A NORMAL READ OPERATION IS NOT LOGGED BUT IS NOT COMMITTED UNTIL THE
6852      * COMMIT SIGNAL ARRIVES. THUS WE CONTINUE PACKING THE RESPONSE.
6853      * ---------------------------------------------------------------------- */
6854     packLqhkeyreqLab(signal);
6855     return;
6856   } else {
6857     FragrecordPtr regFragptr = fragptr;
6858     if (regFragptr.p->logFlag == Fragrecord::STATE_FALSE){
6859       if (regTcPtr->dirtyOp == ZTRUE) {
6860         jam();
6861 	/* ------------------------------------------------------------------
6862 	 * THIS OPERATION WAS A WRITE OPERATION THAT DO NOT NEED LOGGING AND
6863 	 * THAT CAN CAN  BE COMMITTED IMMEDIATELY.
6864 	 * ----------------------------------------------------------------- */
6865         commitContinueAfterBlockedLab(signal);
6866         return;
6867       } else {
6868         jam();
6869 	/* ------------------------------------------------------------------
6870 	 * A NORMAL WRITE OPERATION ON A FRAGMENT WHICH DO NOT NEED LOGGING.
6871 	 * WE WILL PACK THE REQUEST/RESPONSE TO THE NEXT NODE/TO TC.
6872 	 * ------------------------------------------------------------------ */
6873         regTcPtr->logWriteState = TcConnectionrec::NOT_WRITTEN;
6874         packLqhkeyreqLab(signal);
6875         return;
6876       }//if
6877     } else {
6878       jam();
6879       /* --------------------------------------------------------------------
6880        * A DIRTY OPERATION WHICH NEEDS LOGGING. WE START BY LOGGING THE
6881        * REQUEST. IN THIS CASE WE WILL RELEASE THE FRAGMENT LOCK FIRST.
6882        * --------------------------------------------------------------------
6883        * A NORMAL WRITE OPERATION THAT NEEDS LOGGING AND WILL NOT BE
6884        * PREMATURELY COMMITTED.
6885        * -------------------------------------------------------------------- */
6886       logLqhkeyreqLab(signal);
6887       return;
6888     }//if
6889   }//if
6890 }//Dblqh::rwConcludedLab()
6891 
rwConcludedAiLab(Signal * signal)6892 void Dblqh::rwConcludedAiLab(Signal* signal)
6893 {
6894   TcConnectionrec * const regTcPtr = tcConnectptr.p;
6895   fragptr.i = regTcPtr->fragmentptr;
6896   /* ------------------------------------------------------------------------
6897    * WE HAVE NOW CONCLUDED READING/WRITING IN ACC AND TUP FOR THIS OPERATION.
6898    * IT IS NOW TIME TO LOG THE OPERATION, SEND REQUEST TO NEXT NODE OR TC AND
6899    * FOR SOME TYPES OF OPERATIONS IT IS EVEN TIME TO COMMIT THE OPERATION.
6900    * IN THIS CASE WE HAVE ALREADY RELEASED THE FRAGMENT LOCK.
6901    * ERROR CASES AT FRAGMENT CREATION AND STAND-BY NODES ARE THE REASONS FOR
6902    * COMING HERE.
6903    * ------------------------------------------------------------------------ */
6904   if (regTcPtr->operation == ZREAD) {
6905     if (regTcPtr->opSimple == 1) {
6906       jam();
6907       /* --------------------------------------------------------------------
6908        * THE OPERATION IS A SIMPLE READ. WE WILL IMMEDIATELY COMMIT THE
6909        * OPERATION.
6910        * -------------------------------------------------------------------- */
6911       localCommitLab(signal);
6912       return;
6913     } else {
6914       jam();
6915       /* --------------------------------------------------------------------
6916        * A NORMAL READ OPERATION IS NOT LOGGED BUT IS NOT COMMITTED UNTIL
6917        * THE COMMIT SIGNAL ARRIVES. THUS WE CONTINUE PACKING THE RESPONSE.
6918        * -------------------------------------------------------------------- */
6919       c_fragment_pool.getPtr(fragptr);
6920       packLqhkeyreqLab(signal);
6921       return;
6922     }//if
6923   } else {
6924     jam();
6925     c_fragment_pool.getPtr(fragptr);
6926     if (fragptr.p->logFlag == Fragrecord::STATE_FALSE) {
6927       if (regTcPtr->dirtyOp == ZTRUE) {
6928 	/* ------------------------------------------------------------------
6929 	 * THIS OPERATION WAS A WRITE OPERATION THAT DO NOT NEED LOGGING AND
6930 	 * THAT CAN CAN  BE COMMITTED IMMEDIATELY.
6931 	 * ----------------------------------------------------------------- */
6932         jam();
6933 	/* ----------------------------------------------------------------
6934 	 * IT MUST BE ACTIVE CREATION OF A FRAGMENT.
6935 	 * ---------------------------------------------------------------- */
6936         localCommitLab(signal);
6937         return;
6938       } else {
6939 	/* ------------------------------------------------------------------
6940 	 * A NORMAL WRITE OPERATION ON A FRAGMENT WHICH DO NOT NEED LOGGING.
6941 	 * WE WILL PACK THE REQUEST/RESPONSE TO THE NEXT NODE/TO TC.
6942 	 * ------------------------------------------------------------------ */
6943         jam();
6944 	  /* ---------------------------------------------------------------
6945 	   * IT MUST BE ACTIVE CREATION OF A FRAGMENT.
6946 	   * NOT A DIRTY OPERATION THUS PACK REQUEST/RESPONSE.
6947 	   * ---------------------------------------------------------------- */
6948         regTcPtr->logWriteState = TcConnectionrec::NOT_WRITTEN;
6949         packLqhkeyreqLab(signal);
6950         return;
6951       }//if
6952     } else {
6953       jam();
6954       /* --------------------------------------------------------------------
6955        * A DIRTY OPERATION WHICH NEEDS LOGGING. WE START BY LOGGING THE
6956        * REQUEST. IN THIS CASE WE WILL RELEASE THE FRAGMENT LOCK FIRST.
6957        * -------------------------------------------------------------------- */
6958       /* A NORMAL WRITE OPERATION THAT NEEDS LOGGING AND WILL NOT BE
6959        * PREMATURELY COMMITTED.
6960        * -------------------------------------------------------------------- */
6961       logLqhkeyreqLab(signal);
6962       return;
6963     }//if
6964   }//if
6965 }//Dblqh::rwConcludedAiLab()
6966 
6967 /* ##########################################################################
6968  * #######                            LOG MODULE                      #######
6969  *
6970  * ##########################################################################
6971  * --------------------------------------------------------------------------
6972  *       THE LOG MODULE HANDLES THE READING AND WRITING OF THE LOG
6973  *       IT IS ALSO RESPONSIBLE FOR HANDLING THE SYSTEM RESTART.
6974  *       IT CONTROLS THE SYSTEM RESTART IN TUP AND ACC AS WELL.
6975  * -------------------------------------------------------------------------- */
logLqhkeyreqLab(Signal * signal)6976 void Dblqh::logLqhkeyreqLab(Signal* signal)
6977 {
6978   UintR tcurrentFilepage;
6979   TcConnectionrecPtr tmpTcConnectptr;
6980 
6981   const bool out_of_log_buffer = cnoOfLogPages < ZMIN_LOG_PAGES_OPERATION;
6982 
6983   TcConnectionrec * const regTcPtr = tcConnectptr.p;
6984   logPartPtr.i = regTcPtr->m_log_part_ptr_i;
6985   ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
6986   bool abort_on_redo_problems =
6987     (LqhKeyReq::getQueueOnRedoProblemFlag(regTcPtr->reqinfo) == 0);
6988 
6989 /* -------------------------------------------------- */
6990 /*       THIS PART IS USED TO WRITE THE LOG           */
6991 /* -------------------------------------------------- */
6992 /* -------------------------------------------------- */
6993 /*       CHECK IF A LOG OPERATION IS ONGOING ALREADY. */
6994 /*       IF SO THEN QUEUE THE OPERATION FOR LATER     */
6995 /*       RESTART WHEN THE LOG PART IS FREE AGAIN.     */
6996 /* -------------------------------------------------- */
6997   LogPartRecord * const regLogPartPtr = logPartPtr.p;
6998   const bool problem = out_of_log_buffer || regLogPartPtr->m_log_problems != 0;
6999   if (unlikely(problem || ERROR_INSERTED(5083)))
7000   {
7001     /* -----------------------------------------------------------------*/
7002     /* P_TAIL_PROBLEM indicates that the redo log is full. If redo      */
7003     /* log writes are queued in this situation, they will have to wait  */
7004     /* until redo space is freed. Redo space will not be freed          */
7005     /* until the next LCP completes, which can take a long time. To     */
7006     /* avoid long waits and timeouts, redo log writes are aborted       */
7007     /* in case of a P_TAIL_PROBLEM.                                     */
7008     /* -----------------------------------------------------------------*/
7009     if (abort_on_redo_problems ||
7010         regLogPartPtr->m_log_problems & LogPartRecord::P_TAIL_PROBLEM)
7011     {
7012       jam();
7013       logLqhkeyreqLab_problems(signal);
7014       return;
7015     }
7016     else
7017     {
7018       jam();
7019       goto queueop;
7020     }
7021   }
7022 
7023   if (regLogPartPtr->logPartState == LogPartRecord::IDLE)
7024   {
7025     ;
7026   }
7027   else if (regLogPartPtr->logPartState == LogPartRecord::ACTIVE)
7028   {
7029 queueop:
7030     jam();
7031     linkWaitLog(signal, logPartPtr, logPartPtr.p->m_log_prepare_queue);
7032     regTcPtr->transactionState = TcConnectionrec::LOG_QUEUED;
7033     return;
7034   }
7035   else
7036   {
7037     ndbrequire(false);
7038     return;
7039   }//if
7040 
7041   logFilePtr.i = regLogPartPtr->currentLogfile;
7042   ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
7043 /* -------------------------------------------------- */
7044 /*       CHECK IF A NEW MBYTE IS TO BE STARTED. IF    */
7045 /*       SO INSERT A NEXT LOG RECORD, WRITE THE LOG   */
7046 /*       AND PLACE THE LOG POINTER ON THE NEW POSITION*/
7047 /*       IF A NEW FILE IS TO BE USED, CHANGE FILE AND */
7048 /*       ALSO START OPENING THE NEXT LOG FILE. IF A   */
7049 /*       LAP HAS BEEN COMPLETED THEN ADD ONE TO LAP   */
7050 /*       COUNTER.                                     */
7051 /* -------------------------------------------------- */
7052   checkNewMbyte(signal);
7053 /* -------------------------------------------------- */
7054 /*       INSERT THE OPERATION RECORD LAST IN THE LIST */
7055 /*       OF NOT COMPLETED OPERATIONS. ALSO RECORD THE */
7056 /*       FILE NO, PAGE NO AND PAGE INDEX OF THE START */
7057 /*       OF THIS LOG RECORD.                          */
7058 /*       IT IS NOT ALLOWED TO INSERT IT INTO THE LIST */
7059 /*       BEFORE CHECKING THE NEW MBYTE SINCE THAT WILL*/
7060 /*       CAUSE THE OLD VALUES OF TC_CONNECTPTR TO BE  */
7061 /*       USED IN WRITE_FILE_DESCRIPTOR.               */
7062 /* -------------------------------------------------- */
7063   Uint32 tcIndex = tcConnectptr.i;
7064   tmpTcConnectptr.i = regLogPartPtr->lastLogTcrec;
7065   regLogPartPtr->lastLogTcrec = tcIndex;
7066   if (tmpTcConnectptr.i == RNIL) {
7067     jam();
7068     regLogPartPtr->firstLogTcrec = tcIndex;
7069   } else {
7070     ptrCheckGuard(tmpTcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
7071     tmpTcConnectptr.p->nextLogTcrec = tcIndex;
7072   }//if
7073   Uint32 fileNo = logFilePtr.p->fileNo;
7074   tcurrentFilepage = logFilePtr.p->currentFilepage;
7075   logPagePtr.i = logFilePtr.p->currentLogpage;
7076   regTcPtr->nextLogTcrec = RNIL;
7077   regTcPtr->prevLogTcrec = tmpTcConnectptr.i;
7078   ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
7079   Uint32 pageIndex = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX];
7080   regTcPtr->logStartFileNo = fileNo;
7081   regTcPtr->logStartPageNo = tcurrentFilepage;
7082   regTcPtr->logStartPageIndex = pageIndex;
7083 /* -------------------------------------------------- */
7084 /*       WRITE THE LOG HEADER OF THIS OPERATION.      */
7085 /* -------------------------------------------------- */
7086   writeLogHeader(signal);
7087 /* -------------------------------------------------- */
7088 /*       WRITE THE TUPLE KEY OF THIS OPERATION.       */
7089 /* -------------------------------------------------- */
7090   writeKey(signal);
7091 /* -------------------------------------------------- */
7092 /*       WRITE THE ATTRIBUTE INFO OF THIS OPERATION.  */
7093 /* -------------------------------------------------- */
7094   writeAttrinfoLab(signal);
7095 
7096 /* -------------------------------------------------- */
7097 /*       RESET THE STATE OF THE LOG PART. IF ANY      */
7098 /*       OPERATIONS HAVE QUEUED THEN START THE FIRST  */
7099 /*       OF THESE.                                    */
7100 /* -------------------------------------------------- */
7101 /* -------------------------------------------------- */
7102 /*       CONTINUE WITH PACKING OF LQHKEYREQ           */
7103 /* -------------------------------------------------- */
7104   tcurrentFilepage = logFilePtr.p->currentFilepage;
7105   if (logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] == ZPAGE_HEADER_SIZE) {
7106     jam();
7107     tcurrentFilepage--;
7108   }//if
7109   regTcPtr->logStopPageNo = tcurrentFilepage;
7110   regTcPtr->logWriteState = TcConnectionrec::WRITTEN;
7111   if (regTcPtr->abortState != TcConnectionrec::ABORT_IDLE) {
7112 /* -------------------------------------------------- */
7113 /*       AN ABORT HAVE BEEN ORDERED. THE ABORT WAITED */
7114 /*       FOR THE LOG WRITE TO BE COMPLETED. NOW WE    */
7115 /*       CAN PROCEED WITH THE NORMAL ABORT HANDLING.  */
7116 /* -------------------------------------------------- */
7117     jam();
7118     abortCommonLab(signal);
7119     return;
7120   }//if
7121   if (regTcPtr->dirtyOp != ZTRUE) {
7122     packLqhkeyreqLab(signal);
7123   } else {
7124     jam();
7125     /* ----------------------------------------------------------------------
7126      * I NEED TO INSERT A COMMIT LOG RECORD SINCE WE ARE WRITING LOG IN THIS
7127      * TRANSACTION. SINCE WE RELEASED THE LOG LOCK JUST NOW NO ONE ELSE CAN BE
7128      * ACTIVE IN WRITING THE LOG. WE THUS WRITE THE LOG WITHOUT GETTING A LOCK
7129      * SINCE WE ARE ONLY WRITING A COMMIT LOG RECORD.
7130      * ---------------------------------------------------------------------- */
7131     writeCommitLog(signal, logPartPtr);
7132     /* ----------------------------------------------------------------------
7133      * DIRTY OPERATIONS SHOULD COMMIT BEFORE THEY PACK THE REQUEST/RESPONSE.
7134      * ---------------------------------------------------------------------- */
7135     localCommitLab(signal);
7136   }//if
7137 }//Dblqh::logLqhkeyreqLab()
7138 
7139 void
logLqhkeyreqLab_problems(Signal * signal)7140 Dblqh::logLqhkeyreqLab_problems(Signal * signal)
7141 {
7142   jam();
7143   LogPartRecord * const regLogPartPtr = logPartPtr.p;
7144   Uint32 problems = regLogPartPtr->m_log_problems;
7145 
7146   if (cnoOfLogPages < ZMIN_LOG_PAGES_OPERATION)
7147   {
7148     jam();
7149     terrorCode = ZTEMPORARY_REDO_LOG_FAILURE;
7150   }
7151   else if ((problems & LogPartRecord::P_TAIL_PROBLEM) != 0)
7152   {
7153     jam();
7154     terrorCode = ZTAIL_PROBLEM_IN_LOG_ERROR;
7155   }
7156   else if ((problems & LogPartRecord::P_REDO_IO_PROBLEM) != 0)
7157   {
7158     jam();
7159     terrorCode = ZREDO_IO_PROBLEM;
7160   }
7161   else if ((problems & LogPartRecord::P_FILE_CHANGE_PROBLEM) != 0)
7162   {
7163     jam();
7164     terrorCode = ZFILE_CHANGE_PROBLEM_IN_LOG_ERROR;
7165   }
7166   else
7167   {
7168     if (ERROR_INSERTED(5083))
7169     {
7170       terrorCode = 266;
7171     }
7172   }
7173   abortErrorLab(signal);
7174 }
7175 
7176 void
update_log_problem(Signal * signal,Ptr<LogPartRecord> partPtr,Uint32 problem,bool value)7177 Dblqh::update_log_problem(Signal* signal, Ptr<LogPartRecord> partPtr,
7178                           Uint32 problem, bool value)
7179 {
7180   Uint32 problems = partPtr.p->m_log_problems;
7181   if (value)
7182   {
7183     /**
7184      * set
7185      */
7186     jam();
7187     if ((problems & problem) == 0)
7188     {
7189       jam();
7190       problems |= problem;
7191     }
7192   }
7193   else
7194   {
7195     /**
7196      * clear
7197      */
7198     jam();
7199     if ((problems & problem) != 0)
7200     {
7201       jam();
7202       problems &= ~(Uint32)problem;
7203 
7204       if (partPtr.p->LogLqhKeyReqSent == ZFALSE &&
7205           (!partPtr.p->m_log_prepare_queue.isEmpty() ||
7206            !partPtr.p->m_log_complete_queue.isEmpty()))
7207       {
7208         jam();
7209 
7210         partPtr.p->LogLqhKeyReqSent = ZTRUE;
7211         signal->theData[0] = ZLOG_LQHKEYREQ;
7212         signal->theData[1] = partPtr.i;
7213         sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
7214       }
7215     }
7216   }
7217   partPtr.p->m_log_problems = problems;
7218 }
7219 
7220 /* ------------------------------------------------------------------------- */
7221 /* -------                        SEND LQHKEYREQ                             */
7222 /*                                                                           */
7223 /* NO STATE CHECKING SINCE THE SIGNAL IS A LOCAL SIGNAL. THE EXECUTION OF    */
7224 /* THE OPERATION IS COMPLETED. IT IS NOW TIME TO SEND THE OPERATION TO THE   */
7225 /* NEXT REPLICA OR TO TC.                                                    */
7226 /* ------------------------------------------------------------------------- */
packLqhkeyreqLab(Signal * signal)7227 void Dblqh::packLqhkeyreqLab(Signal* signal)
7228 {
7229   TcConnectionrec * const regTcPtr = tcConnectptr.p;
7230   if (regTcPtr->nextReplica == ZNIL) {
7231 /* ------------------------------------------------------------------------- */
7232 /* -------               SEND LQHKEYCONF                             ------- */
7233 /*                                                                           */
7234 /* ------------------------------------------------------------------------- */
7235     sendLqhkeyconfTc(signal, regTcPtr->tcBlockref);
7236     if (! (regTcPtr->dirtyOp ||
7237            (regTcPtr->operation == ZREAD && regTcPtr->opSimple)))
7238     {
7239       jam();
7240       regTcPtr->transactionState = TcConnectionrec::PREPARED;
7241       releaseOprec(signal);
7242     } else {
7243       jam();
7244 
7245 /*************************************************************>*/
7246 /*       DIRTY WRITES ARE USED IN TWO SITUATIONS. THE FIRST    */
7247 /*       SITUATION IS WHEN THEY ARE USED TO UPDATE COUNTERS AND*/
7248 /*       OTHER ATTRIBUTES WHICH ARE NOT SENSITIVE TO CONSISTE- */
7249 /*       NCY. THE SECOND SITUATION IS BY OPERATIONS THAT ARE   */
7250 /*       SENT AS PART OF A COPY FRAGMENT PROCESS.              */
7251 /*                                                             */
7252 /*       DURING A COPY FRAGMENT PROCESS THERE IS NO LOGGING    */
7253 /*       ONGOING SINCE THE FRAGMENT IS NOT COMPLETE YET. THE   */
7254 /*       LOGGING STARTS AFTER COMPLETING THE LAST COPY TUPLE   */
7255 /*       OPERATION. THE EXECUTION OF THE LAST COPY TUPLE DOES  */
7256 /*       ALSO START A LOCAL CHECKPOINT SO THAT THE FRAGMENT    */
7257 /*       REPLICA IS RECOVERABLE. THUS GLOBAL CHECKPOINT ID FOR */
7258 /*       THOSE OPERATIONS ARE NOT INTERESTING.                 */
7259 /*                                                             */
7260 /*       A DIRTY WRITE IS BY DEFINITION NOT CONSISTENT. THUS   */
7261 /*       IT CAN USE ANY GLOBAL CHECKPOINT. THE IDEA HERE IS TO */
7262 /*       ALWAYS USE THE LATEST DEFINED GLOBAL CHECKPOINT ID IN */
7263 /*       THIS NODE.                                            */
7264 /*************************************************************>*/
7265       cleanUp(signal);
7266     }//if
7267     return;
7268   }//if
7269 /* ------------------------------------------------------------------------- */
7270 /* -------            SEND LQHKEYREQ                                 ------- */
7271 /*                                                                           */
7272 /* ------------------------------------------------------------------------- */
7273 /* ------------------------------------------------------------------------- */
7274 /* THERE ARE MORE REPLICAS TO SEND THE OPERATION TO. A NEW LQHKEYREQ WILL BE */
7275 /* PREPARED FOR THE NEXT REPLICA.                                            */
7276 /* ------------------------------------------------------------------------- */
7277 /* CLEAR REPLICA TYPE, ATTRINFO INDICATOR (IN LQHKEYREQ),                    */
7278 /* INTERPRETED EXECUTION, SEQUENTIAL NUMBER OF REPLICA.                      */
7279 // Set bit indicating Client and TC record not the same.
7280 // Set readlenAi indicator if readlenAi != 0
7281 // Stored Procedure Indicator not set.
7282 /* ------------------------------------------------------------------------- */
7283   LqhKeyReq * const lqhKeyReq = (LqhKeyReq *)&signal->theData[0];
7284 
7285   UintR Treqinfo;
7286   UintR sig0, sig1, sig2, sig3, sig4, sig5, sig6;
7287   Treqinfo = preComputedRequestInfoMask & regTcPtr->reqinfo;
7288 
7289   Uint32 nextNodeId = regTcPtr->nextReplica;
7290   Uint32 nextVersion = getNodeInfo(nextNodeId).m_version;
7291 
7292   jam();
7293   /* Send long LqhKeyReq to next replica if it can support it */
7294   bool sendLongReq= ! ((nextVersion < NDBD_LONG_LQHKEYREQ) ||
7295                        ERROR_INSERTED(5051));
7296 
7297   UintR TAiLen = sendLongReq ?
7298     0 :
7299     MIN(regTcPtr->totSendlenAi, LqhKeyReq::MaxAttrInfo);
7300 
7301   /* Long LQHKeyReq uses section size for key length */
7302   Uint32 lqhKeyLen= sendLongReq?
7303     0 :
7304     regTcPtr->primKeyLen;
7305 
7306   UintR TapplAddressIndicator = (regTcPtr->nextSeqNoReplica == 0 ? 0 : 1);
7307   LqhKeyReq::setApplicationAddressFlag(Treqinfo, TapplAddressIndicator);
7308   LqhKeyReq::setInterpretedFlag(Treqinfo, regTcPtr->opExec);
7309   LqhKeyReq::setSeqNoReplica(Treqinfo, regTcPtr->nextSeqNoReplica);
7310   LqhKeyReq::setAIInLqhKeyReq(Treqinfo, TAiLen);
7311   LqhKeyReq::setKeyLen(Treqinfo,lqhKeyLen);
7312 
7313   if (unlikely(nextVersion < NDBD_ROWID_VERSION))
7314   {
7315     LqhKeyReq::setLockType(Treqinfo, regTcPtr->lockType);
7316   }
7317   else
7318   {
7319     regTcPtr->m_use_rowid |=
7320       fragptr.p->m_copy_started_state == Fragrecord::AC_NR_COPY;
7321     LqhKeyReq::setRowidFlag(Treqinfo, regTcPtr->m_use_rowid);
7322   }
7323 
7324   if (LqhKeyReq::getRowidFlag(Treqinfo))
7325   {
7326     //ndbassert(LqhKeyReq::getOperation(Treqinfo) == ZINSERT);
7327   }
7328   else
7329   {
7330     if (fragptr.p->m_copy_started_state != Fragrecord::AC_IGNORED)
7331     {
7332       ndbassert(LqhKeyReq::getOperation(Treqinfo) != ZINSERT ||
7333                 get_node_status(nextNodeId) != ZNODE_UP);
7334     }
7335   }
7336 
7337   UintR TreadLenAiInd = (regTcPtr->readlenAi == 0 ? 0 : 1);
7338   UintR TsameLqhAndClient = (tcConnectptr.i ==
7339                              regTcPtr->tcOprec ? 0 : 1);
7340   LqhKeyReq::setSameClientAndTcFlag(Treqinfo, TsameLqhAndClient);
7341   LqhKeyReq::setReturnedReadLenAIFlag(Treqinfo, TreadLenAiInd);
7342 
7343   /* Long LQHKeyReq uses section size for AttrInfo length */
7344   UintR TotReclenAi = sendLongReq ?
7345     0 :
7346     regTcPtr->totSendlenAi;
7347 
7348   LqhKeyReq::setReorgFlag(TotReclenAi, regTcPtr->m_reorg);
7349 
7350 /* ------------------------------------------------------------------------- */
7351 /* WE ARE NOW PREPARED TO SEND THE LQHKEYREQ. WE HAVE TO DECIDE IF ATTRINFO  */
7352 /* IS INCLUDED IN THE LQHKEYREQ SIGNAL AND THEN SEND IT.                     */
7353 /* TAKE OVER SCAN OPERATION IS NEVER USED ON BACKUPS, LOG RECORDS AND START-UP*/
7354 /* OF NEW REPLICA AND THUS ONLY TOT_SENDLEN_AI IS USED THE UPPER 16 BITS ARE */
7355 /* ZERO.                                                                     */
7356 /* ------------------------------------------------------------------------- */
7357   sig0 = tcConnectptr.i;
7358   sig1 = regTcPtr->savePointId;
7359   sig2 = regTcPtr->hashValue;
7360   sig4 = regTcPtr->tcBlockref;
7361 
7362   lqhKeyReq->clientConnectPtr = sig0;
7363   lqhKeyReq->attrLen = TotReclenAi;
7364   lqhKeyReq->savePointId = sig1;
7365   lqhKeyReq->hashValue = sig2;
7366   lqhKeyReq->requestInfo = Treqinfo;
7367   lqhKeyReq->tcBlockref = sig4;
7368 
7369   sig0 = regTcPtr->tableref + ((regTcPtr->schemaVersion << 16) & 0xFFFF0000);
7370   sig1 = regTcPtr->fragmentid + (regTcPtr->nodeAfterNext[0] << 16);
7371   sig2 = regTcPtr->transid[0];
7372   sig3 = regTcPtr->transid[1];
7373   sig4 = regTcPtr->applRef;
7374   sig5 = regTcPtr->applOprec;
7375   sig6 = regTcPtr->tcOprec;
7376   UintR nextPos = (TapplAddressIndicator << 1);
7377 
7378   lqhKeyReq->tableSchemaVersion = sig0;
7379   lqhKeyReq->fragmentData = sig1;
7380   lqhKeyReq->transId1 = sig2;
7381   lqhKeyReq->transId2 = sig3;
7382   lqhKeyReq->numFiredTriggers = regTcPtr->numFiredTriggers;
7383   lqhKeyReq->variableData[0] = sig4;
7384   lqhKeyReq->variableData[1] = sig5;
7385   lqhKeyReq->variableData[2] = sig6;
7386 
7387   nextPos += TsameLqhAndClient;
7388 
7389   if ((regTcPtr->lastReplicaNo - regTcPtr->nextSeqNoReplica) > 1) {
7390     sig0 = (UintR)regTcPtr->nodeAfterNext[1] +
7391            (UintR)(regTcPtr->nodeAfterNext[2] << 16);
7392     lqhKeyReq->variableData[nextPos] = sig0;
7393     nextPos++;
7394   }//if
7395   sig0 = regTcPtr->readlenAi;
7396   lqhKeyReq->variableData[nextPos] = sig0;
7397   nextPos += TreadLenAiInd;
7398 
7399   if (!sendLongReq)
7400   {
7401     /* Short LQHKEYREQ to older LQH
7402      * First few words of KeyInfo go into LQHKEYREQ
7403      * Sometimes have no Keyinfo
7404      */
7405     if (regTcPtr->primKeyLen != 0)
7406     {
7407       SegmentedSectionPtr keyInfoSection;
7408 
7409       ndbassert(regTcPtr->keyInfoIVal != RNIL);
7410 
7411       getSection(keyInfoSection, regTcPtr->keyInfoIVal);
7412       SectionReader keyInfoReader(keyInfoSection, g_sectionSegmentPool);
7413 
7414       UintR keyLenInLqhKeyReq= MIN(LqhKeyReq::MaxKeyInfo,
7415                                    regTcPtr->primKeyLen);
7416 
7417       keyInfoReader.getWords(&lqhKeyReq->variableData[nextPos],
7418                              keyLenInLqhKeyReq);
7419 
7420       nextPos+= keyLenInLqhKeyReq;
7421     }
7422   }
7423 
7424   sig0 = regTcPtr->gci_hi;
7425   Local_key tmp = regTcPtr->m_row_id;
7426 
7427   lqhKeyReq->variableData[nextPos + 0] = tmp.m_page_no;
7428   lqhKeyReq->variableData[nextPos + 1] = tmp.m_page_idx;
7429   nextPos += 2*LqhKeyReq::getRowidFlag(Treqinfo);
7430 
7431   lqhKeyReq->variableData[nextPos + 0] = sig0;
7432   nextPos += LqhKeyReq::getGCIFlag(Treqinfo);
7433 
7434   // pass full instance key for remote to map to real instance
7435   BlockReference lqhRef = numberToRef(DBLQH,
7436                                       fragptr.p->lqhInstanceKey,
7437                                       regTcPtr->nextReplica);
7438 
7439   if (likely(sendLongReq))
7440   {
7441     /* Long LQHKEYREQ, attach KeyInfo and AttrInfo
7442      * sections to signal
7443      */
7444     SectionHandle handle(this);
7445     handle.m_cnt= 0;
7446 
7447     if (regTcPtr->primKeyLen > 0)
7448     {
7449       SegmentedSectionPtr keyInfoSection;
7450 
7451       ndbassert(regTcPtr->keyInfoIVal != RNIL);
7452       getSection(keyInfoSection, regTcPtr->keyInfoIVal);
7453 
7454       handle.m_ptr[ LqhKeyReq::KeyInfoSectionNum ]= keyInfoSection;
7455       handle.m_cnt= 1;
7456 
7457       if (regTcPtr->totSendlenAi > 0)
7458       {
7459         SegmentedSectionPtr attrInfoSection;
7460 
7461         ndbassert(regTcPtr->attrInfoIVal != RNIL);
7462         getSection(attrInfoSection, regTcPtr->attrInfoIVal);
7463 
7464         handle.m_ptr[ LqhKeyReq::AttrInfoSectionNum ]= attrInfoSection;
7465         handle.m_cnt= 2;
7466       }
7467       else
7468       {
7469         /* No AttrInfo to be sent on.  This can occur for delete
7470          * or with an interpreted update when no actual update
7471          * is made
7472          * In this case, we free any attrInfo section now.
7473          */
7474         if (regTcPtr->attrInfoIVal != RNIL)
7475         {
7476           ndbassert(!( regTcPtr->m_flags &
7477                        TcConnectionrec::OP_SAVEATTRINFO));
7478           releaseSection(regTcPtr->attrInfoIVal);
7479           regTcPtr->attrInfoIVal= RNIL;
7480         }
7481       }
7482     }
7483     else
7484     {
7485       /* Zero-length primary key, better not have any
7486        * AttrInfo
7487        */
7488       ndbrequire(regTcPtr->totSendlenAi == 0);
7489       ndbassert(regTcPtr->keyInfoIVal == RNIL);
7490       ndbassert(regTcPtr->attrInfoIVal == RNIL);
7491     }
7492 
7493     sendSignal(lqhRef, GSN_LQHKEYREQ, signal,
7494                LqhKeyReq::FixedSignalLength + nextPos,
7495                JBB,
7496                &handle);
7497 
7498     /* Long sections were freed as part of sendSignal */
7499     ndbassert( handle.m_cnt == 0);
7500     regTcPtr->keyInfoIVal= RNIL;
7501     regTcPtr->attrInfoIVal= RNIL;
7502   }
7503   else
7504   {
7505     /* Short LQHKEYREQ to older LQH
7506      * First few words of ATTRINFO go into LQHKEYREQ
7507      * (if they fit)
7508      */
7509     if (TAiLen > 0)
7510     {
7511       if (likely(nextPos + TAiLen + LqhKeyReq::FixedSignalLength <= 25))
7512       {
7513         jam();
7514         SegmentedSectionPtr attrInfoSection;
7515 
7516         ndbassert(regTcPtr->attrInfoIVal != RNIL);
7517 
7518         getSection(attrInfoSection, regTcPtr->attrInfoIVal);
7519         SectionReader attrInfoReader(attrInfoSection, getSectionSegmentPool());
7520 
7521         attrInfoReader.getWords(&lqhKeyReq->variableData[nextPos],
7522                                 TAiLen);
7523 
7524         nextPos+= TAiLen;
7525       }
7526       else
7527       {
7528         /* Not enough space in LQHKEYREQ, we'll send everything in
7529          * separate ATTRINFO signals
7530          */
7531         Treqinfo &= ~(Uint32)(RI_AI_IN_THIS_MASK << RI_AI_IN_THIS_SHIFT);
7532         lqhKeyReq->requestInfo = Treqinfo;
7533         TAiLen= 0;
7534       }
7535     }
7536 
7537     sendSignal(lqhRef, GSN_LQHKEYREQ, signal,
7538                nextPos + LqhKeyReq::FixedSignalLength, JBB);
7539 
7540     /* Send extra KeyInfo signals if necessary... */
7541     if (regTcPtr->primKeyLen > LqhKeyReq::MaxKeyInfo) {
7542       jam();
7543       sendTupkey(signal);
7544     }//if
7545 
7546     /* Send extra AttrInfo signals if necessary... */
7547     Uint32 remainingAiLen= regTcPtr->totSendlenAi - TAiLen;
7548 
7549     if (remainingAiLen != 0)
7550     {
7551       sig0 = regTcPtr->tcOprec;
7552       sig1 = regTcPtr->transid[0];
7553       sig2 = regTcPtr->transid[1];
7554       signal->theData[0] = sig0;
7555       signal->theData[1] = sig1;
7556       signal->theData[2] = sig2;
7557 
7558       SectionReader attrInfoReader(regTcPtr->attrInfoIVal,
7559                                    g_sectionSegmentPool);
7560 
7561       ndbassert(attrInfoReader.getSize() == regTcPtr->totSendlenAi);
7562 
7563       /* Step over words already sent in LQHKEYREQ above */
7564       attrInfoReader.step(TAiLen);
7565 
7566       while (remainingAiLen != 0)
7567       {
7568         Uint32 dataInSignal= MIN(AttrInfo::DataLength, remainingAiLen);
7569         attrInfoReader.getWords(&signal->theData[3],
7570                                 dataInSignal);
7571         remainingAiLen-= dataInSignal;
7572         sendSignal(lqhRef, GSN_ATTRINFO, signal,
7573                    AttrInfo::HeaderLength + dataInSignal, JBB);
7574       }
7575     }
7576   }
7577 
7578   /* LQHKEYREQ sent */
7579 
7580   regTcPtr->transactionState = TcConnectionrec::PREPARED;
7581   if (regTcPtr->dirtyOp == ZTRUE) {
7582     jam();
7583 /*************************************************************>*/
7584 /*       DIRTY WRITES ARE USED IN TWO SITUATIONS. THE FIRST    */
7585 /*       SITUATION IS WHEN THEY ARE USED TO UPDATE COUNTERS AND*/
7586 /*       OTHER ATTRIBUTES WHICH ARE NOT SENSITIVE TO CONSISTE- */
7587 /*       NCY. THE SECOND SITUATION IS BY OPERATIONS THAT ARE   */
7588 /*       SENT AS PART OF A COPY FRAGMENT PROCESS.              */
7589 /*                                                             */
7590 /*       DURING A COPY FRAGMENT PROCESS THERE IS NO LOGGING    */
7591 /*       ONGOING SINCE THE FRAGMENT IS NOT COMPLETE YET. THE   */
7592 /*       LOGGING STARTS AFTER COMPLETING THE LAST COPY TUPLE   */
7593 /*       OPERATION. THE EXECUTION OF THE LAST COPY TUPLE DOES  */
7594 /*       ALSO START A LOCAL CHECKPOINT SO THAT THE FRAGMENT    */
7595 /*       REPLICA IS RECOVERABLE. THUS GLOBAL CHECKPOINT ID FOR */
7596 /*       THOSE OPERATIONS ARE NOT INTERESTING.                 */
7597 /*                                                             */
7598 /*       A DIRTY WRITE IS BY DEFINITION NOT CONSISTENT. THUS   */
7599 /*       IT CAN USE ANY GLOBAL CHECKPOINT. THE IDEA HERE IS TO */
7600 /*       ALWAYS USE THE LATEST DEFINED GLOBAL CHECKPOINT ID IN */
7601 /*       THIS NODE.                                            */
7602 /*************************************************************>*/
7603     cleanUp(signal);
7604     return;
7605   }//if
7606   /* ------------------------------------------------------------------------
7607    *   ALL INFORMATION NEEDED BY THE COMMIT PHASE AND COMPLETE PHASE IS
7608    *   KEPT IN THE TC_CONNECT RECORD. TO ENSURE PROPER USE OF MEMORY
7609    *   RESOURCES WE DEALLOCATE THE ATTRINFO RECORD AND KEY RECORDS
7610    *   AS SOON AS POSSIBLE.
7611    * ------------------------------------------------------------------------ */
7612   releaseOprec(signal);
7613 }//Dblqh::packLqhkeyreqLab()
7614 
7615 /* ========================================================================= */
7616 /* ==== CHECK IF THE LOG RECORD FITS INTO THE CURRENT MBYTE,         ======= */
7617 /*      OTHERWISE SWITCH TO NEXT MBYTE.                                      */
7618 /*                                                                           */
7619 /* ========================================================================= */
checkNewMbyte(Signal * signal)7620 void Dblqh::checkNewMbyte(Signal* signal)
7621 {
7622   UintR tcnmTmp;
7623   UintR ttotalLogSize;
7624 
7625 /* -------------------------------------------------- */
7626 /*       CHECK IF A NEW MBYTE OF LOG RECORD IS TO BE  */
7627 /*       OPENED BEFORE WRITING THE LOG RECORD. NO LOG */
7628 /*       RECORDS ARE ALLOWED TO SPAN A MBYTE BOUNDARY */
7629 /*                                                    */
7630 /*       INPUT:  TC_CONNECTPTR   THE OPERATION        */
7631 /*               LOG_FILE_PTR    THE LOG FILE         */
7632 /*       OUTPUT: LOG_FILE_PTR    THE NEW LOG FILE     */
7633 /* -------------------------------------------------- */
7634   ttotalLogSize = ZLOG_HEAD_SIZE + tcConnectptr.p->currTupAiLen;
7635   ttotalLogSize = ttotalLogSize + tcConnectptr.p->primKeyLen;
7636   tcnmTmp = logFilePtr.p->remainingWordsInMbyte;
7637   if ((ttotalLogSize + ZNEXT_LOG_SIZE) <= tcnmTmp) {
7638     ndbrequire(tcnmTmp >= ttotalLogSize);
7639     logFilePtr.p->remainingWordsInMbyte = tcnmTmp - ttotalLogSize;
7640     return;
7641   } else {
7642     jam();
7643 /* -------------------------------------------------- */
7644 /*       IT WAS NOT ENOUGH SPACE IN THIS MBYTE FOR    */
7645 /*       THIS LOG RECORD. MOVE TO NEXT MBYTE          */
7646 /*       THIS MIGHT INCLUDE CHANGING LOG FILE         */
7647 /* -------------------------------------------------- */
7648 /*       WE HAVE TO INSERT A NEXT LOG RECORD FIRST    */
7649 /* -------------------------------------------------- */
7650 /*       THEN CONTINUE BY WRITING THE FILE DESCRIPTORS*/
7651 /* -------------------------------------------------- */
7652     logPagePtr.i = logFilePtr.p->currentLogpage;
7653     ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
7654     changeMbyte(signal);
7655     tcnmTmp = logFilePtr.p->remainingWordsInMbyte;
7656   }//if
7657   ndbrequire(tcnmTmp >= ttotalLogSize);
7658   logFilePtr.p->remainingWordsInMbyte = tcnmTmp - ttotalLogSize;
7659 }//Dblqh::checkNewMbyte()
7660 
7661 /* --------------------------------------------------------------------------
7662  * -------               WRITE OPERATION HEADER TO LOG                -------
7663  *
7664  *       SUBROUTINE SHORT NAME: WLH
7665  * ------------------------------------------------------------------------- */
writeLogHeader(Signal * signal)7666 void Dblqh::writeLogHeader(Signal* signal)
7667 {
7668   Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX];
7669   Uint32 hashValue = tcConnectptr.p->hashValue;
7670   Uint32 operation = tcConnectptr.p->operation;
7671   Uint32 keyLen = tcConnectptr.p->primKeyLen;
7672   Uint32 aiLen = tcConnectptr.p->currTupAiLen;
7673   Local_key rowid = tcConnectptr.p->m_row_id;
7674   Uint32 totLogLen = ZLOG_HEAD_SIZE + aiLen + keyLen;
7675 
7676   if ((logPos + ZLOG_HEAD_SIZE) < ZPAGE_SIZE) {
7677     Uint32* dataPtr = &logPagePtr.p->logPageWord[logPos];
7678     logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos + ZLOG_HEAD_SIZE;
7679     dataPtr[0] = ZPREP_OP_TYPE;
7680     dataPtr[1] = totLogLen;
7681     dataPtr[2] = hashValue;
7682     dataPtr[3] = operation;
7683     dataPtr[4] = aiLen;
7684     dataPtr[5] = keyLen;
7685     dataPtr[6] = rowid.m_page_no;
7686     dataPtr[7] = rowid.m_page_idx;
7687   } else {
7688     writeLogWord(signal, ZPREP_OP_TYPE);
7689     writeLogWord(signal, totLogLen);
7690     writeLogWord(signal, hashValue);
7691     writeLogWord(signal, operation);
7692     writeLogWord(signal, aiLen);
7693     writeLogWord(signal, keyLen);
7694     writeLogWord(signal, rowid.m_page_no);
7695     writeLogWord(signal, rowid.m_page_idx);
7696   }//if
7697 }//Dblqh::writeLogHeader()
7698 
7699 /* --------------------------------------------------------------------------
7700  * -------               WRITE TUPLE KEY TO LOG                       -------
7701  *
7702  *       SUBROUTINE SHORT NAME: WK
7703  * ------------------------------------------------------------------------- */
writeKey(Signal * signal)7704 void Dblqh::writeKey(Signal* signal)
7705 {
7706   TcConnectionrec * const regTcPtr = tcConnectptr.p;
7707   SectionReader keyInfoReader(regTcPtr->keyInfoIVal,
7708                               g_sectionSegmentPool);
7709   const Uint32* srcPtr;
7710   Uint32 length;
7711   Uint32 wordsWritten= 0;
7712 
7713   /* Write contiguous chunks of words from the KeyInfo
7714    * section to the log
7715    */
7716   while (keyInfoReader.getWordsPtr(srcPtr,
7717                                    length))
7718   {
7719     writeLogWords(signal, srcPtr, length);
7720     wordsWritten+= length;
7721   }
7722 
7723   ndbassert( wordsWritten == regTcPtr->primKeyLen );
7724 }//Dblqh::writeKey()
7725 
7726 /* --------------------------------------------------------------------------
7727  * -------               WRITE ATTRINFO TO LOG                        -------
7728  *
7729  *       SUBROUTINE SHORT NAME: WA
7730  * ------------------------------------------------------------------------- */
writeAttrinfoLab(Signal * signal)7731 void Dblqh::writeAttrinfoLab(Signal* signal)
7732 {
7733   TcConnectionrec * const regTcPtr = tcConnectptr.p;
7734   Uint32 totLen = regTcPtr->currTupAiLen;
7735   if (totLen == 0)
7736     return;
7737 
7738   jam();
7739   ndbassert( regTcPtr->attrInfoIVal != RNIL );
7740   SectionReader attrInfoReader(regTcPtr->attrInfoIVal,
7741                                g_sectionSegmentPool);
7742   const Uint32* srcPtr;
7743   Uint32 length;
7744   Uint32 wordsWritten= 0;
7745 
7746   /* Write contiguous chunks of words from the
7747    * AttrInfo section to the log
7748    */
7749   while (attrInfoReader.getWordsPtr(srcPtr,
7750                                     length))
7751   {
7752     writeLogWords(signal, srcPtr, length);
7753     wordsWritten+= length;
7754   }
7755 
7756   ndbassert( wordsWritten == totLen );
7757 }//Dblqh::writeAttrinfoLab()
7758 
7759 /* ------------------------------------------------------------------------- */
7760 /* -------          SEND TUPLE KEY IN KEYINFO SIGNAL(S)              ------- */
7761 /*                                                                           */
7762 /*       SUBROUTINE SHORT NAME: STU                                          */
7763 /* ------------------------------------------------------------------------- */
sendTupkey(Signal * signal)7764 void Dblqh::sendTupkey(Signal* signal)
7765 {
7766   BlockReference lqhRef = 0;
7767   {
7768     // wl4391_todo fragptr
7769     FragrecordPtr Tfragptr;
7770     Tfragptr.i = tcConnectptr.p->fragmentptr;
7771     c_fragment_pool.getPtr(Tfragptr);
7772     Uint32 Tnode = tcConnectptr.p->nextReplica;
7773     Uint32 instanceKey = Tfragptr.p->lqhInstanceKey;
7774     lqhRef = numberToRef(DBLQH, instanceKey, Tnode);
7775   }
7776 
7777   signal->theData[0] = tcConnectptr.p->tcOprec;
7778   signal->theData[1] = tcConnectptr.p->transid[0];
7779   signal->theData[2] = tcConnectptr.p->transid[1];
7780 
7781   Uint32 remainingLen= tcConnectptr.p->primKeyLen -
7782     LqhKeyReq::MaxKeyInfo;
7783 
7784   SectionReader keyInfoReader(tcConnectptr.p->keyInfoIVal,
7785                               g_sectionSegmentPool);
7786 
7787   ndbassert(keyInfoReader.getSize() > LqhKeyReq::MaxKeyInfo);
7788 
7789   /* Step over the words already sent in LQHKEYREQ */
7790   keyInfoReader.step(LqhKeyReq::MaxKeyInfo);
7791 
7792   while (remainingLen != 0)
7793   {
7794     Uint32 dataInSignal= MIN(KeyInfo::DataLength, remainingLen);
7795     keyInfoReader.getWords(&signal->theData[3],
7796                            dataInSignal);
7797     remainingLen-= dataInSignal;
7798     sendSignal(lqhRef, GSN_KEYINFO, signal,
7799                KeyInfo::HeaderLength + dataInSignal, JBB);
7800   }
7801 }//Dblqh::sendTupkey()
7802 
cleanUp(Signal * signal)7803 void Dblqh::cleanUp(Signal* signal)
7804 {
7805   releaseOprec(signal);
7806   deleteTransidHash(signal);
7807   releaseTcrec(signal, tcConnectptr);
7808 }//Dblqh::cleanUp()
7809 
7810 /* --------------------------------------------------------------------------
7811  * ---- RELEASE ALL RECORDS CONNECTED TO THE OPERATION RECORD AND THE    ----
7812  *      OPERATION RECORD ITSELF
7813  * ------------------------------------------------------------------------- */
releaseOprec(Signal * signal)7814 void Dblqh::releaseOprec(Signal* signal)
7815 {
7816   TcConnectionrec * const regTcPtr = tcConnectptr.p;
7817 
7818   /* Release long sections if present */
7819   releaseSection(regTcPtr->keyInfoIVal);
7820   regTcPtr->keyInfoIVal = RNIL;
7821   releaseSection(regTcPtr->attrInfoIVal);
7822   regTcPtr->attrInfoIVal = RNIL;
7823 
7824   if (regTcPtr->m_dealloc)
7825   {
7826     jam();
7827     regTcPtr->m_dealloc = 0;
7828 
7829     if (TRACENR_FLAG)
7830       TRACENR("DELETED: " << regTcPtr->m_row_id << endl);
7831 
7832     TRACE_OP(regTcPtr, "DO DEALLOC");
7833 
7834     const Uint32 sig0 = regTcPtr->fragmentid;
7835     const Uint32 sig1 = regTcPtr->tableref;
7836     const Uint32 sig2 = regTcPtr->m_row_id.m_page_no;
7837     const Uint32 sig3 = regTcPtr->m_row_id.m_page_idx;
7838 
7839     signal->theData[0] = sig0;
7840     signal->theData[1] = sig1;
7841     signal->theData[2] = sig2;
7842     signal->theData[3] = sig3;
7843     signal->theData[4] = RNIL;
7844     EXECUTE_DIRECT(DBTUP, GSN_TUP_DEALLOCREQ, signal, 5);
7845   }
7846 }//Dblqh::releaseOprec()
7847 
7848 /* ------------------------------------------------------------------------- */
7849 /* ------         DELETE TRANSACTION ID FROM HASH TABLE              ------- */
7850 /*                                                                           */
7851 /* ------------------------------------------------------------------------- */
deleteTransidHash(Signal * signal)7852 void Dblqh::deleteTransidHash(Signal* signal)
7853 {
7854   TcConnectionrec * const regTcPtr = tcConnectptr.p;
7855   TcConnectionrecPtr prevHashptr;
7856   TcConnectionrecPtr nextHashptr;
7857   /**
7858    * This operation has not been inserted in the hash list at all.
7859    * (It is a non-transactional 'dirtyOp', or the request failed
7860    *  before it was ever inserted in the hash list.)
7861    */
7862   if (regTcPtr->hashIndex == RNIL)
7863   {
7864     jam();
7865     /* If this operation is 'non-dirty', there should be no duplicates */
7866     ndbassert(regTcPtr->dirtyOp == ZTRUE ||
7867               findTransaction(regTcPtr->transid[0], regTcPtr->transid[1],
7868                               regTcPtr->tcOprec, regTcPtr->tcHashKeyHi) == ZNOT_FOUND);
7869     return;
7870   }
7871 
7872   prevHashptr.i = regTcPtr->prevHashRec;
7873   nextHashptr.i = regTcPtr->nextHashRec;
7874   /* prevHashptr and nextHashptr may be RNIL when the bucket has 1 element */
7875 
7876   if (prevHashptr.i != RNIL) {
7877     jam();
7878     ptrCheckGuard(prevHashptr, ctcConnectrecFileSize, tcConnectionrec);
7879     ndbassert(prevHashptr.p->nextHashRec == tcConnectptr.i);
7880     prevHashptr.p->nextHashRec = nextHashptr.i;
7881   } else {
7882     jam();
7883 /* ------------------------------------------------------------------------- */
7884 /* THE OPERATION WAS PLACED FIRST IN THE LIST OF THE HASH TABLE. NEED TO SET */
7885 /* A NEW LEADER OF THE LIST.                                                 */
7886 /* ------------------------------------------------------------------------- */
7887     Uint32 hashIndex = regTcPtr->hashIndex;
7888     ndbassert(hashIndex == ((regTcPtr->transid[0] ^ regTcPtr->tcOprec) & 1023));
7889     ndbassert(ctransidHash[hashIndex] == tcConnectptr.i);
7890     ctransidHash[hashIndex] = nextHashptr.i;
7891   }//if
7892   if (nextHashptr.i != RNIL) {
7893     jam();
7894     ptrCheckGuard(nextHashptr, ctcConnectrecFileSize, tcConnectionrec);
7895     ndbassert(nextHashptr.p->prevHashRec == tcConnectptr.i);
7896     nextHashptr.p->prevHashRec = prevHashptr.i;
7897   }//if
7898 
7899   regTcPtr->hashIndex = regTcPtr->prevHashRec = regTcPtr->nextHashRec = RNIL;
7900 }//Dblqh::deleteTransidHash()
7901 
7902 /* -------------------------------------------------------------------------
7903  * -------       RELEASE OPERATION FROM ACTIVE LIST ON FRAGMENT      -------
7904  *
7905  *       SUBROUTINE SHORT NAME = RAF
7906  * ------------------------------------------------------------------------- */
7907 /* ######################################################################### */
7908 /* #######                   TRANSACTION MODULE                      ####### */
7909 /*      THIS MODULE HANDLES THE COMMIT AND THE COMPLETE PHASE.               */
7910 /* ######################################################################### */
warningReport(Signal * signal,int place)7911 void Dblqh::warningReport(Signal* signal, int place)
7912 {
7913   switch (place) {
7914   case 0:
7915     jam();
7916 #ifdef ABORT_TRACE
7917     ndbout << "W: Received COMMIT in wrong state in Dblqh" << endl;
7918 #endif
7919     break;
7920   case 1:
7921     jam();
7922 #ifdef ABORT_TRACE
7923     ndbout << "W: Received COMMIT with wrong transid in Dblqh" << endl;
7924 #endif
7925     break;
7926   case 2:
7927     jam();
7928 #ifdef ABORT_TRACE
7929     ndbout << "W: Received COMPLETE in wrong state in Dblqh" << endl;
7930 #endif
7931     break;
7932   case 3:
7933     jam();
7934 #ifdef ABORT_TRACE
7935     ndbout << "W: Received COMPLETE with wrong transid in Dblqh" << endl;
7936 #endif
7937     break;
7938   case 4:
7939     jam();
7940 #ifdef ABORT_TRACE
7941     ndbout << "W: Received COMMITREQ in wrong state in Dblqh" << endl;
7942 #endif
7943     break;
7944   case 5:
7945     jam();
7946 #ifdef ABORT_TRACE
7947     ndbout << "W: Received COMMITREQ with wrong transid in Dblqh" << endl;
7948 #endif
7949     break;
7950   case 6:
7951     jam();
7952 #ifdef ABORT_TRACE
7953     ndbout << "W: Received COMPLETEREQ in wrong state in Dblqh" << endl;
7954 #endif
7955     break;
7956   case 7:
7957     jam();
7958 #ifdef ABORT_TRACE
7959     ndbout << "W: Received COMPLETEREQ with wrong transid in Dblqh" << endl;
7960 #endif
7961     break;
7962   case 8:
7963     jam();
7964 #ifdef ABORT_TRACE
7965     ndbout << "W: Received ABORT with non-existing transid in Dblqh" << endl;
7966 #endif
7967     break;
7968   case 9:
7969     jam();
7970 #ifdef ABORT_TRACE
7971     ndbout << "W: Received ABORTREQ with non-existing transid in Dblqh" << endl;
7972 #endif
7973     break;
7974   case 10:
7975     jam();
7976 #ifdef ABORT_TRACE
7977     ndbout << "W: Received ABORTREQ in wrong state in Dblqh" << endl;
7978 #endif
7979     break;
7980   case 11:
7981     jam();
7982 #ifdef ABORT_TRACE
7983     ndbout << "W: Received COMMIT when tc-rec released in Dblqh" << endl;
7984 #endif
7985     break;
7986   case 12:
7987     jam();
7988 #ifdef ABORT_TRACE
7989     ndbout << "W: Received COMPLETE when tc-rec released in Dblqh" << endl;
7990 #endif
7991     break;
7992   case 13:
7993     jam();
7994 #ifdef ABORT_TRACE
7995     ndbout << "W: Received LQHKEYREF when tc-rec released in Dblqh" << endl;
7996 #endif
7997     break;
7998   case 14:
7999     jam();
8000 #ifdef ABORT_TRACE
8001     ndbout << "W: Received LQHKEYREF with wrong transid in Dblqh" << endl;
8002 #endif
8003     break;
8004   case 15:
8005     jam();
8006 #ifdef ABORT_TRACE
8007     ndbout << "W: Received LQHKEYREF when already aborting in Dblqh" << endl;
8008 #endif
8009     break;
8010   case 16:
8011     jam();
8012     ndbrequire(cstartPhase == ZNIL);
8013 #ifdef ABORT_TRACE
8014     ndbout << "W: Received LQHKEYREF in wrong state in Dblqh" << endl;
8015 #endif
8016     break;
8017   default:
8018     jam();
8019     break;
8020   }//switch
8021   return;
8022 }//Dblqh::warningReport()
8023 
errorReport(Signal * signal,int place)8024 void Dblqh::errorReport(Signal* signal, int place)
8025 {
8026   switch (place) {
8027   case 0:
8028     jam();
8029     break;
8030   case 1:
8031     jam();
8032     break;
8033   case 2:
8034     jam();
8035     break;
8036   case 3:
8037     jam();
8038     break;
8039   default:
8040     jam();
8041     break;
8042   }//switch
8043   systemErrorLab(signal, __LINE__);
8044   return;
8045 }//Dblqh::errorReport()
8046 
8047 void
execFIRE_TRIG_REQ(Signal * signal)8048 Dblqh::execFIRE_TRIG_REQ(Signal* signal)
8049 {
8050   Uint32 tcOprec = signal->theData[0];
8051   Uint32 transid1 = signal->theData[1];
8052   Uint32 transid2 = signal->theData[2];
8053   Uint32 pass = signal->theData[3];
8054   Uint32 senderRef = signal->getSendersBlockRef();
8055 
8056   jamEntry();
8057 
8058   if (ERROR_INSERTED_CLEAR(5064))
8059   {
8060     // throw away...should cause timeout in TC
8061     return;
8062   }
8063 
8064   CRASH_INSERTION(5072);
8065 
8066   Uint32 err;
8067   if (findTransaction(transid1, transid2, tcOprec, 0) == ZOK &&
8068       !ERROR_INSERTED_CLEAR(5065) &&
8069       !ERROR_INSERTED(5070) &&
8070       !ERROR_INSERTED(5071))
8071   {
8072     TcConnectionrec * const regTcPtr = tcConnectptr.p;
8073 
8074     if (unlikely(regTcPtr->transactionState != TcConnectionrec::PREPARED ||
8075                  ERROR_INSERTED_CLEAR(5067)))
8076     {
8077       err = FireTrigRef::FTR_IncorrectState;
8078       goto do_err;
8079     }
8080 
8081     /**
8082      *
8083      */
8084     signal->theData[0] = regTcPtr->tupConnectrec;
8085     signal->theData[1] = regTcPtr->tcBlockref;
8086     signal->theData[2] = regTcPtr->tcOprec;
8087     signal->theData[3] = transid1;
8088     signal->theData[4] = transid2;
8089     signal->theData[5] = pass;
8090     Uint32 tup = refToMain(regTcPtr->tcTupBlockref);
8091     EXECUTE_DIRECT(tup, GSN_FIRE_TRIG_REQ, signal, 6);
8092 
8093     err = signal->theData[0];
8094     Uint32 cnt = signal->theData[1];
8095 
8096     if (ERROR_INSERTED_CLEAR(5066))
8097     {
8098       err = 5066;
8099     }
8100 
8101     if (ERROR_INSERTED_CLEAR(5068))
8102       tcOprec++;
8103     if (ERROR_INSERTED_CLEAR(5069))
8104       transid1++;
8105 
8106     if (err == 0)
8107     {
8108       jam();
8109       Uint32 Tdata[FireTrigConf::SignalLength];
8110       FireTrigConf * conf = CAST_PTR(FireTrigConf, Tdata);
8111       conf->tcOpRec = tcOprec;
8112       conf->transId[0] = transid1;
8113       conf->transId[1] = transid2;
8114       conf->numFiredTriggers = cnt;
8115       sendFireTrigConfTc(signal, regTcPtr->tcBlockref, Tdata);
8116       return;
8117     }
8118   }
8119   else
8120   {
8121     jam();
8122     err = FireTrigRef::FTR_UnknownOperation;
8123   }
8124 
8125 do_err:
8126   if (ERROR_INSERTED_CLEAR(5070))
8127     tcOprec++;
8128 
8129   if (ERROR_INSERTED_CLEAR(5071))
8130     transid1++;
8131 
8132   FireTrigRef * ref = CAST_PTR(FireTrigRef, signal->getDataPtrSend());
8133   ref->tcOpRec = tcOprec;
8134   ref->transId[0] = transid1;
8135   ref->transId[1] = transid2;
8136   ref->errCode = err;
8137   sendSignal(senderRef, GSN_FIRE_TRIG_REF,
8138              signal, FireTrigRef::SignalLength, JBB);
8139 
8140   return;
8141 }
8142 
8143 void
sendFireTrigConfTc(Signal * signal,BlockReference atcBlockref,Uint32 Tdata[])8144 Dblqh::sendFireTrigConfTc(Signal* signal,
8145                           BlockReference atcBlockref,
8146                           Uint32 Tdata[])
8147 {
8148   Uint32 instanceKey = refToInstance(atcBlockref);
8149 
8150   ndbassert(refToMain(atcBlockref) == DBTC);
8151   if (instanceKey > MAX_NDBMT_TC_THREADS)
8152   {
8153     jam();
8154     memcpy(signal->theData, Tdata, 4 * FireTrigConf::SignalLength);
8155     sendSignal(atcBlockref, GSN_FIRE_TRIG_CONF,
8156                signal, FireTrigConf::SignalLength, JBB);
8157     return;
8158   }
8159 
8160   HostRecordPtr Thostptr;
8161   Thostptr.i = refToNode(atcBlockref);
8162   ptrCheckGuard(Thostptr, chostFileSize, hostRecord);
8163   Uint32 len = FireTrigConf::SignalLength;
8164   struct PackedWordsContainer * container = &Thostptr.p->tc_pack[instanceKey];
8165 
8166   if (container->noOfPackedWords > (25 - len))
8167   {
8168     jam();
8169     sendPackedSignal(signal, container);
8170   }
8171   else
8172   {
8173     jam();
8174     updatePackedList(signal, Thostptr.p, Thostptr.i);
8175   }
8176 
8177   ndbassert(FireTrigConf::SignalLength == 4);
8178   Uint32 * dst = &container->packedWords[container->noOfPackedWords];
8179   container->noOfPackedWords += len;
8180   dst[0] = Tdata[0] | (ZFIRE_TRIG_CONF << 28);
8181   dst[1] = Tdata[1];
8182   dst[2] = Tdata[2];
8183   dst[3] = Tdata[3];
8184 }
8185 
8186 bool
check_fire_trig_pass(Uint32 opId,Uint32 pass)8187 Dblqh::check_fire_trig_pass(Uint32 opId, Uint32 pass)
8188 {
8189   /**
8190    * Check that trigger only fires once per pass
8191    *   (per primary key)
8192    */
8193   TcConnectionrecPtr regTcPtr;
8194   regTcPtr.i= opId;
8195   ptrCheckGuard(regTcPtr, ctcConnectrecFileSize, tcConnectionrec);
8196   if (regTcPtr.p->m_fire_trig_pass <= pass)
8197   {
8198     regTcPtr.p->m_fire_trig_pass = pass + 1;
8199     return true;
8200   }
8201   return false;
8202 }
8203 
8204 /* ************************************************************************>>
8205  *  COMMIT: Start commit request from TC. This signal is originally sent as a
8206  *  packed signal and this function is called from execPACKED_SIGNAL.
8207  *  This is the normal commit protocol where TC first send this signal to the
8208  *  backup node which then will send COMMIT to the primary node. If
8209  *  everything is ok the primary node send COMMITTED back to TC.
8210  * ************************************************************************>> */
execCOMMIT(Signal * signal)8211 void Dblqh::execCOMMIT(Signal* signal)
8212 {
8213   TcConnectionrec *regTcConnectionrec = tcConnectionrec;
8214   Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize;
8215   Uint32 tcIndex = signal->theData[0];
8216   Uint32 gci_hi = signal->theData[1];
8217   Uint32 transid1 = signal->theData[2];
8218   Uint32 transid2 = signal->theData[3];
8219   Uint32 gci_lo = signal->theData[4];
8220   jamEntry();
8221   if (tcIndex >= ttcConnectrecFileSize) {
8222     errorReport(signal, 0);
8223     return;
8224   }//if
8225   if (ERROR_INSERTED(5011)) {
8226     CLEAR_ERROR_INSERT_VALUE;
8227     sendSignalWithDelay(cownref, GSN_COMMIT, signal, 2000,signal->getLength());
8228     return;
8229   }//if
8230   if (ERROR_INSERTED(5012)) {
8231     SET_ERROR_INSERT_VALUE(5017);
8232     sendSignalWithDelay(cownref, GSN_COMMIT, signal, 2000,signal->getLength());
8233     return;
8234   }//if
8235   if (ERROR_INSERTED(5062) &&
8236       ((refToMain(signal->getSendersBlockRef()) == DBTC) ||
8237        signal->getSendersBlockRef() == reference()))
8238   {
8239     Uint32 save = signal->getSendersBlockRef();
8240     ndbout_c("Delaying execCOMMIT");
8241     sendSignalWithDelay(cownref, GSN_COMMIT, signal, 2000, signal->getLength());
8242 
8243     if (refToMain(save) == DBTC)
8244     {
8245       ndbout_c("killing %u", refToNode(save));
8246       signal->theData[0] = 9999;
8247       sendSignal(numberToRef(CMVMI, refToNode(save)),
8248                  GSN_NDB_TAMPER, signal, 1, JBB);
8249     }
8250     return;
8251   }
8252 
8253   tcConnectptr.i = tcIndex;
8254   ptrAss(tcConnectptr, regTcConnectionrec);
8255   if ((tcConnectptr.p->transid[0] == transid1) &&
8256       (tcConnectptr.p->transid[1] == transid2)) {
8257 
8258     TcConnectionrec * const regTcPtr = tcConnectptr.p;
8259     TRACE_OP(regTcPtr, "COMMIT");
8260 
8261     CRASH_INSERTION(5048);
8262     if (ERROR_INSERTED(5049))
8263     {
8264       SET_ERROR_INSERT_VALUE(5048);
8265     }
8266 
8267     commitReqLab(signal, gci_hi, gci_lo);
8268     return;
8269   }//if
8270   warningReport(signal, 1);
8271   return;
8272 }//Dblqh::execCOMMIT()
8273 
8274 /* ************************************************************************>>
8275  *  COMMITREQ: Commit request from TC. This is the commit protocol used if
8276  *  one of the nodes is not behaving correctly. TC explicitly sends COMMITREQ
8277  *  to both the backup and primary node and gets a COMMITCONF back if the
8278  *  COMMIT was ok.
8279  * ************************************************************************>> */
execCOMMITREQ(Signal * signal)8280 void Dblqh::execCOMMITREQ(Signal* signal)
8281 {
8282   jamEntry();
8283   Uint32 reqPtr = signal->theData[0];
8284   BlockReference reqBlockref = signal->theData[1];
8285   Uint32 gci_hi = signal->theData[2];
8286   Uint32 transid1 = signal->theData[3];
8287   Uint32 transid2 = signal->theData[4];
8288   Uint32 tcOprec = signal->theData[6];
8289   Uint32 gci_lo = signal->theData[7];
8290 
8291   if (unlikely(signal->getLength() < 8))
8292   {
8293     jam();
8294     gci_lo = 0;
8295     ndbassert(!ndb_check_micro_gcp(getNodeInfo(refToNode(signal->getSendersBlockRef())).m_version));
8296   }
8297 
8298   if (ERROR_INSERTED(5004)) {
8299     systemErrorLab(signal, __LINE__);
8300   }
8301   if (ERROR_INSERTED(5017)) {
8302     CLEAR_ERROR_INSERT_VALUE;
8303     sendSignalWithDelay(cownref, GSN_COMMITREQ, signal, 2000,
8304                         signal->getLength());
8305     return;
8306   }//if
8307   if (findTransaction(transid1,
8308                       transid2,
8309                       tcOprec, 0) != ZOK) {
8310     warningReport(signal, 5);
8311     return;
8312   }//if
8313   TcConnectionrec * const regTcPtr = tcConnectptr.p;
8314   switch (regTcPtr->transactionState) {
8315   case TcConnectionrec::PREPARED:
8316   case TcConnectionrec::LOG_COMMIT_QUEUED_WAIT_SIGNAL:
8317   case TcConnectionrec::LOG_COMMIT_WRITTEN_WAIT_SIGNAL:
8318     jam();
8319 /*-------------------------------------------------------*/
8320 /*       THE NORMAL CASE.                                */
8321 /*-------------------------------------------------------*/
8322     regTcPtr->reqBlockref = reqBlockref;
8323     regTcPtr->reqRef = reqPtr;
8324     regTcPtr->abortState = TcConnectionrec::REQ_FROM_TC;
8325     commitReqLab(signal, gci_hi, gci_lo);
8326     return;
8327     break;
8328   case TcConnectionrec::COMMITTED:
8329     jam();
8330 /*---------------------------------------------------------*/
8331 /*       FOR SOME REASON THE COMMIT PHASE HAVE BEEN        */
8332 /*       FINISHED AFTER A TIME OUT. WE NEED ONLY SEND A    */
8333 /*       COMMITCONF SIGNAL.                                */
8334 /*---------------------------------------------------------*/
8335     regTcPtr->reqBlockref = reqBlockref;
8336     regTcPtr->reqRef = reqPtr;
8337     regTcPtr->abortState = TcConnectionrec::REQ_FROM_TC;
8338     signal->theData[0] = regTcPtr->reqRef;
8339     signal->theData[1] = cownNodeid;
8340     signal->theData[2] = regTcPtr->transid[0];
8341     signal->theData[3] = regTcPtr->transid[1];
8342     sendSignal(regTcPtr->reqBlockref, GSN_COMMITCONF, signal, 4, JBB);
8343     break;
8344   case TcConnectionrec::WAIT_TUP_COMMIT:
8345     jam();
8346     regTcPtr->reqBlockref = reqBlockref;
8347     regTcPtr->reqRef = reqPtr;
8348     regTcPtr->abortState = TcConnectionrec::REQ_FROM_TC;
8349     /*empty*/;
8350     break;
8351   default:
8352     jam();
8353     warningReport(signal, 4);
8354     return;
8355     break;
8356   }//switch
8357   return;
8358 }//Dblqh::execCOMMITREQ()
8359 
8360 /* ************************************************************************>>
8361  *  COMPLETE : Complete the transaction. Sent as a packed signal from TC.
8362  *  Works the same way as COMMIT protocol. This is the normal case with both
8363  *  primary and backup working (See COMMIT).
8364  * ************************************************************************>> */
execCOMPLETE(Signal * signal)8365 void Dblqh::execCOMPLETE(Signal* signal)
8366 {
8367   TcConnectionrec *regTcConnectionrec = tcConnectionrec;
8368   Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize;
8369   Uint32 tcIndex = signal->theData[0];
8370   Uint32 transid1 = signal->theData[1];
8371   Uint32 transid2 = signal->theData[2];
8372   jamEntry();
8373   if (tcIndex >= ttcConnectrecFileSize) {
8374     errorReport(signal, 1);
8375     return;
8376   }//if
8377   CRASH_INSERTION(5042);
8378 
8379   if (ERROR_INSERTED(5013)) {
8380     CLEAR_ERROR_INSERT_VALUE;
8381     sendSignalWithDelay(cownref, GSN_COMPLETE, signal, 2000, 3);
8382     return;
8383   }//if
8384   if (ERROR_INSERTED(5014)) {
8385     SET_ERROR_INSERT_VALUE(5018);
8386     sendSignalWithDelay(cownref, GSN_COMPLETE, signal, 2000, 3);
8387     return;
8388   }//if
8389   if (ERROR_INSERTED(5063) &&
8390       ((refToMain(signal->getSendersBlockRef()) == DBTC) ||
8391        signal->getSendersBlockRef() == reference()))
8392   {
8393     Uint32 save = signal->getSendersBlockRef();
8394     ndbout_c("Delaying execCOMPLETE");
8395     sendSignalWithDelay(cownref, GSN_COMPLETE,signal, 2000,signal->getLength());
8396 
8397     if (refToMain(save) == DBTC)
8398     {
8399       ndbout_c("killing %u", refToNode(save));
8400       signal->theData[0] = 9999;
8401       sendSignal(numberToRef(CMVMI, refToNode(save)),
8402                  GSN_NDB_TAMPER, signal, 1, JBB);
8403     }
8404     return;
8405   }
8406 
8407   tcConnectptr.i = tcIndex;
8408   ptrAss(tcConnectptr, regTcConnectionrec);
8409   if ((tcConnectptr.p->transactionState == TcConnectionrec::COMMITTED) &&
8410       (tcConnectptr.p->transid[0] == transid1) &&
8411       (tcConnectptr.p->transid[1] == transid2)) {
8412 
8413     TcConnectionrec * const regTcPtr = tcConnectptr.p;
8414     TRACE_OP(regTcPtr, "COMPLETE");
8415 
8416     if (tcConnectptr.p->seqNoReplica != 0 &&
8417 	tcConnectptr.p->activeCreat == Fragrecord::AC_NORMAL) {
8418       jam();
8419       localCommitLab(signal);
8420       return;
8421     }
8422     else if (tcConnectptr.p->seqNoReplica == 0)
8423     {
8424       jam();
8425       completeTransLastLab(signal);
8426       return;
8427     }
8428     else
8429     {
8430       jam();
8431       completeTransNotLastLab(signal);
8432       return;
8433     }
8434   }//if
8435   if (tcConnectptr.p->transactionState != TcConnectionrec::COMMITTED) {
8436     warningReport(signal, 2);
8437   } else {
8438     warningReport(signal, 3);
8439   }//if
8440 }//Dblqh::execCOMPLETE()
8441 
8442 /* ************************************************************************>>
8443  * COMPLETEREQ: Complete request from TC. Same as COMPLETE but used if one
8444  * node is not working ok (See COMMIT).
8445  * ************************************************************************>> */
execCOMPLETEREQ(Signal * signal)8446 void Dblqh::execCOMPLETEREQ(Signal* signal)
8447 {
8448   jamEntry();
8449   Uint32 reqPtr = signal->theData[0];
8450   BlockReference reqBlockref = signal->theData[1];
8451   Uint32 transid1 = signal->theData[2];
8452   Uint32 transid2 = signal->theData[3];
8453   Uint32 tcOprec = signal->theData[5];
8454   if (ERROR_INSERTED(5005)) {
8455     systemErrorLab(signal, __LINE__);
8456   }
8457   if (ERROR_INSERTED(5018)) {
8458     CLEAR_ERROR_INSERT_VALUE;
8459     sendSignalWithDelay(cownref, GSN_COMPLETEREQ, signal, 2000, 6);
8460     return;
8461   }//if
8462   if (findTransaction(transid1,
8463                       transid2,
8464                       tcOprec, 0) != ZOK) {
8465     jam();
8466 /*---------------------------------------------------------*/
8467 /*       FOR SOME REASON THE COMPLETE PHASE STARTED AFTER  */
8468 /*       A TIME OUT. THE TRANSACTION IS GONE. WE NEED TO   */
8469 /*       REPORT COMPLETION ANYWAY.                         */
8470 /*---------------------------------------------------------*/
8471     signal->theData[0] = reqPtr;
8472     signal->theData[1] = cownNodeid;
8473     signal->theData[2] = transid1;
8474     signal->theData[3] = transid2;
8475     sendSignal(reqBlockref, GSN_COMPLETECONF, signal, 4, JBB);
8476     warningReport(signal, 7);
8477     return;
8478   }//if
8479   TcConnectionrec * const regTcPtr = tcConnectptr.p;
8480   switch (regTcPtr->transactionState) {
8481   case TcConnectionrec::COMMITTED:
8482     jam();
8483     regTcPtr->reqBlockref = reqBlockref;
8484     regTcPtr->reqRef = reqPtr;
8485     regTcPtr->abortState = TcConnectionrec::REQ_FROM_TC;
8486     /*empty*/;
8487     break;
8488 /*---------------------------------------------------------*/
8489 /*       THE NORMAL CASE.                                  */
8490 /*---------------------------------------------------------*/
8491   case TcConnectionrec::WAIT_TUP_COMMIT:
8492     jam();
8493 /*---------------------------------------------------------*/
8494 /*       FOR SOME REASON THE COMPLETE PHASE STARTED AFTER  */
8495 /*       A TIME OUT. WE HAVE SET THE PROPER VARIABLES SUCH */
8496 /*       THAT A COMPLETECONF WILL BE SENT WHEN COMPLETE IS */
8497 /*       FINISHED.                                         */
8498 /*---------------------------------------------------------*/
8499     regTcPtr->reqBlockref = reqBlockref;
8500     regTcPtr->reqRef = reqPtr;
8501     regTcPtr->abortState = TcConnectionrec::REQ_FROM_TC;
8502     return;
8503     break;
8504   default:
8505     jam();
8506     warningReport(signal, 6);
8507     return;
8508     break;
8509   }//switch
8510   if (regTcPtr->seqNoReplica != 0 &&
8511       regTcPtr->activeCreat != Fragrecord::AC_NR_COPY) {
8512     jam();
8513     localCommitLab(signal);
8514   }
8515   else if (regTcPtr->seqNoReplica == 0)
8516   {
8517     jam();
8518     completeTransLastLab(signal);
8519   }
8520   else
8521   {
8522     jam();
8523     completeTransNotLastLab(signal);
8524   }
8525 }//Dblqh::execCOMPLETEREQ()
8526 
8527 /* ************> */
8528 /*  COMPLETED  > */
8529 /* ************> */
execLQHKEYCONF(Signal * signal)8530 void Dblqh::execLQHKEYCONF(Signal* signal)
8531 {
8532   LqhKeyConf * const lqhKeyConf = (LqhKeyConf *)signal->getDataPtr();
8533   Uint32 tcIndex = lqhKeyConf->opPtr;
8534   Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize;
8535   TcConnectionrec *regTcConnectionrec = tcConnectionrec;
8536   jamEntry();
8537   if (tcIndex >= ttcConnectrecFileSize) {
8538     errorReport(signal, 2);
8539     return;
8540   }//if
8541   tcConnectptr.i = tcIndex;
8542   ptrAss(tcConnectptr, regTcConnectionrec);
8543   switch (tcConnectptr.p->connectState) {
8544   case TcConnectionrec::LOG_CONNECTED:
8545     jam();
8546     completedLab(signal);
8547     return;
8548     break;
8549   case TcConnectionrec::COPY_CONNECTED:
8550     jam();
8551     copyCompletedLab(signal);
8552     return;
8553     break;
8554   default:
8555     jamLine(tcConnectptr.p->connectState);
8556     ndbrequire(false);
8557     break;
8558   }//switch
8559   return;
8560 }//Dblqh::execLQHKEYCONF()
8561 
8562 /* ------------------------------------------------------------------------- */
8563 /* -------                       COMMIT PHASE                        ------- */
8564 /*                                                                           */
8565 /* ------------------------------------------------------------------------- */
commitReqLab(Signal * signal,Uint32 gci_hi,Uint32 gci_lo)8566 void Dblqh::commitReqLab(Signal* signal, Uint32 gci_hi, Uint32 gci_lo)
8567 {
8568   TcConnectionrec * const regTcPtr = tcConnectptr.p;
8569   TcConnectionrec::LogWriteState logWriteState = regTcPtr->logWriteState;
8570   TcConnectionrec::TransactionState transState = regTcPtr->transactionState;
8571   regTcPtr->gci_hi = gci_hi;
8572   regTcPtr->gci_lo = gci_lo;
8573   if (transState == TcConnectionrec::PREPARED) {
8574     if (logWriteState == TcConnectionrec::WRITTEN) {
8575       jam();
8576       regTcPtr->transactionState = TcConnectionrec::PREPARED_RECEIVED_COMMIT;
8577       TcConnectionrecPtr saveTcPtr = tcConnectptr;
8578       Uint32 blockNo = refToMain(regTcPtr->tcTupBlockref);
8579       signal->theData[0] = regTcPtr->tupConnectrec;
8580       signal->theData[1] = gci_hi;
8581       signal->theData[2] = gci_lo;
8582       EXECUTE_DIRECT(blockNo, GSN_TUP_WRITELOG_REQ, signal, 3);
8583       jamEntry();
8584       if (regTcPtr->transactionState == TcConnectionrec::LOG_COMMIT_QUEUED) {
8585         jam();
8586         return;
8587       }//if
8588       ndbrequire(regTcPtr->transactionState == TcConnectionrec::LOG_COMMIT_WRITTEN);
8589       tcConnectptr = saveTcPtr;
8590     } else if (logWriteState == TcConnectionrec::NOT_STARTED) {
8591       jam();
8592     } else if (logWriteState == TcConnectionrec::NOT_WRITTEN) {
8593       jam();
8594 /*---------------------------------------------------------------------------*/
8595 /* IT IS A READ OPERATION OR OTHER OPERATION THAT DO NOT USE THE LOG.        */
8596 /*---------------------------------------------------------------------------*/
8597 /*---------------------------------------------------------------------------*/
8598 /* THE LOG HAS NOT BEEN WRITTEN SINCE THE LOG FLAG WAS FALSE. THIS CAN OCCUR */
8599 /* WHEN WE ARE STARTING A NEW FRAGMENT.                                      */
8600 /*---------------------------------------------------------------------------*/
8601       regTcPtr->logWriteState = TcConnectionrec::NOT_STARTED;
8602     } else {
8603       ndbrequire(logWriteState == TcConnectionrec::NOT_WRITTEN_WAIT);
8604       jam();
8605 /*---------------------------------------------------------------------------*/
8606 /* THE STATE WAS SET TO NOT_WRITTEN BY THE OPERATION BUT LATER A SCAN OF ALL */
8607 /* OPERATION RECORD CHANGED IT INTO NOT_WRITTEN_WAIT. THIS INDICATES THAT WE */
8608 /* ARE WAITING FOR THIS OPERATION TO COMMIT OR ABORT SO THAT WE CAN FIND THE */
8609 /* STARTING GLOBAL CHECKPOINT OF THIS NEW FRAGMENT.                          */
8610 /*---------------------------------------------------------------------------*/
8611       checkScanTcCompleted(signal);
8612     }//if
8613   } else if (transState == TcConnectionrec::LOG_COMMIT_QUEUED_WAIT_SIGNAL) {
8614     jam();
8615     regTcPtr->transactionState = TcConnectionrec::LOG_COMMIT_QUEUED;
8616     return;
8617   } else if (transState == TcConnectionrec::LOG_COMMIT_WRITTEN_WAIT_SIGNAL) {
8618     jam();
8619   } else {
8620     warningReport(signal, 0);
8621     return;
8622   }//if
8623   if (regTcPtr->seqNoReplica == 0 ||
8624       regTcPtr->activeCreat == Fragrecord::AC_NR_COPY) {
8625     jam();
8626     localCommitLab(signal);
8627     return;
8628   }//if
8629   commitReplyLab(signal);
8630   return;
8631 }//Dblqh::commitReqLab()
8632 
execLQH_WRITELOG_REQ(Signal * signal)8633 void Dblqh::execLQH_WRITELOG_REQ(Signal* signal)
8634 {
8635   jamEntry();
8636   tcConnectptr.i = signal->theData[0];
8637   ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
8638   TcConnectionrec * const regTcPtr = tcConnectptr.p;
8639   Uint32 gci_hi = signal->theData[1];
8640   Uint32 gci_lo = signal->theData[2];
8641   Uint32 newestGci = cnewestGci;
8642   TcConnectionrec::LogWriteState logWriteState = regTcPtr->logWriteState;
8643   TcConnectionrec::TransactionState transState = regTcPtr->transactionState;
8644   regTcPtr->gci_hi = gci_hi;
8645   regTcPtr->gci_lo = gci_lo;
8646   if (gci_hi > newestGci) {
8647     jam();
8648 /* ------------------------------------------------------------------------- */
8649 /*       KEEP TRACK OF NEWEST GLOBAL CHECKPOINT THAT LQH HAS HEARD OF.       */
8650 /* ------------------------------------------------------------------------- */
8651     cnewestGci = gci_hi;
8652   }//if
8653   if (logWriteState == TcConnectionrec::WRITTEN) {
8654 /*---------------------------------------------------------------------------*/
8655 /* I NEED TO INSERT A COMMIT LOG RECORD SINCE WE ARE WRITING LOG IN THIS     */
8656 /* TRANSACTION.                                                              */
8657 /*---------------------------------------------------------------------------*/
8658     jam();
8659     LogPartRecordPtr regLogPartPtr;
8660     Uint32 noOfLogPages = cnoOfLogPages;
8661     jam();
8662     regLogPartPtr.i = regTcPtr->m_log_part_ptr_i;
8663     ptrCheckGuard(regLogPartPtr, clogPartFileSize, logPartRecord);
8664     if (!regLogPartPtr.p->m_log_complete_queue.isEmpty() ||
8665         (noOfLogPages == 0))
8666     {
8667       jam();
8668 /*---------------------------------------------------------------------------*/
8669 /* THIS LOG PART WAS CURRENTLY ACTIVE WRITING ANOTHER LOG RECORD. WE MUST    */
8670 /* WAIT UNTIL THIS PART HAS COMPLETED ITS OPERATION.                         */
8671 /*---------------------------------------------------------------------------*/
8672 // We must delay the write of commit info to the log to safe-guard against
8673 // a crash due to lack of log pages. We temporary stop all log writes to this
8674 // log part to ensure that we don't get a buffer explosion in the delayed
8675 // signal buffer instead.
8676 /*---------------------------------------------------------------------------*/
8677       linkWaitLog(signal, regLogPartPtr, regLogPartPtr.p->m_log_complete_queue);
8678       if (transState == TcConnectionrec::PREPARED) {
8679         jam();
8680         regTcPtr->transactionState = TcConnectionrec::LOG_COMMIT_QUEUED_WAIT_SIGNAL;
8681       } else {
8682         jam();
8683         ndbrequire(transState == TcConnectionrec::PREPARED_RECEIVED_COMMIT);
8684         regTcPtr->transactionState = TcConnectionrec::LOG_COMMIT_QUEUED;
8685       }//if
8686       return;
8687     }//if
8688     writeCommitLog(signal, regLogPartPtr);
8689     if (transState == TcConnectionrec::PREPARED) {
8690       jam();
8691       regTcPtr->transactionState = TcConnectionrec::LOG_COMMIT_WRITTEN_WAIT_SIGNAL;
8692     } else {
8693       jam();
8694       ndbrequire(transState == TcConnectionrec::PREPARED_RECEIVED_COMMIT);
8695       regTcPtr->transactionState = TcConnectionrec::LOG_COMMIT_WRITTEN;
8696     }//if
8697   }//if
8698 }//Dblqh::execLQH_WRITELOG_REQ()
8699 
localCommitLab(Signal * signal)8700 void Dblqh::localCommitLab(Signal* signal)
8701 {
8702   FragrecordPtr regFragptr;
8703   regFragptr.i = tcConnectptr.p->fragmentptr;
8704   c_fragment_pool.getPtr(regFragptr);
8705   Fragrecord::FragStatus status = regFragptr.p->fragStatus;
8706   fragptr = regFragptr;
8707   switch (status) {
8708   case Fragrecord::FSACTIVE:
8709   case Fragrecord::CRASH_RECOVERING:
8710   case Fragrecord::ACTIVE_CREATION:
8711     commitContinueAfterBlockedLab(signal);
8712     return;
8713   case Fragrecord::FREE:
8714     jam();
8715   case Fragrecord::DEFINED:
8716     jam();
8717   case Fragrecord::REMOVING:
8718     jam();
8719   default:
8720     ndbrequire(false);
8721     break;
8722   }//switch
8723 }//Dblqh::localCommitLab()
8724 
commitContinueAfterBlockedLab(Signal * signal)8725 void Dblqh::commitContinueAfterBlockedLab(Signal* signal)
8726 {
8727 /* ------------------------------------------------------------------------- */
8728 /*INPUT:          TC_CONNECTPTR           ACTIVE OPERATION RECORD            */
8729 /* ------------------------------------------------------------------------- */
8730 /* ------------------------------------------------------------------------- */
8731 /*CONTINUE HERE AFTER BEING BLOCKED FOR A WHILE DURING LOCAL CHECKPOINT.     */
8732 /*The operation is already removed from the active list since there is no    */
8733 /*chance for any real-time breaks before we need to release it.              */
8734 /* ------------------------------------------------------------------------- */
8735 /*ALSO AFTER NORMAL PROCEDURE WE CONTINUE                                    */
8736 /*WE MUST COMMIT TUP BEFORE ACC TO ENSURE THAT NO ONE RACES IN AND SEES A    */
8737 /*DIRTY STATE IN TUP.                                                        */
8738 /* ------------------------------------------------------------------------- */
8739   Ptr<TcConnectionrec> regTcPtr = tcConnectptr;
8740   Ptr<Fragrecord> regFragptr = fragptr;
8741   Uint32 operation = regTcPtr.p->operation;
8742   Uint32 dirtyOp = regTcPtr.p->dirtyOp;
8743   Uint32 opSimple = regTcPtr.p->opSimple;
8744   bool normalProtocol = (regTcPtr.p->m_flags &
8745                          TcConnectionrec::OP_NORMAL_PROTOCOL);
8746 
8747   if (regTcPtr.p->activeCreat != Fragrecord::AC_IGNORED) {
8748     if (operation != ZREAD) {
8749       TupCommitReq * const tupCommitReq =
8750         (TupCommitReq *)signal->getDataPtrSend();
8751       Uint32 sig0 = regTcPtr.p->tupConnectrec;
8752       Uint32 tup = refToMain(regTcPtr.p->tcTupBlockref);
8753       jam();
8754       tupCommitReq->opPtr = sig0;
8755       tupCommitReq->gci_hi = regTcPtr.p->gci_hi;
8756       tupCommitReq->hashValue = regTcPtr.p->hashValue;
8757       tupCommitReq->diskpage = RNIL;
8758       tupCommitReq->gci_lo = regTcPtr.p->gci_lo;
8759       tupCommitReq->transId1 = regTcPtr.p->transid[0];
8760       tupCommitReq->transId2 = regTcPtr.p->transid[1];
8761       EXECUTE_DIRECT(tup, GSN_TUP_COMMITREQ, signal,
8762 		     TupCommitReq::SignalLength);
8763 
8764       if (TRACENR_FLAG)
8765       {
8766 	TRACENR("COMMIT: ");
8767 	switch (regTcPtr.p->operation) {
8768 	case ZREAD: TRACENR("READ"); break;
8769 	case ZUPDATE: TRACENR("UPDATE"); break;
8770 	case ZWRITE: TRACENR("WRITE"); break;
8771 	case ZINSERT: TRACENR("INSERT"); break;
8772 	case ZDELETE: TRACENR("DELETE"); break;
8773         case ZUNLOCK: TRACENR("UNLOCK"); break;
8774 	}
8775 
8776 	TRACENR(" tab: " << regTcPtr.p->tableref
8777 	       << " frag: " << regTcPtr.p->fragmentid
8778 	       << " activeCreat: " << (Uint32)regTcPtr.p->activeCreat);
8779 	if (LqhKeyReq::getNrCopyFlag(regTcPtr.p->reqinfo))
8780 	  TRACENR(" NrCopy");
8781 	if (LqhKeyReq::getRowidFlag(regTcPtr.p->reqinfo))
8782 	  TRACENR(" rowid: " << regTcPtr.p->m_row_id);
8783 	TRACENR(" key: " << getKeyInfoWordOrZero(regTcPtr.p, 0));
8784 
8785         if (signal->theData[0] != 0)
8786           TRACENR(" TIMESLICE");
8787 	TRACENR(endl);
8788       }
8789 
8790       if(signal->theData[0] != 0)
8791       {
8792         regTcPtr.p->transactionState = TcConnectionrec::WAIT_TUP_COMMIT;
8793         return; // TUP_COMMIT was timesliced
8794       }
8795 
8796       TRACE_OP(regTcPtr.p, "ACC_COMMITREQ");
8797 
8798       Uint32 acc = refToMain(regTcPtr.p->tcAccBlockref);
8799       signal->theData[0] = regTcPtr.p->accConnectrec;
8800       EXECUTE_DIRECT(acc, GSN_ACC_COMMITREQ, signal, 1);
8801 
8802     } else {
8803       if(!dirtyOp){
8804 	TRACE_OP(regTcPtr.p, "ACC_COMMITREQ");
8805 
8806 	Uint32 acc = refToMain(regTcPtr.p->tcAccBlockref);
8807 	signal->theData[0] = regTcPtr.p->accConnectrec;
8808 	EXECUTE_DIRECT(acc, GSN_ACC_COMMITREQ, signal, 1);
8809       }
8810 
8811       if (dirtyOp && normalProtocol == 0)
8812       {
8813 	jam();
8814         /**
8815          * The dirtyRead does not send anything but TRANSID_AI from LDM
8816          */
8817 	fragptr = regFragptr;
8818 	tcConnectptr = regTcPtr;
8819 	cleanUp(signal);
8820 	return;
8821       }
8822 
8823       /**
8824        * The simpleRead will send a LQHKEYCONF
8825        *   but have already released the locks
8826        */
8827       if (opSimple)
8828       {
8829 	fragptr = regFragptr;
8830 	tcConnectptr = regTcPtr;
8831         packLqhkeyreqLab(signal);
8832         return;
8833       }
8834     }
8835   }//if
8836   jamEntry();
8837   fragptr = regFragptr;
8838   tcConnectptr = regTcPtr;
8839   tupcommit_conf(signal, regTcPtr.p, regFragptr.p);
8840 }
8841 
8842 void
tupcommit_conf_callback(Signal * signal,Uint32 tcPtrI)8843 Dblqh::tupcommit_conf_callback(Signal* signal, Uint32 tcPtrI)
8844 {
8845   jamEntry();
8846 
8847   tcConnectptr.i = tcPtrI;
8848   ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
8849   TcConnectionrec * tcPtr = tcConnectptr.p;
8850 
8851   ndbrequire(tcPtr->transactionState == TcConnectionrec::WAIT_TUP_COMMIT);
8852 
8853   FragrecordPtr regFragptr;
8854   regFragptr.i = tcPtr->fragmentptr;
8855   c_fragment_pool.getPtr(regFragptr);
8856   fragptr = regFragptr;
8857 
8858   TRACE_OP(tcPtr, "ACC_COMMITREQ");
8859 
8860   Uint32 acc = refToMain(tcPtr->tcAccBlockref);
8861   signal->theData[0] = tcPtr->accConnectrec;
8862   EXECUTE_DIRECT(acc, GSN_ACC_COMMITREQ, signal, 1);
8863   jamEntry();
8864 
8865   tcConnectptr.i = tcPtrI;
8866   tcConnectptr.p = tcPtr;
8867   tupcommit_conf(signal, tcPtr, regFragptr.p);
8868 }
8869 
8870 void
tupcommit_conf(Signal * signal,TcConnectionrec * tcPtrP,Fragrecord * regFragptr)8871 Dblqh::tupcommit_conf(Signal* signal,
8872 		      TcConnectionrec * tcPtrP,
8873 		      Fragrecord * regFragptr)
8874 {
8875   Uint32 dirtyOp = tcPtrP->dirtyOp;
8876   Uint32 seqNoReplica = tcPtrP->seqNoReplica;
8877   Uint32 activeCreat = tcPtrP->activeCreat;
8878   if (tcPtrP->gci_hi > regFragptr->newestGci) {
8879     jam();
8880 /* ------------------------------------------------------------------------- */
8881 /*IT IS THE FIRST TIME THIS GLOBAL CHECKPOINT IS INVOLVED IN UPDATING THIS   */
8882 /*FRAGMENT. UPDATE THE VARIABLE THAT KEEPS TRACK OF NEWEST GCI IN FRAGMENT   */
8883 /* ------------------------------------------------------------------------- */
8884     regFragptr->newestGci = tcPtrP->gci_hi;
8885   }//if
8886   if (dirtyOp != ZTRUE)
8887   {
8888     if (seqNoReplica == 0 || activeCreat == Fragrecord::AC_NR_COPY)
8889     {
8890       jam();
8891       commitReplyLab(signal);
8892       return;
8893     }//if
8894     if (seqNoReplica == 0)
8895     {
8896       jam();
8897       completeTransLastLab(signal);
8898     }
8899     else
8900     {
8901       jam();
8902       completeTransNotLastLab(signal);
8903     }
8904     return;
8905   } else {
8906 /* ------------------------------------------------------------------------- */
8907 /*WE MUST HANDLE DIRTY WRITES IN A SPECIAL WAY. THESE OPERATIONS WILL NOT    */
8908 /*SEND ANY COMMIT OR COMPLETE MESSAGES TO OTHER NODES. THEY WILL MERELY SEND */
8909 /*THOSE SIGNALS INTERNALLY.                                                  */
8910 /* ------------------------------------------------------------------------- */
8911     if (tcPtrP->abortState == TcConnectionrec::ABORT_IDLE)
8912     {
8913       jam();
8914       if (activeCreat == Fragrecord::AC_NR_COPY)
8915       {
8916 	jam();
8917 	ndbrequire(LqhKeyReq::getNrCopyFlag(tcPtrP->reqinfo));
8918 	ndbrequire(tcPtrP->m_nr_delete.m_cnt == 0);
8919       }
8920       packLqhkeyreqLab(signal);
8921     }
8922     else
8923     {
8924       ndbrequire(tcPtrP->abortState != TcConnectionrec::NEW_FROM_TC);
8925       jam();
8926       sendLqhTransconf(signal, LqhTransConf::Committed);
8927       cleanUp(signal);
8928     }//if
8929   }//if
8930 }//Dblqh::commitContinueAfterBlockedLab()
8931 
commitReplyLab(Signal * signal)8932 void Dblqh::commitReplyLab(Signal* signal)
8933 {
8934 /* -------------------------------------------------------------- */
8935 /* BACKUP AND STAND-BY REPLICAS ONLY UPDATE THE TRANSACTION STATE */
8936 /* -------------------------------------------------------------- */
8937   TcConnectionrec * const regTcPtr = tcConnectptr.p;
8938   TcConnectionrec::AbortState abortState = regTcPtr->abortState;
8939   regTcPtr->transactionState = TcConnectionrec::COMMITTED;
8940   if (abortState == TcConnectionrec::ABORT_IDLE) {
8941     Uint32 clientBlockref = regTcPtr->clientBlockref;
8942     if (regTcPtr->seqNoReplica == 0) {
8943       jam();
8944       sendCommittedTc(signal, clientBlockref);
8945       return;
8946     } else {
8947       jam();
8948       sendCommitLqh(signal, clientBlockref);
8949       return;
8950     }//if
8951   } else if (regTcPtr->abortState == TcConnectionrec::REQ_FROM_TC) {
8952     jam();
8953     signal->theData[0] = regTcPtr->reqRef;
8954     signal->theData[1] = cownNodeid;
8955     signal->theData[2] = regTcPtr->transid[0];
8956     signal->theData[3] = regTcPtr->transid[1];
8957     sendSignal(tcConnectptr.p->reqBlockref, GSN_COMMITCONF, signal, 4, JBB);
8958   } else {
8959     ndbrequire(regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC);
8960   }//if
8961   return;
8962 }//Dblqh::commitReplyLab()
8963 
8964 /* ------------------------------------------------------------------------- */
8965 /* -------                COMPLETE PHASE                             ------- */
8966 /*                                                                           */
8967 /* ------------------------------------------------------------------------- */
completeTransNotLastLab(Signal * signal)8968 void Dblqh::completeTransNotLastLab(Signal* signal)
8969 {
8970   TcConnectionrec * const regTcPtr = tcConnectptr.p;
8971   if (regTcPtr->abortState == TcConnectionrec::ABORT_IDLE) {
8972     Uint32 clientBlockref = regTcPtr->clientBlockref;
8973     jam();
8974     sendCompleteLqh(signal, clientBlockref);
8975     cleanUp(signal);
8976     return;
8977   } else {
8978     jam();
8979     completeUnusualLab(signal);
8980     return;
8981   }//if
8982 }//Dblqh::completeTransNotLastLab()
8983 
completeTransLastLab(Signal * signal)8984 void Dblqh::completeTransLastLab(Signal* signal)
8985 {
8986   TcConnectionrec * const regTcPtr = tcConnectptr.p;
8987   if (regTcPtr->abortState == TcConnectionrec::ABORT_IDLE) {
8988     Uint32 clientBlockref = regTcPtr->clientBlockref;
8989     jam();
8990 /* ------------------------------------------------------------------------- */
8991 /*DIRTY WRITES WHICH ARE LAST IN THE CHAIN OF REPLICAS WILL SEND COMPLETED   */
8992 /*INSTEAD OF SENDING PREPARED TO THE TC (OR OTHER INITIATOR OF OPERATION).   */
8993 /* ------------------------------------------------------------------------- */
8994     sendCompletedTc(signal, clientBlockref);
8995     cleanUp(signal);
8996     return;
8997   } else {
8998     jam();
8999     completeUnusualLab(signal);
9000     return;
9001   }//if
9002 }//Dblqh::completeTransLastLab()
9003 
completeUnusualLab(Signal * signal)9004 void Dblqh::completeUnusualLab(Signal* signal)
9005 {
9006   TcConnectionrec * const regTcPtr = tcConnectptr.p;
9007   if (regTcPtr->abortState == TcConnectionrec::ABORT_FROM_TC) {
9008     jam();
9009     sendAborted(signal);
9010   } else if (regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC) {
9011     jam();
9012   } else {
9013     ndbrequire(regTcPtr->abortState == TcConnectionrec::REQ_FROM_TC);
9014     jam();
9015     signal->theData[0] = regTcPtr->reqRef;
9016     signal->theData[1] = cownNodeid;
9017     signal->theData[2] = regTcPtr->transid[0];
9018     signal->theData[3] = regTcPtr->transid[1];
9019     sendSignal(regTcPtr->reqBlockref,
9020                GSN_COMPLETECONF, signal, 4, JBB);
9021   }//if
9022   cleanUp(signal);
9023   return;
9024 }//Dblqh::completeUnusualLab()
9025 
9026 /* ========================================================================= */
9027 /* =======                        RELEASE TC CONNECT RECORD          ======= */
9028 /*                                                                           */
9029 /*       RELEASE A TC CONNECT RECORD TO THE FREELIST.                        */
9030 /* ========================================================================= */
releaseTcrec(Signal * signal,TcConnectionrecPtr locTcConnectptr)9031 void Dblqh::releaseTcrec(Signal* signal, TcConnectionrecPtr locTcConnectptr)
9032 {
9033   jam();
9034   ndbassert(locTcConnectptr.p->hashIndex==RNIL);
9035   const Uint32 op = locTcConnectptr.p->operation;
9036   const Uint32 firstFree = cfirstfreeTcConrec;
9037   Uint32 numFree = ctcNumFree;
9038   locTcConnectptr.p->tcTimer = 0;
9039   locTcConnectptr.p->transactionState = TcConnectionrec::TC_NOT_CONNECTED;
9040   locTcConnectptr.p->nextTcConnectrec = firstFree;
9041   cfirstfreeTcConrec = locTcConnectptr.i;
9042   ctcNumFree = numFree + 1;
9043 
9044   ndbassert(locTcConnectptr.p->tcScanRec == RNIL);
9045 
9046   TablerecPtr tabPtr;
9047   tabPtr.i = locTcConnectptr.p->tableref;
9048   if(tabPtr.i == RNIL)
9049     return;
9050 
9051   ptrCheckGuard(tabPtr, ctabrecFileSize, tablerec);
9052 
9053   /**
9054    * Normal case
9055    */
9056   if (op == ZREAD || op == ZUNLOCK)
9057   {
9058     ndbrequire(tabPtr.p->usageCountR > 0);
9059     tabPtr.p->usageCountR--;
9060   }
9061   else
9062   {
9063     ndbrequire(tabPtr.p->usageCountW > 0);
9064     tabPtr.p->usageCountW--;
9065   }
9066 }//Dblqh::releaseTcrec()
9067 
releaseTcrecLog(Signal * signal,TcConnectionrecPtr locTcConnectptr)9068 void Dblqh::releaseTcrecLog(Signal* signal, TcConnectionrecPtr locTcConnectptr)
9069 {
9070   jam();
9071   Uint32 numFree = ctcNumFree;
9072   ndbassert(locTcConnectptr.p->hashIndex==RNIL);
9073   locTcConnectptr.p->tcTimer = 0;
9074   locTcConnectptr.p->transactionState = TcConnectionrec::TC_NOT_CONNECTED;
9075   locTcConnectptr.p->nextTcConnectrec = cfirstfreeTcConrec;
9076   cfirstfreeTcConrec = locTcConnectptr.i;
9077   ctcNumFree = numFree + 1;
9078 
9079   TablerecPtr tabPtr;
9080   tabPtr.i = locTcConnectptr.p->tableref;
9081   if(tabPtr.i == RNIL)
9082     return;
9083 
9084 }//Dblqh::releaseTcrecLog()
9085 
9086 /* ------------------------------------------------------------------------- */
9087 /* -------                       ABORT PHASE                         ------- */
9088 /*                                                                           */
9089 /*THIS PART IS USED AT ERRORS THAT CAUSE ABORT OF TRANSACTION.               */
9090 /* ------------------------------------------------------------------------- */
9091 void
remove_commit_marker(TcConnectionrec * const regTcPtr)9092 Dblqh::remove_commit_marker(TcConnectionrec * const regTcPtr)
9093 {
9094   Ptr<CommitAckMarker> tmp;
9095   Uint32 commitAckMarker = regTcPtr->commitAckMarker;
9096   regTcPtr->commitAckMarker = RNIL;
9097   if (commitAckMarker == RNIL)
9098     return;
9099   jam();
9100   m_commitAckMarkerHash.getPtr(tmp, commitAckMarker);
9101 #ifdef MARKER_TRACE
9102   ndbout_c("%u remove marker[%.8x %.8x] op: %u ref: %u",
9103            instance(), tmp.p->transid1, tmp.p->transid2,
9104            Uint32(regTcPtr - tcConnectionrec), tmp.p->reference_count);
9105 #endif
9106   if (tmp.p->in_hash == false)
9107   {
9108     ndbout_c("%u remove_commit_marker failed[%.8x %.8x]"
9109              " remove_by_fail_api = %u"
9110              " ack marker transid[%.8x %.8x]"
9111              " ack marker ref count = %d",
9112              instance(),
9113              regTcPtr->transid[0],
9114              regTcPtr->transid[1],
9115              tmp.p->removed_by_fail_api,
9116              tmp.p->transid1,
9117              tmp.p->transid2,
9118              tmp.p->reference_count);
9119     ndbrequire(tmp.p->reference_count == 0);
9120     ndbrequire(false);
9121     return;
9122   }
9123   ndbrequire(tmp.p->reference_count > 0);
9124   if (regTcPtr->transid[0] != tmp.p->transid1 ||
9125       regTcPtr->transid[1] != tmp.p->transid2)
9126   {
9127     /**
9128      * We refer to a commit ack marker that have already been removed
9129      * and even reused by another transaction.
9130      */
9131     ndbout_c("%u remove_commit_marker failed, moved[%.8x %.8x]"
9132              " remove_by_fail_api = %u"
9133              " ack marker transid[%.8x %.8x]"
9134              " ack marker ref count = %d",
9135              instance(),
9136              regTcPtr->transid[0],
9137              regTcPtr->transid[1],
9138              tmp.p->removed_by_fail_api,
9139              tmp.p->transid1,
9140              tmp.p->transid2,
9141              tmp.p->reference_count);
9142     ndbrequire(false);
9143     return;
9144   }
9145   tmp.p->reference_count--;
9146   if (tmp.p->reference_count == 0)
9147   {
9148     jam();
9149     CommitAckMarker key;
9150     key.transid1 = regTcPtr->transid[0];
9151     key.transid2 = regTcPtr->transid[1];
9152     CommitAckMarkerPtr removedPtr;
9153     m_commitAckMarkerHash.remove(removedPtr, key);
9154     ndbrequire(removedPtr.i != RNIL);
9155     ndbrequire(removedPtr.i == tmp.i);
9156     removedPtr.p->in_hash = false;
9157     m_commitAckMarkerPool.releaseLast(removedPtr);
9158   }
9159 }
9160 
9161 /* ***************************************************>> */
9162 /*  ABORT: Abort transaction in connection. Sender TC.   */
9163 /*  This is the normal protocol (See COMMIT)             */
9164 /* ***************************************************>> */
execABORT(Signal * signal)9165 void Dblqh::execABORT(Signal* signal)
9166 {
9167   jamEntry();
9168   Uint32 tcOprec = signal->theData[0];
9169   BlockReference tcBlockref = signal->theData[1];
9170   Uint32 transid1 = signal->theData[2];
9171   Uint32 transid2 = signal->theData[3];
9172   CRASH_INSERTION(5003);
9173   if (ERROR_INSERTED(5015)) {
9174     CLEAR_ERROR_INSERT_VALUE;
9175     sendSignalWithDelay(cownref, GSN_ABORT, signal, 2000, 4);
9176     return;
9177   }//if
9178   if (findTransaction(transid1,
9179                       transid2,
9180                       tcOprec, 0) != ZOK) {
9181     jam();
9182 
9183     if(ERROR_INSERTED(5039) &&
9184        refToNode(signal->getSendersBlockRef()) != getOwnNodeId()){
9185       jam();
9186       SET_ERROR_INSERT_VALUE(5040);
9187       return;
9188     }
9189 
9190     if(ERROR_INSERTED(5040) &&
9191        refToNode(signal->getSendersBlockRef()) != getOwnNodeId()){
9192       jam();
9193       SET_ERROR_INSERT_VALUE(5003);
9194       return;
9195     }
9196 
9197 /* ------------------------------------------------------------------------- */
9198 // SEND ABORTED EVEN IF NOT FOUND.
9199 //THE TRANSACTION MIGHT NEVER HAVE ARRIVED HERE.
9200 /* ------------------------------------------------------------------------- */
9201     signal->theData[0] = tcOprec;
9202     signal->theData[1] = transid1;
9203     signal->theData[2] = transid2;
9204     signal->theData[3] = cownNodeid;
9205     signal->theData[4] = ZTRUE;
9206     sendSignal(tcBlockref, GSN_ABORTED, signal, 5, JBB);
9207     warningReport(signal, 8);
9208     return;
9209   }//if
9210 
9211   TcConnectionrec * const regTcPtr = tcConnectptr.p;
9212   if (ERROR_INSERTED(5100))
9213   {
9214     SET_ERROR_INSERT_VALUE(5101);
9215     return;
9216   }
9217   CRASH_INSERTION2(5101, regTcPtr->nextReplica != ZNIL);
9218 
9219 /* ------------------------------------------------------------------------- */
9220 /*A GUIDING DESIGN PRINCIPLE IN HANDLING THESE ERROR SITUATIONS HAVE BEEN    */
9221 /*KEEP IT SIMPLE. THUS WE RATHER INSERT A WAIT AND SET THE ABORT_STATE TO    */
9222 /*ACTIVE RATHER THAN WRITE NEW CODE TO HANDLE EVERY SPECIAL SITUATION.       */
9223 /* ------------------------------------------------------------------------- */
9224   if (regTcPtr->nextReplica != ZNIL) {
9225 /* ------------------------------------------------------------------------- */
9226 // We will immediately send the ABORT message also to the next LQH node in line.
9227 /* ------------------------------------------------------------------------- */
9228     FragrecordPtr Tfragptr;
9229     Tfragptr.i = regTcPtr->fragmentptr;
9230     c_fragment_pool.getPtr(Tfragptr);
9231     Uint32 Tnode = regTcPtr->nextReplica;
9232     Uint32 instanceKey = Tfragptr.p->lqhInstanceKey;
9233     BlockReference TLqhRef = numberToRef(DBLQH, instanceKey, Tnode);
9234     signal->theData[0] = regTcPtr->tcOprec;
9235     signal->theData[1] = regTcPtr->tcBlockref;
9236     signal->theData[2] = regTcPtr->transid[0];
9237     signal->theData[3] = regTcPtr->transid[1];
9238     sendSignal(TLqhRef, GSN_ABORT, signal, 4, JBB);
9239   }//if
9240   regTcPtr->abortState = TcConnectionrec::ABORT_FROM_TC;
9241 
9242   remove_commit_marker(regTcPtr);
9243   TRACE_OP(regTcPtr, "ABORT");
9244 
9245   abortStateHandlerLab(signal);
9246 
9247   return;
9248 }//Dblqh::execABORT()
9249 
9250 /* ************************************************************************>>
9251  *  ABORTREQ: Same as ABORT but used in case one node isn't working ok.
9252  *  (See COMMITREQ)
9253  * ************************************************************************>> */
execABORTREQ(Signal * signal)9254 void Dblqh::execABORTREQ(Signal* signal)
9255 {
9256   jamEntry();
9257   Uint32 reqPtr = signal->theData[0];
9258   BlockReference reqBlockref = signal->theData[1];
9259   Uint32 transid1 = signal->theData[2];
9260   Uint32 transid2 = signal->theData[3];
9261   Uint32 tcOprec = signal->theData[5];
9262   if (ERROR_INSERTED(5006)) {
9263     systemErrorLab(signal, __LINE__);
9264   }
9265   if (ERROR_INSERTED(5016)) {
9266     CLEAR_ERROR_INSERT_VALUE;
9267     sendSignalWithDelay(cownref, GSN_ABORTREQ, signal, 2000, 6);
9268     return;
9269   }//if
9270   if (findTransaction(transid1,
9271                       transid2,
9272                       tcOprec, 0) != ZOK) {
9273     signal->theData[0] = reqPtr;
9274     signal->theData[2] = cownNodeid;
9275     signal->theData[3] = transid1;
9276     signal->theData[4] = transid2;
9277     sendSignal(reqBlockref, GSN_ABORTCONF, signal, 5, JBB);
9278     warningReport(signal, 9);
9279     return;
9280   }//if
9281   TcConnectionrec * const regTcPtr = tcConnectptr.p;
9282   if (regTcPtr->transactionState != TcConnectionrec::PREPARED) {
9283     warningReport(signal, 10);
9284     return;
9285   }//if
9286   regTcPtr->reqBlockref = reqBlockref;
9287   regTcPtr->reqRef = reqPtr;
9288   regTcPtr->abortState = TcConnectionrec::REQ_FROM_TC;
9289 
9290   abortCommonLab(signal);
9291   return;
9292 }//Dblqh::execABORTREQ()
9293 
9294 /* ************>> */
9295 /*  ACC_TO_REF  > */
9296 /* ************>> */
execACC_TO_REF(Signal * signal)9297 void Dblqh::execACC_TO_REF(Signal* signal)
9298 {
9299   jamEntry();
9300   terrorCode = signal->theData[1];
9301   abortErrorLab(signal);
9302   return;
9303 }//Dblqh::execACC_TO_REF()
9304 
9305 /* ************> */
9306 /*  ACCKEYREF  > */
9307 /* ************> */
execACCKEYREF(Signal * signal)9308 void Dblqh::execACCKEYREF(Signal* signal)
9309 {
9310   jamEntry();
9311   tcConnectptr.i = signal->theData[0];
9312   terrorCode = signal->theData[1];
9313   ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
9314   TcConnectionrec * const tcPtr = tcConnectptr.p;
9315   switch (tcPtr->transactionState) {
9316   case TcConnectionrec::WAIT_ACC:
9317     jam();
9318     c_fragment_pool.getPtr(tcPtr->fragmentptr)->m_useStat.m_keyRefCount++;
9319     break;
9320   case TcConnectionrec::WAIT_ACC_ABORT:
9321   case TcConnectionrec::ABORT_QUEUED:
9322     jam();
9323 /* ------------------------------------------------------------------------- */
9324 /*IGNORE SINCE ABORT OF THIS OPERATION IS ONGOING ALREADY.                   */
9325 /* ------------------------------------------------------------------------- */
9326     return;
9327     break;
9328   default:
9329     ndbrequire(false);
9330     break;
9331   }//switch
9332   const Uint32 errCode = terrorCode;
9333   tcPtr->errorCode = errCode;
9334 
9335   if (TRACENR_FLAG)
9336   {
9337     TRACENR("ACCKEYREF: " << errCode << " ");
9338     switch (tcPtr->operation) {
9339     case ZREAD: TRACENR("READ"); break;
9340     case ZUPDATE: TRACENR("UPDATE"); break;
9341     case ZWRITE: TRACENR("WRITE"); break;
9342     case ZINSERT: TRACENR("INSERT"); break;
9343     case ZDELETE: TRACENR("DELETE"); break;
9344     case ZUNLOCK: TRACENR("UNLOCK"); break;
9345     default: TRACENR("<Unknown: " << tcPtr->operation << ">"); break;
9346     }
9347 
9348     TRACENR(" tab: " << tcPtr->tableref
9349 	   << " frag: " << tcPtr->fragmentid
9350 	   << " activeCreat: " << (Uint32)tcPtr->activeCreat);
9351     if (LqhKeyReq::getNrCopyFlag(tcPtr->reqinfo))
9352       TRACENR(" NrCopy");
9353     if (LqhKeyReq::getRowidFlag(tcPtr->reqinfo))
9354       TRACENR(" rowid: " << tcPtr->m_row_id);
9355     TRACENR(" key: " << getKeyInfoWordOrZero(tcPtr, 0));
9356     TRACENR(endl);
9357 
9358   }
9359 
9360   ndbrequire(tcPtr->activeCreat == Fragrecord::AC_NORMAL);
9361   ndbrequire(!LqhKeyReq::getNrCopyFlag(tcPtr->reqinfo));
9362 
9363   /**
9364    * Not only primary replica can get ZTUPLE_ALREADY_EXIST || ZNO_TUPLE_FOUND
9365    *
9366    * 1) op1 - primary insert ok
9367    * 2) op1 - backup insert fail (log full or what ever)
9368    * 3) op1 - delete ok @ primary
9369    * 4) op1 - delete fail @ backup
9370    *
9371    * -> ZNO_TUPLE_FOUND is possible
9372    *
9373    * 1) op1 primary delete ok
9374    * 2) op1 backup delete fail (log full or what ever)
9375    * 3) op2 insert ok @ primary
9376    * 4) op2 insert fail @ backup
9377    *
9378    * -> ZTUPLE_ALREADY_EXIST
9379    */
9380   tcPtr->abortState = TcConnectionrec::ABORT_FROM_LQH;
9381   abortCommonLab(signal);
9382   return;
9383 }//Dblqh::execACCKEYREF()
9384 
localAbortStateHandlerLab(Signal * signal)9385 void Dblqh::localAbortStateHandlerLab(Signal* signal)
9386 {
9387   TcConnectionrec * const regTcPtr = tcConnectptr.p;
9388   if (regTcPtr->abortState != TcConnectionrec::ABORT_IDLE) {
9389     jam();
9390     return;
9391   }//if
9392   regTcPtr->abortState = TcConnectionrec::ABORT_FROM_LQH;
9393   regTcPtr->errorCode = terrorCode;
9394   abortStateHandlerLab(signal);
9395   return;
9396 }//Dblqh::localAbortStateHandlerLab()
9397 
abortStateHandlerLab(Signal * signal)9398 void Dblqh::abortStateHandlerLab(Signal* signal)
9399 {
9400   TcConnectionrec * const regTcPtr = tcConnectptr.p;
9401   switch (regTcPtr->transactionState) {
9402   case TcConnectionrec::PREPARED:
9403     jam();
9404 /* ------------------------------------------------------------------------- */
9405 /*THE OPERATION IS ALREADY PREPARED AND SENT TO THE NEXT LQH OR BACK TO TC.  */
9406 /*WE CAN SIMPLY CONTINUE WITH THE ABORT PROCESS.                             */
9407 /*IF IT WAS A CHECK FOR TRANSACTION STATUS THEN WE REPORT THE STATUS TO THE  */
9408 /*NEW TC AND CONTINUE WITH THE NEXT OPERATION IN LQH.                        */
9409 /* ------------------------------------------------------------------------- */
9410     if (regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC) {
9411       jam();
9412       sendLqhTransconf(signal, LqhTransConf::Prepared);
9413       return;
9414     }//if
9415     break;
9416   case TcConnectionrec::LOG_COMMIT_WRITTEN_WAIT_SIGNAL:
9417   case TcConnectionrec::LOG_COMMIT_QUEUED_WAIT_SIGNAL:
9418     jam();
9419 /* ------------------------------------------------------------------------- */
9420 // We can only reach these states for multi-updates on a record in a transaction.
9421 // We know that at least one of those has received the COMMIT signal, thus we
9422 // declare us only prepared since we then receive the expected COMMIT signal.
9423 /* ------------------------------------------------------------------------- */
9424     ndbrequire(regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC);
9425     sendLqhTransconf(signal, LqhTransConf::Prepared);
9426     return;
9427   case TcConnectionrec::WAIT_TUPKEYINFO:
9428   case TcConnectionrec::WAIT_ATTR:
9429     jam();
9430 /* ------------------------------------------------------------------------- */
9431 /* WE ARE CURRENTLY WAITING FOR MORE INFORMATION. WE CAN START THE ABORT     */
9432 /* PROCESS IMMEDIATELY. THE KEYINFO AND ATTRINFO SIGNALS WILL BE DROPPED     */
9433 /* SINCE THE ABORT STATE WILL BE SET.                                        */
9434 /* ------------------------------------------------------------------------- */
9435     break;
9436   case TcConnectionrec::WAIT_TUP:
9437     jam();
9438 /* ------------------------------------------------------------------------- */
9439 // TUP is currently active. We have to wait for the TUPKEYREF or TUPKEYCONF
9440 // to arrive since we might otherwise jeopardise the local checkpoint
9441 // consistency in overload situations.
9442 /* ------------------------------------------------------------------------- */
9443     regTcPtr->transactionState = TcConnectionrec::WAIT_TUP_TO_ABORT;
9444     return;
9445   case TcConnectionrec::WAIT_ACC:
9446     jam();
9447     abortContinueAfterBlockedLab(signal);
9448     return;
9449     break;
9450   case TcConnectionrec::LOG_QUEUED:
9451     jam();
9452     remove_from_prepare_log_queue(signal, tcConnectptr);
9453     break;
9454   case TcConnectionrec::WAIT_AI_AFTER_ABORT:
9455     jam();
9456 /* ------------------------------------------------------------------------- */
9457 /* ABORT OF ACC AND TUP ALREADY COMPLETED. THIS STATE IS ONLY USED WHEN      */
9458 /* CREATING A NEW FRAGMENT.                                                  */
9459 /* ------------------------------------------------------------------------- */
9460     continueAbortLab(signal);
9461     return;
9462     break;
9463   case TcConnectionrec::WAIT_TUP_TO_ABORT:
9464   case TcConnectionrec::LOG_ABORT_QUEUED:
9465   case TcConnectionrec::WAIT_ACC_ABORT:
9466   case TcConnectionrec::ABORT_QUEUED:
9467     jam();
9468 /* ------------------------------------------------------------------------- */
9469 /*ABORT IS ALREADY ONGOING DUE TO SOME ERROR. WE HAVE ALREADY SET THE STATE  */
9470 /*OF THE ABORT SO THAT WE KNOW THAT TC EXPECTS A REPORT. WE CAN THUS SIMPLY  */
9471 /*EXIT.                                                                      */
9472 /* ------------------------------------------------------------------------- */
9473     return;
9474     break;
9475   case TcConnectionrec::WAIT_TUP_COMMIT:
9476   case TcConnectionrec::LOG_COMMIT_QUEUED:
9477   case TcConnectionrec::COMMIT_QUEUED:
9478     jam();
9479 /* ------------------------------------------------------------------------- */
9480 /*THIS IS ONLY AN ALLOWED STATE IF A DIRTY WRITE OR SIMPLE READ IS PERFORMED.*/
9481 /*IF WE ARE MERELY CHECKING THE TRANSACTION STATE IT IS ALSO AN ALLOWED STATE*/
9482 /* ------------------------------------------------------------------------- */
9483     if (regTcPtr->dirtyOp == ZTRUE) {
9484       jam();
9485 /* ------------------------------------------------------------------------- */
9486 /*COMPLETE THE DIRTY WRITE AND THEN REPORT COMPLETED BACK TO TC. SINCE IT IS */
9487 /*A DIRTY WRITE IT IS ALLOWED TO COMMIT EVEN IF THE TRANSACTION ABORTS.      */
9488 /* ------------------------------------------------------------------------- */
9489       return;
9490     }//if
9491     if (regTcPtr->opSimple) {
9492       jam();
9493 /* ------------------------------------------------------------------------- */
9494 /*A SIMPLE READ IS CURRENTLY RELEASING THE LOCKS OR WAITING FOR ACCESS TO    */
9495 /*ACC TO CLEAR THE LOCKS. COMPLETE THIS PROCESS AND THEN RETURN AS NORMAL.   */
9496 /*NO DATA HAS CHANGED DUE TO THIS SIMPLE READ ANYWAY.                        */
9497 /* ------------------------------------------------------------------------- */
9498       return;
9499     }//if
9500     ndbrequire(regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC);
9501     jam();
9502 /* ------------------------------------------------------------------------- */
9503 /*WE ARE ONLY CHECKING THE STATUS OF THE TRANSACTION. IT IS COMMITTING.      */
9504 /*COMPLETE THE COMMIT LOCALLY AND THEN SEND REPORT OF COMMITTED TO THE NEW TC*/
9505 /* ------------------------------------------------------------------------- */
9506     sendLqhTransconf(signal, LqhTransConf::Committed);
9507     return;
9508     break;
9509   case TcConnectionrec::COMMITTED:
9510     jam();
9511     ndbrequire(regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC);
9512 /* ------------------------------------------------------------------------- */
9513 /*WE ARE CHECKING TRANSACTION STATUS. REPORT COMMITTED AND CONTINUE WITH THE */
9514 /*NEXT OPERATION.                                                            */
9515 /* ------------------------------------------------------------------------- */
9516     sendLqhTransconf(signal, LqhTransConf::Committed);
9517     return;
9518     break;
9519   default:
9520     ndbrequire(false);
9521 /* ------------------------------------------------------------------------- */
9522 /*THE STATE WAS NOT AN ALLOWED STATE ON A NORMAL OPERATION. SCANS AND COPY   */
9523 /*FRAGMENT OPERATIONS SHOULD HAVE EXECUTED IN ANOTHER PATH.                  */
9524 /* ------------------------------------------------------------------------- */
9525     break;
9526   }//switch
9527   abortCommonLab(signal);
9528   return;
9529 }//Dblqh::abortStateHandlerLab()
9530 
abortErrorLab(Signal * signal)9531 void Dblqh::abortErrorLab(Signal* signal)
9532 {
9533   ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
9534   TcConnectionrec * const regTcPtr = tcConnectptr.p;
9535   if (regTcPtr->abortState == TcConnectionrec::ABORT_IDLE) {
9536     jam();
9537     regTcPtr->abortState = TcConnectionrec::ABORT_FROM_LQH;
9538     regTcPtr->errorCode = terrorCode;
9539   }//if
9540   abortCommonLab(signal);
9541   return;
9542 }//Dblqh::abortErrorLab()
9543 
abortCommonLab(Signal * signal)9544 void Dblqh::abortCommonLab(Signal* signal)
9545 {
9546   TcConnectionrec * const regTcPtr = tcConnectptr.p;
9547   const Uint32 activeCreat = regTcPtr->activeCreat;
9548 
9549   remove_commit_marker(regTcPtr);
9550 
9551   if (unlikely(activeCreat == Fragrecord::AC_NR_COPY))
9552   {
9553     jam();
9554     if (regTcPtr->m_nr_delete.m_cnt)
9555     {
9556       jam();
9557       /**
9558        * Let operation wait for pending NR operations
9559        */
9560 
9561 #ifdef VM_TRACE
9562       /**
9563        * Only disk table can have pending ops...
9564        */
9565       TablerecPtr tablePtr;
9566       tablePtr.i = regTcPtr->tableref;
9567       ptrCheckGuard(tablePtr, ctabrecFileSize, tablerec);
9568       ndbrequire(tablePtr.p->m_disk_table);
9569 #endif
9570       return;
9571     }
9572   }
9573 
9574   fragptr.i = regTcPtr->fragmentptr;
9575   if (fragptr.i != RNIL) {
9576     jam();
9577     c_fragment_pool.getPtr(fragptr);
9578     switch (fragptr.p->fragStatus) {
9579     case Fragrecord::FSACTIVE:
9580     case Fragrecord::CRASH_RECOVERING:
9581     case Fragrecord::ACTIVE_CREATION:
9582       abortContinueAfterBlockedLab(signal);
9583       return;
9584       break;
9585     case Fragrecord::FREE:
9586       jam();
9587     case Fragrecord::DEFINED:
9588       jam();
9589     case Fragrecord::REMOVING:
9590       jam();
9591     default:
9592       ndbrequire(false);
9593       break;
9594     }//switch
9595   } else {
9596     jam();
9597     continueAbortLab(signal);
9598   }//if
9599 }//Dblqh::abortCommonLab()
9600 
abortContinueAfterBlockedLab(Signal * signal)9601 void Dblqh::abortContinueAfterBlockedLab(Signal* signal)
9602 {
9603   /* ------------------------------------------------------------------------
9604    *       INPUT:          TC_CONNECTPTR           ACTIVE OPERATION RECORD
9605    * ------------------------------------------------------------------------
9606    * ------------------------------------------------------------------------
9607    *       CAN COME HERE AS RESTART AFTER BEING BLOCKED BY A LOCAL CHECKPOINT.
9608    * ------------------------------------------------------------------------
9609    *       ALSO AS PART OF A NORMAL ABORT WITHOUT BLOCKING.
9610    *       WE MUST ABORT TUP BEFORE ACC TO ENSURE THAT NO ONE RACES IN
9611    *       AND SEES A STATE IN TUP.
9612    * ----------------------------------------------------------------------- */
9613   TcConnectionrec * const regTcPtr = tcConnectptr.p;
9614 
9615   TRACE_OP(regTcPtr, "ACC ABORT");
9616   Uint32 canBlock = 2; // 2, block if needed
9617   switch(regTcPtr->transactionState){
9618   case TcConnectionrec::WAIT_TUP:
9619     jam();
9620     /**
9621      * This is when getting from execTUPKEYREF
9622      *   in which case we *do* have ACC lock
9623      *   and should not (need to) block
9624      */
9625     canBlock = 0;
9626     break;
9627   default:
9628     break;
9629   }
9630 
9631   regTcPtr->transactionState = TcConnectionrec::WAIT_ACC_ABORT;
9632   signal->theData[0] = regTcPtr->accConnectrec;
9633   signal->theData[1] = canBlock;
9634   EXECUTE_DIRECT(DBACC, GSN_ACC_ABORTREQ, signal, 2);
9635 
9636   if (signal->theData[1] == RNIL)
9637   {
9638     jam();
9639     /* ------------------------------------------------------------------------
9640      * We need to insert a real-time break by sending ACC_ABORTCONF through the
9641      * job buffer to ensure that we catch any ACCKEYCONF or TUPKEYCONF or
9642      * TUPKEYREF that are in the job buffer but not yet processed. Doing
9643      * everything without that would race and create a state error when they
9644      * are executed.
9645      * --------------------------------------------------------------------- */
9646     return;
9647   }
9648 
9649   execACC_ABORTCONF(signal);
9650   return;
9651 }//Dblqh::abortContinueAfterBlockedLab()
9652 
9653 /* ******************>> */
9654 /*  ACC_ABORTCONF     > */
9655 /* ******************>> */
execACC_ABORTCONF(Signal * signal)9656 void Dblqh::execACC_ABORTCONF(Signal* signal)
9657 {
9658   jamEntry();
9659   tcConnectptr.i = signal->theData[0];
9660   ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
9661   TcConnectionrec * const regTcPtr = tcConnectptr.p;
9662   ndbrequire(regTcPtr->transactionState == TcConnectionrec::WAIT_ACC_ABORT);
9663 
9664   TRACE_OP(regTcPtr, "ACC_ABORTCONF");
9665   signal->theData[0] = regTcPtr->tupConnectrec;
9666   EXECUTE_DIRECT(DBTUP, GSN_TUP_ABORTREQ, signal, 1);
9667 
9668   jamEntry();
9669   continueAbortLab(signal);
9670   return;
9671 }//Dblqh::execACC_ABORTCONF()
9672 
continueAbortLab(Signal * signal)9673 void Dblqh::continueAbortLab(Signal* signal)
9674 {
9675   TcConnectionrec * const regTcPtr = tcConnectptr.p;
9676   /* ------------------------------------------------------------------------
9677    *  AN ERROR OCCURED IN THE ACTIVE CREATION AFTER THE ABORT PHASE.
9678    *  WE NEED TO CONTINUE WITH A NORMAL ABORT.
9679    * ------------------------------------------------------------------------
9680    *       ALSO USED FOR NORMAL CLEAN UP AFTER A NORMAL ABORT.
9681    * ------------------------------------------------------------------------
9682    *       ALSO USED WHEN NO FRAGMENT WAS SET UP ON OPERATION.
9683    * ------------------------------------------------------------------------ */
9684   if (regTcPtr->logWriteState == TcConnectionrec::WRITTEN) {
9685     jam();
9686     /* ----------------------------------------------------------------------
9687      * I NEED TO INSERT A ABORT LOG RECORD SINCE WE ARE WRITING LOG IN THIS
9688      * TRANSACTION.
9689      * ---------------------------------------------------------------------- */
9690     initLogPointers(signal);
9691     if (cnoOfLogPages == 0 ||
9692         !logPartPtr.p->m_log_complete_queue.isEmpty())
9693     {
9694       jam();
9695       /* --------------------------------------------------------------------
9696        * A PREPARE OPERATION IS CURRENTLY WRITING IN THE LOG.
9697        * WE MUST WAIT ON OUR TURN TO WRITE THE LOG.
9698        * IT IS NECESSARY TO WRITE ONE LOG RECORD COMPLETELY
9699        * AT A TIME OTHERWISE WE WILL SCRAMBLE THE LOG.
9700        * -------------------------------------------------------------------- */
9701       linkWaitLog(signal, logPartPtr, logPartPtr.p->m_log_complete_queue);
9702       regTcPtr->transactionState = TcConnectionrec::LOG_ABORT_QUEUED;
9703       return;
9704     }//if
9705     writeAbortLog(signal);
9706     removeLogTcrec(signal);
9707   } else if (regTcPtr->logWriteState == TcConnectionrec::NOT_STARTED) {
9708     jam();
9709   } else if (regTcPtr->logWriteState == TcConnectionrec::NOT_WRITTEN) {
9710     jam();
9711     /* ------------------------------------------------------------------
9712      * IT IS A READ OPERATION OR OTHER OPERATION THAT DO NOT USE THE LOG.
9713      * ------------------------------------------------------------------ */
9714     /* ------------------------------------------------------------------
9715      * THE LOG HAS NOT BEEN WRITTEN SINCE THE LOG FLAG WAS FALSE.
9716      * THIS CAN OCCUR WHEN WE ARE STARTING A NEW FRAGMENT.
9717      * ------------------------------------------------------------------ */
9718     regTcPtr->logWriteState = TcConnectionrec::NOT_STARTED;
9719   } else {
9720     ndbrequire(regTcPtr->logWriteState == TcConnectionrec::NOT_WRITTEN_WAIT);
9721     jam();
9722     /* ----------------------------------------------------------------
9723      * THE STATE WAS SET TO NOT_WRITTEN BY THE OPERATION BUT LATER
9724      * A SCAN OF ALL OPERATION RECORD CHANGED IT INTO NOT_WRITTEN_WAIT.
9725      * THIS INDICATES THAT WE ARE WAITING FOR THIS OPERATION TO COMMIT
9726      * OR ABORT SO THAT WE CAN FIND THE
9727      * STARTING GLOBAL CHECKPOINT OF THIS NEW FRAGMENT.
9728      * ---------------------------------------------------------------- */
9729      checkScanTcCompleted(signal);
9730   }//if
9731   continueAfterLogAbortWriteLab(signal);
9732   return;
9733 }//Dblqh::continueAbortLab()
9734 
continueAfterLogAbortWriteLab(Signal * signal)9735 void Dblqh::continueAfterLogAbortWriteLab(Signal* signal)
9736 {
9737   TcConnectionrec * const regTcPtr = tcConnectptr.p;
9738   bool normalProtocol = (regTcPtr->m_flags &
9739                          TcConnectionrec::OP_NORMAL_PROTOCOL);
9740 
9741   remove_commit_marker(regTcPtr);
9742 
9743   if (regTcPtr->operation == ZREAD && regTcPtr->dirtyOp &&
9744       !normalProtocol)
9745   {
9746     jam();
9747     TcKeyRef * const tcKeyRef = (TcKeyRef *) signal->getDataPtrSend();
9748 
9749     tcKeyRef->connectPtr = regTcPtr->applOprec;
9750     tcKeyRef->transId[0] = regTcPtr->transid[0];
9751     tcKeyRef->transId[1] = regTcPtr->transid[1];
9752     tcKeyRef->errorCode = regTcPtr->errorCode;
9753     sendTCKEYREF(signal, regTcPtr->applRef, regTcPtr->tcBlockref, 0);
9754     cleanUp(signal);
9755     return;
9756   }//if
9757   if (regTcPtr->abortState == TcConnectionrec::ABORT_FROM_LQH) {
9758     LqhKeyRef * const lqhKeyRef = (LqhKeyRef *)signal->getDataPtrSend();
9759 
9760     jam();
9761     lqhKeyRef->userRef = regTcPtr->clientConnectrec;
9762     lqhKeyRef->connectPtr = regTcPtr->tcOprec;
9763     lqhKeyRef->errorCode = regTcPtr->errorCode;
9764     lqhKeyRef->transId1 = regTcPtr->transid[0];
9765     lqhKeyRef->transId2 = regTcPtr->transid[1];
9766     sendSignal(regTcPtr->clientBlockref, GSN_LQHKEYREF, signal,
9767                LqhKeyRef::SignalLength, JBB);
9768   } else if (regTcPtr->abortState == TcConnectionrec::ABORT_FROM_TC) {
9769     jam();
9770     sendAborted(signal);
9771   } else if (regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC) {
9772     jam();
9773     sendLqhTransconf(signal, LqhTransConf::Aborted);
9774   } else {
9775     ndbrequire(regTcPtr->abortState == TcConnectionrec::REQ_FROM_TC);
9776     jam();
9777     signal->theData[0] = regTcPtr->reqRef;
9778     signal->theData[1] = tcConnectptr.i;
9779     signal->theData[2] = cownNodeid;
9780     signal->theData[3] = regTcPtr->transid[0];
9781     signal->theData[4] = regTcPtr->transid[1];
9782     sendSignal(regTcPtr->reqBlockref, GSN_ABORTCONF,
9783                signal, 5, JBB);
9784   }//if
9785   cleanUp(signal);
9786 }//Dblqh::continueAfterLogAbortWriteLab()
9787 
9788 void
sendTCKEYREF(Signal * signal,Uint32 ref,Uint32 routeRef,Uint32 cnt)9789 Dblqh::sendTCKEYREF(Signal* signal, Uint32 ref, Uint32 routeRef, Uint32 cnt)
9790 {
9791   const Uint32 nodeId = refToNode(ref);
9792   const bool connectedToNode = getNodeInfo(nodeId).m_connected;
9793   /**
9794    * ROUTE_ORD signals should not be sent via SPJ as it does not handle these
9795    * and (unlike TC) may not be connected to the API anyway.
9796    */
9797   ndbrequire(routeRef == 0 ||
9798              nodeId == getOwnNodeId() ||
9799              refToMain(routeRef) == DBTC);
9800 
9801   if (likely(connectedToNode &&
9802              !ERROR_INSERTED_CLEAR(5079)))
9803   {
9804     jam();
9805     sendSignal(ref, GSN_TCKEYREF, signal, TcKeyRef::SignalLength, JBB);
9806   }
9807   else
9808   {
9809     if (routeRef &&
9810 	getNodeInfo(refToNode(routeRef)).m_version >= MAKE_VERSION(5,1,14))
9811     {
9812       jam();
9813       memmove(signal->theData+25, signal->theData, 4*TcKeyRef::SignalLength);
9814       RouteOrd* ord = (RouteOrd*)signal->getDataPtrSend();
9815       ord->dstRef = ref;
9816       ord->srcRef = reference();
9817       ord->gsn = GSN_TCKEYREF;
9818       ord->cnt = 0;
9819       LinearSectionPtr ptr[3];
9820       ptr[0].p = signal->theData+25;
9821       ptr[0].sz = TcKeyRef::SignalLength;
9822       sendSignal(routeRef, GSN_ROUTE_ORD, signal, RouteOrd::SignalLength, JBB,
9823 		 ptr, 1);
9824     }
9825     else
9826     {
9827       jam();
9828       memmove(signal->theData + 3, signal->theData, 4*TcKeyRef::SignalLength);
9829       signal->theData[0] = ZRETRY_TCKEYREF;
9830       signal->theData[1] = cnt + 1;
9831       signal->theData[2] = ref;
9832       sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 100,
9833 			  TcKeyRef::SignalLength + 3);
9834     }
9835   }
9836 }
9837 
9838 /* ##########################################################################
9839  * #######                       MODULE TO HANDLE TC FAILURE          #######
9840  *
9841  * ########################################################################## */
9842 
9843 /* ************************************************************************>>
9844  *  NODE_FAILREP: Node failure report. Sender Ndbcntr. Set status of failed
9845  *  node to down and reply with NF_COMPLETEREP to DIH which will report that
9846  *  LQH has completed failure handling.
9847  * ************************************************************************>> */
execNODE_FAILREP(Signal * signal)9848 void Dblqh::execNODE_FAILREP(Signal* signal)
9849 {
9850   UintR TfoundNodes = 0;
9851   UintR TnoOfNodes;
9852   UintR Tdata[MAX_NDB_NODES];
9853   Uint32 i;
9854 
9855   NodeFailRep * const nodeFail = (NodeFailRep *)&signal->theData[0];
9856 
9857   TnoOfNodes = nodeFail->noOfNodes;
9858   UintR index = 0;
9859   for (i = 1; i < MAX_NDB_NODES; i++) {
9860     jam();
9861     if(NdbNodeBitmask::get(nodeFail->theNodes, i)){
9862       jam();
9863       Tdata[index] = i;
9864       index++;
9865     }//if
9866   }//for
9867 
9868 #ifdef ERROR_INSERT
9869   c_master_node_id = nodeFail->masterNodeId;
9870 #endif
9871 
9872   lcpPtr.i = 0;
9873   ptrAss(lcpPtr, lcpRecord);
9874 
9875   ndbrequire(index == TnoOfNodes);
9876   ndbrequire(cnoOfNodes - 1 < MAX_NDB_NODES);
9877   for (i = 0; i < TnoOfNodes; i++) {
9878     const Uint32 nodeId = Tdata[i];
9879 
9880     {
9881       HostRecordPtr Thostptr;
9882       Thostptr.i = nodeId;
9883       ptrCheckGuard(Thostptr, chostFileSize, hostRecord);
9884       Thostptr.p->nodestatus = ZNODE_DOWN;
9885     }
9886 
9887     lcpPtr.p->m_EMPTY_LCP_REQ.clear(nodeId);
9888 
9889     for (Uint32 j = 0; j < cnoOfNodes; j++) {
9890       jam();
9891       if (cnodeData[j] == nodeId){
9892         jam();
9893         cnodeStatus[j] = ZNODE_DOWN;
9894 
9895         TfoundNodes++;
9896       }//if
9897     }//for
9898 
9899     /* Perform block-level ndbd failure handling */
9900     Callback cb = { safe_cast(&Dblqh::ndbdFailBlockCleanupCallback),
9901                     Tdata[i] };
9902     simBlockNodeFailure(signal, Tdata[i], cb);
9903   }//for
9904   ndbrequire(TnoOfNodes == TfoundNodes);
9905 }//Dblqh::execNODE_FAILREP()
9906 
9907 
9908 void
ndbdFailBlockCleanupCallback(Signal * signal,Uint32 failedNodeId,Uint32 ignoredRc)9909 Dblqh::ndbdFailBlockCleanupCallback(Signal* signal,
9910                                     Uint32 failedNodeId,
9911                                     Uint32 ignoredRc)
9912 {
9913   jamEntry();
9914 
9915   NFCompleteRep * const nfCompRep = (NFCompleteRep *)&signal->theData[0];
9916   nfCompRep->blockNo      = DBLQH;
9917   nfCompRep->nodeId       = cownNodeid;
9918   nfCompRep->failedNodeId = failedNodeId;
9919   BlockReference dihRef = !isNdbMtLqh() ? DBDIH_REF : DBLQH_REF;
9920   sendSignal(dihRef, GSN_NF_COMPLETEREP, signal,
9921              NFCompleteRep::SignalLength, JBB);
9922 }
9923 
9924 /* ************************************************************************>>
9925  *  LQH_TRANSREQ: Report status of all transactions where TC was coordinated
9926  *  by a crashed TC
9927  * ************************************************************************>> */
9928 /* ************************************************************************>>
9929  *  THIS SIGNAL IS RECEIVED AFTER A NODE CRASH.
9930  *  THE NODE HAD A TC AND COORDINATED A NUMBER OF TRANSACTIONS.
9931  *  NOW THE MASTER NODE IS PICKING UP THOSE TRANSACTIONS
9932  *  TO COMPLETE THEM. EITHER ABORT THEM OR COMMIT THEM.
9933  * ************************************************************************>> */
execLQH_TRANSREQ(Signal * signal)9934 void Dblqh::execLQH_TRANSREQ(Signal* signal)
9935 {
9936   jamEntry();
9937 
9938   if (!checkNodeFailSequence(signal))
9939   {
9940     jam();
9941     return;
9942   }
9943   LqhTransReq * const lqhTransReq = (LqhTransReq *)&signal->theData[0];
9944   Uint32 newTcPtr = lqhTransReq->senderData;
9945   BlockReference newTcBlockref = lqhTransReq->senderRef;
9946   Uint32 oldNodeId = lqhTransReq->failedNodeId;
9947   Uint32 instanceId = lqhTransReq->instanceId;
9948   if (signal->getLength() < LqhTransReq::SignalLength)
9949   {
9950     /**
9951      * TC that performs take over doesn't suppport taking over one
9952      * TC instance at a time => we read an unitialised variable,
9953      * set it to RNIL to indicate we try take over all instances.
9954      * This code is really only needed in ndbd since ndbmtd handles
9955      * it also in LQH proxy.
9956      */
9957     instanceId = RNIL;
9958   }
9959   TcNodeFailRecordPtr tcNodeFailPtr;
9960   tcNodeFailPtr.i = oldNodeId;
9961   ptrCheckGuard(tcNodeFailPtr, ctcNodeFailrecFileSize, tcNodeFailRecord);
9962   if ((tcNodeFailPtr.p->tcFailStatus == TcNodeFailRecord::TC_STATE_TRUE) ||
9963       (tcNodeFailPtr.p->tcFailStatus == TcNodeFailRecord::TC_STATE_BREAK)) {
9964     jam();
9965     tcNodeFailPtr.p->lastNewTcBlockref = newTcBlockref;
9966   /* ------------------------------------------------------------------------
9967    * WE HAVE RECEIVED A SIGNAL SPECIFYING THAT WE NEED TO HANDLE THE FAILURE
9968    * OF A TC.  NOW WE RECEIVE ANOTHER SIGNAL WITH THE SAME ORDER. THIS CAN
9969    * OCCUR IF THE NEW TC FAILS. WE MUST BE CAREFUL IN THIS CASE SO THAT WE DO
9970    * NOT START PARALLEL ACTIVITIES TRYING TO DO THE SAME THING. WE SAVE THE
9971    * NEW BLOCK REFERENCE TO THE LAST NEW TC IN A VARIABLE AND ASSIGN TO IT TO
9972    * NEW_TC_BLOCKREF WHEN THE OLD PROCESS RETURNS TO LQH_TRANS_NEXT. IT IS
9973    * CERTAIN TO COME THERE SINCE THIS IS THE ONLY PATH TO TAKE CARE OF THE
9974    * NEXT TC CONNECT RECORD. WE SET THE STATUS TO BREAK TO INDICATE TO THE OLD
9975    * PROCESS WHAT IS HAPPENING.
9976    * ------------------------------------------------------------------------ */
9977     tcNodeFailPtr.p->lastNewTcRef = newTcPtr;
9978     tcNodeFailPtr.p->lastTakeOverInstanceId = instanceId;
9979     tcNodeFailPtr.p->tcFailStatus = TcNodeFailRecord::TC_STATE_BREAK;
9980     return;
9981   }//if
9982   tcNodeFailPtr.p->oldNodeId = oldNodeId;
9983   tcNodeFailPtr.p->newTcBlockref = newTcBlockref;
9984   tcNodeFailPtr.p->newTcRef = newTcPtr;
9985   tcNodeFailPtr.p->takeOverInstanceId = instanceId;
9986   tcNodeFailPtr.p->maxInstanceId = 0;
9987   tcNodeFailPtr.p->tcRecNow = 0;
9988   tcNodeFailPtr.p->tcFailStatus = TcNodeFailRecord::TC_STATE_TRUE;
9989   signal->theData[0] = ZLQH_TRANS_NEXT;
9990   signal->theData[1] = tcNodeFailPtr.i;
9991   sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
9992   return;
9993 }//Dblqh::execLQH_TRANSREQ()
9994 
9995 bool
check_tc_and_update_max_instance(BlockReference ref,TcNodeFailRecord * tcNodeFailPtr)9996 Dblqh::check_tc_and_update_max_instance(BlockReference ref,
9997                                         TcNodeFailRecord *tcNodeFailPtr)
9998 {
9999   if (refToNode(ref) == tcNodeFailPtr->oldNodeId)
10000   {
10001     jam();
10002     Uint32 instanceId = refToInstance(ref);
10003     if (instanceId > tcNodeFailPtr->maxInstanceId)
10004     {
10005       /**
10006        * Inform take over TC instance about the maximum instance id
10007        * such that the TC instance knows when to stop the take over
10008        * process.
10009        */
10010       tcNodeFailPtr->maxInstanceId = instanceId;
10011     }
10012     if ((tcNodeFailPtr->takeOverInstanceId == RNIL) ||
10013         (instanceId == tcNodeFailPtr->takeOverInstanceId))
10014     {
10015       jam();
10016       return true;
10017     }
10018   }
10019   jam();
10020   return false;
10021 }
10022 
lqhTransNextLab(Signal * signal,TcNodeFailRecordPtr tcNodeFailPtr)10023 void Dblqh::lqhTransNextLab(Signal* signal,
10024                             TcNodeFailRecordPtr tcNodeFailPtr)
10025 {
10026   UintR tend;
10027   UintR tstart;
10028   UintR guard0;
10029 
10030   if (tcNodeFailPtr.p->tcFailStatus == TcNodeFailRecord::TC_STATE_BREAK) {
10031     jam();
10032     /* ----------------------------------------------------------------------
10033      *  AN INTERRUPTION TO THIS NODE FAIL HANDLING WAS RECEIVED AND A NEW
10034      *  TC HAVE BEEN ASSIGNED TO TAKE OVER THE FAILED TC. PROBABLY THE OLD
10035      *  NEW TC HAVE FAILED.
10036      * ---------------------------------------------------------------------- */
10037     tcNodeFailPtr.p->newTcBlockref = tcNodeFailPtr.p->lastNewTcBlockref;
10038     tcNodeFailPtr.p->newTcRef = tcNodeFailPtr.p->lastNewTcRef;
10039     tcNodeFailPtr.p->takeOverInstanceId =
10040       tcNodeFailPtr.p->lastTakeOverInstanceId;
10041     tcNodeFailPtr.p->maxInstanceId = 0;
10042     tcNodeFailPtr.p->tcRecNow = 0;
10043     tcNodeFailPtr.p->tcFailStatus = TcNodeFailRecord::TC_STATE_TRUE;
10044   }//if
10045   tstart = tcNodeFailPtr.p->tcRecNow;
10046   tend = tstart + 200;
10047   guard0 = tend;
10048   for (tcConnectptr.i = tstart; tcConnectptr.i <= guard0; tcConnectptr.i++) {
10049     jam();
10050     if (tcConnectptr.i >= ctcConnectrecFileSize) {
10051       jam();
10052       /**
10053        * Finished with scanning operation record
10054        *
10055        * now scan markers
10056        */
10057 #ifdef ERROR_INSERT
10058       if (ERROR_INSERTED(5061))
10059       {
10060         CLEAR_ERROR_INSERT_VALUE;
10061         for (Uint32 i = 0; i < cnoOfNodes; i++)
10062         {
10063           Uint32 node = cnodeData[i];
10064           if (node != getOwnNodeId() && cnodeStatus[i] == ZNODE_UP)
10065           {
10066             ndbout_c("clearing ERROR_INSERT in LQH:%u", node);
10067             signal->theData[0] = 0;
10068             sendSignal(numberToRef(DBLQH, node), GSN_NDB_TAMPER,
10069                        signal, 1, JBB);
10070           }
10071         }
10072 
10073         signal->theData[0] = ZSCAN_MARKERS;
10074         signal->theData[1] = tcNodeFailPtr.i;
10075         signal->theData[2] = 0;
10076         signal->theData[3] = RNIL;
10077         sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 5000, 4);
10078         return;
10079       }
10080 
10081       if (ERROR_INSERTED(5050))
10082       {
10083         ndbout_c("send ZSCAN_MARKERS with 5s delay and killing master: %u",
10084                  c_master_node_id);
10085         CLEAR_ERROR_INSERT_VALUE;
10086         signal->theData[0] = ZSCAN_MARKERS;
10087         signal->theData[1] = tcNodeFailPtr.i;
10088         signal->theData[2] = 0;
10089         signal->theData[3] = RNIL;
10090         sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 5000, 4);
10091 
10092         signal->theData[0] = 9999;
10093         sendSignal(numberToRef(CMVMI, c_error_insert_extra),
10094                    GSN_NDB_TAMPER, signal, 1, JBB);
10095         return;
10096       }
10097 #endif
10098       scanMarkers(signal, tcNodeFailPtr.i, 0, RNIL);
10099       return;
10100     }//if
10101     ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
10102     if (tcConnectptr.p->transactionState != TcConnectionrec::IDLE)
10103     {
10104       if (tcConnectptr.p->transactionState !=
10105           TcConnectionrec::TC_NOT_CONNECTED)
10106       {
10107         if (tcConnectptr.p->tcScanRec == RNIL)
10108         {
10109           if (check_tc_and_update_max_instance(tcConnectptr.p->tcBlockref,
10110                                                tcNodeFailPtr.p))
10111           {
10112             /**
10113              * We send the take over message only for operations that belong
10114              * to the failed node and also are part of the TC instance that
10115              * we are currently taking over, instanceId == RNIL means that the
10116              * signal came from an old version that didn't support multi-TC
10117              * instance take over. In this case we try to take over all
10118              * instances in one go.
10119              */
10120             switch( tcConnectptr.p->operation )
10121             {
10122             case ZUNLOCK :
10123               jam(); /* Skip over */
10124               break;
10125             case ZREAD :
10126               jam();
10127               if (tcConnectptr.p->opSimple == ZTRUE)
10128               {
10129                 jam();
10130                 break; /* Skip over */
10131               }
10132               /* Fall through */
10133             default :
10134               jam();
10135               tcConnectptr.p->tcNodeFailrec = tcNodeFailPtr.i;
10136               tcConnectptr.p->abortState = TcConnectionrec::NEW_FROM_TC;
10137               abortStateHandlerLab(signal);
10138               return;
10139             } // switch
10140           }
10141         } else {
10142           /**
10143            * Scans don't require any keeping of state in TC that takes
10144            * over, thus we need not handle scans one instance at a time.
10145            * We can handle all scans immediately. The same goes for copy
10146            * operations since we can have a very limited number of copy
10147            * operations ongoing in parallel.
10148            */
10149           scanptr.i = tcConnectptr.p->tcScanRec;
10150 	  c_scanRecordPool.getPtr(scanptr);
10151 	  switch(scanptr.p->scanType){
10152 	  case ScanRecord::COPY:
10153 	  {
10154             jam();
10155             if (scanptr.p->scanNodeId == tcNodeFailPtr.p->oldNodeId) {
10156               jam();
10157 	      /* ------------------------------------------------------------
10158 	       * THE RECEIVER OF THE COPY HAVE FAILED.
10159 	       * WE HAVE TO CLOSE THE COPY PROCESS.
10160 	       * ----------------------------------------------------------- */
10161 	      if (0) ndbout_c("close copy");
10162               tcConnectptr.p->tcNodeFailrec = tcNodeFailPtr.i;
10163               tcConnectptr.p->abortState = TcConnectionrec::NEW_FROM_TC;
10164               closeCopyRequestLab(signal);
10165               return;
10166             }
10167 	    break;
10168 	  }
10169 	  case ScanRecord::SCAN:
10170 	  {
10171 	    jam();
10172 	    if (refToNode(tcConnectptr.p->tcBlockref) ==
10173 		tcNodeFailPtr.p->oldNodeId) {
10174 	      jam();
10175 	      tcConnectptr.p->tcNodeFailrec = tcNodeFailPtr.i;
10176 	      tcConnectptr.p->abortState = TcConnectionrec::NEW_FROM_TC;
10177 	      closeScanRequestLab(signal);
10178 	      return;
10179 	    }//if
10180 	    break;
10181 	  }
10182 	  default:
10183             ndbout_c("scanptr.p->scanType: %u", scanptr.p->scanType);
10184             ndbout_c("tcConnectptr.p->transactionState: %u",
10185                      tcConnectptr.p->transactionState);
10186 	    ndbrequire(false);
10187 	  }
10188         }
10189       }
10190       else
10191       {
10192 #if defined VM_TRACE || defined ERROR_INSERT
10193         jam();
10194         ndbrequire(tcConnectptr.p->tcScanRec == RNIL);
10195 #endif
10196       }
10197     }
10198     else
10199     {
10200 #if defined VM_TRACE || defined ERROR_INSERT
10201       jam();
10202       ndbrequire(tcConnectptr.p->tcScanRec == RNIL);
10203 #endif
10204     }
10205   }//for
10206   tcNodeFailPtr.p->tcRecNow = tend + 1;
10207   signal->theData[0] = ZLQH_TRANS_NEXT;
10208   signal->theData[1] = tcNodeFailPtr.i;
10209   sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
10210   return;
10211 }//Dblqh::lqhTransNextLab()
10212 
10213 void
scanMarkers(Signal * signal,Uint32 tcNodeFail,Uint32 startBucket,Uint32 i)10214 Dblqh::scanMarkers(Signal* signal,
10215 		   Uint32 tcNodeFail,
10216 		   Uint32 startBucket,
10217 		   Uint32 i){
10218 
10219   jam();
10220 
10221   TcNodeFailRecordPtr tcNodeFailPtr;
10222   tcNodeFailPtr.i = tcNodeFail;
10223   ptrCheckGuard(tcNodeFailPtr, ctcNodeFailrecFileSize, tcNodeFailRecord);
10224 
10225   if (tcNodeFailPtr.p->tcFailStatus == TcNodeFailRecord::TC_STATE_BREAK)
10226   {
10227     jam();
10228 
10229     /* ----------------------------------------------------------------------
10230      *  AN INTERRUPTION TO THIS NODE FAIL HANDLING WAS RECEIVED AND A NEW
10231      *  TC HAVE BEEN ASSIGNED TO TAKE OVER THE FAILED TC. PROBABLY THE OLD
10232      *  NEW TC HAVE FAILED.
10233      * ---------------------------------------------------------------------- */
10234     lqhTransNextLab(signal, tcNodeFailPtr);
10235     return;
10236   }
10237 
10238   CommitAckMarkerIterator iter;
10239   if(i == RNIL){
10240     m_commitAckMarkerHash.next(startBucket, iter);
10241   } else {
10242     jam();
10243     iter.curr.i = i;
10244     iter.bucket = startBucket;
10245     m_commitAckMarkerHash.getPtr(iter.curr);
10246     m_commitAckMarkerHash.next(iter);
10247   }
10248 
10249   const Uint32 RT_BREAK = 256;
10250   for(i = 0; i<RT_BREAK || iter.bucket == startBucket; i++){
10251     jam();
10252 
10253     if(iter.curr.i == RNIL){
10254       /**
10255        * Done with iteration
10256        */
10257       jam();
10258 
10259       tcNodeFailPtr.p->tcFailStatus = TcNodeFailRecord::TC_STATE_FALSE;
10260       LqhTransConf * const lqhTransConf = (LqhTransConf *)&signal->theData[0];
10261       lqhTransConf->tcRef     = tcNodeFailPtr.p->newTcRef;
10262       lqhTransConf->lqhNodeId = cownNodeid;
10263       lqhTransConf->operationStatus = LqhTransConf::LastTransConf;
10264       lqhTransConf->maxInstanceId = tcNodeFailPtr.p->maxInstanceId;
10265       sendSignal(tcNodeFailPtr.p->newTcBlockref, GSN_LQH_TRANSCONF,
10266 		 signal, LqhTransConf::SignalLength, JBB);
10267       return;
10268     }
10269     ndbrequire(iter.curr.p->in_hash);
10270     jam();
10271     if (check_tc_and_update_max_instance(iter.curr.p->tcRef,
10272                                          tcNodeFailPtr.p))
10273     {
10274       jam();
10275 
10276       /**
10277        * Found marker belonging to crashed node and to instance currently
10278        * being handled.
10279        */
10280       LqhTransConf * const lqhTransConf = (LqhTransConf *)&signal->theData[0];
10281       lqhTransConf->tcRef     = tcNodeFailPtr.p->newTcRef;
10282       lqhTransConf->lqhNodeId = cownNodeid;
10283       lqhTransConf->operationStatus = LqhTransConf::Marker;
10284       lqhTransConf->transId1 = iter.curr.p->transid1;
10285       lqhTransConf->transId2 = iter.curr.p->transid2;
10286       lqhTransConf->apiRef   = iter.curr.p->apiRef;
10287       lqhTransConf->apiOpRec = iter.curr.p->apiOprec;
10288       sendSignal(tcNodeFailPtr.p->newTcBlockref, GSN_LQH_TRANSCONF,
10289 		 signal, 7, JBB);
10290 
10291       signal->theData[0] = ZSCAN_MARKERS;
10292       signal->theData[1] = tcNodeFailPtr.i;
10293       signal->theData[2] = iter.bucket;
10294       signal->theData[3] = iter.curr.i;
10295       sendSignal(cownref, GSN_CONTINUEB, signal, 4, JBB);
10296       return;
10297     }
10298     jam();
10299 
10300     m_commitAckMarkerHash.next(iter);
10301   }
10302 
10303   signal->theData[0] = ZSCAN_MARKERS;
10304   signal->theData[1] = tcNodeFailPtr.i;
10305   signal->theData[2] = iter.bucket;
10306   signal->theData[3] = RNIL;
10307   sendSignal(cownref, GSN_CONTINUEB, signal, 4, JBB);
10308 }
10309 
10310 /* #########################################################################
10311  * #######                       SCAN MODULE                         #######
10312  *
10313  * #########################################################################
10314  * -------------------------------------------------------------------------
10315  * THIS MODULE CONTAINS THE CODE THAT HANDLES A SCAN OF A PARTICULAR FRAGMENT
10316  * IT OPERATES UNDER THE CONTROL OF TC AND ORDERS ACC TO PERFORM A SCAN OF
10317  * ALL TUPLES IN THE FRAGMENT. TUP PERFORMS THE NECESSARY SEARCH CONDITIONS
10318  * TO ENSURE THAT ONLY VALID TUPLES ARE RETURNED TO THE APPLICATION.
10319  * ------------------------------------------------------------------------- */
10320 
10321 /**
10322  *  ACC_SCANCONF obsolete by usage of Direct Execute
10323  *
10324  *  Callee of ACC_SCANREQ will get return value in
10325  *  signal[8] and call accScanConf{Scan|Copy}Lab()
10326  *  directly if OK.
10327  */
10328 
get_is_scan_prioritised(Uint32 scan_ptr_i)10329 Uint32 Dblqh::get_is_scan_prioritised(Uint32 scan_ptr_i)
10330 {
10331   ScanRecordPtr scanPtr;
10332   scanPtr.i = scan_ptr_i;
10333   c_scanRecordPool.getPtr(scanPtr);
10334   return is_prioritised_scan(scanPtr.p->scanApiBlockref);
10335 }
10336 
10337 /* ************>> */
10338 /*  ACC_SCANREF > */
10339 /* ************>> */
execACC_SCANREF(Signal * signal)10340 void Dblqh::execACC_SCANREF(Signal* signal)
10341 {
10342   const AccScanRef refCopy = *(const AccScanRef*)signal->getDataPtr();
10343   const AccScanRef* ref = &refCopy;
10344   ndbrequire(ref->errorCode != 0);
10345 
10346   tcConnectptr.p->errorCode = ref->errorCode;
10347 
10348   /*
10349    * MRR scan can hit this between 2 DBTUX scans.  Previous range has
10350    * terminated via last NEXT_SCANCONF, then index is set to Dropping,
10351    * and then next range is started and returns ACC_SCANREF.
10352    */
10353   if (scanptr.p->scanStoredProcId != RNIL) {
10354     jam();
10355     scanptr.p->scanCompletedStatus = ZTRUE;
10356     accScanCloseConfLab(signal);
10357     return;
10358   }
10359   tupScanCloseConfLab(signal);
10360 }//Dblqh::execACC_SCANREF()
10361 
10362 Uint32
get_scan_api_op_ptr(Uint32 scan_api_ptr_i)10363 Dblqh::get_scan_api_op_ptr(Uint32 scan_api_ptr_i)
10364 {
10365   ScanRecordPtr scanPtr;
10366   scanPtr.i = scan_api_ptr_i;
10367   c_scanRecordPool.getPtr(scanPtr);
10368   return scanPtr.p->scanApiOpPtr;
10369 }
10370 
10371 /* ***************>> */
10372 /*  NEXT_SCANCONF  > */
10373 /* ***************>> */
execNEXT_SCANCONF(Signal * signal)10374 void Dblqh::execNEXT_SCANCONF(Signal* signal)
10375 {
10376   FragrecordPtr loc_fragptr;
10377   ScanRecordPtr loc_scanptr;
10378   TcConnectionrecPtr loc_tcConnectptr;
10379   NextScanConf * const nextScanConf = (NextScanConf *)&signal->theData[0];
10380   loc_scanptr.i = nextScanConf->scanPtr;
10381   const Uint32 pageNo = nextScanConf->localKey[0];
10382   const Uint32 pageIdx = nextScanConf->localKey[1];
10383   jamEntry();
10384   c_scanRecordPool.getPtr(loc_scanptr);
10385   ScanRecord * const scanPtr = loc_scanptr.p;
10386   scanptr = loc_scanptr;
10387   loc_fragptr.i = scanPtr->fragPtrI;
10388   loc_tcConnectptr.i = scanPtr->scanTcrec;
10389   scanPtr->m_row_id.m_page_idx = pageIdx;
10390   scanPtr->m_row_id.m_page_no = pageNo;
10391 
10392 #ifdef VM_TRACE
10393   if (signal->getLength() > 2 && nextScanConf->accOperationPtr != RNIL)
10394   {
10395     Ptr<TcConnectionrec> regTcPtr;
10396     regTcPtr.i = scanPtr->scanTcrec;
10397     ptrCheckGuard(regTcPtr, ctcConnectrecFileSize, tcConnectionrec);
10398     ndbassert(regTcPtr.p->fragmentid == nextScanConf->fragId);
10399   }
10400 #endif
10401 
10402   ScanRecord::ScanState scanState = scanPtr->scanState;
10403   c_fragment_pool.getPtr(loc_fragptr);
10404   ptrCheckGuard(loc_tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
10405   fragptr = loc_fragptr;
10406   tcConnectptr = loc_tcConnectptr;
10407   switch (scanState) {
10408   case ScanRecord::WAIT_CLOSE_SCAN:
10409     jam();
10410     accScanCloseConfLab(signal);
10411     break;
10412   case ScanRecord::WAIT_CLOSE_COPY:
10413     jam();
10414     accCopyCloseConfLab(signal);
10415     break;
10416   case ScanRecord::WAIT_NEXT_SCAN:
10417     nextScanConfScanLab(signal,
10418                         scanPtr,
10419                         loc_tcConnectptr.p,
10420                         nextScanConf->fragId,
10421                         nextScanConf->accOperationPtr);
10422     break;
10423   case ScanRecord::WAIT_NEXT_SCAN_COPY:
10424     jam();
10425     nextScanConfCopyLab(signal);
10426     break;
10427   default:
10428     ndbout_c("%d", scanptr.p->scanState);
10429     ndbrequire(false);
10430   }//switch
10431 }//Dblqh::execNEXT_SCANCONF()
10432 
10433 /* ***************> */
10434 /*  NEXT_SCANREF  > */
10435 /* ***************> */
execNEXT_SCANREF(Signal * signal)10436 void Dblqh::execNEXT_SCANREF(Signal* signal)
10437 {
10438   jamEntry();
10439   ndbrequire(refToMain(signal->getSendersBlockRef()) == DBTUX);
10440   const NextScanRef refCopy = *(const NextScanRef*)signal->getDataPtr();
10441   const NextScanRef* ref = &refCopy;
10442   ndbrequire(ref->errorCode != 0);
10443 
10444   scanptr.i = ref->scanPtr;
10445   c_scanRecordPool.getPtr(scanptr);
10446   tcConnectptr.i = scanptr.p->scanTcrec;
10447   ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
10448   tcConnectptr.p->errorCode = ref->errorCode;
10449 
10450   /*
10451    * MRR scan may have other ranges left.  But the scan has already
10452    * failed.  Terminate the scan now.
10453    */
10454   scanptr.p->scanCompletedStatus = ZTRUE;
10455   accScanCloseConfLab(signal);
10456 }//Dblqh::execNEXT_SCANREF()
10457 
10458 /* --------------------------------------------------------------------------
10459  *       ENTER SCAN_NEXTREQ
10460  * --------------------------------------------------------------------------
10461  *       PRECONDITION:
10462  *       TRANSACTION_STATE = SCAN_STATE
10463  *       SCAN_STATE = WAIT_SCAN_NEXTREQ
10464  *
10465  * Case scanLockHold: ZTRUE  = Unlock previous round of
10466  *                             scanned row(s) and fetch next set of rows.
10467  *                    ZFALSE = Fetch new set of rows.
10468  * Number of rows to read depends on parallelism and how many rows
10469  * left to scan in the fragment. SCAN_NEXTREQ can also be sent with
10470  * closeFlag == ZTRUE to close the scan.
10471  * ------------------------------------------------------------------------- */
execSCAN_NEXTREQ(Signal * signal)10472 void Dblqh::execSCAN_NEXTREQ(Signal* signal)
10473 {
10474   jamEntry();
10475   const ScanFragNextReq * const nextReq =
10476                                 (ScanFragNextReq*)&signal->theData[0];
10477   const Uint32 transid1 = nextReq->transId1;
10478   const Uint32 transid2 = nextReq->transId2;
10479   const Uint32 senderData = nextReq->senderData;
10480   Uint32 hashHi = signal->getSendersBlockRef();
10481   // bug#13834481 hashHi!=0 caused timeout (tx not found)
10482   const NodeInfo& senderInfo = getNodeInfo(refToNode(hashHi));
10483   if (unlikely(senderInfo.m_version < NDBD_LONG_SCANFRAGREQ))
10484     hashHi = 0;
10485 
10486   if (findTransaction(transid1, transid2, senderData, hashHi) != ZOK){
10487     jam();
10488     DEBUG(senderData <<
10489 	  " Received SCAN_NEXTREQ in LQH with close flag when closed");
10490     ndbrequire(ScanFragNextReq::getCloseFlag(nextReq->requestInfo));
10491     return;
10492   }
10493 
10494   // Crash node if signal sender is same node
10495   CRASH_INSERTION2(5021, refToNode(signal->senderBlockRef()) == cownNodeid);
10496   // Crash node if signal sender is NOT same node
10497   CRASH_INSERTION2(5022, refToNode(signal->senderBlockRef()) != cownNodeid);
10498 
10499   if (ERROR_INSERTED(5023)){
10500     // Drop signal if sender is same node
10501     if (refToNode(signal->senderBlockRef()) == cownNodeid) {
10502       CLEAR_ERROR_INSERT_VALUE;
10503       return;
10504     }
10505   }//if
10506   if (ERROR_INSERTED(5024)){
10507     // Drop signal if sender is NOT same node
10508     if (refToNode(signal->senderBlockRef()) != cownNodeid) {
10509       CLEAR_ERROR_INSERT_VALUE;
10510       return;
10511     }
10512   }//if
10513   if (ERROR_INSERTED(5025))
10514   {
10515     /**
10516      * This does not work as signal->getSendersBlockRef() is used
10517      *   as "hashHi"...not having a real data-word for this is not optimal
10518      *   but it will work...summary: disable this ERROR_INSERT
10519      */
10520     CLEAR_ERROR_INSERT_VALUE;
10521   }
10522 
10523   if (ERROR_INSERTED(5030)){
10524     ndbout << "ERROR 5030" << endl;
10525     CLEAR_ERROR_INSERT_VALUE;
10526     // Drop signal
10527     return;
10528   }//if
10529 
10530   if(ERROR_INSERTED(5036)){
10531     return;
10532   }
10533 
10534   Uint32 pos = 0;
10535   if (ScanFragNextReq::getCorrFactorFlag(nextReq->requestInfo))
10536   {
10537     jam();
10538     Uint32 corrFactorLo = nextReq->variableData[pos++];
10539     tcConnectptr.p->m_corrFactorLo &= 0xFFFF0000;
10540     tcConnectptr.p->m_corrFactorLo |= corrFactorLo;
10541   }
10542 
10543   scanptr.i = tcConnectptr.p->tcScanRec;
10544   ndbrequire(scanptr.i != RNIL);
10545   c_scanRecordPool.getPtr(scanptr);
10546   scanptr.p->scanTcWaiting = cLqhTimeOutCount;
10547 
10548   /* ------------------------------------------------------------------
10549    * If close flag is set this scan should be closed
10550    * If we are waiting for SCAN_NEXTREQ set flag to stop scanning and
10551    * continue execution else set flags and wait until the scan
10552    * completes itself
10553    * ------------------------------------------------------------------ */
10554   if (ScanFragNextReq::getCloseFlag(nextReq->requestInfo))
10555   {
10556     jam();
10557     if(ERROR_INSERTED(5034)){
10558       CLEAR_ERROR_INSERT_VALUE;
10559     }
10560     if(ERROR_INSERTED(5036)){
10561       CLEAR_ERROR_INSERT_VALUE;
10562       return;
10563     }
10564     closeScanRequestLab(signal);
10565     return;
10566   }//if
10567   scanptr.p->prioAFlag = ScanFragNextReq::getPrioAFlag(nextReq->requestInfo);
10568   scanptr.p->m_exec_direct_batch_size_words = 0;
10569 
10570   fragptr.i = tcConnectptr.p->fragmentptr;
10571   c_fragment_pool.getPtr(fragptr);
10572 
10573   ScanRecord * const scanPtr = scanptr.p;
10574   const Uint32 max_rows = nextReq->batch_size_rows;
10575   const Uint32 max_bytes = nextReq->batch_size_bytes;
10576   scanPtr->m_max_batch_size_bytes = max_bytes;
10577 
10578   {
10579     /**
10580      * To speed up drop table we check for table being dropped here.
10581      * This can speed up drop table by minutes, so even though it is
10582      * a small cost at every scan batch, it will provide us a much
10583      * more reliable time of execution for drop tables. Drop table
10584      * can also be delayed by user transactions. So we could potentially
10585      * make this check for all scan types. This will however require
10586      * user transactions to add checks for this error, this they should
10587      * however already have since it is checked at first SCAN_FRAGREQ.
10588      *
10589      * We don't need to worry about backups since they will take a lock
10590      * before they start, so this won't happen to a backup. No drop tables
10591      * can run concurrently with drop table. Also any ALTER TABLE activity
10592      * cannot run at the same time as a drop table, so this is also safe
10593      * for all sorts of table reorg scans. What remains is node recovery
10594      * scans to synchronize data.
10595      */
10596     TablerecPtr tabPtr;
10597     tabPtr.i = tcConnectptr.p->tableref;
10598     ptrCheckGuard(tabPtr, ctabrecFileSize, tablerec);
10599     if (unlikely(tabPtr.p->tableStatus != Tablerec::TABLE_DEFINED &&
10600                  tabPtr.p->tableStatus != Tablerec::TABLE_READ_ONLY))
10601     {
10602       tcConnectptr.p->errorCode = get_table_state_error(tabPtr);
10603       closeScanRequestLab(signal);
10604       return;
10605     }
10606   }
10607   if (max_rows > scanPtr->m_max_batch_size_rows)
10608   {
10609     jam();
10610     /**
10611      * Extend list...
10612      * Will never happen for LCP, Backup and NR.
10613      */
10614     ndbrequire(scanPtr->m_reserved == 0);
10615     if (!seize_acc_ptr_list(scanPtr,
10616                             scanPtr->m_max_batch_size_rows, max_rows))
10617     {
10618       jam();
10619       tcConnectptr.p->errorCode = ScanFragRef::ZTOO_MANY_ACTIVE_SCAN_ERROR;
10620       closeScanRequestLab(signal);
10621       return;
10622     }
10623     scanPtr->m_max_batch_size_rows = max_rows;
10624   }
10625   else if (unlikely(max_rows < scanPtr->m_max_batch_size_rows))
10626   {
10627     jam();
10628     scanPtr->m_max_batch_size_rows = max_rows;
10629   }
10630 
10631   /* --------------------------------------------------------------------
10632    * If scanLockHold = TRUE we need to unlock previous round of
10633    * scanned records.
10634    * scanReleaseLocks will set states for this and send a NEXT_SCANREQ.
10635    * When confirm signal NEXT_SCANCONF arrives we call
10636    * continueScanNextReqLab to continue scanning new rows and
10637    * acquiring new locks.
10638    * -------------------------------------------------------------------- */
10639   if ((scanPtr->scanLockHold == ZTRUE) &&
10640       (scanPtr->m_curr_batch_size_rows > 0)) {
10641     jam();
10642     scanPtr->scanReleaseCounter = 1;
10643     scanReleaseLocksLab(signal);
10644     return;
10645   }//if
10646 
10647   /* -----------------------------------------------------------------------
10648    * We end up here when scanLockHold = FALSE or no rows was locked from
10649    * previous round.
10650    * Simply continue scanning.
10651    * ----------------------------------------------------------------------- */
10652   continueScanNextReqLab(signal);
10653 }//Dblqh::execSCAN_NEXTREQ()
10654 
continueScanNextReqLab(Signal * signal)10655 void Dblqh::continueScanNextReqLab(Signal* signal)
10656 {
10657   ScanRecord * const scanPtr = scanptr.p;
10658   if (scanPtr->scanCompletedStatus == ZTRUE) {
10659     jam();
10660     closeScanLab(signal);
10661     return;
10662   }//if
10663 
10664   if(scanPtr->m_last_row){
10665     jam();
10666     scanPtr->scanCompletedStatus = ZTRUE;
10667     scanPtr->scanState = ScanRecord::WAIT_SCAN_NEXTREQ;
10668     sendScanFragConf(signal, ZFALSE);
10669     return;
10670   }
10671 
10672   // Update timer on tcConnectRecord
10673   tcConnectptr.p->tcTimer = cLqhTimeOutCount;
10674   init_acc_ptr_list(scanPtr);
10675   scanPtr->scanFlag = NextScanReq::ZSCAN_NEXT;
10676   scanNextLoopLab(signal);
10677 }//Dblqh::continueScanNextReqLab()
10678 
scanLockReleasedLab(Signal * signal)10679 void Dblqh::scanLockReleasedLab(Signal* signal)
10680 {
10681   ScanRecord * const scanPtr = scanptr.p;
10682   if (scanPtr->scanReleaseCounter == scanPtr->m_curr_batch_size_rows) {
10683     if ((scanPtr->scanErrorCounter > 0) ||
10684         (scanPtr->scanCompletedStatus == ZTRUE)) {
10685       jam();
10686       scanPtr->m_curr_batch_size_rows = 0;
10687       scanPtr->m_curr_batch_size_bytes = 0;
10688       closeScanLab(signal);
10689     } else if (scanPtr->m_last_row && !scanPtr->scanLockHold) {
10690       jam();
10691       closeScanLab(signal);
10692     } else if (scanPtr->check_scan_batch_completed() &&
10693                scanPtr->scanLockHold != ZTRUE) {
10694       jam();
10695       scanPtr->scanState = ScanRecord::WAIT_SCAN_NEXTREQ;
10696       sendScanFragConf(signal, ZFALSE);
10697     } else {
10698       jam();
10699       /*
10700        * We came here after releasing locks after
10701        * receiving SCAN_NEXTREQ from TC. We only come here
10702        * when scanHoldLock == ZTRUE
10703        */
10704       scanPtr->m_curr_batch_size_rows = 0;
10705       scanPtr->m_curr_batch_size_bytes = 0;
10706       continueScanNextReqLab(signal);
10707     }//if
10708   }
10709   else if (scanPtr->scanCompletedStatus != ZTRUE)
10710   {
10711     jam();
10712     /*
10713     We come here when we have been scanning for a long time and not been able
10714     to find m_max_batch_size_rows records to return. We needed to release
10715     the record we didn't want, but now we are returning all found records to
10716     the API.
10717     */
10718     scanPtr->scanState = ScanRecord::WAIT_SCAN_NEXTREQ;
10719     sendScanFragConf(signal, ZFALSE);
10720   }
10721   else
10722   {
10723     jam();
10724     closeScanLab(signal);
10725   }
10726   return;
10727 }//Dblqh::scanLockReleasedLab()
10728 
10729 /* -------------------------------------------------------------------------
10730  *       WE NEED TO RELEASE LOCKS BEFORE CONTINUING
10731  * ------------------------------------------------------------------------- */
scanReleaseLocksLab(Signal * signal)10732 void Dblqh::scanReleaseLocksLab(Signal* signal)
10733 {
10734   ScanRecord * const scanPtr = scanptr.p;
10735   ndbrequire(fragptr.p->fragStatus == Fragrecord::FSACTIVE);
10736   check_send_scan_hb_rep(signal, scanPtr, tcConnectptr.p);
10737   while (true)
10738   {
10739     const Uint32 sig1 =
10740       get_acc_ptr_from_scan_record(scanPtr,
10741                                    scanPtr->scanReleaseCounter-1,
10742                                    false);
10743     const Uint32 sig0 = scanPtr->scanAccPtr;
10744     SimulatedBlock *block = scanPtr->scanBlock;
10745     ExecFunction f = scanPtr->scanFunction_NEXT_SCANREQ;
10746 
10747     signal->theData[1] = sig1;
10748     signal->theData[2] = NextScanReq::ZSCAN_COMMIT;
10749     signal->theData[0] = sig0;
10750     /* EXECUTE_DIRECT optimised to NEXT_SCANREQ in TUP/ACC/TUX */
10751 
10752     /**
10753      * DESIGN PATTERN DESCRIPTION:
10754      * ---------------------------
10755      * When calling another block immediately there is a set of ways to
10756      * do this.
10757      *
10758      * Standard, non-optimised manner:
10759      * Use EXECUTE_DIRECT with four parameters that specify block reference
10760      * of receiver, the signal object, the global signal number and the
10761      * length of the signal (There is also a variant used when sending such
10762      * a signal to a different instance). This method is fairly optimised
10763      * but has quite a lot of potential for performance improvement.
10764      *
10765      * Standard, optimised manner:
10766      * In this case we optimise things by translating to block object and
10767      * retrieving the function pointer in the block call. This gives
10768      * the compiler assistance to separate the loads and stores more from
10769      * each other.
10770      * The call will be seen as:
10771      * block->EXECUTE_DIRECT(signal, f);
10772      *
10773      * This manner optimises the code but retains the flexibility and also
10774      * the possibility to trace signal execution between blocks.
10775      *
10776      * Non-standard, optimised manner:
10777      * In this case we remove some of the flexibility of the call to enhance
10778      * the performance yet a bit more. In this case we remove the possibility
10779      * for a flexible receiver of the signal, it is directed to a certain
10780      * block and we also call the method directly without any indirection.
10781      * The call will be seen as e.g.:
10782      * c_tup->execTUPKEYREQ(signal);
10783      *
10784      * The standard manner of calling EXECUTE_DIRECT are both always calling
10785      * functions with one parameter being the signal object and no return
10786      * value. There is however two ways of sending signals back. In some
10787      * cases a signal is always sent back when returning from the
10788      * EXECUTE_DIRECT call, in this case the signal object returned contains
10789      * a signal object with data for the return signal. In some cases
10790      * one gets a return signal in this manner by a combination of the signal
10791      * number and the parameters. In the example below with NEXT_SCANREQ
10792      * we always gets a return signal when specifying ZSCAN_COMMIT
10793      * but not in other cases.
10794      *
10795      * The other manner of sending a return signal is to perform a new
10796      * EXECUTE_DIRECT signal. In those cases one needs to ensure that the
10797      * call chain is bounded to not run out of stack. It is also a good
10798      * idea to try and ensure that the EXECUTE_DIRECT can use the
10799      * tail-call optimisation to avoid using too much stack which is bad
10800      * for CPU caching. This means returning immediately after
10801      * EXECUTE_DIRECT but also avoiding having objects that needs
10802      * destruction after return and also avoiding taking the reference of
10803      * stack variables.
10804      *
10805      * Using the non-standard manner one can obviously also change more
10806      * ways, one can return a bool for example as in the example with
10807      * execTUPKEYREQ, one can add parameters and one can even change the
10808      * name to a different name not according to the standard naming
10809      * conventions. Obviously doing this removes flexibility of using
10810      * blocks in a flexible manner.
10811      */
10812     block->EXECUTE_DIRECT(f, signal);
10813     ndbrequire(signal->theData[0] == 0); /* Failure is not an option */
10814     if (scanPtr->scanReleaseCounter < scanPtr->m_curr_batch_size_rows)
10815     {
10816       jam();
10817       scanPtr->scanReleaseCounter++;
10818       /* Continue looping */
10819     }
10820     else
10821     {
10822       scanLockReleasedLab(signal);
10823       /* No more records to commit for this scan at this time */
10824       return;
10825     }
10826   }
10827 }//Dblqh::scanReleaseLocksLab()
10828 
10829 /* -------------------------------------------------------------------------
10830  *       ENTER SCAN_NEXTREQ
10831  * -------------------------------------------------------------------------
10832  *       SCAN_NEXT_REQ SIGNAL ARRIVED IN THE MIDDLE OF EXECUTION OF THE SCAN.
10833  *       IT WAS A REQUEST TO CLOSE THE SCAN. WE WILL CLOSE THE SCAN IN A
10834  *       CAREFUL MANNER TO ENSURE THAT NO ERROR OCCURS.
10835  * -------------------------------------------------------------------------
10836  *       PRECONDITION:
10837  *       TRANSACTION_STATE = SCAN_STATE_USED
10838  *       TSCAN_COMPLETED = ZTRUE
10839  * -------------------------------------------------------------------------
10840  *       WE CAN ALSO ARRIVE AT THIS LABEL AFTER A NODE CRASH OF THE SCAN
10841  *       COORDINATOR.
10842  * ------------------------------------------------------------------------- */
closeScanRequestLab(Signal * signal)10843 void Dblqh::closeScanRequestLab(Signal* signal)
10844 {
10845   ScanRecord * const scanPtr = scanptr.p;
10846   DEBUG("transactionState = " << tcConnectptr.p->transactionState);
10847   switch (tcConnectptr.p->transactionState) {
10848   case TcConnectionrec::SCAN_STATE_USED:
10849     DEBUG("scanState = " << scanPtr->scanState);
10850     switch (scanPtr->scanState) {
10851     case ScanRecord::IN_QUEUE:
10852       jam();
10853       tupScanCloseConfLab(signal);
10854       return;
10855     case ScanRecord::WAIT_NEXT_SCAN:
10856       jam();
10857       /* -------------------------------------------------------------------
10858        *  SET COMPLETION STATUS AND WAIT FOR OPPORTUNITY TO STOP THE SCAN.
10859        * ------------------------------------------------------------------- */
10860       scanPtr->scanCompletedStatus = ZTRUE;
10861       return;
10862     case ScanRecord::WAIT_ACC_SCAN:
10863       jam();
10864       /* -------------------------------------------------------------------
10865        *  WE ARE CURRENTLY STARTING UP THE SCAN. SET COMPLETED STATUS
10866        *  AND WAIT FOR COMPLETION OF STARTUP.
10867        * ------------------------------------------------------------------- */
10868       scanPtr->scanCompletedStatus = ZTRUE;
10869       return;
10870     case ScanRecord::WAIT_CLOSE_SCAN:
10871       jam();
10872       scanPtr->scanCompletedStatus = ZTRUE;
10873       return;
10874       /* -------------------------------------------------------------------
10875        *       CLOSE IS ALREADY ONGOING. WE NEED NOT DO ANYTHING.
10876        * ------------------------------------------------------------------- */
10877     case ScanRecord::WAIT_SCAN_NEXTREQ:
10878       jam();
10879       /* -------------------------------------------------------------------
10880        * WE ARE WAITING FOR A SCAN_NEXTREQ FROM SCAN COORDINATOR(TC)
10881        * WICH HAVE CRASHED. CLOSE THE SCAN
10882        * ------------------------------------------------------------------- */
10883       scanPtr->scanCompletedStatus = ZTRUE;
10884 
10885       fragptr.i = tcConnectptr.p->fragmentptr;
10886       c_fragment_pool.getPtr(fragptr);
10887 
10888       if (scanPtr->scanLockHold == ZTRUE) {
10889 	if (scanPtr->m_curr_batch_size_rows > 0) {
10890 	  jam();
10891 	  scanPtr->scanReleaseCounter = 1;
10892 	  scanReleaseLocksLab(signal);
10893 	  return;
10894 	}//if
10895       }//if
10896       closeScanLab(signal);
10897       return;
10898     default:
10899       ndbrequire(false);
10900     }//switch
10901     return;
10902   case TcConnectionrec::WAIT_SCAN_AI:
10903     jam();
10904     /* ---------------------------------------------------------------------
10905      *  WE ARE STILL WAITING FOR THE ATTRIBUTE INFORMATION THAT
10906      *  OBVIOUSLY WILL NOT ARRIVE. WE CAN QUIT IMMEDIATELY HERE.
10907      * --------------------------------------------------------------------- */
10908     tupScanCloseConfLab(signal);
10909     return;
10910   case TcConnectionrec::SCAN_TUPKEY:
10911     jam();
10912     /* ---------------------------------------------------------------------
10913      *       SET COMPLETION STATUS AND WAIT FOR OPPORTUNITY TO STOP THE SCAN.
10914      * --------------------------------------------------------------------- */
10915     scanPtr->scanCompletedStatus = ZTRUE;
10916     return;
10917   default:
10918     ndbrequire(false);
10919   }//switch
10920 }//Dblqh::closeScanRequestLab()
10921 
10922 bool
seize_acc_ptr_list(ScanRecord * scanP,Uint32 curr_batch_size,Uint32 new_batch_size)10923 Dblqh::seize_acc_ptr_list(ScanRecord* scanP,
10924                           Uint32 curr_batch_size,
10925                           Uint32 new_batch_size)
10926 {
10927   /*  1 maps to 0 segments
10928    * >1 maps to enough segments to store
10929    */
10930   Uint32 segments= (new_batch_size + (SectionSegment::DataLength -2 )) /
10931     SectionSegment::DataLength;
10932 
10933   if (segments <= scanP->scan_acc_segments)
10934   {
10935     // No need to allocate more segments.
10936     return true;
10937   }
10938 
10939   if (new_batch_size > 1)
10940   {
10941     for (Uint32 i = 1 + scanP->scan_acc_segments; i <= segments; i++)
10942     {
10943       Uint32 seg= seizeSingleSegment();
10944       if (unlikely(seg == RNIL))
10945       {
10946         jam();
10947         /* Cleanup any allocated segments and return */
10948         scanP->scan_acc_segments= (i-1);
10949         release_acc_ptr_list(scanP);
10950         return false;
10951       }
10952       scanP->scan_acc_op_ptr[i]= seg;
10953     }
10954   }
10955   scanP->scan_acc_segments= segments;
10956   return true;
10957 }
10958 
10959 void
release_acc_ptr_list(ScanRecord * scanP)10960 Dblqh::release_acc_ptr_list(ScanRecord* scanP)
10961 {
10962   Uint32 i, segments;
10963   segments= scanP->scan_acc_segments;
10964 
10965   for (i= 1; i <= segments; i++) {
10966     releaseSection(scanP->scan_acc_op_ptr[i]);
10967   }
10968   scanP->scan_acc_segments= 0;
10969   scanP->scan_acc_index = 0;
10970 }
10971 
10972 Uint32
seizeSingleSegment()10973 Dblqh::seizeSingleSegment()
10974 {
10975   Uint32 junk= 0;
10976   Uint32 iVal= RNIL;
10977 
10978   /* Rather grungy way to grab a segment */
10979   if (!appendToSection(iVal, &junk, 1))
10980     return RNIL;
10981 
10982   return iVal;
10983 }
10984 
10985 void
init_acc_ptr_list(ScanRecord * scanP)10986 Dblqh::init_acc_ptr_list(ScanRecord* scanP)
10987 {
10988   scanP->scan_acc_index = 0;
10989 }
10990 
10991 Uint32
get_acc_ptr_from_scan_record(ScanRecord * scanP,Uint32 index,bool crash_flag)10992 Dblqh::get_acc_ptr_from_scan_record(ScanRecord* scanP,
10993                                     Uint32 index,
10994                                     bool crash_flag)
10995 {
10996   Uint32* acc_ptr;
10997   if (!((index < MAX_PARALLEL_OP_PER_SCAN) &&
10998        index < scanP->scan_acc_index)) {
10999     ndbrequire(crash_flag);
11000     return RNIL;
11001   }
11002   i_get_acc_ptr(scanP, acc_ptr, index);
11003   return *acc_ptr;
11004 }
11005 
11006 void
set_acc_ptr_in_scan_record(ScanRecord * scanP,Uint32 index,Uint32 acc)11007 Dblqh::set_acc_ptr_in_scan_record(ScanRecord* scanP,
11008                                   Uint32 index, Uint32 acc)
11009 {
11010   Uint32 *acc_ptr;
11011   ndbrequire((index == 0 || scanP->scan_acc_index == index) &&
11012              (index < MAX_PARALLEL_OP_PER_SCAN));
11013   scanP->scan_acc_index= index + 1;
11014   i_get_acc_ptr(scanP, acc_ptr, index);
11015   *acc_ptr= acc;
11016 }
11017 
11018 /**
11019  * The design of the SCAN algorithm within one LDM instance
11020  * --------------------------------------------------------
11021  * DBLQH controls the execution of scans on tables on behalf of DBTC and
11022  * DBSPJ. Here follows a signal overview of how a scan is performed within
11023  * one LDM instance. For a description of the global scan protocol
11024  * see DbtcMain.cpp as a comment before execSCAN_TABREQ.
11025  *
11026  * DBLQH only controls execution of a scan towards one partition of a
11027  * table. DBTC/DBSPJ is responsible for execution of scans toward the
11028  * entire table and ensuring that the API sees a consistent view of the
11029  * table.
11030  *
11031  * There are currently four types of scans implemented in one LDM
11032  * instance:
11033  *
11034  * Full table scan using hash index. This is implemented in DBACC.
11035  * Full table scan using row by row. This is implemented in DBTUP.
11036  * Full table scan using row by row in disk order. This is implemented in
11037  *   DBTUP.
11038  * Index scan using one or several ranges. This is implemented in DBTUX.
11039  *
11040  * DBLQH controls execution of one partition scan, Dependent on the scan
11041  * type, DBACC/DBTUP/DBTUX is responsible to get the row references to
11042  * the tuple scanned. DBTUP is responsible for reading of those rows and
11043  * finally DBACC is responsible for any locking of rows required as part
11044  * of the scan.
11045  *
11046  * Each scan is controlled by an interpreted program created by the API
11047  * and transported down to DBTUP. This program is sent as part of the
11048  * SCAN_FRAGREQ signal and passed to DBTUP in the STORED_PROCREQ signal.
11049  * This program is applied on each row reference passed to DBTUP by
11050  * execution of the execTUPKEYREQ signal.
11051  *
11052  * In index ranges one or more ranges is sent in the keyinfo part of the
11053  * SCAN_FRAGREQ. This range information is sent to DBTUX one range at a
11054  * time. Actually with multiple ranges, DBLQH will treat each range as a
11055  * separate scan towards the other blocks, so a scan will be started and
11056  * closed towards DBACC/DBTUP/DBTUX for each range involved.
11057  *
11058  * As an optimisation all signals locally in one LDM instance have been
11059  * converted to direct signals.
11060  * The following signals are used as part of the scan of one partition.
11061  * ACC_SCANREQ:
11062  *   This signal initialises an operation record in DBACC/DBTUP/DBTUX for
11063  *   scan of one range or a full partition. Always sent as a direct signal
11064  *   and returned immediately through signal object on return.
11065  *
11066  * STORED_PROCREQ:
11067  *   This signal stores the interpreted program used to read each tuple
11068  *   as part of the scan. The same signal is also used to deallocate the
11069  *   the interpreted program when the entire scan of all ranges have been
11070  *   completed. Always sent as a direct signal and returned immediately
11071  *   through signal object on return.
11072  *
11073  * ACC_LOCKREQ:
11074  *   Certain scans require a lock on the row before the row is read, this
11075  *   signal acquires such a lock. Always sent as a direct signal. Return
11076  *   signal not always sent immediately.
11077  *
11078  * ACCKEYCONF:
11079  *   Signal returned when the lock have been acquired, the signal is
11080  *   normally sent directly when the row is not locked, but for a locked
11081  *   row the signal can be sent even a second or more later. When sent the
11082  *   signal is sent as a direct signal.
11083  *
11084  * ACCKEYREF:
11085  *   Signal returned when acquiring lock failed, e.g. due to record deleted
11086  *   while waiting for it.
11087  *
11088  * ACC_ABORTCONF:
11089  *   Signal returned after aborting a scan using an asynchronous message to
11090  *   ensure that all asynchronous messages are delivered since setting the
11091  *   scan state as aborted.
11092  *
11093  * NEXT_SCANREQ:
11094  *   This signal is used with different meaning:
11095  *   ZSCAN_NEXT:
11096  *     Get the next row reference to read, returned in NEXT_SCANCONF signal.
11097  *   ZSCAN_NEXT_COMMIT:
11098  *     Get the next row reference to read AND unlock the specified row.
11099  *     Returned in NEXT_SCANCONF signal.
11100  *   ZSCAN_COMMIT:
11101  *     Unlock the specified row. Return signal is simply returned when
11102  *     returning from call to execNEXT_SCANREQ.
11103  *   ZSCAN_CLOSE:
11104  *     Close the scan in DBACC/DBTUP/DBTUX.
11105  *
11106  *   When sent as ZSCAN_COMMIT and ZSCAN_CLOSE it is always sent as a direct
11107  *   signal. Otherwise it is sent as direct or asynchronous signal dependent
11108  *   on the value of the scan_direct_count variable in the DBLQH scan
11109  *   record. The scan_direct_count variable ensures that we keep the number
11110  *   of direct signals sent bounded.
11111  *
11112  * NEXT_SCANCONF:
11113  *   Return signal to NEXT_SCANREQ containing row reference to read or
11114  *   indication of close completed. Always sent as a direct signal.
11115  *
11116  * TUPKEYREQ:
11117  *   This signal does the actual read of the row and sends the read row data
11118  *   directly to the API using the TRANSID_AI signal. This signal is always
11119  *   sent as a direct signal.
11120  *
11121  * ACC_CHECK_SCAN:
11122  *   Continue scanning from specified place. Used by DBACC/DBTUP/DBTUX as an
11123  *   internal signal as part of the scan. This signal can be sent both as
11124  *   an asynchronous signal and as a direct signal.
11125  *
11126  * SCAN_FRAGCONF:
11127  *   Return signal sent to DBTC/DBSPJ after completing a part of the scan,
11128  *   the signal carries a set of references to rows sent to the API. After
11129  *   sending this signal DBLQH will stop and wait for a SCAN_NEXTREQ to
11130  *   signal asking DBLQH to continue the scan of the partition. The number
11131  *   of rows scanned before sending SCAN_FRAGCONF is dependent on both
11132  *   configuration parameters and information in the SCAN_FRAGREQ signal.
11133  *
11134  *   This signal is also sent when the scan is fully completed.
11135  *   This signal is normally a distributed signal, so it is always sent as
11136  *   an asynchronous signal.
11137  *
11138  * SCAN_NEXTREQ:
11139  *   Request to continue scanning from DBTC/DBSPJ as requested to them from
11140  *   API.
11141  *   This signal is normally a distributed signal, so it is always sent as
11142  *   an asynchronous signal.
11143  *
11144  *  Below follows an example signal diagram of a scan of one partition.
11145  *
11146  *  DBLQH          ACC          TUP         ACC/TUP/TUX    API      DBTC
11147  *    |ACC_SCANREQ
11148  *    |----------------------------------------->|
11149  *    |<-----------------------------------------|
11150  *    | STORED_PROCREQ
11151  *    |------------------------->|
11152  *    |<-------------------------|
11153  *    | NEXT_SCANREQ (ZSCAN_NEXT)
11154  *    |----------------------------------------->|
11155  *    |                          prepareTUPKEYREQ
11156  *    |                          |<--------------|
11157  *    |                          |-------------->|
11158  *    | NEXT_SCANCONF
11159  *    |<-----------------------------------------|
11160  *    | TUPKEYREQ
11161  *    |------------------------->|  TRANSID_AI
11162  *    |                          |-------------------------->|
11163  *    |<-------------------------|
11164  *    | NEXT_SCANREQ (ZSCAN_NEXT_COMMIT)
11165  *    |----------------------------------------->|
11166  *    |                          prepareTUPKEYREQ
11167  *    |                          |<--------------|
11168  *    |                          |-------------->|
11169  *    | NEXT_SCANCONF
11170  *    |<-----------------------------------------|
11171  *    | TUPKEYREQ
11172  *    |------------------------->|  TRANSID_AI
11173  *    |                          |-------------------------->|
11174  *    |<-------------------------|
11175  *    Repeat above for as many rows as required before returning to the
11176  *    API. The above TRANSID_AI isn't necessary, the interpreted program
11177  *    could perform selection and decide to not send a specific row since
11178  *    it doesn't match the condition checked by the interpreted program.
11179  *    |
11180  *    | SCAN_FRAGCONF
11181  *    |---------------------------------------------------------------->|
11182  *    .... Some time for API and DBTC to process things.
11183  *    | SCAN_NEXTREQ
11184  *    |<----------------------------------------------------------------|
11185  *    | NEXT_SCANREQ (ZSCAN_NEXT_COMMIT)
11186  *    |----------------------------------------->|
11187  *    |                          prepareTUPKEYREQ
11188  *    |                          |<--------------|
11189  *    |                          |-------------->|
11190  *    | NEXT_SCANCONF
11191  *    |<-----------------------------------------|
11192  *    | TUPKEYREQ
11193  *    |------------------------->|  TRANSID_AI
11194  *    |                          |-------------------------->|
11195  *    |<-------------------------|
11196  *    Repeat above again until time for next SCAN_FRAGCONF to be sent.
11197  *    When scan from NEXT_SCANCONF indicates there are no more tuples to
11198  *    fetch one starts to close the scan.
11199  *
11200  *    |
11201  *    | NEXT_SCANREQ (ZSCAN_NEXT_COMMIT)
11202  *    |----------------------------------------->|
11203  *    | NEXT_SCANCONF(no more tuples)
11204  *    |<-----------------------------------------|
11205  *    | NEXT_SCANREQ (ZSCAN_CLOSE)
11206  *    |----------------------------------------->|
11207  *    | NEXT_SCANCONF
11208  *    |<-----------------------------------------|
11209  *    | STORED_PROCREQ (delete interpreted program)
11210  *    |------------------------->|
11211  *    |<-------------------------|
11212  *    | SCAN_FRAGCONF (close flag set)
11213  *    |---------------------------------------------------------------->|
11214  *    Now the scan is completed.
11215  *
11216  *    Now a number of variations on the above signal diagrams:
11217  *    Scan with locking:
11218  *    In this we use the flag ZSCAN_NEXT all the time and never
11219  *    ZSCAN_NEXT_COMMIT, we handle things a bit differently instead when
11220  *    receiving SCAN_NEXTREQ where we perform a signal diagram like this:
11221  *
11222  *    | NEXT_SCANREQ (ZSCAN_COMMIT)
11223  *    |----------------------------------------->|
11224  *    |<-----------------------------------------|
11225  *    This is repeated for each row sent to the API in the previous
11226  *    SCAN_FRAGCONF signal.
11227  *
11228  *    If the application wants the row locked for longer time he have had
11229  *    the chance to perform a key lookup operation that took over the lock
11230  *    such that even when we unlock the scan lock, the transaction still
11231  *    retains a lock on the row.
11232  *
11233  *    After each row scanned we check if we've reached a scan heartbeat
11234  *    timeout. In case we have we send a SCAN_HBREP signal to DBTC/DBSPJ
11235  *    to inform about that we're still actively scanning even though no
11236  *    result rows have been sent. Remember here that a scan in DBLQH can
11237  *    potentially scan billions of rows while only returning very few to
11238  *    the API. Thus we can scan for an extended time without returning to
11239  *    the API. This is handled by the method check_send_scan_hb_rep.
11240  *
11241  *    Already from returning from ACC_SCANREQ we can discover that the
11242  *    partition (== fragment) is empty and go immediately to the close
11243  *    down code.
11244  *    For index scans we will send TUX_BOUND_INFO after ACC_SCANREQ and
11245  *    before sending STORED_PROCREQ to DBTUX. This will provide one range
11246  *    to DBTUX for scanning, if multiple ranges are to be scanned we
11247  *    startup a new scan as if it was a new SCAN_FRAGREQ received, but we
11248  *    don't need to send STORED_PROCREQ since the same interpreted program
11249  *    will be used. We will however send ACC_SCANREQ and TUX_BOUND_INFO
11250  *    also for this new range.
11251  *
11252  *  There are various reasons for temporarily stopping a scan, this could
11253  *  lack of operation records, holding too many row locks, one could also
11254  *  end up in this situation after waiting for a row lock.
11255  *
11256  *  To restart the scan again after any type of temporary stop one sends
11257  *  the signal ACC_CHECK_SCAN either as direct or as an asynchronous signal
11258  *  to DBACC/DBTUP/DBTUX. This signal is sent from many different places in
11259  *  DBLQH, DBACC, DBTUP and DBTUX. It is always sent as part of NEXT_SCANREQ
11260  *  processing.
11261  *
11262  *  When executing ACC_CHECK_SCAN one can flag to DBACC/DBTUP/DBTUX that one
11263  *  should check for a 10 ms delay with the flag ZCHECK_LCP_STOP. In previous
11264  *  versions this was also related to local checkpoints, this is no longer
11265  *  the case. Now it's only related to situations where it is required to
11266  *  perform an extra wait such that resources becomes available again.
11267  *
11268  *  DBTUP and DBTUX sends the signal CHECK_LCP_STOP to DBLQH in a number of
11269  *  situations, among other things when a locked key has been encountered.
11270  *  When the ACCKEYCONF signal then is received indicating that one acquired
11271  *  the lock, DBLQH will still wait for CHECK_LCP_STOP from DBQLH to return
11272  *  after 10ms delay. This is on the TODO-list to fix to ensure that we can
11273  *  proceed with these locked rows immediately after delivery. As it is now
11274  *  we can get up to 10ms delay each time we encounter a locked row.
11275  */
11276 /* -------------------------------------------------------------------------
11277  * SCAN_FRAGREQ: Request to start scanning the specified fragment of a table.
11278  * ------------------------------------------------------------------------- */
execSCAN_FRAGREQ(Signal * signal)11279 void Dblqh::execSCAN_FRAGREQ(Signal* signal)
11280 {
11281   jamEntry();
11282 
11283   /* Reassemble if the request was fragmented */
11284   if (!assembleFragments(signal)){
11285     jam();
11286     return;
11287   }
11288 
11289   ScanFragReq * const scanFragReq = (ScanFragReq *)&signal->theData[0];
11290   ScanFragRef * ref;
11291   Uint32 errorCode= 0;
11292   Uint32 hashIndex;
11293   TcConnectionrecPtr nextHashptr;
11294   TcConnectionrec * regTcPtr;
11295   Uint32 senderHi = signal->getSendersBlockRef();
11296   // bug#13834481 hashHi!=0 caused timeout (tx not found)
11297   const NodeInfo& senderInfo = getNodeInfo(refToNode(senderHi));
11298 
11299   if (unlikely(senderInfo.m_version < NDBD_LONG_SCANFRAGREQ))
11300     senderHi = 0;
11301 
11302   tabptr.i = scanFragReq->tableId;
11303 
11304   /* Short SCANFRAGREQ has no sections, Long SCANFRAGREQ has 1 or 2
11305    * Section 0 : Mandatory ATTRINFO section
11306    * Section 1 : Optional KEYINFO section
11307    */
11308   const Uint32 numSections= signal->getNoOfSections();
11309   bool isLongReq= ( numSections != 0 );
11310 
11311   SectionHandle handle(this, signal);
11312 
11313   SegmentedSectionPtr attrInfoPtr, keyInfoPtr;
11314   Uint32 aiLen= 0;
11315   Uint32 keyLen= 0;
11316 
11317   if (likely(isLongReq))
11318   {
11319     /* Long request, get Attr + Key len from section sizes */
11320     handle.getSection(attrInfoPtr, ScanFragReq::AttrInfoSectionNum);
11321     aiLen= attrInfoPtr.sz;
11322 
11323     if (numSections == 2)
11324     {
11325       handle.getSection(keyInfoPtr, ScanFragReq::KeyInfoSectionNum);
11326       keyLen= keyInfoPtr.sz;
11327     }
11328   }
11329   else
11330   {
11331     /* Short request, get Attr + Key len from signal */
11332     aiLen= ScanFragReq::getAttrLen(scanFragReq->requestInfo);
11333     keyLen= (scanFragReq->fragmentNoKeyLen >> 16);
11334     /*
11335      * bug#13834481.  Clear attribute length so that it is not
11336      * re-interpreted as new 7.x bits.  initScanrec() uses signal
11337      * data so we must modify signal data.
11338      */
11339     ScanFragReq::clearAttrLen(scanFragReq->requestInfo);
11340   }
11341 
11342   const Uint32 transid1 = scanFragReq->transId1;
11343   const Uint32 transid2 = scanFragReq->transId2;
11344   const Uint32 senderData = scanFragReq->senderData;
11345   const Uint32 senderBlockRef = signal->senderBlockRef();
11346 
11347   if (likely(ctcNumFree > ZNUM_RESERVED_TC_CONNECT_RECORDS &&
11348              !ERROR_INSERTED_CLEAR(5055)) ||
11349       (ScanFragReq::getLcpScanFlag(scanFragReq->requestInfo)) ||
11350       (refToMain(senderBlockRef) == BACKUP))
11351   {
11352     /**
11353      * We always keep 3 operation records, one for LCP scans and one for
11354      * Node recovery support (to handle COPY_FRAGREQ when we're aiding a
11355      * node to startup by synchronizing our data with the starting nodes
11356      * recovered data and finally one for backup scans.
11357      */
11358     seizeTcrec();
11359 
11360     regTcPtr = tcConnectptr.p;
11361     const Uint32 savePointId = scanFragReq->savePointId;
11362 
11363     regTcPtr->clientConnectrec = senderData;
11364     regTcPtr->clientBlockref = senderBlockRef;
11365     regTcPtr->savePointId = savePointId;
11366   } else {
11367     jam();
11368     /* --------------------------------------------------------------------
11369      *      NO FREE TC RECORD AVAILABLE, THUS WE CANNOT HANDLE THE REQUEST.
11370      * -------------------------------------------------------------------- */
11371     errorCode = ZNO_TC_CONNECT_ERROR;
11372     goto error_handler_early;
11373   }//if
11374 
11375   ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
11376   if (unlikely(tabptr.p->tableStatus != Tablerec::TABLE_DEFINED &&
11377                tabptr.p->tableStatus != Tablerec::TABLE_READ_ONLY))
11378   {
11379     errorCode = get_table_state_error(tabptr);
11380     goto error_handler;
11381   }
11382 
11383   if (unlikely(table_version_major(scanFragReq->schemaVersion) !=
11384                table_version_major(tabptr.p->schemaVersion)))
11385   {
11386     errorCode = ZINVALID_SCHEMA_VERSION;
11387     goto error_handler;
11388   }
11389 
11390   {
11391     const Uint32 reqinfo = scanFragReq->requestInfo;
11392     const Uint32 fragId = (scanFragReq->fragmentNoKeyLen & 0xFFFF);
11393     const Uint32 max_rows = scanFragReq->batch_size_rows;
11394     const Uint32 scanLockMode = ScanFragReq::getLockMode(reqinfo);
11395     const Uint8 keyinfo = ScanFragReq::getKeyinfoFlag(reqinfo);
11396     const Uint8 rangeScan = ScanFragReq::getRangeScanFlag(reqinfo);
11397     /**
11398      * A write always has to get keyinfo
11399      */
11400     ndbrequire(scanLockMode == 0 || keyinfo);
11401 
11402     ndbrequire(max_rows > 0 && max_rows <= MAX_PARALLEL_OP_PER_SCAN);
11403     if (!getFragmentrec(signal, fragId)) {
11404       errorCode = 1231;
11405       goto error_handler;
11406     }//if
11407 
11408     // Verify scan type vs table type (both sides are boolean)
11409     if (rangeScan != DictTabInfo::isOrderedIndex(fragptr.p->tableType)) {
11410       errorCode = 1232;
11411       goto error_handler;
11412     }//if
11413 
11414     if (ScanFragReq::getLcpScanFlag(reqinfo) ||
11415         refToMain(senderHi) == BACKUP)
11416     {
11417       /* LCP and Backup scans come here */
11418       jam();
11419       ndbrequire(m_reserved_scans.first(scanptr));
11420       m_reserved_scans.remove(scanptr);
11421     }
11422     else if (!c_scanRecordPool.seize(scanptr))
11423     {
11424       jam();
11425       errorCode = ScanFragRef::ZNO_FREE_SCANREC_ERROR;
11426       goto error_handler;
11427     }
11428 
11429     initScanTc(scanFragReq,
11430                transid1,
11431                transid2,
11432                fragId,
11433                ZNIL,
11434                senderHi);
11435 
11436     regTcPtr->opExec =
11437       (1 ^ ScanFragReq::getNotInterpretedFlag(reqinfo));
11438     {
11439       const Uint32 applRef = scanFragReq->resultRef;
11440 
11441       regTcPtr->save1 = 0;
11442       regTcPtr->primKeyLen = keyLen;
11443       regTcPtr->applRef = applRef;
11444     }
11445 
11446     if (likely(isLongReq))
11447     {
11448       regTcPtr->attrInfoIVal= attrInfoPtr.i;
11449       if (keyLen)
11450         regTcPtr->keyInfoIVal= keyInfoPtr.i;
11451       /* Scan state machine is now responsible for freeing
11452        * these sections, usually via releaseOprec()
11453        */
11454       handle.clear();
11455 
11456       /*
11457          Update per fragment statistics. 'attrInfoPtr' is not defined for
11458          short-signal scans, so we ignore these, since they only happen
11459          during online upgrades.
11460        */
11461       if (!ScanFragReq::getLcpScanFlag(reqinfo))
11462       {
11463         jam();
11464         Fragrecord::UsageStat& useStat =
11465           c_fragment_pool.getPtr(tcConnectptr.p->fragmentptr)->m_useStat;
11466         useStat.m_scanFragReqCount++;
11467         useStat.m_scanBoundWords+= keyLen;
11468         if (!ScanFragReq::getNotInterpretedFlag(reqinfo))
11469         {
11470           /* Backup scans do not use interpreted mode. */
11471           jam();
11472           useStat.m_scanProgramWords+= getProgramWordCount(attrInfoPtr);
11473         }
11474       }
11475     }
11476 
11477     if (ScanFragReq::getCorrFactorFlag(reqinfo))
11478     {
11479       /**
11480        * Correlattion factor for SPJ
11481        */
11482       Uint32 corrFactorHi = scanFragReq->variableData[1];
11483       regTcPtr->m_corrFactorLo = scanFragReq->variableData[0];
11484       regTcPtr->m_corrFactorHi = corrFactorHi;
11485     }
11486 
11487     errorCode = initScanrec(scanFragReq, aiLen);
11488     if (errorCode != ZOK) {
11489       jam();
11490       goto error_handler2;
11491     }//if
11492 
11493     /* Check that no equal element already exists */
11494     ndbassert(findTransaction(regTcPtr->transid[0],
11495                               regTcPtr->transid[1],
11496                               regTcPtr->tcOprec,
11497                               senderHi) == ZNOT_FOUND);
11498     hashIndex = (regTcPtr->transid[0] ^ regTcPtr->tcOprec) & 1023;
11499     nextHashptr.i = ctransidHash[hashIndex];
11500     ctransidHash[hashIndex] = tcConnectptr.i;
11501     regTcPtr->prevHashRec = RNIL;
11502     regTcPtr->nextHashRec = nextHashptr.i;
11503     regTcPtr->hashIndex = hashIndex;
11504     if (nextHashptr.i != RNIL) {
11505       jam();
11506       /* ---------------------------------------------------------------------
11507        *   ENSURE THAT THE NEXT RECORD HAS SET PREVIOUS TO OUR RECORD
11508        *   IF IT EXISTS
11509        * --------------------------------------------------------------------- */
11510       ptrCheckGuard(nextHashptr, ctcConnectrecFileSize, tcConnectionrec);
11511       ndbassert(nextHashptr.p->prevHashRec == RNIL);
11512       nextHashptr.p->prevHashRec = tcConnectptr.i;
11513     }//if
11514     if ((! isLongReq ) &&
11515         ( scanptr.p->scanAiLength > 0 )) {
11516       jam();
11517       regTcPtr->transactionState = TcConnectionrec::WAIT_SCAN_AI;
11518       return;
11519     }//if
11520     continueAfterReceivingAllAiLab(signal);
11521     return;
11522   }
11523 
11524 error_handler2:
11525   // no scan number allocated
11526   if (scanptr.p->m_reserved == 0)
11527   {
11528     jam();
11529     c_scanRecordPool.release(scanptr);
11530   }
11531   else
11532   {
11533     jam();
11534     m_reserved_scans.addFirst(scanptr);
11535   }
11536 error_handler:
11537   regTcPtr->abortState = TcConnectionrec::ABORT_ACTIVE;
11538   regTcPtr->tcScanRec = RNIL;
11539   releaseOprec(signal);
11540   releaseTcrec(signal, tcConnectptr);
11541 
11542 error_handler_early:
11543   releaseSections(handle);
11544   ref = (ScanFragRef*)&signal->theData[0];
11545   ref->senderData = senderData;
11546   ref->transId1 = transid1;
11547   ref->transId2 = transid2;
11548   ref->errorCode = errorCode;
11549   sendSignal(senderBlockRef, GSN_SCAN_FRAGREF, signal,
11550 	     ScanFragRef::SignalLength, JBB);
11551 }//Dblqh::execSCAN_FRAGREQ()
11552 
continueAfterReceivingAllAiLab(Signal * signal)11553 void Dblqh::continueAfterReceivingAllAiLab(Signal* signal)
11554 {
11555   TcConnectionrec * const regTcPtr = tcConnectptr.p;
11556   ScanRecord * const scanPtr = scanptr.p;
11557   regTcPtr->transactionState = TcConnectionrec::SCAN_STATE_USED;
11558 
11559   if(scanPtr->scanState == ScanRecord::IN_QUEUE){
11560     jam();
11561     return;
11562   }
11563 
11564   scanPtr->scanState = ScanRecord::WAIT_ACC_SCAN;
11565   AccScanReq * req = (AccScanReq*)&signal->theData[0];
11566 
11567   Uint32 requestInfo = 0;
11568 
11569   AccScanReq::setLockMode(requestInfo, scanPtr->scanLockMode);
11570   AccScanReq::setReadCommittedFlag(requestInfo, scanPtr->readCommitted);
11571   AccScanReq::setDescendingFlag(requestInfo, scanPtr->descending);
11572   AccScanReq::setStatScanFlag(requestInfo, scanPtr->statScan);
11573 
11574   if (refToMain(regTcPtr->clientBlockref) == BACKUP)
11575   {
11576     if (scanPtr->lcpScan)
11577     {
11578       AccScanReq::setNoDiskScanFlag(requestInfo, 1);
11579       AccScanReq::setLcpScanFlag(requestInfo, 1);
11580     }
11581     else
11582     {
11583       /* If backup scan disktables in disk order */
11584       AccScanReq::setNoDiskScanFlag(requestInfo,
11585                                     !regTcPtr->m_disk_table);
11586       AccScanReq::setLcpScanFlag(requestInfo, 0);
11587     }
11588   }
11589   else
11590   {
11591 #if BUG_27776_FIXED
11592     AccScanReq::setNoDiskScanFlag(requestInfo,
11593                                   !regTcPtr->m_disk_table);
11594 #else
11595     AccScanReq::setNoDiskScanFlag(requestInfo, 1);
11596 #endif
11597     AccScanReq::setLcpScanFlag(requestInfo, 0);
11598   }
11599 
11600   SimulatedBlock *block = scanPtr->scanBlock;
11601   req->requestInfo = requestInfo;
11602 
11603   const Uint32 senderData = scanptr.i;
11604   const Uint32 senderRef = cownref;
11605   const Uint32 tableId = regTcPtr->tableref;
11606   const Uint32 fragmentNo = regTcPtr->fragmentid;
11607   const Uint32 transId1 = regTcPtr->transid[0];
11608   const Uint32 transId2 = regTcPtr->transid[1];
11609   const Uint32 savePointId = regTcPtr->savePointId;
11610   ExecFunction f = block->getExecuteFunction(GSN_ACC_SCANREQ);
11611 
11612   req->senderData = senderData;
11613   req->senderRef = senderRef;
11614   req->tableId = tableId;
11615   req->fragmentNo = fragmentNo;
11616   req->transId1 = transId1;
11617   req->transId2 = transId2;
11618   req->savePointId = savePointId;
11619 
11620   block->EXECUTE_DIRECT(f, signal);
11621   if (signal->theData[8] == 0)
11622   {
11623     /* ACC_SCANCONF */
11624     jamEntry();
11625     accScanConfScanLab(signal);
11626   }
11627   else
11628   {
11629     /* ACC_SCANREF */
11630     jamEntry();
11631     execACC_SCANREF(signal);
11632   }
11633 }//Dblqh::continueAfterReceivingAllAiLab()
11634 
scanAttrinfoLab(Signal * signal,Uint32 * dataPtr,Uint32 length)11635 void Dblqh::scanAttrinfoLab(Signal* signal, Uint32* dataPtr, Uint32 length)
11636 {
11637   scanptr.i = tcConnectptr.p->tcScanRec;
11638   c_scanRecordPool.getPtr(scanptr);
11639   if (saveAttrInfoInSection(dataPtr, length) == ZOK) {
11640     if (tcConnectptr.p->currTupAiLen < scanptr.p->scanAiLength) {
11641       jam();
11642     } else {
11643       jam();
11644       ndbrequire(tcConnectptr.p->currTupAiLen == scanptr.p->scanAiLength);
11645       continueAfterReceivingAllAiLab(signal);
11646     }//if
11647     return;
11648   }//if
11649   abort_scan(signal, scanptr.i, ZGET_ATTRINBUF_ERROR);
11650 }
11651 
abort_scan(Signal * signal,Uint32 scan_ptr_i,Uint32 errcode)11652 void Dblqh::abort_scan(Signal* signal, Uint32 scan_ptr_i, Uint32 errcode){
11653   jam();
11654   scanptr.i = scan_ptr_i;
11655   c_scanRecordPool.getPtr(scanptr);
11656 
11657   tcConnectptr.p->errorCode = errcode;
11658   tupScanCloseConfLab(signal);
11659   return;
11660 }
11661 
11662 /*---------------------------------------------------------------------*/
11663 /* Send this 'I am alive' signal to TC when it is received from ACC    */
11664 /* We include the scanPtr.i that comes from ACC in signalData[1], this */
11665 /* tells TC which fragment record to check for a timeout.              */
11666 /*---------------------------------------------------------------------*/
11667 void
check_send_scan_hb_rep(Signal * signal,ScanRecord * scanPtrP,TcConnectionrec * tcPtrP)11668 Dblqh::check_send_scan_hb_rep(Signal* signal,
11669                               ScanRecord* scanPtrP,
11670                               TcConnectionrec* tcPtrP)
11671 {
11672   switch(scanPtrP->scanType){
11673   case ScanRecord::SCAN:
11674     break;
11675   case ScanRecord::COPY:
11676     return;
11677 #ifdef NDEBUG
11678   case ScanRecord::ST_IDLE:
11679   default:
11680     return;
11681 #else
11682   case ScanRecord::ST_IDLE:
11683     ndbrequire(false);
11684 #endif
11685   }
11686 
11687   const Uint32 now = cLqhTimeOutCount;         // measure in 10ms
11688   const Uint32 last = scanPtrP->scanTcWaiting; // last time we reported to TC (10ms)
11689   const Uint32 timeout = cTransactionDeadlockDetectionTimeout; // (ms)
11690   const Uint32 limit = timeout / 16;
11691   const Uint32 time_waiting = (now - last) * 10; // Convert to ms
11692 
11693   ndbassert(limit > 0);
11694   /**
11695    * We need to ensure we send heartbeats before TC decides to timeout based
11696    * on a deadlock. We use 1/16th of the timeout period for this. The other
11697    * thing to consider is wraparound, but this will work fine since then we
11698    * we will get an immediate very high number and immediate timeout.
11699   */
11700 
11701   if (time_waiting > limit)
11702   {
11703     jam();
11704 
11705     scanPtrP->scanTcWaiting = Uint32(now);
11706     if (tcPtrP->tcTimer != 0)
11707     {
11708       tcPtrP->tcTimer = Uint32(now);
11709     }
11710 
11711     Uint32 save[3];
11712     save[0] = signal->theData[0];
11713     save[1] = signal->theData[1];
11714     save[2] = signal->theData[2];
11715 
11716     signal->theData[0] = tcPtrP->clientConnectrec;
11717     signal->theData[1] = tcPtrP->transid[0];
11718     signal->theData[2] = tcPtrP->transid[1];
11719     sendSignal(tcPtrP->clientBlockref,
11720                GSN_SCAN_HBREP, signal, 3, JBB);
11721 
11722     signal->theData[0] = save[0];
11723     signal->theData[1] = save[1];
11724     signal->theData[2] = save[2];
11725   }
11726 }
11727 
accScanConfScanLab(Signal * signal)11728 void Dblqh::accScanConfScanLab(Signal* signal)
11729 {
11730   AccScanConf * const accScanConf = (AccScanConf *)&signal->theData[0];
11731   ScanRecord * const scanPtr = scanptr.p;
11732 
11733   /* -----------------------------------------------------------------------
11734    *       PRECONDITION: SCAN_STATE = WAIT_ACC_SCAN
11735    * ----------------------------------------------------------------------- */
11736   if (accScanConf->flag == AccScanConf::ZEMPTY_FRAGMENT) {
11737     jam();
11738     /* ---------------------------------------------------------------------
11739      *       THE FRAGMENT WAS EMPTY.
11740      *       REPORT SUCCESSFUL COPYING.
11741      * --------------------------------------------------------------------- */
11742     /*
11743      * MRR scan + delete can hit this when the fragment was not
11744      * initially empty, but has become empty after previous range.
11745      */
11746     if (scanPtr->scanStoredProcId != RNIL) {
11747       jam();
11748       scanPtr->scanCompletedStatus = ZTRUE;
11749       accScanCloseConfLab(signal);
11750       return;
11751     }
11752     tupScanCloseConfLab(signal);
11753     return;
11754   }//if
11755 
11756   check_send_scan_hb_rep(signal, scanPtr, tcConnectptr.p);
11757 
11758   scanPtr->scanAccPtr = accScanConf->accPtr;
11759   if (scanPtr->rangeScan) {
11760     TuxBoundInfo* req = (TuxBoundInfo*)signal->getDataPtrSend();
11761     req->errorCode = RNIL;
11762     req->tuxScanPtrI = scanPtr->scanAccPtr;
11763     Uint32 len = req->boundAiLength = copyNextRange(req->data, tcConnectptr.p);
11764     signal->setLength(TuxBoundInfo::SignalLength + len);
11765     c_tux->execTUX_BOUND_INFO(signal);
11766     jamEntry();
11767     if (req->errorCode != 0) {
11768       jam();
11769       /*
11770        * Cannot use STORED_PROCREF to abort since even the REF
11771        * returns a stored proc id.  So record error and continue.
11772        * The scan is already Invalid in TUX and returns empty set.
11773        */
11774       tcConnectptr.p->errorCode = req->errorCode;
11775     }
11776   }
11777 
11778   if(scanPtr->scanStoredProcId == RNIL)
11779   {
11780     TcConnectionrec * const regTcPtr = tcConnectptr.p;
11781     jam();
11782     /* Send AttrInfo to TUP to store as 'stored procedure'
11783      * and get storedProcId back for future reference
11784      */
11785     const Uint32 sig0 = regTcPtr->tupConnectrec;
11786     const Uint32 sig1 = regTcPtr->tableref;
11787     const Uint32 sig2 = scanPtr->scanSchemaVersion;
11788     const Uint32 sig5 = scanPtr->scanApiBlockref;
11789     const Uint32 sig6 = regTcPtr->attrInfoIVal;
11790 
11791     signal->theData[0] = sig0;
11792     signal->theData[1] = sig1;
11793     signal->theData[2] = sig2;
11794     signal->theData[3] = ZSTORED_PROC_SCAN;
11795 // theData[4] is not used
11796     signal->theData[5] = sig5;
11797     signal->theData[6] = sig6;
11798 
11799     /* Pass ATTRINFO as long section, we don't need
11800      * it after this
11801      */
11802     regTcPtr->attrInfoIVal= RNIL;
11803 
11804     c_tup->execSTORED_PROCREQ(signal);
11805     if (signal->theData[0] == 0)
11806     {
11807       /* STORED_PROCCONF */
11808       jamEntry();
11809       scanPtr->scanStoredProcId = signal->theData[1];
11810       storedProcConfScanLab(signal);
11811     }
11812     else
11813     {
11814       /* STORED_PROCREF */
11815       jamEntry();
11816       scanPtr->scanCompletedStatus = ZTRUE;
11817       tcConnectptr.p->errorCode = signal->theData[1];
11818       scanPtr->scanStoredProcId = signal->theData[2];
11819       closeScanLab(signal);
11820     }
11821   }
11822   else
11823   {
11824     /* TUP already has the Stored procedure, continue */
11825     jam();
11826     storedProcConfScanLab(signal);
11827   }
11828 }//Dblqh::accScanConfScanLab()
11829 
11830 Uint32
copyNextRange(Uint32 * dst,TcConnectionrec * tcPtrP)11831 Dblqh::copyNextRange(Uint32 * dst, TcConnectionrec* tcPtrP)
11832 {
11833   /**
11834    * Copy the bound info for the next range from the KeyInfo
11835    * to *dst
11836    * There may be zero or more bounds
11837    * A SectionReader is used to read bound information, its
11838    * position is saved between calls
11839    * This method also extracts range numbers from the
11840    * KeyInfo
11841    */
11842   Uint32 totalLen = tcPtrP->primKeyLen;
11843   if (totalLen == 0)
11844   {
11845     return 0;
11846   }
11847 
11848   Uint32 * save = dst;
11849   do
11850   {
11851     ndbassert( tcPtrP->keyInfoIVal != RNIL );
11852     SectionReader keyInfoReader(tcPtrP->keyInfoIVal,
11853                                 g_sectionSegmentPool);
11854 
11855     if (tcPtrP->m_flags & TcConnectionrec::OP_SCANKEYINFOPOSSAVED)
11856     {
11857       /* Second or higher range in an MRR scan
11858        * Restore SectionReader to the last position it was in
11859        */
11860       bool ok= keyInfoReader.setPos(tcPtrP->scanKeyInfoPos);
11861       ndbrequire(ok);
11862     }
11863 
11864     /* Get first word of next range and extract range
11865      * length, number from it.
11866      * For non MRR, these will be zero.
11867      */
11868     Uint32 firstWord;
11869     ndbrequire( keyInfoReader.getWord(&firstWord) );
11870     const Uint32 rangeLen= (firstWord >> 16) ? (firstWord >> 16) : totalLen;
11871     Uint32 range_no = (firstWord & 0xFFF0) >> 4;
11872     tcPtrP->m_scan_curr_range_no= range_no;
11873     tcPtrP->m_corrFactorLo &= 0x0000FFFF;
11874     tcPtrP->m_corrFactorLo |= (range_no << 16);
11875     firstWord &= 0xF; // Remove length+range num from first word
11876 
11877     /* Write range info to dst */
11878     *(dst++)= firstWord;
11879     bool ok= keyInfoReader.getWords(dst, rangeLen - 1);
11880     ndbassert(ok);
11881     if (unlikely(!ok))
11882       break;
11883 
11884     if (ERROR_INSERTED(5074))
11885       break;
11886 
11887     tcPtrP->primKeyLen-= rangeLen;
11888 
11889     if (rangeLen == totalLen)
11890     {
11891       /* All range information has been copied, free the section */
11892       releaseSection(tcPtrP->keyInfoIVal);
11893       tcPtrP->keyInfoIVal= RNIL;
11894     }
11895     else
11896     {
11897       /* Save position of SectionReader for next range (if any) */
11898       tcPtrP->scanKeyInfoPos= keyInfoReader.getPos();
11899       tcPtrP->m_flags|= TcConnectionrec::OP_SCANKEYINFOPOSSAVED;
11900     }
11901 
11902     return rangeLen;
11903   } while (0);
11904 
11905   /**
11906    * We enter here if there was some error in the keyinfo
11907    *   this has (once) been seen in customer lab,
11908    *   never at in the wild, and never in internal lab.
11909    *   root-cause unknown, maybe ndbapi application bug
11910    *
11911    * Crash in debug, or ERROR_INSERT (unless 5074)
11912    * else
11913    *   generate an incorrect bound...that will make TUX abort the scan
11914    */
11915 #ifdef ERROR_INSERT
11916   ndbrequire(ERROR_INSERTED_CLEAR(5074));
11917 #else
11918   ndbassert(false);
11919 #endif
11920 
11921   * save = TuxBoundInfo::InvalidBound;
11922   return 1;
11923 }
11924 
11925 /* -------------------------------------------------------------------------
11926  *       ENTER STORED_PROCCONF WITH
11927  *         0 success == CONF, 1 failure == REF
11928  *         STORED_PROC_ID
11929  * ------------------------------------------------------------------------- */
storedProcConfScanLab(Signal * signal)11930 void Dblqh::storedProcConfScanLab(Signal* signal)
11931 {
11932   ScanRecord * const scanPtr = scanptr.p;
11933   fragptr.i = tcConnectptr.p->fragmentptr;
11934 
11935   c_fragment_pool.getPtr(fragptr);
11936   if (scanPtr->scanCompletedStatus == ZTRUE) {
11937     jam();
11938     // STOP THE SCAN PROCESS IF THIS HAS BEEN REQUESTED.
11939     closeScanLab(signal);
11940     return;
11941   }//if
11942   if (likely(fragptr.p->fragStatus == Fragrecord::FSACTIVE))
11943   {
11944     const Uint32 sig0 = scanPtr->scanAccPtr;
11945     SimulatedBlock *block = scanPtr->scanBlock;
11946     ExecFunction f = scanPtr->scanFunction_NEXT_SCANREQ;
11947     signal->theData[1] = RNIL;
11948     signal->theData[2] = NextScanReq::ZSCAN_NEXT;
11949     signal->theData[0] = sig0;
11950     scanPtr->scanState = ScanRecord::WAIT_NEXT_SCAN;
11951     send_next_NEXT_SCANREQ(signal, block, f, scanPtr);
11952     return;
11953   }
11954   else
11955   {
11956     jamLine(fragptr.p->fragStatus);
11957     ndbout_c("fragptr.p->fragStatus: %u",
11958              fragptr.p->fragStatus);
11959     // wl4391_todo SR 2-node CRASH_RECOVERING from BACKUP
11960     ndbrequire(false);
11961     return;
11962   }
11963 }//Dblqh::storedProcConfScanLab()
11964 
11965 /* -------------------------------------------------------------------------
11966  * When executing a scan we must come up to the surface at times to make
11967  * sure we can quickly start local checkpoints.
11968  * ------------------------------------------------------------------------- */
execCHECK_LCP_STOP(Signal * signal)11969 void Dblqh::execCHECK_LCP_STOP(Signal* signal)
11970 {
11971   const Uint32 scanPtrI = signal->theData[0];
11972   jamEntry();
11973   if (signal->theData[1] == ZTRUE) {
11974     jam();
11975     signal->theData[0] = ZCHECK_LCP_STOP_BLOCKED;
11976     signal->theData[1] = scanPtrI;
11977     sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 10, 2);
11978     signal->theData[0] = RNIL;
11979   }//if
11980 }//Dblqh::execCHECK_LCP_STOP()
11981 
checkLcpStopBlockedLab(Signal * signal)11982 void Dblqh::checkLcpStopBlockedLab(Signal* signal)
11983 {
11984   Fragrecord::FragStatus fragstatus = fragptr.p->fragStatus;
11985   ScanRecord * const scanPtr = scanptr.p;
11986   BlockReference blockRef = scanPtr->scanBlockref;
11987   signal->theData[0] = scanPtr->scanAccPtr;
11988   signal->theData[1] = AccCheckScan::ZNOT_CHECK_LCP_STOP;
11989   ndbrequire(fragstatus == Fragrecord::FSACTIVE);
11990   EXECUTE_DIRECT(refToMain(blockRef), GSN_ACC_CHECK_SCAN,
11991       signal, 2);
11992 }//Dblqh::checkLcpStopBlockedLab()
11993 
11994 /* -------------------------------------------------------------------------
11995  *       ENTER NEXT_SCANCONF
11996  * -------------------------------------------------------------------------
11997  *       PRECONDITION: SCAN_STATE = WAIT_NEXT_SCAN
11998  * ------------------------------------------------------------------------- */
nextScanConfScanLab(Signal * signal,ScanRecord * const scanPtr,TcConnectionrec * const regTcPtr,Uint32 fragId,Uint32 accOpPtr)11999 void Dblqh::nextScanConfScanLab(Signal* signal,
12000                                 ScanRecord * const scanPtr,
12001                                 TcConnectionrec * const regTcPtr,
12002                                 Uint32 fragId,
12003                                 Uint32 accOpPtr)
12004 {
12005   if (fragId != RNIL && accOpPtr != RNIL) {
12006     check_send_scan_hb_rep(signal, scanPtr, regTcPtr);
12007     set_acc_ptr_in_scan_record(scanPtr,
12008                                scanPtr->m_curr_batch_size_rows,
12009                                accOpPtr);
12010 
12011     Fragrecord* fragPtrP= fragptr.p;
12012     /* ----------------------------------------------------------------------
12013      *       STOP THE SCAN PROCESS IF THIS HAS BEEN REQUESTED.
12014      * ---------------------------------------------------------------------- */
12015     if (scanPtr->scanCompletedStatus == ZTRUE) {
12016       if ((scanPtr->scanLockHold == ZTRUE) &&
12017           (scanPtr->m_curr_batch_size_rows > 0)) {
12018         jam();
12019         scanPtr->scanReleaseCounter = 1;
12020         scanReleaseLocksLab(signal);
12021         return;
12022       }//if
12023       jam();
12024       closeScanLab(signal);
12025       return;
12026     }//if
12027 
12028     const Uint32 fragPtrI = fragPtrP->tableFragptr;
12029     const Uint32 rangeScan = scanPtr->rangeScan;
12030     bool disk_table = regTcPtr->m_disk_table;
12031     jam();
12032     regTcPtr->transactionState = TcConnectionrec::SCAN_TUPKEY;
12033     if (rangeScan) {
12034       // for ordered index use primary table
12035       fragPtrP= c_fragment_pool.getPtr(fragPtrI);
12036       jam();
12037     }
12038 
12039     if (!disk_table)
12040     {
12041       next_scanconf_tupkeyreq(signal, scanPtr, regTcPtr, fragPtrP, RNIL);
12042     }
12043     else
12044     {
12045       next_scanconf_load_diskpage(signal, scanPtr, tcConnectptr,fragPtrP);
12046     }
12047   }
12048   else
12049   {
12050     // If accOperationPtr == RNIL no record was returned by ACC
12051     /* ---------------------------------------------------------------------
12052      *       THERE ARE NO MORE TUPLES TO FETCH. IF WE HAVE ANY
12053      *       OPERATIONS STILL NEEDING A LOCK WE REPORT TO THE
12054      *       APPLICATION AND CLOSE THE SCAN WHEN THE NEXT SCAN
12055      *       REQUEST IS RECEIVED. IF WE DO NOT HAVE ANY NEED FOR
12056      *       LOCKS WE CAN CLOSE THE SCAN IMMEDIATELY.
12057      * --------------------------------------------------------------------- */
12058     /*************************************************************
12059      *       STOP THE SCAN PROCESS IF THIS HAS BEEN REQUESTED.
12060      ************************************************************ */
12061     if (fragId == RNIL && !scanPtr->scanLockHold)
12062     {
12063       jam();
12064       closeScanLab(signal);
12065       return;
12066     }
12067 
12068     if (scanPtr->scanCompletedStatus == ZTRUE) {
12069       if ((scanPtr->scanLockHold == ZTRUE) &&
12070 	  (scanPtr->m_curr_batch_size_rows > 0)) {
12071 	jam();
12072 	scanPtr->scanReleaseCounter = 1;
12073 	scanReleaseLocksLab(signal);
12074 	return;
12075       }//if
12076       jam();
12077       closeScanLab(signal);
12078       return;
12079     }//if
12080 
12081     if (scanPtr->m_curr_batch_size_rows > 0) {
12082       if (fragId == RNIL && regTcPtr->primKeyLen == 0)
12083       {
12084         jam();
12085 	scanPtr->scanCompletedStatus = ZTRUE;
12086       }
12087       jam();
12088       scanPtr->scanState = ScanRecord::WAIT_SCAN_NEXTREQ;
12089       sendScanFragConf(signal, ZFALSE);
12090       return;
12091     }//if
12092 
12093     if (fragId == RNIL)
12094     {
12095       jam();
12096       closeScanLab(signal);
12097       return;
12098     }
12099     else
12100     {
12101       Uint32 sig0 = scanPtr->scanAccPtr;
12102       BlockReference blockRef = scanPtr->scanBlockref;
12103       jam();
12104       signal->theData[0] = sig0;
12105       signal->theData[1] = AccCheckScan::ZCHECK_LCP_STOP;
12106       sendSignal(blockRef, GSN_ACC_CHECK_SCAN, signal, 2, JBB);
12107       return;
12108     }
12109   }
12110 }//Dblqh::nextScanConfScanLab()
12111 
12112 void
next_scanconf_tupkeyreq(Signal * signal,ScanRecord * scanPtr,TcConnectionrec * regTcPtr,Fragrecord * fragPtrP,Uint32 disk_page)12113 Dblqh::next_scanconf_tupkeyreq(Signal* signal,
12114 			       ScanRecord * scanPtr,
12115 			       TcConnectionrec * regTcPtr,
12116 			       Fragrecord * fragPtrP,
12117 			       Uint32 disk_page)
12118 {
12119   TupKeyReq * const tupKeyReq = (TupKeyReq *)signal->getDataPtrSend();
12120   const Uint32 fragPtr = fragPtrP->tupFragptr;
12121   Uint32 reqinfo = 0;
12122   TupKeyReq::setDirtyFlag(reqinfo, (scanPtr->scanLockHold == ZFALSE));
12123   TupKeyReq::setPrioAFlag(reqinfo, scanPtr->prioAFlag);
12124   TupKeyReq::setOperation(reqinfo, regTcPtr->operation);
12125   TupKeyReq::setInterpretedFlag(reqinfo, regTcPtr->opExec);
12126   TupKeyReq::setReorgFlag(reqinfo, regTcPtr->m_reorg);
12127   tupKeyReq->disk_page= disk_page;
12128   tupKeyReq->attrInfoIVal= RNIL;
12129   tupKeyReq->attrBufLen = 0;
12130   jam();
12131 
12132   tupKeyReq->fragPtr = fragPtr;
12133   tupKeyReq->request = reqinfo;
12134   /* No AttrInfo sent to TUP, it uses a stored procedure */
12135 
12136   {
12137     const Uint32 connectPtr = regTcPtr->tupConnectrec;
12138     const Uint32 keyRef1 = scanPtr->m_row_id.m_page_no;
12139     const Uint32 opRef = scanPtr->scanApiOpPtr;
12140     const Uint32 applRef = scanPtr->scanApiBlockref;
12141     const Uint32 storedProcedure = scanPtr->scanStoredProcId;
12142     const Uint32 keyRef2 = scanPtr->m_row_id.m_page_idx;
12143 
12144     tupKeyReq->connectPtr = connectPtr;
12145     tupKeyReq->keyRef1 = keyRef1;
12146     tupKeyReq->keyRef2 = keyRef2;
12147     tupKeyReq->opRef = opRef;
12148     tupKeyReq->applRef = applRef;
12149     tupKeyReq->storedProcedure = storedProcedure;
12150   }
12151   {
12152     const Uint32 seqNoReplica = regTcPtr->seqNoReplica;
12153     const Uint32 coordinatorTC = regTcPtr->tcBlockref;
12154     const Uint32 tcOpIndex = regTcPtr->tcOprec;
12155     const Uint32 savePointId = regTcPtr->savePointId;
12156     const Uint32 transId1 = regTcPtr->transid[0];
12157     const Uint32 transId2 = regTcPtr->transid[1];
12158 
12159     tupKeyReq->primaryReplica = (seqNoReplica == 0) ? true : false;
12160     tupKeyReq->coordinatorTC = coordinatorTC;
12161     tupKeyReq->tcOpIndex = tcOpIndex;
12162     tupKeyReq->savePointId = savePointId;
12163     tupKeyReq->transId1 = transId1;
12164     tupKeyReq->transId2 = transId2;
12165   }
12166   if (c_tup->execTUPKEYREQ(signal))
12167   {
12168     execTUPKEYCONF(signal);
12169   }
12170   else
12171   {
12172     execTUPKEYREF(signal);
12173   }
12174 }
12175 
12176 void
next_scanconf_load_diskpage(Signal * signal,ScanRecord * const scanPtr,Ptr<TcConnectionrec> regTcPtr,Fragrecord * fragPtrP)12177 Dblqh::next_scanconf_load_diskpage(Signal* signal,
12178 				   ScanRecord * const scanPtr,
12179 				   Ptr<TcConnectionrec> regTcPtr,
12180 				   Fragrecord* fragPtrP)
12181 {
12182   jam();
12183 
12184   int res;
12185 
12186   if((res= c_tup->load_diskpage_scan(signal,
12187 				     regTcPtr.p->tupConnectrec,
12188 				     fragPtrP->tupFragptr,
12189 				     scanPtr->m_row_id.m_page_no,
12190 				     scanPtr->m_row_id.m_page_idx,
12191 				     0)) > 0)
12192   {
12193     next_scanconf_tupkeyreq(signal, scanPtr, regTcPtr.p, fragPtrP, res);
12194   }
12195   else if(unlikely(res != 0))
12196   {
12197     jam();
12198     TupKeyRef * ref = (TupKeyRef *)signal->getDataPtr();
12199     ref->userRef= regTcPtr.i;
12200     ref->errorCode= ~0;
12201     execTUPKEYREF(signal);
12202   }
12203 }
12204 
12205 void
next_scanconf_load_diskpage_callback(Signal * signal,Uint32 callbackData,Uint32 disk_page)12206 Dblqh::next_scanconf_load_diskpage_callback(Signal* signal,
12207 					    Uint32 callbackData,
12208 					    Uint32 disk_page)
12209 {
12210   jamEntry();
12211 
12212   Ptr<TcConnectionrec> regTcPtr;
12213   regTcPtr.i= callbackData;
12214   ptrCheckGuard(regTcPtr, ctcConnectrecFileSize, tcConnectionrec);
12215 
12216   ScanRecordPtr scanPtr;
12217   c_scanRecordPool.getPtr(scanPtr, regTcPtr.p->tcScanRec);
12218 
12219   if(disk_page > 0)
12220   {
12221     jam();
12222     FragrecordPtr fragPtr;
12223     c_fragment_pool.getPtr(fragPtr, regTcPtr.p->fragmentptr);
12224     if (scanPtr.p->rangeScan) {
12225       // for ordered index use primary table
12226       fragPtr.i = fragPtr.p->tableFragptr;
12227       fragPtr.p = c_fragment_pool.getPtr(fragPtr.i);
12228       jam();
12229     }
12230     c_tup->prepareTUPKEYREQ(scanPtr.p->m_row_id.m_page_no,
12231                             scanPtr.p->m_row_id.m_page_idx,
12232                             fragPtr.p->tupFragptr);
12233     next_scanconf_tupkeyreq(signal, scanPtr.p, regTcPtr.p, fragPtr.p, disk_page);
12234   }
12235   else
12236   {
12237     jam();
12238     TupKeyRef * ref = (TupKeyRef *)signal->getDataPtr();
12239     ref->userRef= callbackData;
12240     ref->errorCode= disk_page;
12241     execTUPKEYREF(signal);
12242   }
12243 }
12244 
12245 /* -------------------------------------------------------------------------
12246  *       STORE KEYINFO IN A LONG SECTION PRIOR TO SENDING
12247  * -------------------------------------------------------------------------
12248  *       PRECONDITION:   SCAN_STATE = WAIT_SCAN_KEYINFO
12249  * ------------------------------------------------------------------------- */
12250 bool
keyinfoLab(const Uint32 * src,Uint32 len)12251 Dblqh::keyinfoLab(const Uint32 * src, Uint32 len)
12252 {
12253   ndbassert( tcConnectptr.p->keyInfoIVal == RNIL );
12254   ndbassert( len > 0 );
12255 
12256   if (ERROR_INSERTED(5052) || ERROR_INSERTED_CLEAR(5060))
12257     return false;
12258 
12259   return(appendToSection(tcConnectptr.p->keyInfoIVal,
12260                          src,
12261                          len));
12262 }//Dblqh::keyinfoLab()
12263 
12264 Uint32
readPrimaryKeys(ScanRecord * scanP,TcConnectionrec * tcConP,Uint32 * dst)12265 Dblqh::readPrimaryKeys(ScanRecord *scanP, TcConnectionrec *tcConP, Uint32 *dst)
12266 {
12267   Uint32 tableId = tcConP->tableref;
12268   Uint32 fragId = tcConP->fragmentid;
12269   Uint32 fragPageId = scanP->m_row_id.m_page_no;
12270   Uint32 pageIndex = scanP->m_row_id.m_page_idx;
12271 
12272   if(scanP->rangeScan)
12273   {
12274     jam();
12275     // for ordered index use primary table
12276     FragrecordPtr tFragPtr;
12277     tFragPtr.i = fragptr.p->tableFragptr;
12278     c_fragment_pool.getPtr(tFragPtr);
12279     tableId = tFragPtr.p->tabRef;
12280   }
12281 
12282   int ret = c_tup->accReadPk(tableId, fragId, fragPageId, pageIndex, dst, false);
12283   jamEntry();
12284   if(0)
12285     ndbout_c("readPrimaryKeys(table: %d fragment: %d [ %d %d ] -> %d",
12286 	     tableId, fragId, fragPageId, pageIndex, ret);
12287   ndbassert(ret > 0);
12288 
12289   return ret;
12290 }
12291 
12292 /* -------------------------------------------------------------------------
12293  *         ENTER TUPKEYCONF
12294  * -------------------------------------------------------------------------
12295  *       PRECONDITION:   TRANSACTION_STATE = SCAN_TUPKEY
12296  * ------------------------------------------------------------------------- */
scanTupkeyConfLab(Signal * signal)12297 void Dblqh::scanTupkeyConfLab(Signal* signal)
12298 {
12299   TcConnectionrec * const regTcPtr = tcConnectptr.p;
12300   scanptr.i = regTcPtr->tcScanRec;
12301   const TupKeyConf * conf = (TupKeyConf *)signal->getDataPtr();
12302   UintR tdata4 = conf->readLength;
12303   UintR tdata5 = conf->lastRow;
12304   c_scanRecordPool.getPtr(scanptr);
12305 
12306   if (!scanptr.p->lcpScan)
12307   {
12308     Fragrecord::UsageStat& useStat =
12309       c_fragment_pool.getPtr(tcConnectptr.p->fragmentptr)->m_useStat;
12310     ndbassert(useStat.m_scanFragReqCount > 0);
12311 
12312     useStat.m_scanRowsExamined++;
12313     useStat.m_scanInstructionCount += conf->noExecInstructions;
12314   }
12315 
12316   regTcPtr->transactionState = TcConnectionrec::SCAN_STATE_USED;
12317 
12318   ScanRecord * const scanPtr = scanptr.p;
12319 
12320   const Uint32 rows = scanPtr->m_curr_batch_size_rows;
12321   const Uint32 accOpPtr= get_acc_ptr_from_scan_record(scanPtr, rows, false);
12322   if (accOpPtr != (Uint32)-1)
12323   {
12324     c_acc->execACCKEY_ORD(signal, accOpPtr);
12325     jamEntry();
12326   }
12327   else
12328   {
12329     ndbassert(refToBlock(scanPtr->scanBlockref) != DBACC);
12330   }
12331 
12332   if (scanPtr->scanCompletedStatus == ZTRUE) {
12333     /* ---------------------------------------------------------------------
12334      *       STOP THE SCAN PROCESS IF THIS HAS BEEN REQUESTED.
12335      * --------------------------------------------------------------------- */
12336     if ((scanPtr->scanLockHold == ZTRUE) && rows)
12337     {
12338       jam();
12339       scanPtr->scanReleaseCounter = 1;
12340       scanReleaseLocksLab(signal);
12341       return;
12342     }//if
12343     jam();
12344     closeScanLab(signal);
12345     return;
12346   }//if
12347   if (scanPtr->scanKeyinfoFlag) {
12348     jam();
12349     // Inform API about keyinfo len aswell
12350     tdata4 += sendKeyinfo20(signal, scanPtr, tcConnectptr.p);
12351   }//if
12352   ndbrequire(scanPtr->m_curr_batch_size_rows < MAX_PARALLEL_OP_PER_SCAN);
12353   scanPtr->m_exec_direct_batch_size_words += tdata4;
12354   scanPtr->m_curr_batch_size_bytes+= tdata4 * sizeof(Uint32);
12355   scanPtr->m_curr_batch_size_rows = rows + 1;
12356   scanPtr->m_last_row = tdata5;
12357 
12358   const NodeBitmask& all = globalTransporterRegistry.get_status_slowdown();
12359   if (unlikely(!all.isclear()))
12360   {
12361     if (all.get(refToNode(scanptr.p->scanApiBlockref)))
12362     {
12363       /**
12364        * End scan batch if transporter-buffer are in slowdown state
12365        *
12366        */
12367       scanPtr->m_stop_batch = 1;
12368 
12369       c_scanSlowDowns++;
12370     }
12371   }
12372 
12373   if (scanPtr->check_scan_batch_completed() | tdata5){
12374     if (scanPtr->scanLockHold == ZTRUE) {
12375       jam();
12376       scanPtr->scanState = ScanRecord::WAIT_SCAN_NEXTREQ;
12377       sendScanFragConf(signal, ZFALSE);
12378       return;
12379     } else {
12380       jam();
12381       scanPtr->scanReleaseCounter = rows + 1;
12382       scanReleaseLocksLab(signal);
12383       return;
12384     }
12385   } else {
12386     if (scanPtr->scanLockHold == ZTRUE) {
12387       jam();
12388       scanPtr->scanFlag = NextScanReq::ZSCAN_NEXT;
12389     } else {
12390       jam();
12391       scanPtr->scanFlag = NextScanReq::ZSCAN_NEXT_COMMIT;
12392     }
12393   }
12394   scanNextLoopLab(signal);
12395 }//Dblqh::scanTupkeyConfLab()
12396 
scanNextLoopLab(Signal * signal)12397 void Dblqh::scanNextLoopLab(Signal* signal)
12398 {
12399   Uint32 accOpPtr;
12400   ScanRecord * const scanPtr = scanptr.p;
12401   Uint32 scanFlag = scanPtr->scanFlag;
12402   if (likely(scanFlag == NextScanReq::ZSCAN_NEXT_COMMIT)) {
12403     accOpPtr= get_acc_ptr_from_scan_record(scanPtr,
12404 					   scanPtr->m_curr_batch_size_rows-1,
12405 					   false);
12406   } else if (scanPtr->scanFlag == NextScanReq::ZSCAN_NEXT_ABORT) {
12407     jam();
12408     scanFlag = scanPtr->scanFlag = NextScanReq::ZSCAN_NEXT_COMMIT;
12409     accOpPtr= get_acc_ptr_from_scan_record(scanPtr,
12410 					   scanPtr->m_curr_batch_size_rows,
12411 					   false);
12412     scanPtr->scan_acc_index--;
12413   } else {
12414     jam();
12415     accOpPtr = RNIL; // The value is not used in ACC
12416   }//if
12417   Fragrecord::FragStatus fragstatus = fragptr.p->fragStatus;
12418   const Uint32 sig0 = scanPtr->scanAccPtr;
12419   SimulatedBlock *block = scanPtr->scanBlock;
12420   ExecFunction f = scanPtr->scanFunction_NEXT_SCANREQ;
12421 
12422   signal->theData[0] = sig0;
12423   signal->theData[1] = accOpPtr;
12424   signal->theData[2] = scanFlag;
12425 
12426   ndbrequire(fragstatus == Fragrecord::FSACTIVE);
12427   scanPtr->scanState = ScanRecord::WAIT_NEXT_SCAN;
12428   send_next_NEXT_SCANREQ(signal, block, f, scanPtr);
12429 }//Dblqh::scanNextLoopLab()
12430 
12431 /* -------------------------------------------------------------------------
12432  *         ENTER TUPKEYREF WITH
12433  *               TC_CONNECTPTR,
12434  *               TERROR_CODE
12435  * -------------------------------------------------------------------------
12436  *       PRECONDITION:   TRANSACTION_STATE = SCAN_TUPKEY
12437  * ------------------------------------------------------------------------- */
scanTupkeyRefLab(Signal * signal)12438 void Dblqh::scanTupkeyRefLab(Signal* signal)
12439 {
12440   TcConnectionrec * const regTcPtr = tcConnectptr.p;
12441   scanptr.i = regTcPtr->tcScanRec;
12442   c_scanRecordPool.getPtr(scanptr);
12443   ScanRecord * const scanPtr = scanptr.p;
12444   regTcPtr->transactionState = TcConnectionrec::SCAN_STATE_USED;
12445 
12446   if (!scanptr.p->lcpScan)
12447   {
12448     Fragrecord::UsageStat& useStat =
12449       c_fragment_pool.getPtr(tcConnectptr.p->fragmentptr)->m_useStat;
12450     ndbassert(useStat.m_scanFragReqCount > 0);
12451 
12452     useStat.m_scanRowsExamined++;
12453 
12454     const TupKeyRef* const ref =
12455       reinterpret_cast<const TupKeyRef*>(signal->getDataPtr());
12456     useStat.m_scanInstructionCount += ref->noExecInstructions;
12457   }
12458 
12459   Uint32 rows = scanPtr->m_curr_batch_size_rows;
12460   Uint32 accOpPtr= get_acc_ptr_from_scan_record(scanPtr, rows, false);
12461   if (accOpPtr != (Uint32)-1)
12462   {
12463     c_acc->execACCKEY_ORD(signal, accOpPtr);
12464     jamEntry();
12465   }
12466   else
12467   {
12468     ndbassert(refToBlock(scanPtr->scanBlockref) != DBACC);
12469     jam();
12470   }
12471 
12472   if (scanPtr->scanCompletedStatus == ZTRUE) {
12473     /* ---------------------------------------------------------------------
12474      *       STOP THE SCAN PROCESS IF THIS HAS BEEN REQUESTED.
12475      * --------------------------------------------------------------------- */
12476     if ((scanPtr->scanLockHold == ZTRUE) && rows)
12477     {
12478       jam();
12479       scanPtr->scanReleaseCounter = 1;
12480       scanReleaseLocksLab(signal);
12481       return;
12482     }//if
12483     jam();
12484     closeScanLab(signal);
12485     return;
12486   }//if
12487   if ((terrorCode != ZUSER_SEARCH_CONDITION_FALSE_CODE) &&
12488       (terrorCode != ZNO_TUPLE_FOUND)) {
12489 #ifdef VM_TRACE
12490     ndbout << "Dblqh::scanTupkeyRefLab() aborting scan terrorCode="
12491            << terrorCode << endl;
12492 #endif
12493     scanPtr->scanErrorCounter++;
12494     tcConnectptr.p->errorCode = terrorCode;
12495 
12496     if (scanPtr->scanLockHold == ZTRUE && rows > 0) {
12497       jam();
12498       scanPtr->scanReleaseCounter = 1;
12499     } else {
12500       jam();
12501       scanPtr->m_curr_batch_size_rows = rows + 1;
12502       scanPtr->scanReleaseCounter = rows + 1;
12503     }//if
12504     /* --------------------------------------------------------------------
12505      *       WE NEED TO RELEASE ALL LOCKS CURRENTLY
12506      *       HELD BY THIS SCAN.
12507      * -------------------------------------------------------------------- */
12508     scanReleaseLocksLab(signal);
12509     return;
12510   }//if
12511   Uint32 time_passed= cLqhTimeOutCount - tcConnectptr.p->tcTimer;
12512   if (rows)
12513   {
12514     if (time_passed > 1)
12515     {
12516   /* -----------------------------------------------------------------------
12517    *  WE NEED TO ENSURE THAT WE DO NOT SEARCH FOR THE NEXT TUPLE FOR A
12518    *  LONG TIME WHILE WE KEEP A LOCK ON A FOUND TUPLE. WE RATHER REPORT
12519    *  THE FOUND TUPLE IF FOUND TUPLES ARE RARE. If more than 10 ms passed we
12520    *  send the found tuples to the API.
12521    * ----------------------------------------------------------------------- */
12522       scanPtr->scanReleaseCounter = rows + 1;
12523       scanReleaseLocksLab(signal);
12524       return;
12525     }
12526   }
12527 
12528   scanPtr->scanFlag = NextScanReq::ZSCAN_NEXT_ABORT;
12529   scanNextLoopLab(signal);
12530 }//Dblqh::scanTupkeyRefLab()
12531 
12532 /* -------------------------------------------------------------------------
12533  *   THE SCAN HAS BEEN COMPLETED. EITHER BY REACHING THE END OR BY COMMAND
12534  *   FROM THE APPLICATION OR BY SOME SORT OF ERROR CONDITION.
12535  * ------------------------------------------------------------------------- */
closeScanLab(Signal * signal)12536 void Dblqh::closeScanLab(Signal* signal)
12537 {
12538   FragrecordPtr regFragPtr;
12539   TcConnectionrec * const regTcPtr = tcConnectptr.p;
12540   ScanRecord * const scanPtr = scanptr.p;
12541   regFragPtr.i = regTcPtr->fragmentptr;
12542   SimulatedBlock *block = scanPtr->scanBlock;
12543   const Uint32 sig0 = scanPtr->scanAccPtr;
12544   c_fragment_pool.getPtr(regFragPtr);
12545   Fragrecord::FragStatus fragstatus = regFragPtr.p->fragStatus;
12546   ExecFunction f = scanPtr->scanFunction_NEXT_SCANREQ;
12547 
12548   scanPtr->scanState = ScanRecord::WAIT_CLOSE_SCAN;
12549   regTcPtr->transactionState = TcConnectionrec::SCAN_STATE_USED;
12550   signal->theData[1] = RNIL;
12551   signal->theData[2] = NextScanReq::ZSCAN_CLOSE;
12552   signal->theData[0] = sig0;
12553   ndbrequire(fragstatus == Fragrecord::FSACTIVE);
12554   block->EXECUTE_DIRECT(f, signal);
12555 }//Dblqh::closeScanLab()
12556 
12557 /* -------------------------------------------------------------------------
12558  *       ENTER NEXT_SCANCONF
12559  * -------------------------------------------------------------------------
12560  *       PRECONDITION: SCAN_STATE = WAIT_CLOSE_SCAN
12561  * ------------------------------------------------------------------------- */
accScanCloseConfLab(Signal * signal)12562 void Dblqh::accScanCloseConfLab(Signal* signal)
12563 {
12564   ScanRecord * const scanPtr = scanptr.p;
12565 
12566   /* Do we have another range to scan? */
12567   if((tcConnectptr.p->primKeyLen > 0) &&
12568      (scanPtr->scanCompletedStatus != ZTRUE))
12569   {
12570     jam();
12571     /* Start next range scan...*/
12572     scanPtr->scan_direct_count++;
12573     continueAfterReceivingAllAiLab(signal);
12574     return;
12575   }
12576   TcConnectionrec * const regTcPtr = tcConnectptr.p;
12577 
12578   const Uint32 sig0 = regTcPtr->tupConnectrec;
12579   const Uint32 sig1 = regTcPtr->tableref;
12580   const Uint32 sig2 = scanPtr->scanSchemaVersion;
12581   const Uint32 sig4 = scanPtr->scanStoredProcId;
12582   const Uint32 sig5 = scanPtr->scanApiBlockref;
12583 
12584   signal->theData[0] = sig0;
12585   signal->theData[1] = sig1;
12586   signal->theData[2] = sig2;
12587   signal->theData[3] = ZDELETE_STORED_PROC_ID;
12588   signal->theData[4] = sig4;
12589   signal->theData[5] = sig5;
12590   c_tup->execSTORED_PROCREQ(signal);
12591   ndbrequire(signal->theData[0] == 0);
12592 /* -------------------------------------------------------------------------
12593  *       ENTER STORED_PROCCONF
12594  * ------------------------------------------------------------------------- */
12595   tupScanCloseConfLab(signal);
12596 }//Dblqh::accScanCloseConfLab()
12597 
tupScanCloseConfLab(Signal * signal)12598 void Dblqh::tupScanCloseConfLab(Signal* signal)
12599 {
12600   TcConnectionrec * const regTcPtr = tcConnectptr.p;
12601   fragptr.i = regTcPtr->fragmentptr;
12602   c_fragment_pool.getPtr(fragptr);
12603   if (regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC) {
12604     jam();
12605     TcNodeFailRecordPtr tcNodeFailPtr;
12606     tcNodeFailPtr.i = regTcPtr->tcNodeFailrec;
12607     ptrCheckGuard(tcNodeFailPtr, ctcNodeFailrecFileSize, tcNodeFailRecord);
12608     tcNodeFailPtr.p->tcRecNow = tcConnectptr.i + 1;
12609     signal->theData[0] = ZLQH_TRANS_NEXT;
12610     signal->theData[1] = tcNodeFailPtr.i;
12611     sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
12612   } else if (regTcPtr->errorCode != 0) {
12613     jam();
12614     ScanFragRef * ref = (ScanFragRef*)&signal->theData[0];
12615     ref->senderData = regTcPtr->clientConnectrec;
12616     ref->transId1 = regTcPtr->transid[0];
12617     ref->transId2 = regTcPtr->transid[1];
12618     ref->errorCode = regTcPtr->errorCode;
12619     sendSignal(tcConnectptr.p->clientBlockref, GSN_SCAN_FRAGREF, signal,
12620 	 ScanFragRef::SignalLength, JBB);
12621   } else {
12622     jam();
12623     sendScanFragConf(signal, ZSCAN_FRAG_CLOSED);
12624   }//if
12625   {
12626     ScanRecordPtr restart;
12627     bool restart_flag = finishScanrec(signal, restart);
12628     releaseScanrec(signal);
12629     tcConnectptr.p->tcScanRec = RNIL;
12630     deleteTransidHash(signal);
12631     releaseOprec(signal);
12632     releaseTcrec(signal, tcConnectptr);
12633     if (restart_flag)
12634     {
12635       jam();
12636       tcConnectptr.i = restart.p->scanTcrec;
12637       ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
12638       scanptr = restart;
12639       continueAfterReceivingAllAiLab(signal);
12640       return;
12641     }
12642     return;
12643   }
12644 }//Dblqh::tupScanCloseConfLab()
12645 
12646 /* =========================================================================
12647  * =======              INITIATE SCAN RECORD                         =======
12648  *
12649  *       SUBROUTINE SHORT NAME = ISC
12650  * ========================================================================= */
initScanrec(const ScanFragReq * scanFragReq,Uint32 aiLen)12651 Uint32 Dblqh::initScanrec(const ScanFragReq* scanFragReq,
12652                           Uint32 aiLen)
12653 {
12654   ScanRecord * const scanPtr = scanptr.p;
12655 
12656   const Uint32 reqinfo = scanFragReq->requestInfo;
12657   const Uint32 keyinfo = ScanFragReq::getKeyinfoFlag(reqinfo);
12658   const Uint32 scanLockHold = ScanFragReq::getHoldLockFlag(reqinfo);
12659   const Uint32 schemaVersion = scanFragReq->schemaVersion;
12660 
12661   scanPtr->scanAiLength = aiLen;
12662   scanPtr->copyPtr = RNIL;
12663   scanPtr->scanStoredProcId = RNIL;
12664   scanPtr->scanNumber = ~0;
12665   scanPtr->scan_direct_count = ZMAX_SCAN_DIRECT_COUNT - 1;
12666   scanPtr->scanType = ScanRecord::SCAN;
12667   scanPtr->scanState = ScanRecord::SCAN_FREE;
12668   scanPtr->scanCompletedStatus = ZFALSE;
12669   scanPtr->scanFlag = ZFALSE;
12670   scanPtr->scanErrorCounter = 0;
12671   scanPtr->m_stop_batch = 0;
12672   scanPtr->m_curr_batch_size_rows = 0;
12673   scanPtr->m_curr_batch_size_bytes= 0;
12674   scanPtr->m_exec_direct_batch_size_words = 0;
12675   scanPtr->m_last_row = 0;
12676   scanptr.p->scan_acc_segments = 0;
12677   scanPtr->m_row_id.setNull();
12678   scanPtr->scanKeyinfoFlag = keyinfo;
12679   scanPtr->scanLockHold = scanLockHold;
12680   scanPtr->scanSchemaVersion = schemaVersion;
12681 
12682   const Uint32 scanLockMode = ScanFragReq::getLockMode(reqinfo);
12683   const Uint32 readCommitted = ScanFragReq::getReadCommittedFlag(reqinfo);
12684   const Uint32 rangeScan = ScanFragReq::getRangeScanFlag(reqinfo);
12685   const Uint32 prioAFlag = ScanFragReq::getPrioAFlag(reqinfo);
12686 
12687   scanPtr->scanLockMode = scanLockMode;
12688   scanPtr->readCommitted = readCommitted;
12689   scanPtr->rangeScan = rangeScan;
12690   scanPtr->prioAFlag = prioAFlag;
12691 
12692   const Uint32 descending = ScanFragReq::getDescendingFlag(reqinfo);
12693   Uint32 tupScan = ScanFragReq::getTupScanFlag(reqinfo);
12694   const Uint32 resultRef = scanFragReq->resultRef;
12695   const Uint32 tcPtrI = tcConnectptr.i;
12696 
12697   scanPtr->descending = descending;
12698   scanPtr->tupScan = tupScan;
12699   scanPtr->scanApiBlockref = resultRef;
12700   scanPtr->scanTcrec = tcPtrI;
12701   TcConnectionrec * const regTcPtr = tcConnectptr.p;
12702   const bool accScan = (rangeScan == 0) && (tupScan == 0);
12703 
12704   Uint32 blockRef;
12705   SimulatedBlock *block;
12706   ExecFunction f;
12707   if (accScan)
12708   {
12709     blockRef = regTcPtr->tcAccBlockref;
12710     block = c_acc;
12711     f = c_acc->getExecuteFunction(GSN_NEXT_SCANREQ);
12712   }
12713   else if (! tupScan)
12714   {
12715     blockRef = regTcPtr->tcTuxBlockref;
12716     block = c_tux;
12717     f = c_tux->getExecuteFunction(GSN_NEXT_SCANREQ);
12718   }
12719   else
12720   {
12721     blockRef = regTcPtr->tcTupBlockref;
12722     block = c_tup;
12723     f = c_tup->getExecuteFunction(GSN_NEXT_SCANREQ);
12724   }
12725   scanPtr->scanBlockref = blockRef;
12726   scanPtr->scanBlock = block;
12727   scanPtr->scanFunction_NEXT_SCANREQ = f;
12728 
12729   const Uint32 lcpScan = ScanFragReq::getLcpScanFlag(reqinfo);
12730   const Uint32 statScan = ScanFragReq::getStatScanFlag(reqinfo);
12731   const Uint32 scanTcWaiting = cLqhTimeOutCount;
12732   const Uint32 scanApiOpPtr = scanFragReq->clientOpPtr;
12733   const Uint32 max_rows = scanFragReq->batch_size_rows;
12734   const Uint32 max_bytes = scanFragReq->batch_size_bytes;
12735 
12736   scanPtr->lcpScan = lcpScan;
12737   scanPtr->statScan = statScan;
12738   scanPtr->scanTcWaiting = scanTcWaiting;
12739   scanPtr->scanApiOpPtr = scanApiOpPtr;
12740   scanPtr->m_max_batch_size_rows = max_rows;
12741   scanPtr->m_max_batch_size_bytes = max_bytes;
12742 
12743   const Uint32 scanPrio = ScanFragReq::getScanPrio(reqinfo);
12744 
12745   if (max_rows == 0 || (max_bytes > 0 && max_rows > max_bytes)){
12746     jam();
12747     return ScanFragRef::ZWRONG_BATCH_SIZE;
12748   }
12749 
12750   if (ERROR_INSERTED(5057))
12751   {
12752     CLEAR_ERROR_INSERT_VALUE;
12753     return ScanFragRef::ZTOO_MANY_ACTIVE_SCAN_ERROR;
12754   }
12755 
12756   if (!seize_acc_ptr_list(scanPtr, 0, max_rows)){
12757     jam();
12758     return ScanFragRef::ZTOO_MANY_ACTIVE_SCAN_ERROR;
12759   }
12760   init_acc_ptr_list(scanPtr);
12761 
12762   /**
12763    * Used for scan take over
12764    */
12765   FragrecordPtr tFragPtr;
12766   tFragPtr.i = fragptr.p->tableFragptr;
12767   c_fragment_pool.getPtr(tFragPtr);
12768   scanPtr->fragPtrI = fragptr.p->tableFragptr;
12769 
12770   /**
12771    * ACC scan uses 1 - (MAX_PARALLEL_SCANS_PER_FRAG - 1) inclusive  =  0-11
12772    * Range scans uses from MAX_PARALLEL_SCANS_PER_FRAG - MAX = 12-134
12773    * TUP scans uses from 135 - 252
12774    * The boundary between Range and TUP scans are configurable and is
12775    * set in variable c_max_parallel_scans_per_frag.
12776    */
12777 
12778   /**
12779    * ACC only supports 12 parallel scans per fragment (hard limit)
12780    * TUP/TUX does not have any such limit...but when scanning with keyinfo
12781    *         (for take-over) no more than 255 such scans can be active
12782    *         at a fragment (dur to 8 bit number in scan-keyinfo protocol)
12783    *
12784    * TODO: Make TUP/TUX limits depend on scanKeyinfoFlag (possibly with
12785    *       other config limit too)
12786    */
12787 
12788   Uint32 start, stop;
12789   Uint32 max_parallel_scans_per_frag = c_max_parallel_scans_per_frag;
12790   if (accScan)
12791   {
12792     jam();
12793     start = 0;
12794     stop = MAX_PARALLEL_SCANS_PER_FRAG;
12795   }
12796   else if (rangeScan)
12797   {
12798     jam();
12799     start = MAX_PARALLEL_SCANS_PER_FRAG;
12800     stop = start + max_parallel_scans_per_frag;
12801   }
12802   else
12803   {
12804     jam();
12805     ndbassert(tupScan);
12806     start = MAX_PARALLEL_SCANS_PER_FRAG + max_parallel_scans_per_frag;
12807     stop = start + max_parallel_scans_per_frag;
12808     if (stop > NR_ScanNo)
12809     {
12810       jam();
12811       stop = NR_ScanNo;
12812     }
12813   }
12814   ndbrequire((start < 32 * tFragPtr.p->m_scanNumberMask.Size) &&
12815              (stop < 32 * tFragPtr.p->m_scanNumberMask.Size));
12816 
12817   const BlockReference senderBlock = refToMain(regTcPtr->clientBlockref);
12818   Uint32 free;
12819 
12820   if (senderBlock == BACKUP)
12821   {
12822     /**
12823      * Both LCP scans and Backup scans have predefined scan numbers.
12824      * They will never be queued and so completing them will not
12825      * start any queued scans.
12826      */
12827     if (lcpScan)
12828     {
12829       jam();
12830       free = LCP_ScanNo;
12831     }
12832     else
12833     {
12834       /* Backup scan */
12835       jam();
12836       free = Backup_ScanNo;
12837     }
12838     ndbassert(tFragPtr.p->m_scanNumberMask.get(free));
12839   }
12840   else
12841   {
12842     ndbassert(!lcpScan);
12843     /*
12844       This error insert causes an SPJ index scan to be queued (see ndbinfo.test).
12845       Checking 5084 twice to ensure that the optimized build will see this as
12846       'testQueue = false' and not generate code to evaluate subsequent terms.
12847     */
12848     const bool testQueue = ERROR_INSERTED(5084) && rangeScan &&
12849       refToMain(resultRef)==DBSPJ && ERROR_INSERTED_CLEAR(5084);
12850 
12851     free = testQueue ? Fragrecord::ScanNumberMask::NotFound :
12852       tFragPtr.p->m_scanNumberMask.find(start);
12853 
12854     if (free == Fragrecord::ScanNumberMask::NotFound || free >= stop)
12855     {
12856       /**
12857        * stop isn't inclusive, so we allow only ids in the range
12858        * [ start, stop ) .
12859        */
12860       jam();
12861 
12862       if(scanPrio == 0)
12863       {
12864         jam();
12865         return ScanFragRef::ZTOO_MANY_ACTIVE_SCAN_ERROR;
12866       }
12867 
12868       /**
12869        * Put on queue
12870        */
12871       scanPtr->scanState = ScanRecord::IN_QUEUE;
12872       LocalDLCFifoList<ScanRecord> queue(c_scanRecordPool,
12873                                          rangeScan != 0 ?
12874                                          fragptr.p->m_queuedScans :
12875                                          tupScan  != 0 ?
12876                                          fragptr.p->m_queuedTupScans :
12877                                          fragptr.p->m_queuedAccScans);
12878       queue.addLast(scanptr);
12879       fragptr.p->m_useStat.m_queuedScanCount++;
12880       return ZOK;
12881     }
12882   }
12883   scanPtr->scanNumber = free;
12884   tFragPtr.p->m_scanNumberMask.clear(free);// Update mask
12885 
12886   {
12887     LocalDLCList<ScanRecord> active(c_scanRecordPool, fragptr.p->m_activeScans);
12888     active.addFirst(scanptr);
12889   }
12890   if(scanPtr->scanKeyinfoFlag){
12891     jam();
12892 #if defined VM_TRACE || defined ERROR_INSERT
12893     ScanRecordPtr tmp;
12894     ndbrequire(!c_scanTakeOverHash.find(tmp, * scanptr.p));
12895 #endif
12896 #ifdef TRACE_SCAN_TAKEOVER
12897     ndbout_c("adding (%d %d) table: %d fragId: %d frag.i: %d tableFragptr: %d",
12898 	     scanPtr->scanNumber, scanPtr->fragPtrI,
12899 	     tabptr.i, scanFragReq->fragmentNoKeyLen & 0xFFFF,
12900 	     fragptr.i, fragptr.p->tableFragptr);
12901 #endif
12902     c_scanTakeOverHash.add(scanptr);
12903   }
12904   return ZOK;
12905 }
12906 
12907 /* =========================================================================
12908  * =======             INITIATE TC RECORD AT SCAN                    =======
12909  *
12910  *       SUBROUTINE SHORT NAME = IST
12911  * ========================================================================= */
initScanTc(const ScanFragReq * req,Uint32 transid1,Uint32 transid2,Uint32 fragId,Uint32 nodeId,Uint32 hashHi)12912 void Dblqh::initScanTc(const ScanFragReq* req,
12913                        Uint32 transid1,
12914                        Uint32 transid2,
12915                        Uint32 fragId,
12916                        Uint32 nodeId,
12917                        Uint32 hashHi)
12918 {
12919   TcConnectionrec * const regTcPtr = tcConnectptr.p;
12920   regTcPtr->transid[0] = transid1;
12921   regTcPtr->transid[1] = transid2;
12922   regTcPtr->fragmentid = fragId;
12923   regTcPtr->nextReplica = nodeId;
12924   regTcPtr->tcHashKeyHi = hashHi;
12925 
12926   regTcPtr->m_reorg = (req == NULL) ?
12927     (Uint8)ScanFragReq::REORG_ALL :
12928     (Uint8)ScanFragReq::getReorgFlag(req->requestInfo);
12929   TablerecPtr tTablePtr;
12930   tTablePtr.i = tabptr.p->primaryTableId;
12931   ptrCheckGuard(tTablePtr, ctabrecFileSize, tablerec);
12932   regTcPtr->m_disk_table = tTablePtr.p->m_disk_table &&
12933     (!req || !ScanFragReq::getNoDiskFlag(req->requestInfo));
12934   tabptr.p->usageCountR++;
12935 
12936   regTcPtr->errorCode = 0;
12937   regTcPtr->currTupAiLen = 0;
12938   regTcPtr->reclenAiLqhkey = 0;
12939   regTcPtr->m_scan_curr_range_no = 0;
12940   regTcPtr->m_dealloc = 0;
12941   regTcPtr->operation = ZREAD;
12942   regTcPtr->opExec = 1;
12943   regTcPtr->abortState = TcConnectionrec::ABORT_IDLE;
12944   // set TcConnectionrec::OP_SAVEATTRINFO so that a
12945   // "old" scan (short signals) update currTupAiLen which is checked
12946   // in scanAttrinfoLab
12947   regTcPtr->m_flags = TcConnectionrec::OP_SAVEATTRINFO;
12948   regTcPtr->commitAckMarker = RNIL;
12949   regTcPtr->activeCreat = Fragrecord::AC_NORMAL;
12950 
12951   {
12952     const Uint32 scanPtrI = scanptr.i;
12953     const Uint32 tabPtrI = tabptr.i;
12954     const Uint32 fragPtrI = fragptr.i;
12955     const Uint32 tcOprec = regTcPtr->clientConnectrec;
12956     const Uint32 tcBlockref = regTcPtr->clientBlockref;
12957 
12958     regTcPtr->tcScanRec = scanPtrI;
12959     regTcPtr->tableref = tabPtrI;
12960     regTcPtr->fragmentptr = fragPtrI;
12961     regTcPtr->tcOprec = tcOprec;
12962     regTcPtr->tcBlockref = tcBlockref;
12963   }
12964 }//Dblqh::initScanTc()
12965 
12966 /* =========================================================================
12967  * =======                       FINISH  SCAN RECORD                 =======
12968  *
12969  *       REMOVE SCAN RECORD FROM PER FRAGMENT LIST.
12970  * ========================================================================= */
finishScanrec(Signal * signal,ScanRecordPtr & restart_scan)12971 bool Dblqh::finishScanrec(Signal* signal, ScanRecordPtr &restart_scan)
12972 {
12973   ScanRecord * const scanPtr = scanptr.p;
12974   Uint32 reserved = scanPtr->m_reserved;
12975 
12976   if (reserved == 0)
12977   {
12978     release_acc_ptr_list(scanPtr);
12979   }
12980 
12981   Uint32 tupScan = scanPtr->tupScan;
12982   Uint32 rangeScan = scanPtr->rangeScan;
12983 
12984   if (scanPtr->scanState == ScanRecord::IN_QUEUE)
12985   {
12986     LocalDLCFifoList<ScanRecord> queue(c_scanRecordPool,
12987                                        rangeScan != 0 ?
12988                                        fragptr.p->m_queuedScans :
12989                                        tupScan != 0 ?
12990                                        fragptr.p->m_queuedTupScans :
12991                                        fragptr.p->m_queuedAccScans);
12992     jam();
12993     ndbrequire(reserved == 0);
12994     queue.release(scanptr);
12995     return false;
12996   }
12997 
12998   if (scanPtr->scanKeyinfoFlag)
12999   {
13000     jam();
13001     ScanRecordPtr tmp;
13002 #ifdef TRACE_SCAN_TAKEOVER
13003     ndbout_c("removing (%d %d)", scanPtr->scanNumber, scanPtr->fragPtrI);
13004 #endif
13005     c_scanTakeOverHash.remove(tmp, * scanPtr);
13006     ndbrequire(tmp.p == scanPtr);
13007   }
13008 
13009   {
13010     /**
13011      * DESIGN PATTERN DESCRIPTION:
13012      * ---------------------------
13013      * The scans object below is created on the stack, it is deleted
13014      * when we reach the end of the code block where it is created, to
13015      * avoid keeping the object around for too long we remove it from
13016      * the context by creating a code block around its use.
13017      *
13018      * This enables tail-call optimisations below in the code and also
13019      * avoids keeping the object around even when no longer needed which
13020      * can easily lead to false positives in asserts in the template
13021      * code generated by the object.
13022      */
13023     LocalDLCList<ScanRecord> scans(c_scanRecordPool, fragptr.p->m_activeScans);
13024     if (reserved == 0)
13025     {
13026       jam();
13027       scans.release(scanptr);
13028     }
13029     else
13030     {
13031       jam();
13032       scans.remove(scanptr);
13033       m_reserved_scans.addFirst(scanptr);
13034     }
13035   }
13036 
13037   FragrecordPtr tFragPtr;
13038   tFragPtr.i = scanptr.p->fragPtrI;
13039   c_fragment_pool.getPtr(tFragPtr);
13040 
13041   const Uint32 scanNumber = scanPtr->scanNumber;
13042   ndbrequire(!tFragPtr.p->m_scanNumberMask.get(scanNumber));
13043   ScanRecordPtr restart;
13044 
13045   {
13046     LocalDLCFifoList<ScanRecord> queue(c_scanRecordPool,
13047                                        rangeScan != 0 ?
13048                                        fragptr.p->m_queuedScans :
13049                                        tupScan != 0 ?
13050                                        fragptr.p->m_queuedTupScans :
13051                                        fragptr.p->m_queuedAccScans);
13052     /**
13053      * Start of queued scans
13054      */
13055     if (likely(!queue.first(restart)) ||
13056          (scanNumber >= NR_ScanNo &&
13057           scanNumber <= Backup_ScanNo))
13058     {
13059       jam();
13060 
13061       /**
13062        * LCP scan, NR scan, Backup scans won't start any queued scans since
13063        * no scanNumber useful for normal scans have been freed. Also come
13064        * here when no scans are queued.
13065        */
13066       ndbassert(!tFragPtr.p->m_scanNumberMask.get(scanNumber));
13067       tFragPtr.p->m_scanNumberMask.set(scanNumber);
13068       return false;
13069     }
13070 
13071     if(ERROR_INSERTED(5034))
13072     {
13073       jam();
13074       tFragPtr.p->m_scanNumberMask.set(scanNumber);
13075       return false;
13076     }
13077     ndbrequire(restart.p->scanState == ScanRecord::IN_QUEUE);
13078     queue.remove(restart);
13079   }
13080 
13081   restart.p->scanNumber = scanNumber;
13082   {
13083     LocalDLCList<ScanRecord> scans(c_scanRecordPool, fragptr.p->m_activeScans);
13084     scans.addFirst(restart);
13085   }
13086   if(restart.p->scanKeyinfoFlag)
13087   {
13088     jam();
13089 #if defined VM_TRACE || defined ERROR_INSERT
13090     ScanRecordPtr tmp;
13091     ndbrequire(!c_scanTakeOverHash.find(tmp, * restart.p));
13092 #endif
13093     c_scanTakeOverHash.add(restart);
13094 #ifdef TRACE_SCAN_TAKEOVER
13095     ndbout_c("adding-r (%d %d)", restart.p->scanNumber, restart.p->fragPtrI);
13096 #endif
13097   }
13098 
13099   /**
13100    * This state is a bit weird, but that what set in initScanRec
13101    */
13102   restart.p->scanState = ScanRecord::SCAN_FREE;
13103   if(tcConnectptr.p->transactionState == TcConnectionrec::SCAN_STATE_USED)
13104   {
13105     jam();
13106     restart_scan = restart;
13107     return true;
13108   }
13109   else
13110   {
13111     jam();
13112     ndbrequire(tcConnectptr.p->transactionState ==
13113                TcConnectionrec::WAIT_SCAN_AI);
13114     return false;
13115   }
13116 }//Dblqh::finishScanrec()
13117 
13118 /* =========================================================================
13119  * =======                       RELEASE SCAN RECORD                 =======
13120  *
13121  *       RELEASE A SCAN RECORD TO THE FREELIST.
13122  * ========================================================================= */
releaseScanrec(Signal * signal)13123 void Dblqh::releaseScanrec(Signal* signal)
13124 {
13125   ScanRecord * const scanPtr = scanptr.p;
13126   scanPtr->scanState = ScanRecord::SCAN_FREE;
13127   scanPtr->scanType = ScanRecord::ST_IDLE;
13128   scanPtr->scanTcWaiting = 0;
13129 }//Dblqh::releaseScanrec()
13130 
13131 /* ------------------------------------------------------------------------
13132  * -------              SEND KEYINFO20 TO API                       -------
13133  *
13134  * Return: Length in number of Uint32 words
13135  * ------------------------------------------------------------------------  */
sendKeyinfo20(Signal * signal,ScanRecord * scanP,TcConnectionrec * tcConP)13136 Uint32 Dblqh::sendKeyinfo20(Signal* signal,
13137 			    ScanRecord * scanP,
13138 			    TcConnectionrec * tcConP)
13139 {
13140   ndbrequire(scanP->m_curr_batch_size_rows < MAX_PARALLEL_OP_PER_SCAN);
13141   KeyInfo20 * keyInfo = (KeyInfo20 *)&signal->theData[0];
13142 
13143   /**
13144    * Note that this code requires signal->theData to be big enough for
13145    * a entire key
13146    */
13147   const BlockReference ref = scanP->scanApiBlockref;
13148   const Uint32 scanOp = scanP->m_curr_batch_size_rows;
13149   Uint32 nodeId = refToNode(ref);
13150   const bool connectedToNode = getNodeInfo(nodeId).m_connected;
13151 #ifdef NOT_USED
13152   const Uint32 type = getNodeInfo(nodeId).m_type;
13153   const bool is_api= (type >= NodeInfo::API && type <= NodeInfo::REP);
13154   const bool old_dest= (getNodeInfo(nodeId).m_version < MAKE_VERSION(3,5,0));
13155 #endif
13156   const bool longable = true; // TODO is_api && !old_dest;
13157 
13158   if (isNdbMtLqh())
13159   {
13160     jam();
13161     nodeId = 0; // prevent execute direct
13162   }
13163 
13164   Uint32 * dst = keyInfo->keyData;
13165   dst += nodeId == getOwnNodeId() ? 0 : KeyInfo20::DataLength;
13166 
13167   /**
13168    * This is ugly :-(
13169    *  currently only SUMA receives KEYINFO20 inside kernel..
13170    *  and it's not really interested in the actual keyinfo,
13171    *  only the scanInfo_Node...so send only that and avoid
13172    *  messing with if's below...
13173    */
13174   Uint32 keyLen ;
13175   if (refToMain(ref) == SUMA && nodeId == getOwnNodeId())
13176   {
13177     keyLen = 0;
13178   }
13179   else
13180   {
13181     keyLen = readPrimaryKeys(scanP, tcConP, dst);
13182   }
13183 
13184   Uint32 fragId = tcConP->fragmentid;
13185   keyInfo->clientOpPtr   = scanP->scanApiOpPtr;
13186   keyInfo->keyLen        = keyLen;
13187   keyInfo->scanInfo_Node =
13188     KeyInfo20::setScanInfo(scanOp, scanP->scanNumber) + (fragId << 20);
13189   keyInfo->transId1 = tcConP->transid[0];
13190   keyInfo->transId2 = tcConP->transid[1];
13191 
13192   Uint32 * src = signal->theData+25;
13193   if(connectedToNode)
13194   {
13195     jam();
13196 
13197     if (nodeId == getOwnNodeId())
13198     {
13199       EXECUTE_DIRECT(refToBlock(ref), GSN_KEYINFO20, signal,
13200                      KeyInfo20::HeaderLength + keyLen);
13201       jamEntry();
13202       return keyLen;
13203     }
13204     else
13205     {
13206       if(keyLen <= KeyInfo20::DataLength || !longable) {
13207 	while(keyLen > KeyInfo20::DataLength){
13208 	  jam();
13209 	  MEMCOPY_NO_WORDS(keyInfo->keyData, src, KeyInfo20::DataLength);
13210 	  sendSignal(ref, GSN_KEYINFO20, signal, 25, JBB);
13211 	  src += KeyInfo20::DataLength;;
13212 	  keyLen -= KeyInfo20::DataLength;
13213 	}
13214 
13215 	MEMCOPY_NO_WORDS(keyInfo->keyData, src, keyLen);
13216 	sendSignal(ref, GSN_KEYINFO20, signal,
13217 		   KeyInfo20::HeaderLength+keyLen, JBB);
13218 	return keyLen;
13219       }
13220 
13221       LinearSectionPtr ptr[3];
13222       ptr[0].p = src;
13223       ptr[0].sz = keyLen;
13224       sendSignal(ref, GSN_KEYINFO20, signal, KeyInfo20::HeaderLength,
13225 		 JBB, ptr, 1);
13226       return keyLen;
13227     }
13228   }
13229 
13230   /**
13231    * If this node does not have a direct connection
13232    * to the receiving node we want to send the signals
13233    * routed via the node that controls this read
13234    */
13235   Uint32 routeBlockref = tcConP->clientBlockref;
13236 
13237   if(keyLen < KeyInfo20::DataLength || !longable){
13238     jam();
13239 
13240     while (keyLen > (KeyInfo20::DataLength - 1)) {
13241       jam();
13242       MEMCOPY_NO_WORDS(keyInfo->keyData, src, KeyInfo20::DataLength - 1);
13243       keyInfo->keyData[KeyInfo20::DataLength-1] = ref;
13244       sendSignal(routeBlockref, GSN_KEYINFO20_R, signal, 25, JBB);
13245       src += KeyInfo20::DataLength - 1;
13246       keyLen -= KeyInfo20::DataLength - 1;
13247     }
13248 
13249     MEMCOPY_NO_WORDS(keyInfo->keyData, src, keyLen);
13250     keyInfo->keyData[keyLen] = ref;
13251     sendSignal(routeBlockref, GSN_KEYINFO20_R, signal,
13252 	       KeyInfo20::HeaderLength+keyLen+1, JBB);
13253     return keyLen;
13254   }
13255 
13256   keyInfo->keyData[0] = ref;
13257   LinearSectionPtr ptr[3];
13258   ptr[0].p = src;
13259   ptr[0].sz = keyLen;
13260   sendSignal(routeBlockref, GSN_KEYINFO20_R, signal,
13261 	     KeyInfo20::HeaderLength+1, JBB, ptr, 1);
13262   return keyLen;
13263 }
13264 
13265 /**
13266  * Function used to send NEXT_SCANREQ, we need to decide whether to
13267  * continue in the same signal or sending a new signal and if sending
13268  * a new signal we need to decide whether B-level, Bounded delay or
13269  * even A-level signal.
13270  *
13271  * We need to ensure that we keep track of how many outstanding NEXT_SCANREQ
13272  * we have, each time we send a NEXT_SCANREQ with ZSCAN_NEXT we need to
13273  * increment this counter to ensure that we don't end up in calling too
13274  * deep into the stack which otherwise can happen when we use multiple
13275  * ranges.
13276  */
send_next_NEXT_SCANREQ(Signal * signal,SimulatedBlock * block,ExecFunction f,ScanRecord * const scanPtr)13277 void Dblqh::send_next_NEXT_SCANREQ(Signal* signal,
13278                                    SimulatedBlock* block,
13279                                    ExecFunction f,
13280                                    ScanRecord * const scanPtr)
13281 {
13282   /**
13283    * We have a number of different cases here. There are normal
13284    * scan operations, these always execute at B-level such that
13285    * they are scheduled among the other user level transactions.
13286    *
13287    * We also have prioritised scans, these could be scans for
13288    * LCPs, Backups, Node recovery or various ALTER TABLE activities.
13289    *
13290    * All internal scan activities are treated as prioritised scans.
13291    * These need to operate with a bounded delay. Therefore we send
13292    * these signals with a bounded delay signal (implemented through
13293    * a delayed signal with delay 0). These signals can also set the
13294    * priority flag to A-level to ensure that they process more rows
13295    * per scheduling slot than otherwise. This can be necessary at
13296    * very high loads when we scan for rather small rows.
13297    *
13298    * For efficiency reasons we try to execute a number of rows before
13299    * we send a new signal. We will never go beyond ZMAX_SCAN_DIRECT_COUNT
13300    * to avoid using too much of the CPU stack and also to avoid executing
13301    * for too long without putting ourselves back in the job buffer.
13302    *
13303    * We try to maintain the coding rule of NDB to never execute for more
13304    * than about 5-10 microseconds. Executing a 100 byte row scan on normal
13305    * CPUs in 2015 will take about 1 microsecond. If we instead scan 1000
13306    * bytes we estimate the time to be about 3 microseconds. So we use the
13307    * formula 750 ns of fixed cost per row + 8 ns per word. With this formula
13308    * we want to avoid that current cost has exceeded 5000 ns. If it has we
13309    * we will schedule a signal rather than execute directly again. Given that
13310    * the exactness of the formula isn't perfect and that we want scheduling
13311    * to happen at least before 10 microseconds we will use a simplified
13312    * formula. We know that scan_direct_count must be between 0 and 3 when
13313    * coming here and not being immediately decided to send signal, so the
13314    * fixed part of the cost here is between 750 ns and 3000 ns. So we will
13315    * allow for up to 4000 ns of words before we decide to send a signal.
13316    * This means that when the number of words sent exceeds 500, then we
13317    * we will send a signal.
13318    *
13319    * These calculations are valid for HW of 2015. Future HW is likely to be
13320    * faster and also we're likely to improve the efficiency of creating
13321    * LCPs by optimising the code. The coding rules for how long a signal
13322    * can execute should stay more or less constant over time. We had the
13323    * same coding rules also in the 1990s as we have now. However if we
13324    * can execute 300 MByte per second in a CPU rather than 150 MByte per
13325    * second then we can increase those limits. So effectively we should
13326    * not change the coding rules, but we should adapt our algorithms to
13327    * make use of the coding rules in an optimal manner. Not fixing this
13328    * when HW gets faster means isn't likely to cause much problems given
13329    * that also signals from user transactions are likely to execute faster.
13330    * So mainly when we optimise the LCP code we should consider changing
13331    * those values and when we start allowing more computations due to
13332    * higher CPU throughput also in signals part of user transactions.
13333    */
13334 #define ZMAX_WORDS_PER_SCAN_BATCH_LOW_PRIO 500
13335 #define ZMAX_WORDS_PER_SCAN_BATCH_HIGH_PRIO 4000
13336 
13337   Uint32 prioAFlag = scanPtr->prioAFlag;
13338   const Uint32 scan_direct_count = scanPtr->scan_direct_count;
13339   const Uint32 exec_direct_batch_size_words =
13340               scanPtr->m_exec_direct_batch_size_words;
13341   const Uint32 exec_direct_limit = prioAFlag ?
13342                             ZMAX_WORDS_PER_SCAN_BATCH_HIGH_PRIO :
13343                             ZMAX_WORDS_PER_SCAN_BATCH_LOW_PRIO;
13344 
13345   if (scan_direct_count >= ZMAX_SCAN_DIRECT_COUNT ||
13346       exec_direct_batch_size_words > exec_direct_limit)
13347   {
13348     BlockReference blockRef = scanPtr->scanBlockref;
13349     BlockReference resultRef = scanPtr->scanApiBlockref;
13350     scanPtr->scan_direct_count = 0;
13351 
13352     if (!is_prioritised_scan(resultRef))
13353     {
13354       /* Normal user scans */
13355       jam();
13356       sendSignal(blockRef, GSN_NEXT_SCANREQ, signal, 3, JBB);
13357       return;
13358     }
13359     if (exec_direct_batch_size_words > ZMAX_WORDS_PER_SCAN_BATCH_HIGH_PRIO)
13360     {
13361       /**
13362        * See Backup.cpp for explanation of this limit and how it is derived */
13363       jam();
13364       prioAFlag = false;
13365     }
13366     scanPtr->m_exec_direct_batch_size_words = 0;
13367     if (prioAFlag)
13368     {
13369       /* Prioritised scan at high load situation */
13370       jam();
13371       sendSignal(blockRef, GSN_NEXT_SCANREQ, signal, 3, JBA);
13372       return;
13373     }
13374     else
13375     {
13376       /* Prioritised scan operation */
13377       jam();
13378       sendSignalWithDelay(blockRef, GSN_NEXT_SCANREQ,
13379                           signal, BOUNDED_DELAY, 3);
13380       return;
13381     }
13382   }
13383   else
13384   {
13385     scanPtr->scan_direct_count = scan_direct_count + 1;
13386     jam();
13387     block->EXECUTE_DIRECT(f, signal);
13388     return;
13389   }
13390 }
13391 
13392 /* ------------------------------------------------------------------------
13393  * -------        SEND SCAN_FRAGCONF TO TC THAT CONTROLS THE SCAN   -------
13394  *
13395  * ------------------------------------------------------------------------ */
sendScanFragConf(Signal * signal,Uint32 scanCompleted)13396 void Dblqh::sendScanFragConf(Signal* signal, Uint32 scanCompleted)
13397 {
13398   ScanRecord * const scanPtr = scanptr.p;
13399   const Uint32 completed_ops= scanPtr->m_curr_batch_size_rows;
13400   const Uint32 total_len= scanPtr->m_curr_batch_size_bytes / sizeof(Uint32);
13401 
13402   ndbassert((scanPtr->m_curr_batch_size_bytes % sizeof(Uint32)) == 0);
13403 
13404   scanPtr->scanTcWaiting = 0;
13405 
13406   if(ERROR_INSERTED(5037)){
13407     CLEAR_ERROR_INSERT_VALUE;
13408     return;
13409   }
13410 
13411   if (!scanPtr->lcpScan)
13412   {
13413     jam();
13414     Fragrecord::UsageStat& useStat =
13415       c_fragment_pool.getPtr(tcConnectptr.p->fragmentptr)->m_useStat;
13416     ndbassert(useStat.m_scanFragReqCount > 0);
13417 
13418     useStat.m_scanRowsReturned += scanPtr->m_curr_batch_size_rows;
13419     useStat.m_scanWordsReturned +=
13420       scanPtr->m_curr_batch_size_bytes/sizeof(Uint32);
13421   }
13422 
13423   if(!scanPtr->scanLockHold)
13424   {
13425     jam();
13426     scanPtr->m_curr_batch_size_rows = 0;
13427     scanPtr->m_curr_batch_size_bytes= 0;
13428   }
13429 
13430   scanPtr->m_stop_batch = 0;
13431   ScanFragConf * conf = (ScanFragConf*)&signal->theData[0];
13432   TcConnectionrec * const regTcPtr = tcConnectptr.p;
13433 #ifdef NOT_USED
13434   NodeId tc_node_id= refToNode(regTcPtr->clientBlockref);
13435 #endif
13436   const Uint32 senderData = regTcPtr->clientConnectrec;
13437   const Uint32 trans_id1= regTcPtr->transid[0];
13438   const Uint32 trans_id2= regTcPtr->transid[1];
13439   const BlockReference blockRef = regTcPtr->clientBlockref;
13440 
13441   conf->senderData = senderData;
13442   conf->completedOps = completed_ops;
13443   conf->fragmentCompleted = scanCompleted;
13444   conf->transId1 = trans_id1;
13445   conf->transId2 = trans_id2;
13446   conf->total_len= total_len;
13447 
13448   JobBufferLevel prio_level = JBB;
13449   if (scanPtr->prioAFlag)
13450   {
13451     jam();
13452     prio_level = JBA;
13453   }
13454   sendSignal(blockRef, GSN_SCAN_FRAGCONF,
13455              signal, ScanFragConf::SignalLength, prio_level);
13456 }//Dblqh::sendScanFragConf()
13457 
13458 /* ######################################################################### */
13459 /* #######                NODE RECOVERY MODULE                       ####### */
13460 /*                                                                           */
13461 /* ######################################################################### */
13462 /*---------------------------------------------------------------------------*/
13463 /*                                                                           */
13464 /*   THIS MODULE IS USED WHEN A NODE HAS FAILED. IT PERFORMS A COPY OF A     */
13465 /*   FRAGMENT TO A NEW REPLICA OF THE FRAGMENT. IT DOES ALSO SHUT DOWN ALL   */
13466 /*   CONNECTIONS TO THE FAILED NODE.                                         */
13467 /*---------------------------------------------------------------------------*/
13468 Uint32
calculateHash(Uint32 tableId,const Uint32 * src)13469 Dblqh::calculateHash(Uint32 tableId, const Uint32* src)
13470 {
13471   jam();
13472   Uint64 Tmp[(MAX_KEY_SIZE_IN_WORDS*MAX_XFRM_MULTIPLY) >> 1];
13473   Uint32 keyPartLen[MAX_ATTRIBUTES_IN_INDEX];
13474   Uint32 keyLen = xfrm_key(tableId, src, (Uint32*)Tmp, sizeof(Tmp) >> 2,
13475 			   keyPartLen);
13476   ndbrequire(keyLen);
13477 
13478   return md5_hash(Tmp, keyLen);
13479 }//Dblqh::calculateHash()
13480 
13481 /**
13482  * PREPARE COPY FRAG REQ
13483  */
13484 void
execPREPARE_COPY_FRAG_REQ(Signal * signal)13485 Dblqh::execPREPARE_COPY_FRAG_REQ(Signal* signal)
13486 {
13487   jamEntry();
13488   PrepareCopyFragReq req = *(PrepareCopyFragReq*)signal->getDataPtr();
13489 
13490   CRASH_INSERTION(5045);
13491 
13492   tabptr.i = req.tableId;
13493   ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
13494 
13495   Uint32 max_page = RNIL;
13496 
13497   if (getOwnNodeId() != req.startingNodeId)
13498   {
13499     jam();
13500     /**
13501      * This is currently dead code...
13502      *   but is provided so we can impl. a better scan+delete on
13503      *   starting node wo/ having to change running node
13504      */
13505     ndbrequire(getOwnNodeId() == req.copyNodeId);
13506     c_tup->get_frag_info(req.tableId, req.fragId, &max_page);
13507 
13508     PrepareCopyFragConf* conf = (PrepareCopyFragConf*)signal->getDataPtrSend();
13509     conf->senderData = req.senderData;
13510     conf->senderRef = reference();
13511     conf->tableId = req.tableId;
13512     conf->fragId = req.fragId;
13513     conf->copyNodeId = req.copyNodeId;
13514     conf->startingNodeId = req.startingNodeId;
13515     conf->maxPageNo = max_page;
13516     sendSignal(req.senderRef, GSN_PREPARE_COPY_FRAG_CONF,
13517                signal, PrepareCopyFragConf::SignalLength, JBB);
13518 
13519     return;
13520   }
13521 
13522   if (! DictTabInfo::isOrderedIndex(tabptr.p->tableType))
13523   {
13524     jam();
13525     ndbrequire(getFragmentrec(signal, req.fragId));
13526 
13527     /**
13528      *
13529      */
13530     fragptr.p->m_copy_started_state = Fragrecord::AC_IGNORED;
13531     fragptr.p->fragStatus = Fragrecord::ACTIVE_CREATION;
13532     fragptr.p->logFlag = Fragrecord::STATE_FALSE;
13533 
13534     c_tup->get_frag_info(req.tableId, req.fragId, &max_page);
13535   }
13536 
13537   if (c_fragmentCopyStart == 0)
13538   {
13539     c_fragmentCopyStart = NdbTick_CurrentMillisecond();
13540     g_eventLogger->info("LDM(%u): Starting to copy fragments.",
13541                         instance());
13542   }
13543   c_fragmentsCopied++;
13544 
13545   /* Assuming 1 at a time... */
13546   c_fragCopyTable = req.tableId;
13547   c_fragCopyFrag = req.fragId;
13548 
13549   PrepareCopyFragConf* conf = (PrepareCopyFragConf*)signal->getDataPtrSend();
13550   conf->senderData = req.senderData;
13551   conf->senderRef = reference();
13552   conf->tableId = req.tableId;
13553   conf->fragId = req.fragId;
13554   conf->copyNodeId = req.copyNodeId;
13555   conf->startingNodeId = req.startingNodeId;
13556   conf->maxPageNo = max_page;
13557   sendSignal(req.senderRef, GSN_PREPARE_COPY_FRAG_CONF,
13558              signal, PrepareCopyFragConf::SignalLength, JBB);
13559 }
13560 
13561 /* *************************************** */
13562 /*  COPY_FRAGREQ: Start copying a fragment */
13563 /* *************************************** */
execCOPY_FRAGREQ(Signal * signal)13564 void Dblqh::execCOPY_FRAGREQ(Signal* signal)
13565 {
13566   jamEntry();
13567   const CopyFragReq * const copyFragReq = (CopyFragReq *)&signal->theData[0];
13568   tabptr.i = copyFragReq->tableId;
13569   ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
13570   Uint32 i;
13571   const Uint32 fragId = copyFragReq->fragId;
13572   const Uint32 copyPtr = copyFragReq->userPtr;
13573   const Uint32 userRef = copyFragReq->userRef;
13574   const Uint32 nodeId = copyFragReq->nodeId;
13575   const Uint32 gci = copyFragReq->gci;
13576 
13577   ndbrequire(cnoActiveCopy < 3);
13578   ndbrequire(getFragmentrec(signal, fragId));
13579   ndbrequire(fragptr.p->copyFragState == ZIDLE);
13580   ndbrequire(cfirstfreeTcConrec != RNIL);
13581   ndbrequire(fragptr.p->m_scanNumberMask.get(NR_ScanNo));
13582 
13583   Uint32 checkversion = NDB_VERSION >= MAKE_VERSION(5,1,0) ?
13584     NDBD_UPDATE_FRAG_DIST_KEY_51 :  NDBD_UPDATE_FRAG_DIST_KEY_50;
13585 
13586   Uint32 nodeCount = copyFragReq->nodeCount;
13587   NdbNodeBitmask nodemask;
13588   if (getNodeInfo(refToNode(userRef)).m_version >= checkversion)
13589   {
13590     ndbrequire(nodeCount <= MAX_REPLICAS);
13591     for (i = 0; i<nodeCount; i++)
13592       nodemask.set(copyFragReq->nodeList[i]);
13593   }
13594   Uint32 maxPage = copyFragReq->nodeList[nodeCount];
13595   Uint32 version = getNodeInfo(refToNode(userRef)).m_version;
13596   Uint32 requestInfo = copyFragReq->nodeList[nodeCount + 1];
13597   if (ndb_check_prep_copy_frag_version(version) < 2)
13598   {
13599     jam();
13600     maxPage = RNIL;
13601   }
13602 
13603   if (signal->getLength() < CopyFragReq::SignalLength + nodeCount)
13604   {
13605     jam();
13606     requestInfo = CopyFragReq::CFR_TRANSACTIONAL;
13607   }
13608 
13609   if (requestInfo == CopyFragReq::CFR_NON_TRANSACTIONAL)
13610   {
13611     jam();
13612   }
13613   else
13614   {
13615     fragptr.p->fragDistributionKey = copyFragReq->distributionKey;
13616   }
13617   Uint32 key = fragptr.p->fragDistributionKey;
13618 
13619   if (DictTabInfo::isOrderedIndex(tabptr.p->tableType)) {
13620     jam();
13621     /**
13622      * Ordered index doesn't need to be copied
13623      */
13624     CopyFragConf * const conf = (CopyFragConf *)&signal->theData[0];
13625     conf->userPtr = copyPtr;
13626     conf->sendingNodeId = cownNodeid;
13627     conf->startingNodeId = nodeId;
13628     conf->tableId = tabptr.i;
13629     conf->fragId = fragId;
13630     sendSignal(userRef, GSN_COPY_FRAGCONF, signal,
13631 	       CopyFragConf::SignalLength, JBB);
13632     return;
13633   }//if
13634 
13635   {
13636     /* NR Scans allocate reserved scan records */
13637     LocalDLCList<ScanRecord> scans(c_scanRecordPool, fragptr.p->m_activeScans);
13638     ndbrequire(m_reserved_scans.first(scanptr));
13639     m_reserved_scans.remove(scanptr);
13640     scans.addFirst(scanptr);
13641   }
13642 
13643 /* ------------------------------------------------------------------------- */
13644 // We keep track of how many operation records in ACC that has been booked.
13645 // Copy fragment has records always booked and thus need not book any. The
13646 // most operations in parallel use is the m_max_batch_size_rows.
13647 // This variable has to be set-up here since it is used by releaseScanrec
13648 // to unbook operation records in ACC.
13649 /* ------------------------------------------------------------------------- */
13650   ScanRecord * const scanPtr = scanptr.p;
13651   scanPtr->m_max_batch_size_rows = 0;
13652   scanPtr->rangeScan = 0;
13653   scanPtr->tupScan = 0;
13654   /**
13655    * Will always succeed since we can only call this once at a time for
13656    * NR operations, LCP scan operation and backup scan operation. All these
13657    * 3 operations have a reserved record always available for them.
13658    * The seizeTcrec would crash if this wasn't true and we've run out this
13659    * resource.
13660    */
13661   seizeTcrec();
13662   tcConnectptr.p->clientBlockref = userRef;
13663 
13664   /**
13665    * Remove implicit cast/usage of CopyFragReq
13666    */
13667   //initCopyrec(signal);
13668   {
13669     const Uint32 tcPtrI = tcConnectptr.i;
13670     const Uint32 fragPtrI = fragptr.i;
13671     const Uint32 schemaVersion = copyFragReq->schemaVersion;
13672     const BlockReference myRef = reference();
13673     const BlockReference tupRef = ctupBlockref;
13674 
13675     scanPtr->copyPtr = copyPtr;
13676     scanPtr->scanNodeId = nodeId;
13677     scanPtr->scanTcrec = tcPtrI;
13678     scanPtr->scanApiOpPtr = tcPtrI;
13679     scanPtr->fragPtrI = fragPtrI;
13680     scanPtr->scanSchemaVersion = schemaVersion;
13681     scanPtr->scanApiBlockref = myRef;
13682     scanPtr->scanBlockref = tupRef;
13683     scanPtr->scanBlock = c_tup;
13684     scanPtr->scanFunction_NEXT_SCANREQ =
13685       c_tup->getExecuteFunction(GSN_NEXT_SCANREQ);
13686     scanPtr->scanType = ScanRecord::COPY;
13687     scanPtr->scanCompletedStatus = ZFALSE;
13688     scanPtr->scanErrorCounter = 0;
13689     scanPtr->scanNumber = NR_ScanNo;
13690     scanPtr->scanKeyinfoFlag = 0; // Don't put into hash
13691     scanPtr->scanLockHold = ZFALSE;
13692     scanPtr->m_curr_batch_size_rows = 0;
13693     scanPtr->m_curr_batch_size_bytes= 0;
13694     scanPtr->m_exec_direct_batch_size_words = 0;
13695     scanPtr->readCommitted = 0;
13696     scanPtr->scan_direct_count = ZMAX_SCAN_DIRECT_COUNT - 1;
13697     fragptr.p->m_scanNumberMask.clear(NR_ScanNo);
13698   }
13699 
13700   initScanTc(0,
13701              0,
13702              (DBLQH << 20) + (cownNodeid << 8),
13703              fragId,
13704              copyFragReq->nodeId,
13705              0);
13706   cactiveCopy[cnoActiveCopy] = fragptr.i;
13707   cnoActiveCopy++;
13708 
13709   {
13710     TcConnectionrec * const regTcPtr = tcConnectptr.p;
13711     const Uint32 tcPtrI = tcConnectptr.i;
13712 
13713     regTcPtr->schemaVersion = scanPtr->scanSchemaVersion;
13714     regTcPtr->copyCountWords = 0;
13715     regTcPtr->tcHashKeyHi = 0;
13716     regTcPtr->tcOprec = tcPtrI;
13717     regTcPtr->savePointId = gci;
13718     regTcPtr->applRef = 0;
13719     regTcPtr->transactionState = TcConnectionrec::SCAN_STATE_USED;
13720   }
13721 
13722   if (! nodemask.isclear())
13723   {
13724     ndbrequire(nodemask.get(getOwnNodeId()));
13725     ndbrequire(nodemask.get(nodeId)); // cpy dest
13726     nodemask.clear(getOwnNodeId());
13727     nodemask.clear(nodeId);
13728 
13729     UpdateFragDistKeyOrd*
13730       ord = (UpdateFragDistKeyOrd*)signal->getDataPtrSend();
13731     ord->tableId = tabptr.i;
13732     ord->fragId = fragId;
13733     ord->fragDistributionKey = key;
13734     i = 0;
13735     while ((i = nodemask.find(i+1)) != NdbNodeBitmask::NotFound)
13736     {
13737       if (getNodeInfo(i).m_version >=  checkversion)
13738 	sendSignal(calcInstanceBlockRef(number(), i),
13739                    GSN_UPDATE_FRAG_DIST_KEY_ORD,
13740 		   signal, UpdateFragDistKeyOrd::SignalLength, JBB);
13741     }
13742   }
13743 
13744   {
13745     AccScanReq * req = (AccScanReq*)&signal->theData[0];
13746     Uint32 sig_request_info = 0;
13747     if (requestInfo == CopyFragReq::CFR_TRANSACTIONAL)
13748     {
13749       jam();
13750       /**
13751        * An node-recovery scan, is shared lock
13752        *   and may not perform disk-scan (as it then can miss uncomitted
13753        *   inserts)
13754        */
13755       //AccScanReq::setLockMode(sig_request_info, 0);
13756       //AccScanReq::setReadCommittedFlag(sig_request_info, 0);
13757       AccScanReq::setNRScanFlag(sig_request_info, 1);
13758       AccScanReq::setNoDiskScanFlag(sig_request_info, 1);
13759     }
13760     else
13761     {
13762       jam();
13763       /**
13764        * The non-transaction scan is really only a "normal" tup scan
13765        *   committed read, and don't disable disk-scan
13766        */
13767       //AccScanReq::setLockMode(sig_request_info, 0);
13768       AccScanReq::setReadCommittedFlag(sig_request_info, 1);
13769       scanPtr->readCommitted = 1;
13770     }
13771     req->requestInfo = sig_request_info;
13772     scanPtr->scanState = ScanRecord::WAIT_ACC_COPY;
13773     const Uint32 scanPtrI = scanptr.i;
13774     const Uint32 my_ref = cownref;
13775     const Uint32 tabPtrI = tabptr.i;
13776     TcConnectionrec * const regTcPtr = tcConnectptr.p;
13777 
13778     req->senderData = scanPtrI;
13779     req->senderRef = my_ref;
13780     req->tableId = tabPtrI;
13781     req->fragmentNo = fragId;
13782 
13783     SimulatedBlock *block = scanPtr->scanBlock;
13784     const Uint32 transId1 = regTcPtr->transid[0];
13785     const Uint32 transId2 = regTcPtr->transid[1];
13786     const Uint32 savePointId = regTcPtr->savePointId;
13787     ExecFunction f = block->getExecuteFunction(GSN_ACC_SCANREQ);
13788 
13789     req->transId1 = transId1;
13790     req->transId2 = transId2;
13791     req->savePointId = savePointId;
13792     req->maxPage = maxPage;
13793 
13794     block->EXECUTE_DIRECT(f, signal);
13795   }
13796   if (signal->theData[8] == 0)
13797   {
13798     /* ACC_SCANCONF */
13799     jamEntry();
13800     accScanConfCopyLab(signal);
13801   }
13802   else
13803   {
13804     /* ACC_SCANREF */
13805     jamEntry();
13806     execACC_SCANREF(signal);
13807   }
13808 }//Dblqh::execCOPY_FRAGREQ()
13809 
13810 void
execUPDATE_FRAG_DIST_KEY_ORD(Signal * signal)13811 Dblqh::execUPDATE_FRAG_DIST_KEY_ORD(Signal * signal)
13812 {
13813   jamEntry();
13814   UpdateFragDistKeyOrd* ord =(UpdateFragDistKeyOrd*)signal->getDataPtr();
13815 
13816   tabptr.i = ord->tableId;
13817   ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
13818   ndbrequire(getFragmentrec(signal, ord->fragId));
13819   fragptr.p->fragDistributionKey = ord->fragDistributionKey;
13820 }
13821 
accScanConfCopyLab(Signal * signal)13822 void Dblqh::accScanConfCopyLab(Signal* signal)
13823 {
13824   ScanRecord * const scanPtr = scanptr.p;
13825   AccScanConf * const accScanConf = (AccScanConf *)&signal->theData[0];
13826   tcConnectptr.i = scanPtr->scanTcrec;
13827   ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
13828 /*--------------------------------------------------------------------------*/
13829 /*  PRECONDITION: SCAN_STATE = WAIT_ACC_COPY                                */
13830 /*--------------------------------------------------------------------------*/
13831   if (accScanConf->flag == AccScanConf::ZEMPTY_FRAGMENT) {
13832     jam();
13833 /*---------------------------------------------------------------------------*/
13834 /*   THE FRAGMENT WAS EMPTY.                                                 */
13835 /*   REPORT SUCCESSFUL COPYING.                                              */
13836 /*---------------------------------------------------------------------------*/
13837     tupCopyCloseConfLab(signal);
13838     return;
13839   }//if
13840   TcConnectionrec * const regTcPtr = tcConnectptr.p;
13841   {
13842     const Uint32 accPtr = accScanConf->accPtr;
13843     const Uint32 sig0 = regTcPtr->tupConnectrec;
13844     const Uint32 sig1 = regTcPtr->tableref;
13845     const Uint32 sig2 = scanPtr->scanSchemaVersion;
13846     const Uint32 sig5 = scanPtr->scanApiBlockref;
13847     scanPtr->scanAccPtr = accPtr;
13848     signal->theData[0] = sig0;
13849     signal->theData[1] = sig1;
13850     signal->theData[2] = sig2;
13851     signal->theData[3] = ZSTORED_PROC_COPY;
13852 // theData[4] is not used in TUP with ZSTORED_PROC_COPY
13853     signal->theData[5] = sig5;
13854     c_tup->execSTORED_PROCREQ(signal);
13855   }
13856 /*---------------------------------------------------------------------------*/
13857 /*   ENTER STORED_PROCCONF WITH                                              */
13858 /*     0 success == CONF, 1 failure == REF                                   */
13859 /*     STORED_PROC_ID                                                        */
13860 /*---------------------------------------------------------------------------*/
13861   ndbrequire(signal->theData[0] == 0);
13862   scanPtr->scanStoredProcId = signal->theData[1];
13863 
13864   if (scanPtr->scanCompletedStatus == ZTRUE) {
13865     jam();
13866 /*---------------------------------------------------------------------------*/
13867 /*   THE COPY PROCESS HAVE BEEN COMPLETED, MOST LIKELY DUE TO A NODE FAILURE.*/
13868 /*---------------------------------------------------------------------------*/
13869     closeCopyLab(signal);
13870     return;
13871   }//if
13872   fragptr.i = regTcPtr->fragmentptr;
13873   c_fragment_pool.getPtr(fragptr);
13874   scanPtr->scanState = ScanRecord::WAIT_NEXT_SCAN_COPY;
13875   ndbrequire(fragptr.p->fragStatus == Fragrecord::FSACTIVE);
13876 
13877   /**
13878    * Start sending ROWID for all operations from now on
13879    */
13880   fragptr.p->m_copy_started_state = Fragrecord::AC_NR_COPY;
13881   if (ERROR_INSERTED(5714))
13882   {
13883     ndbout_c("Starting copy of tab: %u frag: %u",
13884              fragptr.p->tabRef, fragptr.p->fragId);
13885   }
13886 
13887   if (false && fragptr.p->tabRef > 4)
13888   {
13889     ndbout_c("STOPPING COPY X = [ %d %d %d %d ]",
13890 	     refToBlock(scanPtr->scanBlockref),
13891 	     scanPtr->scanAccPtr, RNIL, NextScanReq::ZSCAN_NEXT);
13892 
13893     /**
13894      * RESTART: > DUMP 7020 332 X
13895      */
13896     return;
13897   }
13898   {
13899     const Uint32 sig0 = scanPtr->scanAccPtr;
13900     SimulatedBlock *block = scanPtr->scanBlock;
13901     ExecFunction f = scanPtr->scanFunction_NEXT_SCANREQ;
13902 
13903     signal->theData[1] = RNIL;
13904     signal->theData[2] = NextScanReq::ZSCAN_NEXT;
13905     signal->theData[0] = sig0;
13906     scanPtr->scanState = ScanRecord::WAIT_NEXT_SCAN_COPY;
13907     send_next_NEXT_SCANREQ(signal, block, f, scanPtr);
13908   }
13909 }//Dblqh::accScanConfCopyLab()
13910 
13911 /*---------------------------------------------------------------------------*/
13912 /*       ENTER NEXT_SCANCONF WITH                                            */
13913 /*         SCANPTR,                                                          */
13914 /*         TFRAGID,                                                          */
13915 /*         TACC_OPPTR,                                                       */
13916 /*         TLOCAL_KEY1,                                                      */
13917 /*         TLOCAL_KEY2,                                                      */
13918 /*         TKEY_LENGTH,                                                      */
13919 /*         TKEY1,                                                            */
13920 /*         TKEY2,                                                            */
13921 /*         TKEY3,                                                            */
13922 /*         TKEY4                                                             */
13923 /*---------------------------------------------------------------------------*/
13924 /*       PRECONDITION: SCAN_STATE = WAIT_NEXT_SCAN_COPY                      */
13925 /*---------------------------------------------------------------------------*/
nextScanConfCopyLab(Signal * signal)13926 void Dblqh::nextScanConfCopyLab(Signal* signal)
13927 {
13928   NextScanConf * const nextScanConf = (NextScanConf *)&signal->theData[0];
13929   if (nextScanConf->fragId == RNIL) {
13930     jam();
13931 /*---------------------------------------------------------------------------*/
13932 /*   THERE ARE NO MORE TUPLES TO FETCH. WE NEED TO CLOSE                     */
13933 /*   THE COPY IN ACC AND DELETE THE STORED PROCEDURE IN TUP                  */
13934 /*---------------------------------------------------------------------------*/
13935     if (tcConnectptr.p->copyCountWords == 0) {
13936       closeCopyLab(signal);
13937       return;
13938     }//if
13939 /*---------------------------------------------------------------------------*/
13940 // Wait until copying is completed also at the starting node before reporting
13941 // completion. Signal completion through scanCompletedStatus-flag.
13942 /*---------------------------------------------------------------------------*/
13943     scanptr.p->scanCompletedStatus = ZTRUE;
13944     scanptr.p->scanState = ScanRecord::WAIT_LQHKEY_COPY;
13945     if (ERROR_INSERTED(5043))
13946     {
13947       CLEAR_ERROR_INSERT_VALUE;
13948       tcConnectptr.p->copyCountWords = ~0;
13949       signal->theData[0] = 9999;
13950       sendSignal(numberToRef(CMVMI, scanptr.p->scanNodeId),
13951 		 GSN_NDB_TAMPER, signal, 1, JBA);
13952     }
13953     return;
13954   }//if
13955 
13956   TcConnectionrec * tcConP = tcConnectptr.p;
13957 
13958   tcConP->m_use_rowid = true;
13959   tcConP->m_row_id = scanptr.p->m_row_id;
13960 
13961   scanptr.p->m_curr_batch_size_rows++;
13962 
13963   if (signal->getLength() == NextScanConf::SignalLengthNoKeyInfo)
13964   {
13965     jam();
13966     ndbrequire(nextScanConf->accOperationPtr == RNIL);
13967     initCopyTc(signal, ZDELETE);
13968     set_acc_ptr_in_scan_record(scanptr.p, 0, RNIL);
13969     tcConP->gci_hi = nextScanConf->gci;
13970     tcConP->gci_lo = 0;
13971 
13972     tcConP->primKeyLen = 0;
13973     tcConP->totSendlenAi = 0;
13974     tcConP->connectState = TcConnectionrec::COPY_CONNECTED;
13975 
13976 /*---------------------------------------------------------------------------*/
13977 // To avoid using up to many operation records in ACC we will increase the
13978 // constant to ensure that we never send more than 40 records at a time.
13979 // This is where the constant 56 comes from. For long records this constant
13980 // will not matter that much. The current maximum is 6000 words outstanding
13981 // (including a number of those 56 words not really sent). We also have to
13982 // ensure that there are never more simultaneous usage of these operation
13983 // records to ensure that node recovery does not fail because of simultaneous
13984 // scanning.
13985 /*---------------------------------------------------------------------------*/
13986     UintR TnoOfWords = 8;
13987     TnoOfWords = TnoOfWords + MAGIC_CONSTANT;
13988     TnoOfWords = TnoOfWords + (TnoOfWords >> 2);
13989 
13990     /*-----------------------------------------------------------------
13991      * NOTE for transid1!
13992      * Transid1 in the tcConnection record is used load regulate the
13993      * copy(node recovery) process.
13994      * The number of outstanding words are written in the transid1
13995      * variable. This will be sent to the starting node in the
13996      * LQHKEYREQ signal and when the answer is returned in the LQHKEYCONF
13997      * we can reduce the number of outstanding words and check to see
13998      * if more LQHKEYREQ signals should be sent.
13999      *
14000      * However efficient this method is rather unsafe in such way that
14001      * it overwrites the transid1 original data.
14002      *
14003      * Also see TR 587.
14004      *----------------------------------------------------------------*/
14005     tcConP->transid[0] = TnoOfWords; // Data overload, see note!
14006     packLqhkeyreqLab(signal);
14007     tcConP->copyCountWords += TnoOfWords;
14008     scanptr.p->scanState = ScanRecord::WAIT_LQHKEY_COPY;
14009     if (tcConP->copyCountWords < cmaxWordsAtNodeRec) {
14010       nextRecordCopy(signal);
14011     }
14012     return;
14013   }
14014   else
14015   {
14016     // If accOperationPtr == RNIL no record was returned by ACC
14017     if (nextScanConf->accOperationPtr == RNIL) {
14018       jam();
14019       signal->theData[0] = scanptr.p->scanAccPtr;
14020       signal->theData[1] = AccCheckScan::ZCHECK_LCP_STOP;
14021       sendSignal(scanptr.p->scanBlockref, GSN_ACC_CHECK_SCAN, signal, 2, JBB);
14022       return;
14023     }
14024 
14025     initCopyTc(signal, ZINSERT);
14026     set_acc_ptr_in_scan_record(scanptr.p, 0, nextScanConf->accOperationPtr);
14027 
14028     Fragrecord* fragPtrP= fragptr.p;
14029     scanptr.p->scanState = ScanRecord::WAIT_TUPKEY_COPY;
14030     tcConP->transactionState = TcConnectionrec::COPY_TUPKEY;
14031     if(tcConP->m_disk_table)
14032     {
14033       next_scanconf_load_diskpage(signal, scanptr.p, tcConnectptr,fragPtrP);
14034     }
14035     else
14036     {
14037       next_scanconf_tupkeyreq(signal, scanptr.p, tcConP, fragPtrP, RNIL);
14038     }
14039   }
14040 }//Dblqh::nextScanConfCopyLab()
14041 
14042 
14043 /*---------------------------------------------------------------------------*/
14044 /*   USED IN COPYING OPERATION TO RECEIVE ATTRINFO FROM TUP.                 */
14045 /*---------------------------------------------------------------------------*/
14046 /* ************>> */
14047 /*  TRANSID_AI  > */
14048 /* ************>> */
execTRANSID_AI(Signal * signal)14049 void Dblqh::execTRANSID_AI(Signal* signal)
14050 {
14051   jamEntry();
14052   /* TransID_AI received from local TUP, data is linear inline in
14053    * signal buff
14054    */
14055   tcConnectptr.i = signal->theData[0];
14056   ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
14057   Uint32 length = signal->length() - TransIdAI::HeaderLength;
14058   ndbrequire(tcConnectptr.p->transactionState == TcConnectionrec::COPY_TUPKEY);
14059   Uint32 * src = &signal->theData[ TransIdAI::HeaderLength ];
14060   bool ok= appendToSection(tcConnectptr.p->attrInfoIVal,
14061                            src,
14062                            length);
14063   if (unlikely(! ok))
14064   {
14065     jam();
14066     tcConnectptr.p->errorCode = ZGET_ATTRINBUF_ERROR;
14067   }
14068 }//Dblqh::execTRANSID_AI()
14069 
14070 /*--------------------------------------------------------------------------*/
14071 /*     ENTER TUPKEYCONF WITH                                                */
14072 /*          TC_CONNECTPTR,                                                  */
14073 /*          TDATA2,                                                         */
14074 /*          TDATA3,                                                         */
14075 /*          TDATA4,                                                         */
14076 /*          TDATA5                                                          */
14077 /*--------------------------------------------------------------------------*/
14078 /*  PRECONDITION:   TRANSACTION_STATE = COPY_TUPKEY                         */
14079 /*--------------------------------------------------------------------------*/
copyTupkeyRefLab(Signal * signal)14080 void Dblqh::copyTupkeyRefLab(Signal* signal)
14081 {
14082   //const TupKeyRef * tupKeyRef = (TupKeyRef *)signal->getDataPtr();
14083 
14084   scanptr.i = tcConnectptr.p->tcScanRec;
14085   c_scanRecordPool.getPtr(scanptr);
14086   ScanRecord* scanP = scanptr.p;
14087 
14088   if (scanP->readCommitted == 0)
14089   {
14090     jam();
14091     ndbrequire(false); // Should not be possibe...we read with lock
14092   }
14093   else
14094   {
14095     jam();
14096     /**
14097      * Any readCommitted scan, can get 626 if it finds a candidate record
14098      *   that is not visible to the scan (i.e uncommitted inserts)
14099      *   if scanning with locks (shared/exclusive) this is not visible
14100      *   to LQH as lock is taken earlier
14101      */
14102     ndbrequire(terrorCode == 626);
14103   }
14104 
14105   ndbrequire(scanptr.p->scanState == ScanRecord::WAIT_TUPKEY_COPY);
14106   if (tcConnectptr.p->errorCode != 0)
14107   {
14108     jam();
14109     closeCopyLab(signal);
14110     return;
14111   }
14112 
14113   if (scanptr.p->scanCompletedStatus == ZTRUE)
14114   {
14115     jam();
14116     closeCopyLab(signal);
14117     return;
14118   }
14119 
14120   ndbrequire(tcConnectptr.p->copyCountWords < cmaxWordsAtNodeRec);
14121   scanptr.p->scanState = ScanRecord::WAIT_LQHKEY_COPY;
14122   nextRecordCopy(signal);
14123 }
14124 
copyTupkeyConfLab(Signal * signal)14125 void Dblqh::copyTupkeyConfLab(Signal* signal)
14126 {
14127   const TupKeyConf * const tupKeyConf = (TupKeyConf *)signal->getDataPtr();
14128 
14129   UintR readLength = tupKeyConf->readLength;
14130   Uint32 tableId = tcConnectptr.p->tableref;
14131   scanptr.i = tcConnectptr.p->tcScanRec;
14132   c_scanRecordPool.getPtr(scanptr);
14133   ScanRecord* scanP = scanptr.p;
14134 
14135   if (scanP->readCommitted == 0)
14136   {
14137     jam();
14138     Uint32 accOpPtr= get_acc_ptr_from_scan_record(scanP, 0, false);
14139     ndbassert(accOpPtr != (Uint32)-1);
14140     c_acc->execACCKEY_ORD(signal, accOpPtr);
14141   }
14142 
14143   if (tcConnectptr.p->errorCode != 0) {
14144     jam();
14145     closeCopyLab(signal);
14146     return;
14147   }//if
14148   if (scanptr.p->scanCompletedStatus == ZTRUE) {
14149     jam();
14150 /*---------------------------------------------------------------------------*/
14151 /*   THE COPY PROCESS HAVE BEEN CLOSED. MOST LIKELY A NODE FAILURE.          */
14152 /*---------------------------------------------------------------------------*/
14153     closeCopyLab(signal);
14154     return;
14155   }//if
14156   TcConnectionrec * tcConP = tcConnectptr.p;
14157   tcConnectptr.p->totSendlenAi = readLength;
14158   tcConnectptr.p->connectState = TcConnectionrec::COPY_CONNECTED;
14159 
14160   /* Read primary keys from TUP into signal buffer space
14161    * (used to get here via scan keyinfo)
14162    */
14163   Uint32* tmp = signal->getDataPtrSend()+24;
14164   Uint32 len= tcConnectptr.p->primKeyLen = readPrimaryKeys(scanP, tcConP, tmp);
14165 
14166   tcConP->gci_hi = tmp[len];
14167   tcConP->gci_lo = 0;
14168   // Calculate hash (no need to linearise key)
14169   if (g_key_descriptor_pool.getPtr(tableId)->hasCharAttr)
14170   {
14171     tcConnectptr.p->hashValue = calculateHash(tableId, tmp);
14172   }
14173   else
14174   {
14175     tcConnectptr.p->hashValue = md5_hash((Uint64*)tmp, len);
14176   }
14177 
14178   // Copy keyinfo into long section for LQHKEYREQ below
14179   if (unlikely(!keyinfoLab(tmp, len)))
14180   {
14181     /* Failed to store keyInfo, fail copy
14182      * This will result in a COPY_FRAGREF being sent to
14183      * the starting node, which will cause it to fail
14184      */
14185     scanptr.p->scanErrorCounter++;
14186     tcConP->errorCode= ZGET_DATAREC_ERROR;
14187     scanptr.p->scanCompletedStatus= ZTRUE;
14188 
14189     closeCopyLab(signal);
14190     return;
14191   }
14192 
14193   LqhKeyReq::setKeyLen(tcConP->reqinfo, len);
14194 
14195 /*---------------------------------------------------------------------------*/
14196 // To avoid using up to many operation records in ACC we will increase the
14197 // constant to ensure that we never send more than 40 records at a time.
14198 // This is where the constant 56 comes from. For long records this constant
14199 // will not matter that much. The current maximum is 6000 words outstanding
14200 // (including a number of those 56 words not really sent). We also have to
14201 // ensure that there are never more simultaneous usage of these operation
14202 // records to ensure that node recovery does not fail because of simultaneous
14203 // scanning.
14204 /*---------------------------------------------------------------------------*/
14205   UintR TnoOfWords = readLength + len;
14206   scanP->m_curr_batch_size_bytes += 4 * TnoOfWords;
14207   scanP->m_exec_direct_batch_size_words += readLength;
14208   TnoOfWords = TnoOfWords + MAGIC_CONSTANT;
14209   TnoOfWords = TnoOfWords + (TnoOfWords >> 2);
14210 
14211   /*-----------------------------------------------------------------
14212    * NOTE for transid1!
14213    * Transid1 in the tcConnection record is used load regulate the
14214    * copy(node recovery) process.
14215    * The number of outstanding words are written in the transid1
14216    * variable. This will be sent to the starting node in the
14217    * LQHKEYREQ signal and when the answer is returned in the LQHKEYCONF
14218    * we can reduce the number of outstanding words and check to see
14219    * if more LQHKEYREQ signals should be sent.
14220    *
14221    * However efficient this method is rather unsafe in such way that
14222    * it overwrites the transid1 original data.
14223    *
14224    * Also see TR 587.
14225    *----------------------------------------------------------------*/
14226   tcConnectptr.p->transid[0] = TnoOfWords; // Data overload, see note!
14227   packLqhkeyreqLab(signal);
14228   tcConnectptr.p->copyCountWords += TnoOfWords;
14229   scanptr.p->scanState = ScanRecord::WAIT_LQHKEY_COPY;
14230   if (tcConnectptr.p->copyCountWords < cmaxWordsAtNodeRec) {
14231     nextRecordCopy(signal);
14232     return;
14233   }//if
14234   return;
14235 }//Dblqh::copyTupkeyConfLab()
14236 
14237 /*---------------------------------------------------------------------------*/
14238 /*     ENTER LQHKEYCONF                                                      */
14239 /*---------------------------------------------------------------------------*/
14240 /*   PRECONDITION: CONNECT_STATE = COPY_CONNECTED                            */
14241 /*---------------------------------------------------------------------------*/
copyCompletedLab(Signal * signal)14242 void Dblqh::copyCompletedLab(Signal* signal)
14243 {
14244   const LqhKeyConf * const lqhKeyConf = (LqhKeyConf *)signal->getDataPtr();
14245 
14246   ndbrequire(tcConnectptr.p->transid[1] == lqhKeyConf->transId2);
14247   scanptr.i = tcConnectptr.p->tcScanRec;
14248   c_scanRecordPool.getPtr(scanptr);
14249   if (tcConnectptr.p->copyCountWords >= cmaxWordsAtNodeRec) {
14250     tcConnectptr.p->copyCountWords -= lqhKeyConf->transId1; // Data overload, see note!
14251     if (scanptr.p->scanCompletedStatus == ZTRUE) {
14252       jam();
14253 /*---------------------------------------------------------------------------*/
14254 // Copy to complete, we will not start any new copying.
14255 /*---------------------------------------------------------------------------*/
14256       closeCopyLab(signal);
14257       return;
14258     }//if
14259     if (tcConnectptr.p->copyCountWords < cmaxWordsAtNodeRec) {
14260       jam();
14261       nextRecordCopy(signal);
14262     }//if
14263     return;
14264   }//if
14265   tcConnectptr.p->copyCountWords -= lqhKeyConf->transId1; // Data overload, see note!
14266   ndbrequire(tcConnectptr.p->copyCountWords <= cmaxWordsAtNodeRec);
14267   if (tcConnectptr.p->copyCountWords > 0) {
14268     jam();
14269     return;
14270   }//if
14271 /*---------------------------------------------------------------------------*/
14272 // No more outstanding copies. We will only start new ones from here if it was
14273 // stopped before and this only happens when copyCountWords is bigger than the
14274 // threshold value. Since this did not occur we must be waiting for completion.
14275 // Check that this is so. If not we crash to find out what is going on.
14276 /*---------------------------------------------------------------------------*/
14277   if (scanptr.p->scanCompletedStatus == ZTRUE) {
14278     jam();
14279     closeCopyLab(signal);
14280     return;
14281   }//if
14282 
14283   if (scanptr.p->scanState == ScanRecord::WAIT_LQHKEY_COPY &&
14284       scanptr.p->scanErrorCounter)
14285   {
14286     jam();
14287     closeCopyLab(signal);
14288     return;
14289   }
14290 
14291   if (scanptr.p->scanState == ScanRecord::WAIT_LQHKEY_COPY) {
14292     jam();
14293 /*---------------------------------------------------------------------------*/
14294 // Make sure that something is in progress. Otherwise we will simply stop
14295 // and nothing more will happen.
14296 /*---------------------------------------------------------------------------*/
14297     systemErrorLab(signal, __LINE__);
14298     return;
14299   }//if
14300   return;
14301 }//Dblqh::copyCompletedLab()
14302 
nextRecordCopy(Signal * signal)14303 void Dblqh::nextRecordCopy(Signal* signal)
14304 {
14305   TcConnectionrec * const regTcPtr = tcConnectptr.p;
14306 
14307   fragptr.i = regTcPtr->fragmentptr;
14308   c_fragment_pool.getPtr(fragptr);
14309   scanptr.i = regTcPtr->tcScanRec;
14310   c_scanRecordPool.getPtr(scanptr);
14311   if (scanptr.p->scanState != ScanRecord::WAIT_LQHKEY_COPY) {
14312     jam();
14313 /*---------------------------------------------------------------------------*/
14314 // Make sure that nothing is in progress. Otherwise we will have to simultaneous
14315 // scans on the same record and this will certainly lead to unexpected
14316 // behaviour.
14317 /*---------------------------------------------------------------------------*/
14318     systemErrorLab(signal, __LINE__);
14319     return;
14320   }//if
14321   ScanRecord * const scanPtr = scanptr.p;
14322   ndbrequire(fragptr.p->fragStatus == Fragrecord::FSACTIVE);
14323 
14324   regTcPtr->errorCode = 0;
14325   Uint32 acc_op_ptr= get_acc_ptr_from_scan_record(scanptr.p, 0, false);
14326   SimulatedBlock *block = scanPtr->scanBlock;
14327   ExecFunction f = scanPtr->scanFunction_NEXT_SCANREQ;
14328   const Uint32 sig0 = scanPtr->scanAccPtr;
14329 
14330   /**
14331    * Here I can assign theData[1] through acc_op_ptr in the case of
14332    * acc_op_ptr != RNIL and also in the case of acc_op_ptr == RNIL
14333    * since theData[1] is assigned RNIL in the case when acc_op_ptr == RNIL
14334    */
14335   signal->theData[0] = sig0;
14336   signal->theData[1] = acc_op_ptr;
14337   signal->theData[2] = acc_op_ptr != RNIL ?
14338                        NextScanReq::ZSCAN_NEXT_COMMIT :
14339                        NextScanReq::ZSCAN_NEXT;
14340   /**
14341    * No need to commit (unlock) if no previous operation in ACC
14342    */
14343   scanPtr->scanState = ScanRecord::WAIT_NEXT_SCAN_COPY;
14344   send_next_NEXT_SCANREQ(signal, block, f, scanPtr);
14345 }//Dblqh::nextRecordCopy()
14346 
copyLqhKeyRefLab(Signal * signal)14347 void Dblqh::copyLqhKeyRefLab(Signal* signal)
14348 {
14349   ndbrequire(tcConnectptr.p->transid[1] == signal->theData[4]);
14350   Uint32 copyWords = signal->theData[3];
14351   scanptr.i = tcConnectptr.p->tcScanRec;
14352   c_scanRecordPool.getPtr(scanptr);
14353   scanptr.p->scanErrorCounter++;
14354   tcConnectptr.p->errorCode = terrorCode;
14355 
14356   LqhKeyConf* conf = (LqhKeyConf*)signal->getDataPtrSend();
14357   conf->transId1 = copyWords;
14358   conf->transId2 = tcConnectptr.p->transid[1];
14359   copyCompletedLab(signal);
14360 }//Dblqh::copyLqhKeyRefLab()
14361 
closeCopyLab(Signal * signal)14362 void Dblqh::closeCopyLab(Signal* signal)
14363 {
14364   TcConnectionrec * const regTcPtr = tcConnectptr.p;
14365   ScanRecord * const scanPtr = scanptr.p;
14366 
14367   if (regTcPtr->copyCountWords > 0) {
14368 /*---------------------------------------------------------------------------*/
14369 // We are still waiting for responses from the starting node.
14370 // Wait until all of those have arrived until we start the
14371 // close process.
14372 /*---------------------------------------------------------------------------*/
14373     jam();
14374     scanPtr->scanState = ScanRecord::WAIT_LQHKEY_COPY;
14375     return;
14376   }//if
14377   fragptr.i = regTcPtr->fragmentptr;
14378   regTcPtr->transid[0] = 0;
14379   regTcPtr->transid[1] = 0;
14380   c_fragment_pool.getPtr(fragptr);
14381 
14382   /**
14383    * Stop sending ROWID for all operations from now on
14384    */
14385   fragptr.p->m_copy_started_state = Fragrecord::AC_NORMAL;
14386   if (ERROR_INSERTED(5714))
14387   {
14388     ndbout_c("Copy of tab: %u frag: %u complete",
14389              fragptr.p->tabRef, fragptr.p->fragId);
14390   }
14391 
14392   Fragrecord::FragStatus fragstatus = fragptr.p->fragStatus;
14393 
14394   const Uint32 sig0 = scanPtr->scanAccPtr;
14395   SimulatedBlock *block = scanPtr->scanBlock;
14396   ExecFunction f = scanPtr->scanFunction_NEXT_SCANREQ;
14397 
14398   scanPtr->scanState = ScanRecord::WAIT_CLOSE_COPY;
14399   signal->theData[0] = sig0;
14400   signal->theData[1] = RNIL;
14401   signal->theData[2] = NextScanReq::ZSCAN_CLOSE;
14402   ndbrequire(fragstatus == Fragrecord::FSACTIVE);
14403   block->EXECUTE_DIRECT(f, signal);
14404 }//Dblqh::closeCopyLab()
14405 
14406 /*---------------------------------------------------------------------------*/
14407 /*   ENTER NEXT_SCANCONF WITH                                                */
14408 /*     SCANPTR,                                                              */
14409 /*     TFRAGID,                                                              */
14410 /*     TACC_OPPTR,                                                           */
14411 /*     TLOCAL_KEY1,                                                          */
14412 /*     TLOCAL_KEY2,                                                          */
14413 /*     TKEY_LENGTH,                                                          */
14414 /*     TKEY1,                                                                */
14415 /*     TKEY2,                                                                */
14416 /*     TKEY3,                                                                */
14417 /*     TKEY4                                                                 */
14418 /*---------------------------------------------------------------------------*/
14419 /*   PRECONDITION: SCAN_STATE = WAIT_CLOSE_COPY                              */
14420 /*---------------------------------------------------------------------------*/
accCopyCloseConfLab(Signal * signal)14421 void Dblqh::accCopyCloseConfLab(Signal* signal)
14422 {
14423   ScanRecord * const scanPtr = scanptr.p;
14424   TcConnectionrec * const regTcPtr = tcConnectptr.p;
14425   const Uint32 sig0 = regTcPtr->tupConnectrec;
14426   const Uint32 sig1 = regTcPtr->tableref;
14427   const Uint32 sig2 = scanPtr->scanSchemaVersion;
14428   const Uint32 sig4 = scanPtr->scanStoredProcId;
14429   const Uint32 sig5 = scanPtr->scanApiBlockref;
14430 
14431   signal->theData[0] = sig0;
14432   signal->theData[1] = sig1;
14433   signal->theData[2] = sig2;
14434   signal->theData[3] = ZDELETE_STORED_PROC_ID;
14435   signal->theData[4] = sig4;
14436   signal->theData[5] = sig5;
14437   c_tup->execSTORED_PROCREQ(signal);
14438   tupCopyCloseConfLab(signal);
14439   return;
14440 }//Dblqh::accCopyCloseConfLab()
14441 
14442 /*---------------------------------------------------------------------------*/
14443 /*   ENTER STORED_PROCCONF WITH                                              */
14444 /*     0 success = CONF, 1 failure == REF                                    */
14445 /*     STORED_PROC_ID                                                        */
14446 /*---------------------------------------------------------------------------*/
tupCopyCloseConfLab(Signal * signal)14447 void Dblqh::tupCopyCloseConfLab(Signal* signal)
14448 {
14449   fragptr.i = tcConnectptr.p->fragmentptr;
14450   c_fragment_pool.getPtr(fragptr);
14451   fragptr.p->copyFragState = ZIDLE;
14452 
14453   if (tcConnectptr.p->abortState == TcConnectionrec::NEW_FROM_TC) {
14454     jam();
14455     TcNodeFailRecordPtr tcNodeFailPtr;
14456     tcNodeFailPtr.i = tcConnectptr.p->tcNodeFailrec;
14457     ptrCheckGuard(tcNodeFailPtr, ctcNodeFailrecFileSize, tcNodeFailRecord);
14458     tcNodeFailPtr.p->tcRecNow = tcConnectptr.i + 1;
14459     signal->theData[0] = ZLQH_TRANS_NEXT;
14460     signal->theData[1] = tcNodeFailPtr.i;
14461     sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
14462 
14463     CopyFragRef * const ref = (CopyFragRef *)&signal->theData[0];
14464     ref->userPtr = scanptr.p->copyPtr;
14465     ref->sendingNodeId = cownNodeid;
14466     ref->startingNodeId = scanptr.p->scanNodeId;
14467     ref->tableId = fragptr.p->tabRef;
14468     ref->fragId = fragptr.p->fragId;
14469     ref->errorCode = ZNODE_FAILURE_ERROR;
14470     sendSignal(tcConnectptr.p->clientBlockref, GSN_COPY_FRAGREF, signal,
14471                CopyFragRef::SignalLength, JBB);
14472   } else {
14473     if (scanptr.p->scanErrorCounter > 0) {
14474       jam();
14475       CopyFragRef * const ref = (CopyFragRef *)&signal->theData[0];
14476       ref->userPtr = scanptr.p->copyPtr;
14477       ref->sendingNodeId = cownNodeid;
14478       ref->startingNodeId = scanptr.p->scanNodeId;
14479       ref->tableId = fragptr.p->tabRef;
14480       ref->fragId = fragptr.p->fragId;
14481       ref->errorCode = tcConnectptr.p->errorCode;
14482       sendSignal(tcConnectptr.p->clientBlockref, GSN_COPY_FRAGREF, signal,
14483                  CopyFragRef::SignalLength, JBB);
14484     } else {
14485       jam();
14486       CopyFragConf * const conf = (CopyFragConf *)&signal->theData[0];
14487       conf->userPtr = scanptr.p->copyPtr;
14488       conf->sendingNodeId = cownNodeid;
14489       conf->startingNodeId = scanptr.p->scanNodeId;
14490       conf->tableId = tcConnectptr.p->tableref;
14491       conf->fragId = tcConnectptr.p->fragmentid;
14492       conf->rows_lo = scanptr.p->m_curr_batch_size_rows;
14493       conf->bytes_lo = scanptr.p->m_curr_batch_size_bytes;
14494       sendSignal(tcConnectptr.p->clientBlockref, GSN_COPY_FRAGCONF, signal,
14495 		 CopyFragConf::SignalLength, JBB);
14496     }//if
14497   }//if
14498   releaseActiveCopy(signal);
14499   {
14500     ScanRecordPtr restart;
14501     bool restart_flag = finishScanrec(signal, restart);
14502     releaseScanrec(signal);
14503     tcConnectptr.p->tcScanRec = RNIL;
14504     releaseOprec(signal);
14505     releaseTcrec(signal, tcConnectptr);
14506     if (restart_flag)
14507     {
14508       jam();
14509       tcConnectptr.i = restart.p->scanTcrec;
14510       ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
14511       scanptr = restart;
14512       continueAfterReceivingAllAiLab(signal);
14513       return;
14514     }
14515     return;
14516   }
14517 }//Dblqh::tupCopyCloseConfLab()
14518 
14519 /*---------------------------------------------------------------------------*/
14520 /*   A NODE FAILURE OCCURRED DURING THE COPY PROCESS. WE NEED TO CLOSE THE   */
14521 /*   COPY PROCESS SINCE A NODE FAILURE DURING THE COPY PROCESS WILL ALSO     */
14522 /*   FAIL THE NODE THAT IS TRYING TO START-UP.                               */
14523 /*---------------------------------------------------------------------------*/
closeCopyRequestLab(Signal * signal)14524 void Dblqh::closeCopyRequestLab(Signal* signal)
14525 {
14526   scanptr.p->scanErrorCounter++;
14527   if (0) ndbout_c("closeCopyRequestLab: scanState: %d", scanptr.p->scanState);
14528   switch (scanptr.p->scanState) {
14529   case ScanRecord::WAIT_TUPKEY_COPY:
14530   case ScanRecord::WAIT_NEXT_SCAN_COPY:
14531     jam();
14532 /*---------------------------------------------------------------------------*/
14533 /*   SET COMPLETION STATUS AND WAIT FOR OPPORTUNITY TO STOP THE SCAN.        */
14534 //   ALSO SET NO OF WORDS OUTSTANDING TO ZERO TO AVOID ETERNAL WAIT.
14535 /*---------------------------------------------------------------------------*/
14536     scanptr.p->scanCompletedStatus = ZTRUE;
14537     tcConnectptr.p->copyCountWords = 0;
14538     break;
14539   case ScanRecord::WAIT_ACC_COPY:
14540     jam();
14541 /*---------------------------------------------------------------------------*/
14542 /*   WE ARE CURRENTLY STARTING UP THE SCAN. SET COMPLETED STATUS AND WAIT FOR*/
14543 /*   COMPLETION OF STARTUP.                                                  */
14544 /*---------------------------------------------------------------------------*/
14545     scanptr.p->scanCompletedStatus = ZTRUE;
14546     break;
14547   case ScanRecord::WAIT_CLOSE_COPY:
14548     jam();
14549 /*---------------------------------------------------------------------------*/
14550 /*   CLOSE IS ALREADY ONGOING. WE NEED NOT DO ANYTHING.                      */
14551 /*---------------------------------------------------------------------------*/
14552     break;
14553   case ScanRecord::WAIT_LQHKEY_COPY:
14554     jam();
14555 /*---------------------------------------------------------------------------*/
14556 /*   WE ARE WAITING FOR THE FAILED NODE. THE NODE WILL NEVER COME BACK.      */
14557 //   WE NEED TO START THE FAILURE HANDLING IMMEDIATELY.
14558 //   ALSO SET NO OF WORDS OUTSTANDING TO ZERO TO AVOID ETERNAL WAIT.
14559 /*---------------------------------------------------------------------------*/
14560     tcConnectptr.p->copyCountWords = 0;
14561     closeCopyLab(signal);
14562     break;
14563   default:
14564     ndbrequire(false);
14565     break;
14566   }//switch
14567   return;
14568 }//Dblqh::closeCopyRequestLab()
14569 
14570 /* ****************************************************** */
14571 /*  COPY_ACTIVEREQ: Change state of a fragment to ACTIVE. */
14572 /* ****************************************************** */
execCOPY_ACTIVEREQ(Signal * signal)14573 void Dblqh::execCOPY_ACTIVEREQ(Signal* signal)
14574 {
14575   CRASH_INSERTION(5026);
14576 
14577   const CopyActiveReq * const req = (CopyActiveReq *)&signal->theData[0];
14578   jamEntry();
14579   Uint32 masterPtr = req->userPtr;
14580   BlockReference masterRef = req->userRef;
14581   tabptr.i = req->tableId;
14582   ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
14583   Uint32 fragId = req->fragId;
14584   Uint32 flags = req->flags;
14585   if (unlikely(signal->getLength() < CopyActiveReq::SignalLength))
14586   {
14587     jam();
14588     flags = 0;
14589   }
14590 
14591   ndbrequire(getFragmentrec(signal, fragId));
14592 
14593   fragptr.p->fragStatus = Fragrecord::FSACTIVE;
14594   fragptr.p->fragDistributionKey = req->distributionKey;
14595 
14596   if (TRACENR_FLAG)
14597     TRACENR("tab: " << tabptr.i
14598 	    << " frag: " << fragId
14599 	    << " COPY ACTIVE"
14600             << " flags: " << hex << flags << endl);
14601 
14602   ndbrequire(cnoActiveCopy < 3);
14603   cactiveCopy[cnoActiveCopy] = fragptr.i;
14604   cnoActiveCopy++;
14605   fragptr.p->masterBlockref = masterRef;
14606   fragptr.p->masterPtr = masterPtr;
14607 
14608   if (flags)
14609   {
14610     /**
14611       We send with flags first that indicates no logging
14612       and no wait, we then send without flags to activate
14613       REDO logging. We thus use the flags to indicate when
14614       a new fragment is to be copied.
14615     */
14616     log_fragment_copied(signal);
14617   }
14618   if ((flags & CopyActiveReq::CAR_NO_LOGGING) == 0)
14619   {
14620     jam();
14621     if (fragptr.p->lcpFlag == Fragrecord::LCP_STATE_TRUE)
14622     {
14623       jam();
14624       fragptr.p->logFlag = Fragrecord::STATE_TRUE;
14625     }
14626   }
14627 
14628   if (flags & CopyActiveReq::CAR_NO_WAIT)
14629   {
14630     jam();
14631     ndbrequire(fragptr.p->activeTcCounter == 0);
14632     Uint32 save = fragptr.p->startGci;
14633     fragptr.p->startGci = 0;
14634     sendCopyActiveConf(signal, tabptr.i);
14635     fragptr.p->startGci = save;
14636     return;
14637   }
14638 
14639   fragptr.p->activeTcCounter = 1;
14640 /*------------------------------------------------------*/
14641 /*       SET IT TO ONE TO ENSURE THAT IT IS NOT POSSIBLE*/
14642 /*       TO DECREASE IT TO ZERO UNTIL WE HAVE COMPLETED */
14643 /*       THE SCAN.                                      */
14644 /*------------------------------------------------------*/
14645   signal->theData[0] = ZSCAN_TC_CONNECT;
14646   signal->theData[1] = 0;
14647   signal->theData[2] = tabptr.i;
14648   signal->theData[3] = fragId;
14649   sendSignal(cownref, GSN_CONTINUEB, signal, 4, JBB);
14650   return;
14651 }//Dblqh::execCOPY_ACTIVEREQ()
14652 
scanTcConnectLab(Signal * signal,Uint32 tstartTcConnect,Uint32 fragId)14653 void Dblqh::scanTcConnectLab(Signal* signal, Uint32 tstartTcConnect, Uint32 fragId)
14654 {
14655   Uint32 tendTcConnect;
14656 
14657   ndbrequire(getFragmentrec(signal, fragId));
14658   if ((tstartTcConnect + 200) >= ctcConnectrecFileSize) {
14659     jam();
14660     tendTcConnect = ctcConnectrecFileSize - 1;
14661   } else {
14662     jam();
14663     tendTcConnect = tstartTcConnect + 200;
14664   }//if
14665   for (tcConnectptr.i = tstartTcConnect;
14666        tcConnectptr.i <= tendTcConnect;
14667        tcConnectptr.i++) {
14668     jam();
14669     ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
14670     if (tcConnectptr.p->transactionState != TcConnectionrec::IDLE) {
14671       switch (tcConnectptr.p->logWriteState) {
14672       case TcConnectionrec::NOT_WRITTEN:
14673         jam();
14674         if (fragptr.i == tcConnectptr.p->fragmentptr) {
14675           jam();
14676           fragptr.p->activeTcCounter = fragptr.p->activeTcCounter + 1;
14677           tcConnectptr.p->logWriteState = TcConnectionrec::NOT_WRITTEN_WAIT;
14678         }//if
14679         break;
14680       default:
14681         jam();
14682         /*empty*/;
14683         break;
14684       }//switch
14685     }//if
14686   }//for
14687   if (tendTcConnect < (ctcConnectrecFileSize - 1)) {
14688     jam();
14689     signal->theData[0] = ZSCAN_TC_CONNECT;
14690     signal->theData[1] = tendTcConnect + 1;
14691     signal->theData[2] = tabptr.i;
14692     signal->theData[3] = fragId;
14693     sendSignal(cownref, GSN_CONTINUEB, signal, 4, JBB);
14694   } else {
14695     jam();
14696 /*------------------------------------------------------*/
14697 /*       THE SCAN HAVE BEEN COMPLETED. WE CHECK IF ALL  */
14698 /*       OPERATIONS HAVE ALREADY BEEN COMPLETED.        */
14699 /*------------------------------------------------------*/
14700     ndbrequire(fragptr.p->activeTcCounter > 0);
14701     fragptr.p->activeTcCounter--;
14702     if (fragptr.p->activeTcCounter == 0) {
14703       jam();
14704 /*------------------------------------------------------*/
14705 /*       SET START GLOBAL CHECKPOINT TO THE NEXT        */
14706 /*       CHECKPOINT WE HAVE NOT YET HEARD ANYTHING ABOUT*/
14707 /*       THIS GCP WILL BE COMPLETELY COVERED BY THE LOG.*/
14708 /*------------------------------------------------------*/
14709       fragptr.p->startGci = cnewestGci + 1;
14710       sendCopyActiveConf(signal, tabptr.i);
14711     }//if
14712   }//if
14713   return;
14714 }//Dblqh::scanTcConnectLab()
14715 
14716 /* ========================================================================= */
14717 /* =======              INITIATE TC RECORD AT COPY FRAGMENT          ======= */
14718 /*                                                                           */
14719 /*       SUBROUTINE SHORT NAME = ICT                                         */
14720 /* ========================================================================= */
initCopyTc(Signal * signal,Operation_t op)14721 void Dblqh::initCopyTc(Signal* signal, Operation_t op)
14722 {
14723   tcConnectptr.p->operation = ZREAD;
14724   tcConnectptr.p->opExec = 0;	/* NOT INTERPRETED MODE */
14725   tcConnectptr.p->schemaVersion = scanptr.p->scanSchemaVersion;
14726   Uint32 reqinfo = 0;
14727   LqhKeyReq::setDirtyFlag(reqinfo, 1);
14728   LqhKeyReq::setSimpleFlag(reqinfo, 1);
14729   LqhKeyReq::setOperation(reqinfo, op);
14730   LqhKeyReq::setGCIFlag(reqinfo, 1);
14731   LqhKeyReq::setNrCopyFlag(reqinfo, 1);
14732                                         /* AILen in LQHKEYREQ  IS ZERO */
14733   tcConnectptr.p->reqinfo = reqinfo;
14734 /* ------------------------------------------------------------------------ */
14735 /* THE RECEIVING NODE WILL EXPECT THAT IT IS THE LAST NODE AND WILL         */
14736 /* SEND COMPLETED AS THE RESPONSE SIGNAL SINCE DIRTY_OP BIT IS SET.         */
14737 /* ------------------------------------------------------------------------ */
14738   tcConnectptr.p->nodeAfterNext[0] = ZNIL;
14739   tcConnectptr.p->nodeAfterNext[1] = ZNIL;
14740   tcConnectptr.p->tcBlockref = cownref;
14741   tcConnectptr.p->readlenAi = 0;
14742   tcConnectptr.p->storedProcId = ZNIL;
14743   tcConnectptr.p->nextSeqNoReplica = 0;
14744   tcConnectptr.p->dirtyOp = ZFALSE;
14745   tcConnectptr.p->lastReplicaNo = 0;
14746   tcConnectptr.p->currTupAiLen = 0;
14747   tcConnectptr.p->tcTimer = cLqhTimeOutCount;
14748 }//Dblqh::initCopyTc()
14749 
14750 /* ------------------------------------------------------------------------- */
14751 /* -------               SEND COPY_ACTIVECONF TO MASTER DIH          ------- */
14752 /*                                                                           */
14753 /* ------------------------------------------------------------------------- */
sendCopyActiveConf(Signal * signal,Uint32 tableId)14754 void Dblqh::sendCopyActiveConf(Signal* signal, Uint32 tableId)
14755 {
14756   releaseActiveCopy(signal);
14757   CopyActiveConf * const conf = (CopyActiveConf *)&signal->theData[0];
14758   conf->userPtr = fragptr.p->masterPtr;
14759   conf->tableId = tableId;
14760   conf->fragId = fragptr.p->fragId;
14761   conf->startingNodeId = cownNodeid;
14762   conf->startGci = fragptr.p->startGci;
14763   sendSignal(fragptr.p->masterBlockref, GSN_COPY_ACTIVECONF, signal,
14764              CopyActiveConf::SignalLength, JBB);
14765 }//Dblqh::sendCopyActiveConf()
14766 
14767 /* ##########################################################################
14768  * #######                       LOCAL CHECKPOINT MODULE              #######
14769  *
14770  * ##########################################################################
14771  * --------------------------------------------------------------------------
14772  *  THIS MODULE HANDLES THE EXECUTION AND CONTROL OF LOCAL CHECKPOINTS
14773  *  IT CONTROLS THE LOCAL CHECKPOINTS IN TUP AND ACC. IT DOES ALSO INTERACT
14774  *  WITH DIH TO CONTROL WHICH GLOBAL CHECKPOINTS THAT ARE RECOVERABLE
14775  * ------------------------------------------------------------------------- */
execEMPTY_LCP_REQ(Signal * signal)14776 void Dblqh::execEMPTY_LCP_REQ(Signal* signal)
14777 {
14778   /**
14779    * This code executes only in ndbd nodes. In ndbmtd the Dblqh Proxy will
14780    * take over of this processing. But since ndbd have no proxy block we have
14781    * to handle it for ndbd here in the local Dblqh block.
14782    */
14783   jamEntry();
14784   CRASH_INSERTION(5008);
14785   EmptyLcpReq * const emptyLcpOrd = (EmptyLcpReq*)&signal->theData[0];
14786 
14787   ndbrequire(!isNdbMtLqh()); // Handled by DblqhProxy
14788 
14789   lcpPtr.i = 0;
14790   ptrAss(lcpPtr, lcpRecord);
14791 
14792   Uint32 nodeId = refToNode(emptyLcpOrd->senderRef);
14793 
14794   lcpPtr.p->m_EMPTY_LCP_REQ.set(nodeId);
14795   lcpPtr.p->reportEmpty = true;
14796 
14797   if (lcpPtr.p->lcpState == LcpRecord::LCP_IDLE){
14798     jam();
14799     bool ok = false;
14800     switch(clcpCompletedState){
14801     case LCP_IDLE:
14802       ok = true;
14803       sendEMPTY_LCP_CONF(signal, true);
14804       break;
14805     case LCP_RUNNING:
14806       ok = true;
14807       sendEMPTY_LCP_CONF(signal, false);
14808       break;
14809     case LCP_CLOSE_STARTED:
14810       jam();
14811       ok = true;
14812       break;
14813     }
14814     ndbrequire(ok);
14815 
14816   }//if
14817 
14818   return;
14819 }//Dblqh::execEMPTY_LCPREQ()
14820 
14821 #ifdef NDB_DEBUG_FULL
14822 static struct TraceLCP {
14823   void sendSignal(Uint32 ref, Uint32 gsn, Signal* signal,
14824 		  Uint32 len, Uint32 prio);
14825   void save(Signal*);
14826   void restore(SimulatedBlock&, Signal* sig);
14827   struct Sig {
14828     enum {
14829       Sig_save = 0,
14830       Sig_send = 1
14831     } type;
14832     SignalHeader header;
14833     Uint32 theData[25];
14834   };
14835   Vector<Sig> m_signals;
14836 } g_trace_lcp;
14837 template class Vector<TraceLCP::Sig>;
14838 #else
14839 #endif
14840 
14841 void
force_lcp(Signal * signal)14842 Dblqh::force_lcp(Signal* signal)
14843 {
14844   if (cLqhTimeOutCount == c_last_force_lcp_time)
14845   {
14846     jam();
14847     return;
14848   }
14849 
14850   c_last_force_lcp_time = cLqhTimeOutCount;
14851   signal->theData[0] = DumpStateOrd::DihStartLcpImmediately;
14852   sendSignal(DBDIH_REF, GSN_DUMP_STATE_ORD, signal, 1, JBB);
14853 }
14854 
execLCP_FRAG_ORD(Signal * signal)14855 void Dblqh::execLCP_FRAG_ORD(Signal* signal)
14856 {
14857   jamEntry();
14858   CRASH_INSERTION(5010);
14859 
14860   LcpFragOrd lcpFragOrdCopy = * (LcpFragOrd *)&signal->theData[0];
14861   LcpFragOrd * lcpFragOrd = &lcpFragOrdCopy;
14862 
14863   Uint32 lcpId = lcpFragOrd->lcpId;
14864 
14865   lcpPtr.i = 0;
14866   ptrAss(lcpPtr, lcpRecord);
14867 
14868   if (c_lcpId < lcpFragOrd->lcpId)
14869   {
14870     jam();
14871 
14872     lcpPtr.p->firstFragmentFlag= true;
14873 
14874 #ifdef ERROR_INSERT
14875     if (check_ndb_versions())
14876     {
14877       /**
14878        * Only (so-far) in error insert
14879        *   check that keepGci (tail of REDO) is smaller than of head of REDO
14880        *
14881        */
14882       if (! ((cnewestCompletedGci >= lcpFragOrd->keepGci) &&
14883              (cnewestGci >= lcpFragOrd->keepGci)))
14884       {
14885         ndbout_c("lcpFragOrd->keepGci: %u cnewestCompletedGci: %u cnewestGci: %u",
14886                  lcpFragOrd->keepGci, cnewestCompletedGci, cnewestGci);
14887       }
14888       ndbrequire(cnewestCompletedGci >= lcpFragOrd->keepGci);
14889       ndbrequire(cnewestGci >= lcpFragOrd->keepGci);
14890     }
14891 #endif
14892 
14893     c_lcpId = lcpFragOrd->lcpId;
14894     ndbrequire(lcpPtr.p->lcpState == LcpRecord::LCP_IDLE);
14895     setLogTail(signal, lcpFragOrd->keepGci);
14896     ndbrequire(clcpCompletedState == LCP_IDLE);
14897     clcpCompletedState = LCP_RUNNING;
14898 
14899     /**
14900      * We preset some variables that will stay the same for the entire
14901      * LCP execution.
14902      */
14903     lcpPtr.p->currentFragment.lcpFragOrd.lcpId = c_lcpId;
14904     lcpPtr.p->currentFragment.lcpFragOrd.keepGci = lcpFragOrd->keepGci;
14905     lcpPtr.p->currentFragment.lcpFragOrd.lastFragmentFlag = FALSE;
14906     /* These should be set before each LCP fragment execution */
14907     lcpPtr.p->currentFragment.lcpFragOrd.tableId = RNIL;
14908     lcpPtr.p->currentFragment.lcpFragOrd.fragmentId = RNIL;
14909     lcpPtr.p->currentFragment.lcpFragOrd.lcpNo = RNIL;
14910   }
14911   else
14912   {
14913     jam();
14914     ndbrequire(c_lcpId == lcpFragOrd->lcpId);
14915     if (lcpPtr.p->lastFragmentFlag || clcpCompletedState == LCP_IDLE)
14916     {
14917       jam();
14918       /**
14919        * Drop any message received after LCP_FRAG_ORD with last fragment
14920        * marker, must be ndbd we're running since Proxy should handle this.
14921        * Can happen after a master takeover.
14922        *
14923        * DIH doesn't keep track of number of outstanding messages, so
14924        * no need to do anything when receiving multiple LCP_FRAG_ORDs
14925        * that are discarded.
14926        */
14927       ndbrequire(!isNdbMtLqh());
14928       return;
14929     }
14930   }
14931 
14932   if (lcpFragOrd->lastFragmentFlag)
14933   {
14934     jam();
14935     lcpPtr.p->lastFragmentFlag = true;
14936     CRASH_INSERTION(5054);
14937     if (lcpPtr.p->lcpState == LcpRecord::LCP_IDLE) {
14938       jam();
14939       /* ----------------------------------------------------------
14940        *       NOW THE COMPLETE LOCAL CHECKPOINT ROUND IS COMPLETED.
14941        * -------------------------------------------------------- */
14942       if (cnoOfFragsCheckpointed > 0) {
14943         jam();
14944         completeLcpRoundLab(signal, lcpId);
14945       } else {
14946         jam();
14947         sendLCP_COMPLETE_REP(signal, lcpId);
14948       }//if
14949     }
14950     return;
14951   }//if
14952 
14953   tabptr.i = lcpFragOrd->tableId;
14954   ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
14955 
14956   if (unlikely(tabptr.p->tableStatus != Tablerec::TABLE_DEFINED &&
14957                tabptr.p->tableStatus != Tablerec::TABLE_READ_ONLY))
14958   {
14959     /**
14960      * There is no way to discover if we had multiple messages for this
14961      * since the table is already deleted and we don't keep information
14962      * about it anymore. Should not be a problem since the signal is
14963      * likely to be dropped somewhere and an extra LCP_FRAG_REP to a
14964      * dropped table will simply be dropped again in DBDIH.
14965      */
14966     jam();
14967     LcpRecord::FragOrd fragOrd;
14968     fragOrd.lcpFragOrd = * lcpFragOrd;
14969 
14970     Fragrecord tmp;
14971     tmp.maxGciInLcp = cnewestGci;
14972     tmp.maxGciCompletedInLcp = cnewestCompletedGci;
14973     sendLCP_FRAG_REP(signal, fragOrd, &tmp);
14974     return;
14975   }
14976 
14977   ndbrequire(getFragmentrec(signal, lcpFragOrd->fragmentId));
14978 
14979   if (fragptr.p->lcp_frag_ord_lcp_id == lcpFragOrd->lcpId)
14980   {
14981     /**
14982      * The LCP_FRAG_ORD have already been received, we need to send a report
14983      * back to the Proxy for ndbmtd to keep the outstanding counter up-to-date.
14984      * For ndbd we can simply drop the signal.
14985      */
14986     jam();
14987     if (!isNdbMtLqh())
14988     {
14989       jam();
14990       return;
14991     }
14992     /**
14993      * This signal is identified by its length, it will be used to decrease
14994      * the number of outstanding LCP_FRAG_ORD operations to the LQH instances.
14995      * From a modular point of view DBLQH will always drop this LCP_FRAG_ORD
14996      * since it already received it. In the case of ndbmtd we do however need
14997      * to ensure that DBLQH proxy also knows about the drop since it keeps
14998      * track of the number of outstanding LCP_FRAG_ORDs. When DBLQH proxy
14999      * receives this signal it will update the counter and then drop the
15000      * signal. So no signal will be sent to DBDIH in any case.
15001      */
15002     sendSignal(DBLQH_REF, GSN_LCP_FRAG_REP, signal, 1, JBA);
15003     return;
15004   }
15005 
15006   /**
15007    * Add the fragment to the queue of LCP_FRAG_ORDs.
15008    * We need to store lcpId as a flag that we received an
15009    * LCP_FRAG_ORD for this LCP, we need the lcpNo for
15010    * later when executing the LCP and we need the state
15011    * to indicate if we have completed the LCP yet which
15012    * is needed for drop table.
15013    */
15014   fragptr.p->lcp_frag_ord_lcp_no = lcpFragOrd->lcpNo;
15015   fragptr.p->lcp_frag_ord_lcp_id = lcpFragOrd->lcpId;
15016   fragptr.p->lcp_frag_ord_state = Fragrecord::LCP_QUEUED;
15017   c_queued_lcp_frag_ord.addLast(fragptr);
15018 
15019   cnoOfFragsCheckpointed++;
15020 
15021   if (lcpPtr.p->lcpState != LcpRecord::LCP_IDLE)
15022   {
15023     jam();
15024     return;
15025   }//if
15026   sendLCP_FRAGIDREQ(signal);
15027 }//Dblqh::execLCP_FRAGORD()
15028 
execLCP_PREPARE_REF(Signal * signal)15029 void Dblqh::execLCP_PREPARE_REF(Signal* signal)
15030 {
15031   jamEntry();
15032 
15033   LcpPrepareRef* ref= (LcpPrepareRef*)signal->getDataPtr();
15034 
15035   lcpPtr.i = ref->senderData;
15036   ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord);
15037   ndbrequire(lcpPtr.p->lcpState == LcpRecord::LCP_WAIT_FRAGID);
15038 
15039   fragptr.i = lcpPtr.p->currentFragment.fragPtrI;
15040   c_fragment_pool.getPtr(fragptr);
15041 
15042   ndbrequire(ref->tableId == fragptr.p->tabRef);
15043   ndbrequire(ref->fragmentId == fragptr.p->fragId);
15044 
15045   tabptr.i = ref->tableId;
15046   ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
15047 
15048   ndbrequire(lcpPtr.p->m_outstanding);
15049   lcpPtr.p->m_outstanding--;
15050 
15051   /**
15052    * Only BACKUP is allowed to ref LCP_PREPARE
15053    */
15054   ndbrequire(refToMain(signal->getSendersBlockRef()) == BACKUP);
15055   lcpPtr.p->m_error = ref->errorCode;
15056 
15057   /**
15058    * Only table no longer present is acceptable - anything
15059    * else is a hard error.
15060    * This sometimes manifests as error 785 - 'Schema object is busy with another...'
15061    * which we treat in the same way. This happens when the table is dropping when
15062    * we ask for the table information. So both are symptoms of a table which is
15063    * being dropped or already been dropped.
15064    */
15065   if (ref->errorCode != GetTabInfoRef::TableNotDefined &&
15066       ref->errorCode != DropTableRef::ActiveSchemaTrans)
15067   {
15068     g_eventLogger->critical("Fatal : LCP_PREPARE_REF t%uf%u errorCode %u",
15069                             ref->tableId,
15070                             ref->fragmentId,
15071                             ref->errorCode);
15072     ndbrequire(false);
15073     return;
15074   };
15075 
15076   /* Carry on with the next table... */
15077 
15078   stopLcpFragWatchdog();
15079 
15080   if (lcpPtr.p->m_outstanding == 0)
15081   {
15082     jam();
15083 
15084     if(lcpPtr.p->firstFragmentFlag)
15085     {
15086       jam();
15087       LcpFragOrd *ord= (LcpFragOrd*)signal->getDataPtrSend();
15088       lcpPtr.p->firstFragmentFlag= false;
15089 
15090       if (!isNdbMtLqh())
15091       {
15092         jam();
15093         *ord = lcpPtr.p->currentFragment.lcpFragOrd;
15094         EXECUTE_DIRECT(PGMAN, GSN_LCP_FRAG_ORD, signal, signal->length());
15095         jamEntry();
15096 
15097         /**
15098          * First fragment mean that last LCP is complete :-)
15099          */
15100         jam();
15101         *ord = lcpPtr.p->currentFragment.lcpFragOrd;
15102         EXECUTE_DIRECT(TSMAN, GSN_LCP_FRAG_ORD,
15103                        signal, signal->length(), 0);
15104         jamEntry();
15105       }
15106       else
15107       {
15108         /**
15109          * Handle by LqhProxy
15110          */
15111       }
15112     }
15113 
15114     lcpPtr.p->lcpState = LcpRecord::LCP_COMPLETED;
15115     contChkpNextFragLab(signal);
15116   }
15117 }
15118 
15119 /* --------------------------------------------------------------------------
15120  *       PRECONDITION: LCP_PTR:LCP_STATE = WAIT_FRAGID
15121  * --------------------------------------------------------------------------
15122  *       WE NOW HAVE THE LOCAL FRAGMENTS THAT THE LOCAL CHECKPOINT WILL USE.
15123  * -------------------------------------------------------------------------- */
execLCP_PREPARE_CONF(Signal * signal)15124 void Dblqh::execLCP_PREPARE_CONF(Signal* signal)
15125 {
15126   jamEntry();
15127 
15128   LcpPrepareConf* conf= (LcpPrepareConf*)signal->getDataPtr();
15129 
15130   lcpPtr.i = conf->senderData;
15131   ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord);
15132   ndbrequire(lcpPtr.p->lcpState == LcpRecord::LCP_WAIT_FRAGID);
15133 
15134   fragptr.i = lcpPtr.p->currentFragment.fragPtrI;
15135   c_fragment_pool.getPtr(fragptr);
15136 
15137   // wl4391_todo obsolete
15138   if (refToBlock(signal->getSendersBlockRef()) != PGMAN)
15139   {
15140     ndbrequire(conf->tableId == fragptr.p->tabRef);
15141     ndbrequire(conf->fragmentId == fragptr.p->fragId);
15142   }
15143 
15144   ndbrequire(lcpPtr.p->m_outstanding);
15145   lcpPtr.p->m_outstanding--;
15146   if (lcpPtr.p->m_outstanding == 0)
15147   {
15148     jam();
15149 
15150     if(lcpPtr.p->firstFragmentFlag)
15151     {
15152       jam();
15153       LcpFragOrd *ord= (LcpFragOrd*)signal->getDataPtrSend();
15154       lcpPtr.p->firstFragmentFlag= false;
15155 
15156       // proxy is used in MT LQH to handle also the extra pgman worker
15157       if (!isNdbMtLqh())
15158       {
15159         jam();
15160         *ord = lcpPtr.p->currentFragment.lcpFragOrd;
15161         EXECUTE_DIRECT(PGMAN, GSN_LCP_FRAG_ORD, signal, signal->length());
15162         jamEntry();
15163 
15164         /**
15165          * First fragment mean that last LCP is complete :-)
15166          */
15167         jam();
15168         *ord = lcpPtr.p->currentFragment.lcpFragOrd;
15169         EXECUTE_DIRECT(TSMAN, GSN_LCP_FRAG_ORD,
15170                        signal, signal->length(), 0);
15171         jamEntry();
15172       }
15173       else
15174       {
15175         /**
15176          * Handled by proxy
15177          */
15178       }
15179     }
15180 
15181     if (lcpPtr.p->m_error)
15182     {
15183       jam();
15184 
15185       lcpPtr.p->lcpState = LcpRecord::LCP_COMPLETED;
15186       contChkpNextFragLab(signal);
15187       return;
15188     }
15189 
15190     lcpPtr.p->lcpState = LcpRecord::LCP_WAIT_HOLDOPS;
15191     lcpPtr.p->lcpState = LcpRecord::LCP_START_CHKP;
15192 
15193     /* ----------------------------------------------------------------------
15194      *    UPDATE THE MAX_GCI_IN_LCP AND MAX_GCI_COMPLETED_IN_LCP NOW BEFORE
15195      *    ACTIVATING THE FRAGMENT AGAIN.
15196      * --------------------------------------------------------------------- */
15197     ndbrequire(lcpPtr.p->currentFragment.lcpFragOrd.lcpNo < MAX_LCP_STORED);
15198     fragptr.p->maxGciInLcp = fragptr.p->newestGci;
15199     fragptr.p->maxGciCompletedInLcp = cnewestCompletedGci;
15200 
15201     {
15202       LcpFragOrd *ord= (LcpFragOrd*)signal->getDataPtrSend();
15203       *ord = lcpPtr.p->currentFragment.lcpFragOrd;
15204       Logfile_client lgman(this, c_lgman, 0);
15205       lgman.exec_lcp_frag_ord(signal);
15206       jamEntry();
15207 
15208       *ord = lcpPtr.p->currentFragment.lcpFragOrd;
15209       EXECUTE_DIRECT(DBTUP, GSN_LCP_FRAG_ORD, signal, signal->length());
15210       jamEntry();
15211     }
15212 
15213     BackupFragmentReq* req= (BackupFragmentReq*)signal->getDataPtr();
15214     req->tableId = lcpPtr.p->currentFragment.lcpFragOrd.tableId;
15215     req->fragmentNo = 0;
15216     req->backupPtr = m_backup_ptr;
15217     req->backupId = lcpPtr.p->currentFragment.lcpFragOrd.lcpId;
15218     req->count = 0;
15219 
15220 #ifdef NDB_DEBUG_FULL
15221     if(ERROR_INSERTED(5904))
15222     {
15223     g_trace_lcp.sendSignal(BACKUP_REF, GSN_BACKUP_FRAGMENT_REQ, signal,
15224 			   BackupFragmentReq::SignalLength, JBA);
15225     }
15226     else
15227 #endif
15228     {
15229       if (ERROR_INSERTED(5044) &&
15230 	  (fragptr.p->tabRef == c_error_insert_table_id) &&
15231 	  fragptr.p->fragId) // Not first frag
15232       {
15233 	/**
15234 	 * Force CRASH_INSERTION in 10s
15235 	 */
15236 	ndbout_c("table: %d frag: %d", fragptr.p->tabRef, fragptr.p->fragId);
15237 	SET_ERROR_INSERT_VALUE(5027);
15238 	sendSignalWithDelay(reference(), GSN_START_RECREQ, signal, 10000, 1);
15239       }
15240       else if (ERROR_INSERTED(5053))
15241       {
15242         BlockReference backupRef = calcInstanceBlockRef(BACKUP);
15243         sendSignalWithDelay(backupRef, GSN_BACKUP_FRAGMENT_REQ, signal,
15244                             150, BackupFragmentReq::SignalLength);
15245       }
15246       else
15247       {
15248         BlockReference backupRef = calcInstanceBlockRef(BACKUP);
15249 	sendSignal(backupRef, GSN_BACKUP_FRAGMENT_REQ, signal,
15250 		   BackupFragmentReq::SignalLength, JBA);
15251       }
15252     }
15253   }
15254 }
15255 
execBACKUP_FRAGMENT_REF(Signal * signal)15256 void Dblqh::execBACKUP_FRAGMENT_REF(Signal* signal)
15257 {
15258   BackupFragmentRef *ref= (BackupFragmentRef*)signal->getDataPtr();
15259   char buf[100];
15260   BaseString::snprintf(buf,sizeof(buf),
15261                        "Unable to store fragment during LCP. NDBFS Error: %u",
15262                        ref->errorCode);
15263 
15264   progError(__LINE__,
15265             (ref->errorCode & FsRef::FS_ERR_BIT)?
15266             NDBD_EXIT_AFS_UNKNOWN
15267             : ref->errorCode,
15268             buf);
15269 }
15270 
execBACKUP_FRAGMENT_CONF(Signal * signal)15271 void Dblqh::execBACKUP_FRAGMENT_CONF(Signal* signal)
15272 {
15273   jamEntry();
15274 
15275   if (ERROR_INSERTED(5073))
15276   {
15277     ndbout_c("Delaying BACKUP_FRAGMENT_CONF");
15278     sendSignalWithDelay(reference(), GSN_BACKUP_FRAGMENT_CONF, signal, 500,
15279                         signal->getLength());
15280     return;
15281   }
15282 
15283   BackupFragmentConf* conf= (BackupFragmentConf*)signal->getDataPtr();
15284   Uint64 noOfRecordsLow = conf->noOfRecordsLow;
15285   Uint64 noOfRecordsHigh = conf->noOfRecordsHigh;
15286   Uint64 noOfRecords = (noOfRecordsHigh << 32) + noOfRecordsLow;
15287 
15288   Uint64 noOfBytesLow = conf->noOfBytesLow;
15289   Uint64 noOfBytesHigh = conf->noOfBytesHigh;
15290   Uint64 noOfBytes = (noOfBytesHigh << 32) + noOfBytesLow;
15291 
15292   lcpPtr.i = 0;
15293   ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord);
15294   ndbrequire(lcpPtr.p->lcpState == LcpRecord::LCP_START_CHKP);
15295   lcpPtr.p->lcpState = LcpRecord::LCP_COMPLETED;
15296   lcpPtr.p->m_no_of_records += noOfRecords;
15297   lcpPtr.p->m_no_of_bytes += noOfBytes;
15298 
15299   stopLcpFragWatchdog();
15300 
15301   /* ------------------------------------------------------------------------
15302    *   THE LOCAL CHECKPOINT HAS BEEN COMPLETED. IT IS NOW TIME TO START
15303    *   A LOCAL CHECKPOINT ON THE NEXT FRAGMENT OR COMPLETE THIS LCP ROUND.
15304    * ------------------------------------------------------------------------
15305    *   WE START BY SENDING LCP_REPORT TO DIH TO REPORT THE COMPLETED LCP.
15306    *   TO CATER FOR NODE CRASHES WE SEND IT IN PARALLEL TO ALL NODES.
15307    * ----------------------------------------------------------------------- */
15308   fragptr.i = lcpPtr.p->currentFragment.fragPtrI;
15309   c_fragment_pool.getPtr(fragptr);
15310 
15311   /**
15312    * Update maxGciInLcp after scan has been performed
15313    */
15314 #if defined VM_TRACE || defined ERROR_INSERT
15315   if (fragptr.p->newestGci != fragptr.p->maxGciInLcp)
15316   {
15317     ndbout_c("tab: %u frag: %u increasing maxGciInLcp from %u to %u",
15318              fragptr.p->tabRef,
15319              fragptr.p->fragId,
15320              fragptr.p->maxGciInLcp, fragptr.p->newestGci);
15321   }
15322 #endif
15323 
15324   fragptr.p->maxGciInLcp = fragptr.p->newestGci;
15325 
15326   contChkpNextFragLab(signal);
15327   return;
15328 }//Dblqh::lcpCompletedLab()
15329 
15330 void
sendLCP_FRAG_REP(Signal * signal,const LcpRecord::FragOrd & fragOrd,const Fragrecord * fragPtrP) const15331 Dblqh::sendLCP_FRAG_REP(Signal * signal,
15332 			const LcpRecord::FragOrd & fragOrd,
15333                         const Fragrecord * fragPtrP) const
15334 {
15335   ndbrequire(fragOrd.lcpFragOrd.lcpNo < MAX_LCP_STORED);
15336   LcpFragRep * const lcpReport = (LcpFragRep *)&signal->theData[0];
15337   lcpReport->nodeId = cownNodeid;
15338   lcpReport->lcpId = fragOrd.lcpFragOrd.lcpId;
15339   lcpReport->lcpNo = fragOrd.lcpFragOrd.lcpNo;
15340   lcpReport->tableId = fragOrd.lcpFragOrd.tableId;
15341   lcpReport->fragId = fragOrd.lcpFragOrd.fragmentId;
15342   lcpReport->maxGciCompleted = fragPtrP->maxGciCompletedInLcp;
15343   lcpReport->maxGciStarted = fragPtrP->maxGciInLcp;
15344 
15345   Uint32 ref = DBDIH_REF;
15346   if (isNdbMtLqh())
15347   {
15348     jam();
15349     ref = DBLQH_REF;
15350   }
15351   lcpReport->nodeId = LcpFragRep::BROADCAST_REQ;
15352   sendSignal(ref, GSN_LCP_FRAG_REP, signal,
15353              LcpFragRep::SignalLength, JBA);
15354 }
15355 
contChkpNextFragLab(Signal * signal)15356 void Dblqh::contChkpNextFragLab(Signal* signal)
15357 {
15358   /* ------------------------------------------------------------------------
15359    *       UPDATE THE LATEST LOCAL CHECKPOINT COMPLETED ON FRAGMENT.
15360    *       UPDATE THE LCP_ID OF THIS CHECKPOINT.
15361    *       REMOVE THE LINK BETWEEN THE FRAGMENT RECORD AND THE LCP RECORD.
15362    * ----------------------------------------------------------------------- */
15363   /**
15364    * Send rep when fragment is done + unblocked
15365    */
15366   FragrecordPtr curr_fragptr;
15367   curr_fragptr.i = lcpPtr.p->currentFragment.fragPtrI;
15368   c_fragment_pool.getPtr(curr_fragptr);
15369   curr_fragptr.p->lcp_frag_ord_state = Fragrecord::LCP_EXECUTED;
15370   sendLCP_FRAG_REP(signal, lcpPtr.p->currentFragment, curr_fragptr.p);
15371 
15372   /* ------------------------------------------------------------------------
15373    *       WE ALSO RELEASE THE LOCAL LCP RECORDS.
15374    * ----------------------------------------------------------------------- */
15375   if (!c_queued_lcp_frag_ord.isEmpty())
15376   {
15377     jam();
15378     /* ----------------------------------------------------------------------
15379      *       START THE FIRST QUEUED LOCAL CHECKPOINT.
15380      * --------------------------------------------------------------------- */
15381     sendLCP_FRAGIDREQ(signal);
15382     return;
15383   }//if
15384 
15385   lcpPtr.p->lcpState = LcpRecord::LCP_IDLE;
15386   if (lcpPtr.p->lastFragmentFlag){
15387     jam();
15388     /* ----------------------------------------------------------------------
15389      *       NOW THE COMPLETE LOCAL CHECKPOINT ROUND IS COMPLETED.
15390      * --------------------------------------------------------------------- */
15391     completeLcpRoundLab(signal, lcpPtr.p->currentFragment.lcpFragOrd.lcpId);
15392     return;
15393   }//if
15394 
15395   if (lcpPtr.p->reportEmpty) {
15396     jam();
15397     sendEMPTY_LCP_CONF(signal, false);
15398   }//if
15399   return;
15400 }//Dblqh::contChkpNextFragLab()
15401 
sendLCP_FRAGIDREQ(Signal * signal)15402 void Dblqh::sendLCP_FRAGIDREQ(Signal* signal)
15403 {
15404   FragrecordPtr curr_fragptr;
15405   TablerecPtr tabPtr;
15406   /* ----------------------------------------------------------------------
15407    *  Remove first queued fragment from queue.
15408    *  Transfer the state from the queued to the active LCP.
15409    * --------------------------------------------------------------------- */
15410   c_queued_lcp_frag_ord.first(curr_fragptr);
15411   c_queued_lcp_frag_ord.removeFirst(curr_fragptr);
15412 
15413   tabPtr.i = curr_fragptr.p->tabRef;
15414   ptrCheckGuard(tabPtr, ctabrecFileSize, tablerec);
15415   curr_fragptr.p->lcp_frag_ord_state = Fragrecord::LCP_EXECUTING;
15416   lcpPtr.p->currentFragment.fragPtrI = curr_fragptr.i;
15417   lcpPtr.p->currentFragment.lcpFragOrd.lcpNo =
15418     curr_fragptr.p->lcp_frag_ord_lcp_no;
15419   lcpPtr.p->currentFragment.lcpFragOrd.fragmentId = curr_fragptr.p->fragId;
15420   lcpPtr.p->currentFragment.lcpFragOrd.tableId = tabPtr.i;
15421 
15422   if (unlikely(tabPtr.p->tableStatus != Tablerec::TABLE_DEFINED &&
15423                tabPtr.p->tableStatus != Tablerec::TABLE_READ_ONLY))
15424   {
15425     jam();
15426     /**
15427      * Fake that the fragment is done
15428      */
15429     contChkpNextFragLab(signal);
15430     return;
15431   }
15432 
15433   /**
15434    * We need to perform LCPs also of read-only tables since there might
15435    * have been changes to the table between now and when the table was
15436    * made read only.
15437    */
15438   lcpPtr.p->m_error = 0;
15439   lcpPtr.p->m_outstanding = 1;
15440 
15441   lcpPtr.p->lcpState = LcpRecord::LCP_WAIT_FRAGID;
15442   LcpPrepareReq* req= (LcpPrepareReq*)signal->getDataPtr();
15443   req->senderData = lcpPtr.i;
15444   req->senderRef = reference();
15445   req->lcpNo = lcpPtr.p->currentFragment.lcpFragOrd.lcpNo;
15446   req->tableId = lcpPtr.p->currentFragment.lcpFragOrd.tableId;
15447   req->fragmentId = lcpPtr.p->currentFragment.lcpFragOrd.fragmentId;
15448   req->lcpId = lcpPtr.p->currentFragment.lcpFragOrd.lcpId % MAX_LCP_STORED;
15449   req->backupPtr = m_backup_ptr;
15450   req->backupId = lcpPtr.p->currentFragment.lcpFragOrd.lcpId;
15451   BlockReference backupRef = calcInstanceBlockRef(BACKUP);
15452   sendSignal(backupRef, GSN_LCP_PREPARE_REQ, signal,
15453 	     LcpPrepareReq::SignalLength, JBA);
15454 
15455   /* Now start the LCP fragment watchdog */
15456   startLcpFragWatchdog(signal);
15457 
15458 }//Dblqh::sendLCP_FRAGIDREQ()
15459 
sendEMPTY_LCP_CONF(Signal * signal,bool idle)15460 void Dblqh::sendEMPTY_LCP_CONF(Signal* signal, bool idle)
15461 {
15462   EmptyLcpRep * sig = (EmptyLcpRep*)signal->getDataPtrSend();
15463   EmptyLcpConf * rep = (EmptyLcpConf*)sig->conf;
15464 
15465   /* ----------------------------------------------------------------------
15466    *       We have been requested to report when there are no more local
15467    *       waiting to be started or ongoing. In this signal we also report
15468    *       the last completed fragments state.
15469    * ---------------------------------------------------------------------- */
15470   rep->senderNodeId = getOwnNodeId();
15471   if(!idle){
15472     jam();
15473     rep->idle = 0 ;
15474     rep->tableId = lcpPtr.p->currentFragment.lcpFragOrd.tableId;
15475     rep->fragmentId = lcpPtr.p->currentFragment.lcpFragOrd.fragmentId;
15476     rep->lcpNo = lcpPtr.p->currentFragment.lcpFragOrd.lcpNo;
15477     rep->lcpId = lcpPtr.p->currentFragment.lcpFragOrd.lcpId;
15478   } else {
15479     jam();
15480     rep->idle = 1;
15481     rep->tableId = ~0;
15482     rep->fragmentId = ~0;
15483     rep->lcpNo = ~0;
15484     rep->lcpId = c_lcpId;
15485   }
15486 
15487   lcpPtr.p->m_EMPTY_LCP_REQ.copyto(NdbNodeBitmask::Size, sig->receiverGroup);
15488   sendSignal(DBDIH_REF, GSN_EMPTY_LCP_REP, signal,
15489              EmptyLcpRep::SignalLength + EmptyLcpConf::SignalLength, JBB);
15490 
15491   lcpPtr.p->reportEmpty = false;
15492   lcpPtr.p->m_EMPTY_LCP_REQ.clear();
15493 }//Dblqh::sendEMPTY_LCPCONF()
15494 
15495 /* --------------------------------------------------------------------------
15496  *       THE LOCAL CHECKPOINT ROUND IS NOW COMPLETED. SEND COMPLETED MESSAGE
15497  *       TO THE MASTER DIH.
15498  * ------------------------------------------------------------------------- */
completeLcpRoundLab(Signal * signal,Uint32 lcpId)15499 void Dblqh::completeLcpRoundLab(Signal* signal, Uint32 lcpId)
15500 {
15501   clcpCompletedState = LCP_CLOSE_STARTED;
15502 
15503   lcpPtr.i = 0;
15504   ptrAss(lcpPtr, lcpRecord);
15505   lcpPtr.p->m_outstanding = 0;
15506 
15507   EndLcpReq* req= (EndLcpReq*)signal->getDataPtr();
15508   req->senderData= lcpPtr.i;
15509   req->senderRef= reference();
15510   req->backupPtr= m_backup_ptr;
15511   req->backupId= lcpId;
15512 
15513   BlockReference backupRef = calcInstanceBlockRef(BACKUP);
15514 
15515   lcpPtr.p->m_outstanding++;
15516   sendSignal(backupRef, GSN_END_LCPREQ, signal,
15517 	     EndLcpReq::SignalLength, JBA);
15518 
15519   if (!isNdbMtLqh())
15520   {
15521     jam();
15522     lcpPtr.p->m_outstanding++;
15523     sendSignal(PGMAN_REF, GSN_END_LCPREQ, signal,
15524                EndLcpReq::SignalLength, JBA);
15525 
15526     lcpPtr.p->m_outstanding++;
15527     sendSignal(LGMAN_REF, GSN_END_LCPREQ, signal,
15528                EndLcpReq::SignalLength, JBA);
15529 
15530     EXECUTE_DIRECT(TSMAN, GSN_END_LCPREQ,
15531                    signal, EndLcpReq::SignalLength, 0);
15532   }
15533   else
15534   {
15535     /**
15536      * This is all handled by LqhProxy
15537      */
15538   }
15539   return;
15540 }//Dblqh::completeLcpRoundLab()
15541 
execEND_LCPCONF(Signal * signal)15542 void Dblqh::execEND_LCPCONF(Signal* signal)
15543 {
15544   jamEntry();
15545   lcpPtr.i = 0;
15546   ptrAss(lcpPtr, lcpRecord);
15547 
15548   ndbrequire(clcpCompletedState == LCP_CLOSE_STARTED);
15549   ndbrequire(lcpPtr.p->m_outstanding);
15550 
15551   lcpPtr.p->m_outstanding--;
15552   if(lcpPtr.p->m_outstanding == 0)
15553   {
15554     jam();
15555     sendLCP_COMPLETE_REP(signal, lcpPtr.p->currentFragment.lcpFragOrd.lcpId);
15556 
15557     CRASH_INSERTION(5056);
15558   }
15559 }//Dblqh::execEND_LCPCONF()
15560 
sendLCP_COMPLETE_REP(Signal * signal,Uint32 lcpId)15561 void Dblqh::sendLCP_COMPLETE_REP(Signal* signal, Uint32 lcpId)
15562 {
15563   ndbrequire((cnoOfNodes - 1) < (MAX_NDB_NODES - 1));
15564   /* ------------------------------------------------------------------------
15565    *       WE SEND COMP_LCP_ROUND TO ALL NODES TO PREPARE FOR NODE CRASHES.
15566    * ----------------------------------------------------------------------- */
15567   lcpPtr.i = 0;
15568   ptrAss(lcpPtr, lcpRecord);
15569 
15570   infoEvent("LDM(%u): Completed LCP, #frags = %u"
15571             " #records = %llu, #bytes = %llu",
15572             instance(),
15573             cnoOfFragsCheckpointed,
15574             lcpPtr.p->m_no_of_records,
15575             lcpPtr.p->m_no_of_bytes);
15576 
15577   lcpPtr.p->lastFragmentFlag = false;
15578   lcpPtr.p->firstFragmentFlag = false;
15579   lcpPtr.p->m_no_of_records = 0;
15580   lcpPtr.p->m_no_of_bytes = 0;
15581   cnoOfFragsCheckpointed = 0;
15582   clcpCompletedState = LCP_IDLE;
15583 
15584   LcpCompleteRep* rep = (LcpCompleteRep*)signal->getDataPtrSend();
15585   rep->nodeId = getOwnNodeId();
15586   rep->lcpId = lcpId;
15587   rep->blockNo = DBLQH;
15588 
15589   Uint32 ref = DBDIH_REF;
15590   if (isNdbMtLqh())
15591   {
15592     jam();
15593     ref = DBLQH_REF;
15594   }
15595   rep->nodeId = LcpFragRep::BROADCAST_REQ;
15596 
15597   sendSignal(ref, GSN_LCP_COMPLETE_REP, signal,
15598              LcpCompleteRep::SignalLength, JBA);
15599 
15600   if(lcpPtr.p->reportEmpty){
15601     jam();
15602     sendEMPTY_LCP_CONF(signal, true);
15603   }
15604 
15605   if (cstartRecReq < SRR_FIRST_LCP_DONE)
15606   {
15607     jam();
15608     ndbrequire(cstartRecReq == SRR_REDO_COMPLETE);
15609     cstartRecReq = SRR_FIRST_LCP_DONE;
15610   }
15611   return;
15612 
15613 }//Dblqh::sendCOMP_LCP_ROUND()
15614 
15615 #if NOT_YET
15616 void
execLCP_COMPLETE_REP(Signal * signal)15617 Dblqh::execLCP_COMPLETE_REP(Signal* signal)
15618 {
15619   /**
15620    * This is sent when last LCP is restorable
15621    */
15622   LcpCompleteRep * rep = (LcpCompleteRep*)signal->getDataPtr();
15623   Uint32 keepGci = rep->keepGci;
15624   setLogTail(signal, keepGci);
15625 }
15626 #endif
15627 
15628 /* ------------------------------------------------------------------------- */
15629 /* -------               SEND ACC_LCPREQ AND TUP_LCPREQ              ------- */
15630 /*                                                                           */
15631 /*       INPUT:          LCP_PTR             LOCAL CHECKPOINT RECORD         */
15632 /*                       FRAGPTR             FRAGMENT RECORD                 */
15633 /*       SUBROUTINE SHORT NAME = STL                                         */
15634 /* ------------------------------------------------------------------------- */
sendStartLcp(Signal * signal)15635 void Dblqh::sendStartLcp(Signal* signal)
15636 {
15637 }//Dblqh::sendStartLcp()
15638 
15639 /* ------------------------------------------------------------------------- */
15640 /* -------               SET THE LOG TAIL IN THE LOG FILES           ------- */
15641 /*                                                                           */
15642 /*THIS SUBROUTINE HAVE BEEN BUGGY AND IS RATHER COMPLEX. IT IS IMPORTANT TO  */
15643 /*REMEMBER THAT WE SEARCH FROM THE TAIL UNTIL WE REACH THE HEAD (CURRENT).   */
15644 /*THE TAIL AND HEAD CAN BE ON THE SAME MBYTE. WE SEARCH UNTIL WE FIND A MBYTE*/
15645 /*THAT WE NEED TO KEEP. WE THEN SET THE TAIL TO BE THE PREVIOUS. IF WE DO    */
15646 /*NOT FIND A MBYTE THAT WE NEED TO KEEP UNTIL WE REACH THE HEAD THEN WE USE  */
15647 /*THE HEAD AS TAIL. FINALLY WE HAVE TO MOVE BACK THE TAIL TO ALSO INCLUDE    */
15648 /*ALL PREPARE RECORDS. THIS MEANS THAT LONG-LIVED TRANSACTIONS ARE DANGEROUS */
15649 /*FOR SHORT LOGS.                                                            */
15650 /* ------------------------------------------------------------------------- */
15651 
setLogTail(Signal * signal,Uint32 keepGci)15652 void Dblqh::setLogTail(Signal* signal, Uint32 keepGci)
15653 {
15654   LogPartRecordPtr sltLogPartPtr;
15655   LogFileRecordPtr sltLogFilePtr;
15656   UintR tsltMbyte;
15657   UintR tsltStartMbyte;
15658   UintR tsltIndex;
15659   UintR tsltFlag;
15660 
15661   for (sltLogPartPtr.i = 0; sltLogPartPtr.i < clogPartFileSize; sltLogPartPtr.i++) {
15662     jam();
15663     bool TchangeMB = false;
15664 retry:
15665     ptrAss(sltLogPartPtr, logPartRecord);
15666     findLogfile(signal, sltLogPartPtr.p->logTailFileNo,
15667                 sltLogPartPtr, &sltLogFilePtr);
15668 
15669     tsltMbyte = sltLogPartPtr.p->logTailMbyte;
15670     tsltStartMbyte = tsltMbyte;
15671     tsltFlag = ZFALSE;
15672     if (sltLogFilePtr.i == sltLogPartPtr.p->currentLogfile) {
15673 /* ------------------------------------------------------------------------- */
15674 /*THE LOG AND THE TAIL IS ALREADY IN THE SAME FILE.                          */
15675 /* ------------------------------------------------------------------------- */
15676       if (sltLogFilePtr.p->currentMbyte >= sltLogPartPtr.p->logTailMbyte) {
15677         jam();
15678 /* ------------------------------------------------------------------------- */
15679 /*THE CURRENT MBYTE IS AHEAD OF OR AT THE TAIL. THUS WE WILL ONLY LOOK FOR   */
15680 /*THE TAIL UNTIL WE REACH THE CURRENT MBYTE WHICH IS IN THIS LOG FILE.       */
15681 /*IF THE LOG TAIL IS AHEAD OF THE CURRENT MBYTE BUT IN THE SAME LOG FILE     */
15682 /*THEN WE HAVE TO SEARCH THROUGH ALL FILES BEFORE WE COME TO THE CURRENT     */
15683 /*MBYTE. WE ALWAYS STOP WHEN WE COME TO THE CURRENT MBYTE SINCE THE TAIL     */
15684 /*CAN NEVER BE BEFORE THE HEAD.                                              */
15685 /* ------------------------------------------------------------------------- */
15686         tsltFlag = ZTRUE;
15687       }//if
15688     }//if
15689 
15690 /* ------------------------------------------------------------------------- */
15691 /*NOW START SEARCHING FOR THE NEW TAIL, STARTING AT THE CURRENT TAIL AND     */
15692 /*PROCEEDING UNTIL WE FIND A MBYTE WHICH IS NEEDED TO KEEP OR UNTIL WE REACH */
15693 /*CURRENT MBYTE (THE HEAD).                                                  */
15694 /* ------------------------------------------------------------------------- */
15695   SLT_LOOP:
15696     for (tsltIndex = tsltStartMbyte;
15697 	 tsltIndex <= clogFileSize - 1;
15698 	 tsltIndex++) {
15699       if (sltLogFilePtr.p->logMaxGciStarted[tsltIndex] >= keepGci) {
15700 /* ------------------------------------------------------------------------- */
15701 /*WE ARE NOT ALLOWED TO STEP THE LOG ANY FURTHER AHEAD                       */
15702 /*SET THE NEW LOG TAIL AND CONTINUE WITH NEXT LOG PART.                      */
15703 /*THIS MBYTE IS NOT TO BE INCLUDED SO WE NEED TO STEP BACK ONE MBYTE.        */
15704 /* ------------------------------------------------------------------------- */
15705         /* Check keepGCI MB has a reasonable GCI value */
15706         ndbrequire(sltLogFilePtr.p->logMaxGciStarted[tsltIndex] != ((Uint32) -1));
15707         if (tsltIndex != 0) {
15708           jam();
15709           tsltMbyte = tsltIndex - 1;
15710         } else {
15711           jam();
15712 /* ------------------------------------------------------------------------- */
15713 /*STEPPING BACK INCLUDES ALSO STEPPING BACK TO THE PREVIOUS LOG FILE.        */
15714 /* ------------------------------------------------------------------------- */
15715           tsltMbyte = clogFileSize - 1;
15716           sltLogFilePtr.i = sltLogFilePtr.p->prevLogFile;
15717           ptrCheckGuard(sltLogFilePtr, clogFileFileSize, logFileRecord);
15718         }//if
15719         goto SLT_BREAK;
15720       } else {
15721         jam();
15722         if (tsltFlag == ZTRUE) {
15723 /* ------------------------------------------------------------------------- */
15724 /*WE ARE IN THE SAME FILE AS THE CURRENT MBYTE AND WE CAN REACH THE CURRENT  */
15725 /*MBYTE BEFORE WE REACH A NEW TAIL.                                          */
15726 /* ------------------------------------------------------------------------- */
15727           if (tsltIndex == sltLogFilePtr.p->currentMbyte) {
15728             jam();
15729 /* ------------------------------------------------------------------------- */
15730 /*THE TAIL OF THE LOG IS ACTUALLY WITHIN THE CURRENT MBYTE. THUS WE SET THE  */
15731 /*LOG TAIL TO BE THE CURRENT MBYTE.                                          */
15732 /* ------------------------------------------------------------------------- */
15733             tsltMbyte = sltLogFilePtr.p->currentMbyte;
15734             goto SLT_BREAK;
15735           }//if
15736         }//if
15737       }//if
15738     }//for
15739     sltLogFilePtr.i = sltLogFilePtr.p->nextLogFile;
15740     ptrCheckGuard(sltLogFilePtr, clogFileFileSize, logFileRecord);
15741     if (sltLogFilePtr.i == sltLogPartPtr.p->currentLogfile) {
15742       jam();
15743       tsltFlag = ZTRUE;
15744     }//if
15745     tsltStartMbyte = 0;
15746     goto SLT_LOOP;
15747   SLT_BREAK:
15748     jam();
15749     {
15750       UintR ToldTailFileNo = sltLogPartPtr.p->logTailFileNo;
15751       UintR ToldTailMByte = sltLogPartPtr.p->logTailMbyte;
15752 
15753 /* ------------------------------------------------------------------------- */
15754 /*SINCE LOG_MAX_GCI_STARTED ONLY KEEP TRACK OF COMMIT LOG RECORDS WE ALSO    */
15755 /*HAVE TO STEP BACK THE TAIL SO THAT WE INCLUDE ALL PREPARE RECORDS          */
15756 /*NEEDED FOR THOSE COMMIT RECORDS IN THIS MBYTE. THIS IS A RATHER            */
15757 /*CONSERVATIVE APPROACH BUT IT WORKS.                                        */
15758 /* ------------------------------------------------------------------------- */
15759       arrGuard(tsltMbyte, clogFileSize);
15760       sltLogPartPtr.p->logTailFileNo =
15761         sltLogFilePtr.p->logLastPrepRef[tsltMbyte] >> 16;
15762       sltLogPartPtr.p->logTailMbyte =
15763         sltLogFilePtr.p->logLastPrepRef[tsltMbyte] & 65535;
15764 
15765       if (DEBUG_REDO)
15766       {
15767         ndbout_c("part: %u setLogTail(gci: %u): file: %u mb: %u",
15768                  sltLogPartPtr.p->logPartNo,
15769                  keepGci,
15770                  sltLogPartPtr.p->logTailFileNo,
15771                  sltLogPartPtr.p->logTailMbyte);
15772       }
15773 
15774       bool tailmoved = !(ToldTailFileNo == sltLogPartPtr.p->logTailFileNo &&
15775                          ToldTailMByte == sltLogPartPtr.p->logTailMbyte);
15776 
15777       LogFileRecordPtr tmpfile;
15778       tmpfile.i = sltLogPartPtr.p->currentLogfile;
15779       ptrCheckGuard(tmpfile, clogFileFileSize, logFileRecord);
15780 
15781       LogPosition head = { tmpfile.p->fileNo, tmpfile.p->currentMbyte };
15782       LogPosition tail = { sltLogPartPtr.p->logTailFileNo,
15783                            sltLogPartPtr.p->logTailMbyte};
15784       Uint64 mb = free_log(head, tail, sltLogPartPtr.p->noLogFiles,
15785                            clogFileSize);
15786 
15787       if (mb <= c_free_mb_force_lcp_limit)
15788       {
15789         /**
15790          * Force a new LCP
15791          */
15792         force_lcp(signal);
15793       }
15794 
15795       if (tailmoved && mb > c_free_mb_tail_problem_limit)
15796       {
15797         jam();
15798         update_log_problem(signal, sltLogPartPtr,
15799                            LogPartRecord::P_TAIL_PROBLEM, false);
15800       }
15801       else if (!tailmoved && mb <= c_free_mb_force_lcp_limit)
15802       {
15803         jam();
15804         /**
15805          * Tail didn't move...and we forced a new LCP
15806          *   This could be as currentMb, contains backreferences making it
15807          *   Check if changing mb forward will help situation
15808          */
15809         if (mb < 2)
15810         {
15811           /**
15812            * 0 or 1 mb free, no point in trying to changeMbyte forward...
15813            */
15814           jam();
15815           goto next;
15816         }
15817 
15818         if (TchangeMB)
15819         {
15820           jam();
15821           /**
15822            * We already did move forward...
15823            */
15824           goto next;
15825         }
15826 
15827         TcConnectionrecPtr tmp;
15828         tmp.i = sltLogPartPtr.p->firstLogTcrec;
15829         if (tmp.i != RNIL)
15830         {
15831           jam();
15832           ptrCheckGuard(tmp, ctcConnectrecFileSize, tcConnectionrec);
15833           Uint32 fileNo = tmp.p->logStartFileNo;
15834           Uint32 mbyte = tmp.p->logStartPageNo >> ZTWOLOG_NO_PAGES_IN_MBYTE;
15835 
15836           if (fileNo == sltLogPartPtr.p->logTailFileNo &&
15837               mbyte == sltLogPartPtr.p->logTailMbyte)
15838           {
15839             jam();
15840             /**
15841              * An uncommitted operation...still pending...
15842              *   with back-reference to tail...not much to do
15843              *   (theoretically we could rewrite log-entry here...
15844              *    but this is for future)
15845              * skip to next
15846              */
15847             goto next;
15848           }
15849         }
15850 
15851         {
15852           /**
15853            * Try forcing a changeMbyte
15854            */
15855           jam();
15856           logPartPtr = sltLogPartPtr;
15857           logFilePtr.i = logPartPtr.p->currentLogfile;
15858           ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
15859           logPagePtr.i = logFilePtr.p->currentLogpage;
15860           ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
15861           changeMbyte(signal);
15862           TchangeMB = true; // don't try this twice...
15863           goto retry;
15864         }
15865       }
15866     }
15867 next:
15868     (void)1;
15869   }//for
15870 }//Dblqh::setLogTail()
15871 
15872 /* ######################################################################### */
15873 /* #######                       GLOBAL CHECKPOINT MODULE            ####### */
15874 /*                                                                           */
15875 /* ######################################################################### */
15876 /*---------------------------------------------------------------------------*/
15877 /* THIS MODULE HELPS DIH IN DISCOVERING WHEN GLOBAL CHECKPOINTS ARE          */
15878 /* RECOVERABLE. IT HANDLES THE REQUEST GCP_SAVEREQ THAT REQUESTS LQH TO      */
15879 /* SAVE A PARTICULAR GLOBAL CHECKPOINT TO DISK AND RESPOND WHEN COMPLETED.   */
15880 /*---------------------------------------------------------------------------*/
15881 /* *************** */
15882 /*  GCP_SAVEREQ  > */
15883 /* *************** */
15884 
15885 #if defined VM_TRACE || defined ERROR_INSERT
15886 static Uint32 m_gcp_monitor = 0;
15887 #endif
15888 
execGCP_SAVEREQ(Signal * signal)15889 void Dblqh::execGCP_SAVEREQ(Signal* signal)
15890 {
15891   jamEntry();
15892   const GCPSaveReq * const saveReq = (GCPSaveReq *)&signal->theData[0];
15893 
15894   CRASH_INSERTION(5000);
15895 
15896   if (ERROR_INSERTED(5007)){
15897     CLEAR_ERROR_INSERT_VALUE;
15898     sendSignalWithDelay(cownref, GSN_GCP_SAVEREQ, signal, 10000,
15899 			signal->length());
15900     return;
15901   }
15902 
15903   if (unlikely(refToNode(signal->getSendersBlockRef()) != getOwnNodeId()))
15904   {
15905     /**
15906      * This code is only run during upgrade from pre-micro-gcp version.
15907      *
15908      * During startup, we make sure not to allow starting multi-threaded
15909      * NDBD while such an upgrade is taking place. So the EXECUTE_DIRECT()
15910      * below, which would be cross-thread in multi-threaded NDBD, is thus
15911      * safe since it never runs in the non-safe case.
15912      */
15913     ndbassert(!isMultiThreaded());
15914     jam();
15915     ndbassert(!ndb_check_micro_gcp
15916               (getNodeInfo(refToNode
15917                            (signal->getSendersBlockRef())).m_version));
15918     EXECUTE_DIRECT(DBDIH, GSN_GCP_SAVEREQ, signal, signal->getLength());
15919     return;
15920   }
15921 
15922   const Uint32 dihBlockRef = saveReq->dihBlockRef;
15923   const Uint32 dihPtr = saveReq->dihPtr;
15924   const Uint32 gci = saveReq->gci;
15925 
15926 #if defined VM_TRACE || defined ERROR_INSERT
15927   if (!isNdbMtLqh()) { // wl4391_todo mt-safe
15928   ndbrequire(m_gcp_monitor == 0 ||
15929              (m_gcp_monitor == gci) ||
15930              (m_gcp_monitor + 1) == gci);
15931   }
15932   m_gcp_monitor = gci;
15933 #endif
15934 
15935   if(getNodeState().startLevel >= NodeState::SL_STOPPING_4){
15936     GCPSaveRef * const saveRef = (GCPSaveRef*)&signal->theData[0];
15937     saveRef->dihPtr = dihPtr;
15938     saveRef->nodeId = getOwnNodeId();
15939     saveRef->gci    = gci;
15940     saveRef->errorCode = GCPSaveRef::NodeShutdownInProgress;
15941     sendSignal(dihBlockRef, GSN_GCP_SAVEREF, signal,
15942 	       GCPSaveRef::SignalLength, JBB);
15943     return;
15944   }
15945 
15946   Uint32 saveNewestCompletedGci = cnewestCompletedGci;
15947   cnewestCompletedGci = gci;
15948 
15949   if (cstartRecReq < SRR_REDO_COMPLETE)
15950   {
15951     /**
15952      * REDO running is not complete
15953      */
15954     GCPSaveRef * const saveRef = (GCPSaveRef*)&signal->theData[0];
15955     saveRef->dihPtr = dihPtr;
15956     saveRef->nodeId = getOwnNodeId();
15957     saveRef->gci    = gci;
15958     saveRef->errorCode = GCPSaveRef::NodeRestartInProgress;
15959     sendSignal(dihBlockRef, GSN_GCP_SAVEREF, signal,
15960 	       GCPSaveRef::SignalLength, JBB);
15961     return;
15962   }
15963 
15964   ndbrequire(gci >= saveNewestCompletedGci);
15965 
15966   if (gci == saveNewestCompletedGci)
15967   {
15968 /*---------------------------------------------------------------------------*/
15969 /* GLOBAL CHECKPOINT HAVE ALREADY BEEN HANDLED. REQUEST MUST HAVE BEEN SENT  */
15970 /* FROM NEW MASTER DIH.                                                      */
15971 /*---------------------------------------------------------------------------*/
15972     if (ccurrentGcprec == RNIL) {
15973       jam();
15974 /*---------------------------------------------------------------------------*/
15975 /* THIS INDICATES THAT WE HAVE ALREADY SENT GCP_SAVECONF TO PREVIOUS MASTER. */
15976 /* WE SIMPLY SEND IT ALSO TO THE NEW MASTER.                                 */
15977 /*---------------------------------------------------------------------------*/
15978       GCPSaveConf * const saveConf = (GCPSaveConf*)&signal->theData[0];
15979       saveConf->dihPtr = dihPtr;
15980       saveConf->nodeId = getOwnNodeId();
15981       saveConf->gci    = cnewestCompletedGci;
15982       sendSignal(dihBlockRef, GSN_GCP_SAVECONF, signal,
15983 		 GCPSaveConf::SignalLength, JBA);
15984       return;
15985     }
15986     jam();
15987 /*---------------------------------------------------------------------------*/
15988 /* WE HAVE NOT YET SENT THE RESPONSE TO THE OLD MASTER. WE WILL SET THE NEW  */
15989 /* RECEIVER OF THE RESPONSE AND THEN EXIT SINCE THE PROCESS IS ALREADY       */
15990 /* STARTED.                                                                  */
15991 /*---------------------------------------------------------------------------*/
15992     gcpPtr.i = ccurrentGcprec;
15993     ptrCheckGuard(gcpPtr, cgcprecFileSize, gcpRecord);
15994     gcpPtr.p->gcpUserptr = dihPtr;
15995     gcpPtr.p->gcpBlockref = dihBlockRef;
15996     return;
15997   }//if
15998 
15999   ndbrequire(ccurrentGcprec == RNIL);
16000   cnewestCompletedGci = gci;
16001   if (gci > cnewestGci) {
16002     jam();
16003     cnewestGci = gci;
16004   }//if
16005 
16006   if(cstartRecReq < SRR_FIRST_LCP_DONE)
16007   {
16008     /**
16009      * First LCP has not been done
16010      */
16011     GCPSaveRef * const saveRef = (GCPSaveRef*)&signal->theData[0];
16012     saveRef->dihPtr = dihPtr;
16013     saveRef->nodeId = getOwnNodeId();
16014     saveRef->gci    = gci;
16015     saveRef->errorCode = GCPSaveRef::NodeRestartInProgress;
16016     sendSignal(dihBlockRef, GSN_GCP_SAVEREF, signal,
16017 	       GCPSaveRef::SignalLength, JBB);
16018 
16019     if (ERROR_INSERTED(5052))
16020     {
16021       jam();
16022       signal->theData[0] = 9999;
16023       sendSignalWithDelay(CMVMI_REF, GSN_NDB_TAMPER, signal, 300, 1);
16024     }
16025     return;
16026   }
16027 
16028   CRASH_INSERTION(5052);
16029 
16030 #ifdef GCP_TIMER_HACK
16031   globalData.gcp_timer_save[0] = NdbTick_getCurrentTicks();
16032 #endif
16033 
16034   ccurrentGcprec = 0;
16035   gcpPtr.i = ccurrentGcprec;
16036   ptrCheckGuard(gcpPtr, cgcprecFileSize, gcpRecord);
16037 
16038   gcpPtr.p->gcpBlockref = dihBlockRef;
16039   gcpPtr.p->gcpUserptr = dihPtr;
16040   gcpPtr.p->gcpId = gci;
16041   bool tlogActive = false;
16042   for (logPartPtr.i = 0; logPartPtr.i < clogPartFileSize; logPartPtr.i++) {
16043     ptrAss(logPartPtr, logPartRecord);
16044     if (logPartPtr.p->logPartState == LogPartRecord::ACTIVE) {
16045       jam();
16046       logPartPtr.p->waitWriteGciLog = LogPartRecord::WWGL_TRUE;
16047       tlogActive = true;
16048       if (logPartPtr.p->LogLqhKeyReqSent == ZFALSE)
16049       {
16050         jam();
16051         logPartPtr.p->LogLqhKeyReqSent = ZTRUE;
16052         signal->theData[0] = ZLOG_LQHKEYREQ;
16053         signal->theData[1] = logPartPtr.i;
16054         sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
16055       }
16056     } else {
16057       jam();
16058       logPartPtr.p->waitWriteGciLog = LogPartRecord::WWGL_FALSE;
16059       logFilePtr.i = logPartPtr.p->currentLogfile;
16060       ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
16061       logPagePtr.i = logFilePtr.p->currentLogpage;
16062       ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
16063       writeCompletedGciLog(signal);
16064     }//if
16065   }//for
16066   if (tlogActive == true) {
16067     jam();
16068     return;
16069   }//if
16070   initGcpRecLab(signal);
16071   startTimeSupervision(signal);
16072   return;
16073 }//Dblqh::execGCP_SAVEREQ()
16074 
16075 /**
16076  * This is needed for ndbmtd to serialize
16077  * SUB_GCP_COMPLETE_REP vs FIRE_TRIG_ORD
16078  */
16079 void
execSUB_GCP_COMPLETE_REP(Signal * signal)16080 Dblqh::execSUB_GCP_COMPLETE_REP(Signal* signal)
16081 {
16082   jamEntry();
16083   Uint32 len = signal->getLength();
16084   EXECUTE_DIRECT(DBTUP, GSN_SUB_GCP_COMPLETE_REP, signal, len);
16085   sendSignal(SUMA_REF, GSN_SUB_GCP_COMPLETE_REP, signal, len, JBB);
16086 }
16087 
16088 /* ------------------------------------------------------------------------- */
16089 /*  START TIME SUPERVISION OF THE LOG PARTS.                                 */
16090 /* ------------------------------------------------------------------------- */
startTimeSupervision(Signal * signal)16091 void Dblqh::startTimeSupervision(Signal* signal)
16092 {
16093   for (logPartPtr.i = 0; logPartPtr.i < clogPartFileSize; logPartPtr.i++) {
16094     jam();
16095     ptrAss(logPartPtr, logPartRecord);
16096 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
16097 /* WE HAVE TO START CHECKING IF THE LOG IS TO BE WRITTEN EVEN IF PAGES ARE   */
16098 /* FULL. INITIALISE THE VALUES OF WHERE WE ARE IN THE LOG CURRENTLY.         */
16099 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
16100     logPartPtr.p->logPartTimer = 0;
16101     logPartPtr.p->logTimer = 1;
16102     signal->theData[0] = ZTIME_SUPERVISION;
16103     signal->theData[1] = logPartPtr.i;
16104     sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
16105   }//for
16106 }//Dblqh::startTimeSupervision()
16107 
16108 /*---------------------------------------------------------------------------*/
16109 /* WE SET THE GLOBAL CHECKPOINT VARIABLES AFTER WRITING THE COMPLETED GCI LOG*/
16110 /* RECORD. THIS ENSURES THAT WE WILL ENCOUNTER THE COMPLETED GCI RECORD WHEN */
16111 /* WE EXECUTE THE FRAGMENT LOG.                                              */
16112 /*---------------------------------------------------------------------------*/
initGcpRecLab(Signal * signal)16113 void Dblqh::initGcpRecLab(Signal* signal)
16114 {
16115 /* ======================================================================== */
16116 /* =======               INITIATE GCP RECORD                        ======= */
16117 /*                                                                          */
16118 /*       SUBROUTINE SHORT NAME = IGR                                        */
16119 /* ======================================================================== */
16120   for (logPartPtr.i = 0; logPartPtr.i < clogPartFileSize; logPartPtr.i++) {
16121     jam();
16122     ptrAss(logPartPtr, logPartRecord);
16123 /*--------------------------------------------------*/
16124 /*       BY SETTING THE GCPREC = 0 WE START THE     */
16125 /*       CHECKING BY CHECK_GCP_COMPLETED. THIS      */
16126 /*       CHECKING MUST NOT BE STARTED UNTIL WE HAVE */
16127 /*       INSERTED ALL COMPLETE GCI LOG RECORDS IN   */
16128 /*       ALL LOG PARTS.                             */
16129 /*--------------------------------------------------*/
16130     logPartPtr.p->gcprec = 0;
16131     gcpPtr.p->gcpLogPartState[logPartPtr.i] = ZWAIT_DISK;
16132     gcpPtr.p->gcpSyncReady[logPartPtr.i] = ZFALSE;
16133     logFilePtr.i = logPartPtr.p->currentLogfile;
16134     ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
16135     gcpPtr.p->gcpFilePtr[logPartPtr.i] = logFilePtr.i;
16136     logPagePtr.i = logFilePtr.p->currentLogpage;
16137     ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
16138     if (logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] == ZPAGE_HEADER_SIZE) {
16139       jam();
16140 /*--------------------------------------------------*/
16141 /*       SINCE THE CURRENT FILEPAGE POINTS AT THE   */
16142 /*       NEXT WORD TO BE WRITTEN WE HAVE TO ADJUST  */
16143 /*       FOR THIS BY DECREASING THE FILE PAGE BY ONE*/
16144 /*       IF NO WORD HAS BEEN WRITTEN ON THE CURRENT */
16145 /*       FILEPAGE.                                  */
16146 /*--------------------------------------------------*/
16147       gcpPtr.p->gcpPageNo[logPartPtr.i] = logFilePtr.p->currentFilepage - 1;
16148       gcpPtr.p->gcpWordNo[logPartPtr.i] = ZPAGE_SIZE - 1;
16149     } else {
16150       jam();
16151       gcpPtr.p->gcpPageNo[logPartPtr.i] = logFilePtr.p->currentFilepage;
16152       gcpPtr.p->gcpWordNo[logPartPtr.i] =
16153 	logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] - 1;
16154     }//if
16155   }//for
16156   // initialize un-used part
16157   Uint32 Ti;
16158   for (Ti = clogPartFileSize; Ti < NDB_MAX_LOG_PARTS; Ti++) {
16159     gcpPtr.p->gcpFilePtr[Ti] = ZNIL;
16160     gcpPtr.p->gcpPageNo[Ti] = ZNIL;
16161     gcpPtr.p->gcpSyncReady[Ti] = FALSE;
16162     gcpPtr.p->gcpWordNo[Ti] = ZNIL;
16163   }
16164   return;
16165 }//Dblqh::initGcpRecLab()
16166 
16167 /* ========================================================================= */
16168 /* ==== CHECK IF ANY GLOBAL CHECKPOINTS ARE COMPLETED AFTER A COMPLETED===== */
16169 /*      DISK WRITE.                                                          */
16170 /*                                                                           */
16171 /*       SUBROUTINE SHORT NAME = CGC                                         */
16172 /* return: true if gcp was completed */
16173 /* ========================================================================= */
16174 bool
checkGcpCompleted(Signal * signal,Uint32 tcgcPageWritten,Uint32 tcgcWordWritten)16175 Dblqh::checkGcpCompleted(Signal* signal,
16176                          Uint32 tcgcPageWritten,
16177                          Uint32 tcgcWordWritten)
16178 {
16179   UintR tcgcFlag;
16180   UintR tcgcJ;
16181 
16182   gcpPtr.i = logPartPtr.p->gcprec;
16183   if (gcpPtr.i != RNIL)
16184   {
16185     jam();
16186 /* ------------------------------------------------------------------------- */
16187 /* IF THE GLOBAL CHECKPOINT IS NOT WAITING FOR COMPLETION THEN WE CAN QUIT   */
16188 /* THE SEARCH IMMEDIATELY.                                                   */
16189 /* ------------------------------------------------------------------------- */
16190     ptrCheckGuard(gcpPtr, cgcprecFileSize, gcpRecord);
16191     if (gcpPtr.p->gcpFilePtr[logPartPtr.i] == logFilePtr.i) {
16192 /* ------------------------------------------------------------------------- */
16193 /* IF THE COMPLETED DISK OPERATION WAS ON ANOTHER FILE THAN THE ONE WE ARE   */
16194 /* WAITING FOR, THEN WE CAN ALSO QUIT THE SEARCH IMMEDIATELY.                */
16195 /* ------------------------------------------------------------------------- */
16196       if (tcgcPageWritten < gcpPtr.p->gcpPageNo[logPartPtr.i]) {
16197         jam();
16198 /* ------------------------------------------------------------------------- */
16199 /* THIS LOG PART HAVE NOT YET WRITTEN THE GLOBAL CHECKPOINT TO DISK.         */
16200 /* ------------------------------------------------------------------------- */
16201         return false;
16202       } else {
16203         if (tcgcPageWritten == gcpPtr.p->gcpPageNo[logPartPtr.i]) {
16204           if (tcgcWordWritten < gcpPtr.p->gcpWordNo[logPartPtr.i]) {
16205             jam();
16206 /* ------------------------------------------------------------------------- */
16207 /* THIS LOG PART HAVE NOT YET WRITTEN THE GLOBAL CHECKPOINT TO DISK.         */
16208 /* ------------------------------------------------------------------------- */
16209             return false;
16210           }//if
16211         }//if
16212       }//if
16213 /* ------------------------------------------------------------------------- */
16214 /* THIS LOG PART HAVE WRITTEN THE GLOBAL CHECKPOINT TO DISK.                 */
16215 /* ------------------------------------------------------------------------- */
16216       logPartPtr.p->gcprec = RNIL;
16217       gcpPtr.p->gcpLogPartState[logPartPtr.i] = ZON_DISK;
16218       tcgcFlag = ZTRUE;
16219       for (tcgcJ = 0; tcgcJ < clogPartFileSize; tcgcJ++)
16220       {
16221         jam();
16222         if (gcpPtr.p->gcpLogPartState[tcgcJ] != ZON_DISK) {
16223           jam();
16224 /* ------------------------------------------------------------------------- */
16225 /*ALL LOG PARTS HAVE NOT SAVED THIS GLOBAL CHECKPOINT TO DISK YET. WAIT FOR  */
16226 /*THEM TO COMPLETE.                                                          */
16227 /* ------------------------------------------------------------------------- */
16228           tcgcFlag = ZFALSE;
16229         }//if
16230       }//for
16231       if (tcgcFlag == ZFALSE)
16232       {
16233         return false;
16234       }
16235 
16236       if (tcgcFlag == ZTRUE)
16237       {
16238         jam();
16239 /* ------------------------------------------------------------------------- */
16240 /*WE HAVE FOUND A COMPLETED GLOBAL CHECKPOINT OPERATION. WE NOW NEED TO SEND */
16241 /*GCP_SAVECONF, REMOVE THE GCP RECORD FROM THE LIST OF WAITING GCP RECORDS   */
16242 /*ON THIS LOG PART AND RELEASE THE GCP RECORD.                               */
16243 // After changing the log implementation we need to perform a FSSYNCREQ on all
16244 // log files where the last log word resided first before proceeding.
16245 /* ------------------------------------------------------------------------- */
16246         UintR Ti;
16247         for (Ti = 0; Ti < clogPartFileSize; Ti++) {
16248           LogFileRecordPtr loopLogFilePtr;
16249           loopLogFilePtr.i = gcpPtr.p->gcpFilePtr[Ti];
16250           ptrCheckGuard(loopLogFilePtr, clogFileFileSize, logFileRecord);
16251           if (loopLogFilePtr.p->logFileStatus == LogFileRecord::OPEN) {
16252             jam();
16253             signal->theData[0] = loopLogFilePtr.p->fileRef;
16254             signal->theData[1] = cownref;
16255             signal->theData[2] = gcpPtr.p->gcpFilePtr[Ti];
16256             sendSignal(NDBFS_REF, GSN_FSSYNCREQ, signal, 3, JBA);
16257           } else {
16258             ndbrequire((loopLogFilePtr.p->logFileStatus ==
16259                         LogFileRecord::CLOSED) ||
16260                         (loopLogFilePtr.p->logFileStatus ==
16261                          LogFileRecord::CLOSING_WRITE_LOG) ||
16262                         (loopLogFilePtr.p->logFileStatus ==
16263                          LogFileRecord::OPENING_WRITE_LOG));
16264             signal->theData[0] = loopLogFilePtr.i;
16265             execFSSYNCCONF(signal);
16266           }//if
16267         }//for
16268       }//if
16269     }//if
16270     return true;
16271   }//if
16272   return false;
16273 }//Dblqh::checkGcpCompleted()
16274 
16275 void
execFSSYNCCONF(Signal * signal)16276 Dblqh::execFSSYNCCONF(Signal* signal)
16277 {
16278   GcpRecordPtr localGcpPtr;
16279   LogFileRecordPtr localLogFilePtr;
16280   LogPartRecordPtr localLogPartPtr;
16281   localLogFilePtr.i = signal->theData[0];
16282   ptrCheckGuard(localLogFilePtr, clogFileFileSize, logFileRecord);
16283   localLogPartPtr.i = localLogFilePtr.p->logPartRec;
16284   ptrCheckGuard(localLogPartPtr, clogPartFileSize, logPartRecord);
16285   localGcpPtr.i = ccurrentGcprec;
16286   ptrCheckGuard(localGcpPtr, cgcprecFileSize, gcpRecord);
16287   localGcpPtr.p->gcpSyncReady[localLogPartPtr.i] = ZTRUE;
16288   UintR Ti;
16289 
16290   if (DEBUG_REDO)
16291   {
16292     ndbout_c("part: %u file: %u gci: %u SYNC CONF",
16293              localLogPartPtr.p->logPartNo,
16294              localLogFilePtr.p->fileNo,
16295              localGcpPtr.p->gcpId);
16296   }
16297   for (Ti = 0; Ti < clogPartFileSize; Ti++) {
16298     jam();
16299     if (localGcpPtr.p->gcpSyncReady[Ti] == ZFALSE) {
16300       jam();
16301       return;
16302     }//if
16303   }//for
16304 
16305 #ifdef GCP_TIMER_HACK
16306   globalData.gcp_timer_save[1] = NdbTick_getCurrentTicks();
16307 #endif
16308 
16309   GCPSaveConf * const saveConf = (GCPSaveConf *)&signal->theData[0];
16310   saveConf->dihPtr = localGcpPtr.p->gcpUserptr;
16311   saveConf->nodeId = getOwnNodeId();
16312   saveConf->gci    = localGcpPtr.p->gcpId;
16313   sendSignal(localGcpPtr.p->gcpBlockref, GSN_GCP_SAVECONF, signal,
16314 	     GCPSaveConf::SignalLength, JBA);
16315   ccurrentGcprec = RNIL;
16316 }//Dblqh::execFSSYNCCONF()
16317 
16318 
16319 /* ######################################################################### */
16320 /* #######                            FILE HANDLING MODULE           ####### */
16321 /*                                                                           */
16322 /* ######################################################################### */
16323 /*       THIS MODULE HANDLES RESPONSE MESSAGES FROM THE FILE SYSTEM          */
16324 /* ######################################################################### */
16325 /* ######################################################################### */
16326 /*       SIGNAL RECEPTION MODULE                                             */
16327 /*       THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING.            */
16328 /*                                                                           */
16329 /*  THIS MODULE CHECKS THE STATE AND JUMPS TO THE PROPER PART OF THE FILE    */
16330 /*  HANDLING MODULE.                                                         */
16331 /* ######################################################################### */
16332 /* *************** */
16333 /*  FSCLOSECONF  > */
16334 /* *************** */
execFSCLOSECONF(Signal * signal)16335 void Dblqh::execFSCLOSECONF(Signal* signal)
16336 {
16337   jamEntry();
16338   logFilePtr.i = signal->theData[0];
16339   ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
16340   logFilePtr.p->fileRef = RNIL;
16341 
16342   if (DEBUG_REDO)
16343   {
16344     logPartPtr.i = logFilePtr.p->logPartRec;
16345     ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
16346     ndbout_c("part: %u file: %u CLOSE CONF",
16347              logPartPtr.p->logPartNo,
16348              logFilePtr.p->fileNo);
16349   }
16350 
16351   switch (logFilePtr.p->logFileStatus) {
16352   case LogFileRecord::CLOSE_SR_READ_INVALIDATE_PAGES:
16353     jam();
16354     logFilePtr.p->logFileStatus = LogFileRecord::CLOSED;
16355 
16356     logPartPtr.i = logFilePtr.p->logPartRec;
16357     ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
16358 
16359     readFileInInvalidate(signal, 2);
16360     return;
16361 
16362   case LogFileRecord::CLOSE_SR_READ_INVALIDATE_SEARCH_FILES:
16363     jam();
16364     logFilePtr.p->logFileStatus = LogFileRecord::CLOSED;
16365 
16366     logPartPtr.i = logFilePtr.p->logPartRec;
16367     ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
16368 
16369     readFileInInvalidate(signal, 4);
16370     return;
16371   case LogFileRecord::CLOSE_SR_READ_INVALIDATE_SEARCH_LAST_FILE:
16372     logFilePtr.p->logFileStatus = LogFileRecord::CLOSED;
16373 
16374     logPartPtr.i = logFilePtr.p->logPartRec;
16375     ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
16376 
16377     readFileInInvalidate(signal, 7);
16378     return;
16379   case LogFileRecord::CLOSE_SR_WRITE_INVALIDATE_PAGES:
16380     jam();
16381     logFilePtr.p->logFileStatus = LogFileRecord::CLOSED;
16382 
16383     logPartPtr.i = logFilePtr.p->logPartRec;
16384     ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
16385 
16386     writeFileInInvalidate(signal, 1);
16387     return;
16388   case LogFileRecord::CLOSING_INIT:
16389     jam();
16390     logFileInitDone++ ;
16391     closingInitLab(signal);
16392     return;
16393   case LogFileRecord::CLOSING_SR:
16394     jam();
16395     closingSrLab(signal);
16396     return;
16397   case LogFileRecord::CLOSING_EXEC_SR:
16398     jam();
16399     closeExecSrLab(signal);
16400     return;
16401   case LogFileRecord::CLOSING_EXEC_SR_COMPLETED:
16402     jam();
16403     closeExecSrCompletedLab(signal);
16404     return;
16405   case LogFileRecord::CLOSING_WRITE_LOG:
16406     jam();
16407     closeWriteLogLab(signal);
16408     return;
16409   case LogFileRecord::CLOSING_EXEC_LOG:
16410     jam();
16411     closeExecLogLab(signal);
16412     return;
16413 #ifndef NO_REDO_OPEN_FILE_CACHE
16414   case LogFileRecord::CLOSING_EXEC_LOG_CACHED:
16415     jam();
16416     logFilePtr.p->logFileStatus = LogFileRecord::CLOSED;
16417     release(signal, m_redo_open_file_cache);
16418     return;
16419 #endif
16420   case LogFileRecord::CLOSING_SR_FRONTPAGE:
16421     jam();
16422     closingSrFrontPage(signal);
16423     return;
16424   default:
16425     jam();
16426     systemErrorLab(signal, __LINE__);
16427     return;
16428   }//switch
16429 }//Dblqh::execFSCLOSECONF()
16430 
16431 
16432 /* ************>> */
16433 /*  FSOPENCONF  > */
16434 /* ************>> */
execFSOPENCONF(Signal * signal)16435 void Dblqh::execFSOPENCONF(Signal* signal)
16436 {
16437   jamEntry();
16438   initFsopenconf(signal);
16439   switch (logFilePtr.p->logFileStatus) {
16440   case LogFileRecord::OPEN_SR_READ_INVALIDATE_PAGES:
16441     jam();
16442     logFilePtr.p->logFileStatus = LogFileRecord::OPEN;
16443     readFileInInvalidate(signal, 0);
16444     return;
16445   case LogFileRecord::OPEN_SR_READ_INVALIDATE_SEARCH_FILES:
16446     jam();
16447     logFilePtr.p->logFileStatus = LogFileRecord::OPEN;
16448     readFileInInvalidate(signal, 5);
16449     return;
16450   case LogFileRecord::OPEN_SR_WRITE_INVALIDATE_PAGES:
16451     jam();
16452     logFilePtr.p->logFileStatus = LogFileRecord::OPEN;
16453     writeFileInInvalidate(signal, 0);
16454     return;
16455   case LogFileRecord::OPENING_INIT:
16456     jam();
16457     logFilePtr.p->logFileStatus = LogFileRecord::OPEN;
16458     openFileInitLab(signal);
16459     return;
16460   case LogFileRecord::OPEN_SR_FRONTPAGE:
16461     jam();
16462     logFilePtr.p->logFileStatus = LogFileRecord::OPEN;
16463     openSrFrontpageLab(signal);
16464     return;
16465   case LogFileRecord::OPEN_SR_LAST_FILE:
16466     jam();
16467     logFilePtr.p->logFileStatus = LogFileRecord::OPEN;
16468     openSrLastFileLab(signal);
16469     return;
16470   case LogFileRecord::OPEN_SR_NEXT_FILE:
16471     jam();
16472     logFilePtr.p->logFileStatus = LogFileRecord::OPEN;
16473     openSrNextFileLab(signal);
16474     return;
16475   case LogFileRecord::OPEN_EXEC_SR_START:
16476     jam();
16477     logFilePtr.p->logFileStatus = LogFileRecord::OPEN;
16478     openExecSrStartLab(signal);
16479     return;
16480   case LogFileRecord::OPEN_EXEC_SR_NEW_MBYTE:
16481     jam();
16482     logFilePtr.p->logFileStatus = LogFileRecord::OPEN;
16483     openExecSrNewMbyteLab(signal);
16484     return;
16485   case LogFileRecord::OPEN_SR_FOURTH_PHASE:
16486     jam();
16487     logFilePtr.p->logFileStatus = LogFileRecord::OPEN;
16488     openSrFourthPhaseLab(signal);
16489     return;
16490   case LogFileRecord::OPEN_SR_FOURTH_NEXT:
16491     jam();
16492     logFilePtr.p->logFileStatus = LogFileRecord::OPEN;
16493     openSrFourthNextLab(signal);
16494     return;
16495   case LogFileRecord::OPEN_SR_FOURTH_ZERO:
16496     jam();
16497     logFilePtr.p->logFileStatus = LogFileRecord::OPEN;
16498     openSrFourthZeroLab(signal);
16499     return;
16500   case LogFileRecord::OPENING_WRITE_LOG:
16501     jam();
16502     logFilePtr.p->logFileStatus = LogFileRecord::OPEN;
16503     return;
16504   case LogFileRecord::OPEN_EXEC_LOG:
16505     jam();
16506     logFilePtr.p->logFileStatus = LogFileRecord::OPEN;
16507 #ifndef NO_REDO_OPEN_FILE_CACHE
16508     {
16509       jam();
16510       m_redo_open_file_cache.m_lru.addFirst(logFilePtr);
16511     }
16512     // Fall through
16513   case LogFileRecord::OPEN_EXEC_LOG_CACHED:
16514     jam();
16515 #endif
16516     openExecLogLab(signal);
16517     return;
16518   default:
16519     jam();
16520     systemErrorLab(signal, __LINE__);
16521     return;
16522   }//switch
16523 }//Dblqh::execFSOPENCONF()
16524 
16525 void
execFSOPENREF(Signal * signal)16526 Dblqh::execFSOPENREF(Signal* signal)
16527 {
16528   jamEntry();
16529   FsRef* ref = (FsRef*)signal->getDataPtr();
16530   Uint32 err = ref->errorCode;
16531   if (err == FsRef::fsErrInvalidFileSize)
16532   {
16533     char buf[256];
16534     BaseString::snprintf(buf, sizeof(buf),
16535                          "Invalid file size for redo logfile, "
16536                          " size only changable with --initial");
16537     progError(__LINE__,
16538               NDBD_EXIT_INVALID_CONFIG,
16539               buf);
16540     return;
16541   }
16542 
16543   SimulatedBlock::execFSOPENREF(signal);
16544 }
16545 
16546 /* ************>> */
16547 /*  FSREADCONF  > */
16548 /* ************>> */
execFSREADCONF(Signal * signal)16549 void Dblqh::execFSREADCONF(Signal* signal)
16550 {
16551   jamEntry();
16552   initFsrwconf(signal, false);
16553 
16554   switch (lfoPtr.p->lfoState) {
16555   case LogFileOperationRecord::READ_SR_LAST_MBYTE:
16556     jam();
16557     releaseLfo(signal);
16558     readSrLastMbyteLab(signal);
16559     return;
16560   case LogFileOperationRecord::READ_SR_FRONTPAGE:
16561     jam();
16562     releaseLfo(signal);
16563     readSrFrontpageLab(signal);
16564     return;
16565   case LogFileOperationRecord::READ_SR_LAST_FILE:
16566     jam();
16567     releaseLfo(signal);
16568     readSrLastFileLab(signal);
16569     return;
16570   case LogFileOperationRecord::READ_SR_NEXT_FILE:
16571     jam();
16572     releaseLfo(signal);
16573     readSrNextFileLab(signal);
16574     return;
16575   case LogFileOperationRecord::READ_EXEC_SR:
16576     jam();
16577     readExecSrLab(signal);
16578     return;
16579   case LogFileOperationRecord::READ_EXEC_LOG:
16580     jam();
16581     readExecLogLab(signal);
16582     return;
16583   case LogFileOperationRecord::READ_SR_INVALIDATE_PAGES:
16584     jam();
16585     invalidateLogAfterLastGCI(signal);
16586     return;
16587   case LogFileOperationRecord::READ_SR_INVALIDATE_SEARCH_FILES:
16588     jam();
16589     invalidateLogAfterLastGCI(signal);
16590     return;
16591   case LogFileOperationRecord::READ_SR_FOURTH_PHASE:
16592     jam();
16593     releaseLfo(signal);
16594     readSrFourthPhaseLab(signal);
16595     return;
16596   case LogFileOperationRecord::READ_SR_FOURTH_ZERO:
16597     jam();
16598     releaseLfo(signal);
16599     readSrFourthZeroLab(signal);
16600     return;
16601   default:
16602     jam();
16603     systemErrorLab(signal, __LINE__);
16604     return;
16605   }//switch
16606 }//Dblqh::execFSREADCONF()
16607 
16608 /* ************>> */
16609 /*  FSREADCONF  > */
16610 /* ************>> */
execFSREADREF(Signal * signal)16611 void Dblqh::execFSREADREF(Signal* signal)
16612 {
16613   jamEntry();
16614   lfoPtr.i = signal->theData[0];
16615   ptrCheckGuard(lfoPtr, clfoFileSize, logFileOperationRecord);
16616   switch (lfoPtr.p->lfoState) {
16617   case LogFileOperationRecord::READ_SR_LAST_MBYTE:
16618     jam();
16619     break;
16620   case LogFileOperationRecord::READ_SR_FRONTPAGE:
16621     jam();
16622     break;
16623   case LogFileOperationRecord::READ_SR_LAST_FILE:
16624     jam();
16625     break;
16626   case LogFileOperationRecord::READ_SR_NEXT_FILE:
16627     jam();
16628     break;
16629   case LogFileOperationRecord::READ_EXEC_SR:
16630     jam();
16631     break;
16632   case LogFileOperationRecord::READ_EXEC_LOG:
16633     jam();
16634     break;
16635   case LogFileOperationRecord::READ_SR_FOURTH_PHASE:
16636     jam();
16637     break;
16638   case LogFileOperationRecord::READ_SR_FOURTH_ZERO:
16639     jam();
16640     break;
16641   case LogFileOperationRecord::READ_SR_INVALIDATE_PAGES:
16642     jam();
16643     break;
16644   default:
16645     jam();
16646     break;
16647   }//switch
16648   {
16649     char msg[100];
16650     sprintf(msg, "File system read failed during LogFileOperationRecord state %d", (Uint32)lfoPtr.p->lfoState);
16651     fsRefError(signal,__LINE__,msg);
16652   }
16653 }//Dblqh::execFSREADREF()
16654 
16655 /* *************** */
16656 /*  FSWRITECONF  > */
16657 /* *************** */
execFSWRITECONF(Signal * signal)16658 void Dblqh::execFSWRITECONF(Signal* signal)
16659 {
16660   jamEntry();
16661   initFsrwconf(signal, true);
16662   switch (lfoPtr.p->lfoState) {
16663   case LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES:
16664     jam();
16665     invalidateLogAfterLastGCI(signal);
16666     CRASH_INSERTION(5047);
16667     return;
16668   case LogFileOperationRecord::WRITE_PAGE_ZERO:
16669     jam();
16670     writePageZeroLab(signal, __LINE__);
16671     releaseLfo(signal);
16672     return;
16673   case LogFileOperationRecord::LAST_WRITE_IN_FILE:
16674     jam();
16675     lastWriteInFileLab(signal);
16676     return;
16677   case LogFileOperationRecord::INIT_WRITE_AT_END:
16678     jam();
16679     initWriteEndLab(signal);
16680     return;
16681   case LogFileOperationRecord::INIT_FIRST_PAGE:
16682     jam();
16683     logMBytesInitDone++;
16684     initFirstPageLab(signal);
16685     return;
16686   case LogFileOperationRecord::WRITE_GCI_ZERO:
16687     jam();
16688     writeGciZeroLab(signal);
16689     return;
16690   case LogFileOperationRecord::WRITE_DIRTY:
16691     jam();
16692     writeDirtyLab(signal);
16693     return;
16694   case LogFileOperationRecord::WRITE_INIT_MBYTE:
16695     jam();
16696     logMBytesInitDone++;
16697     writeInitMbyteLab(signal);
16698     return;
16699   case LogFileOperationRecord::ACTIVE_WRITE_LOG:
16700     jam();
16701     writeLogfileLab(signal);
16702     return;
16703   case LogFileOperationRecord::FIRST_PAGE_WRITE_IN_LOGFILE:
16704     jam();
16705     firstPageWriteLab(signal);
16706     return;
16707   case LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES_UPDATE_PAGE0:
16708     jam();
16709     // We are done...send completed signal and exit this phase.
16710     releaseLfo(signal);
16711     signal->theData[0] = ZSR_FOURTH_COMP;
16712     signal->theData[1] = logPartPtr.i;
16713     sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
16714     return;
16715   default:
16716     jam();
16717     systemErrorLab(signal, __LINE__);
16718     return;
16719   }//switch
16720 }//Dblqh::execFSWRITECONF()
16721 
16722 /* ************>> */
16723 /*  FSWRITEREF  > */
16724 /* ************>> */
execFSWRITEREF(Signal * signal)16725 void Dblqh::execFSWRITEREF(Signal* signal)
16726 {
16727   jamEntry();
16728   lfoPtr.i = signal->theData[0];
16729   ptrCheckGuard(lfoPtr, clfoFileSize, logFileOperationRecord);
16730   terrorCode = signal->theData[1];
16731   switch (lfoPtr.p->lfoState) {
16732   case LogFileOperationRecord::WRITE_PAGE_ZERO:
16733     jam();
16734     break;
16735   case LogFileOperationRecord::LAST_WRITE_IN_FILE:
16736     jam();
16737     break;
16738   case LogFileOperationRecord::INIT_WRITE_AT_END:
16739     jam();
16740     break;
16741   case LogFileOperationRecord::INIT_FIRST_PAGE:
16742     jam();
16743     break;
16744   case LogFileOperationRecord::WRITE_GCI_ZERO:
16745     jam();
16746     break;
16747   case LogFileOperationRecord::WRITE_DIRTY:
16748     jam();
16749     break;
16750   case LogFileOperationRecord::WRITE_INIT_MBYTE:
16751     jam();
16752     break;
16753   case LogFileOperationRecord::ACTIVE_WRITE_LOG:
16754     jam();
16755     break;
16756   case LogFileOperationRecord::FIRST_PAGE_WRITE_IN_LOGFILE:
16757     jam();
16758     break;
16759   case LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES:
16760     jam();
16761     systemErrorLab(signal, __LINE__);
16762   default:
16763     jam();
16764     break;
16765   }//switch
16766   {
16767     char msg[100];
16768     sprintf(msg, "File system write failed during LogFileOperationRecord state %d", (Uint32)lfoPtr.p->lfoState);
16769     fsRefError(signal,__LINE__,msg);
16770   }
16771 }//Dblqh::execFSWRITEREF()
16772 
16773 
16774 /* ========================================================================= */
16775 /* =======              INITIATE WHEN RECEIVING FSOPENCONF           ======= */
16776 /*                                                                           */
16777 /* ========================================================================= */
initFsopenconf(Signal * signal)16778 void Dblqh::initFsopenconf(Signal* signal)
16779 {
16780   logFilePtr.i = signal->theData[0];
16781   ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
16782   logFilePtr.p->fileRef = signal->theData[1];
16783   logPartPtr.i = logFilePtr.p->logPartRec;
16784   ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
16785   logFilePtr.p->currentMbyte = 0;
16786   logFilePtr.p->filePosition = 0;
16787 }//Dblqh::initFsopenconf()
16788 
16789 /* ========================================================================= */
16790 /* =======       INITIATE WHEN RECEIVING FSREADCONF AND FSWRITECONF  ======= */
16791 /*                                                                           */
16792 /* ========================================================================= */
initFsrwconf(Signal * signal,bool write)16793 void Dblqh::initFsrwconf(Signal* signal, bool write)
16794 {
16795   LogPageRecordPtr logP;
16796   Uint32 noPages, totPages;
16797   lfoPtr.i = signal->theData[0];
16798   ptrCheckGuard(lfoPtr, clfoFileSize, logFileOperationRecord);
16799   totPages= lfoPtr.p->noPagesRw;
16800   logFilePtr.i = lfoPtr.p->logFileRec;
16801   ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
16802   logPartPtr.i = logFilePtr.p->logPartRec;
16803   ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
16804   logPagePtr.i = lfoPtr.p->firstLfoPage;
16805   ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
16806   logP= logPagePtr;
16807   noPages= 1;
16808   ndbassert(totPages > 0);
16809 
16810   if (write)
16811   {
16812     Uint32 bytesWritten = totPages * 32768;
16813     logPartPtr.p->m_io_tracker.complete_io(bytesWritten);
16814   }
16815 
16816   for (;;)
16817   {
16818     logP.p->logPageWord[ZPOS_IN_WRITING]= 0;
16819     logP.p->logPageWord[ZPOS_IN_FREE_LIST]= 0;
16820     if (noPages == totPages)
16821       return;
16822     if (write)
16823       logP.i= logP.p->logPageWord[ZNEXT_PAGE];
16824     else
16825       logP.i= lfoPtr.p->logPageArray[noPages];
16826     ptrCheckGuard(logP, clogPageFileSize, logPageRecord);
16827     noPages++;
16828   }
16829 
16830 }//Dblqh::initFsrwconf()
16831 
16832 /* ######################################################################### */
16833 /*       NORMAL OPERATION MODULE                                             */
16834 /*       THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING.            */
16835 /*                                                                           */
16836 /*   THIS PART HANDLES THE NORMAL OPENING, CLOSING AND WRITING OF LOG FILES  */
16837 /*   DURING NORMAL OPERATION.                                                */
16838 /* ######################################################################### */
16839 /*---------------------------------------------------------------------------*/
16840 /* THIS SIGNAL IS USED TO SUPERVISE THAT THE LOG RECORDS ARE NOT KEPT IN MAIN*/
16841 /* MEMORY FOR MORE THAN 1 SECOND TO ACHIEVE THE PROPER RELIABILITY.          */
16842 /*---------------------------------------------------------------------------*/
timeSup(Signal * signal)16843 void Dblqh::timeSup(Signal* signal)
16844 {
16845   LogPageRecordPtr origLogPagePtr;
16846   Uint32 wordWritten;
16847 
16848   jamEntry();
16849   logPartPtr.i = signal->theData[0];
16850   ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
16851   logFilePtr.i = logPartPtr.p->currentLogfile;
16852   ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
16853   logPagePtr.i = logFilePtr.p->currentLogpage;
16854   ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
16855   if (logPartPtr.p->logPartTimer != logPartPtr.p->logTimer) {
16856     jam();
16857     if (true) // less merge conflicts
16858     {
16859 /*---------------------------------------------------------------------------*/
16860 /* IDLE AND NOT WRITTEN TO DISK IN A SECOND. ALSO WHEN WE HAVE A TAIL PROBLEM*/
16861 /* WE HAVE TO WRITE TO DISK AT TIMES. WE WILL FIRST CHECK WHETHER ANYTHING   */
16862 /* AT ALL HAVE BEEN WRITTEN TO THE PAGES BEFORE WRITING TO DISK.             */
16863 /*---------------------------------------------------------------------------*/
16864 /* WE HAVE TO WRITE TO DISK IN ALL CASES SINCE THERE COULD BE INFORMATION    */
16865 /* STILL IN THE LOG THAT WAS GENERATED BEFORE THE PREVIOUS TIME SUPERVISION  */
16866 /* BUT AFTER THE LAST DISK WRITE. THIS PREVIOUSLY STOPPED ALL DISK WRITES    */
16867 /* WHEN NO MORE LOG WRITES WERE PERFORMED (THIS HAPPENED WHEN LOG GOT FULL   */
16868 /* AND AFTER LOADING THE INITIAL RECORDS IN INITIAL START).                  */
16869 /*---------------------------------------------------------------------------*/
16870       if (((logFilePtr.p->currentFilepage + 1) & (ZPAGES_IN_MBYTE -1)) == 0) {
16871         jam();
16872 /*---------------------------------------------------------------------------*/
16873 /* THIS IS THE LAST PAGE IN THIS MBYTE. WRITE NEXT LOG AND SWITCH TO NEXT    */
16874 /* MBYTE.                                                                    */
16875 /*---------------------------------------------------------------------------*/
16876         changeMbyte(signal);
16877       } else {
16878 /*---------------------------------------------------------------------------*/
16879 /* WRITE THE LOG PAGE TO DISK EVEN IF IT IS NOT FULL. KEEP PAGE AND WRITE A  */
16880 /* COPY. THE ORIGINAL PAGE WILL BE WRITTEN AGAIN LATER ON.                   */
16881 /*---------------------------------------------------------------------------*/
16882         wordWritten = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] - 1;
16883         origLogPagePtr.i = logPagePtr.i;
16884         origLogPagePtr.p = logPagePtr.p;
16885         seizeLogpage(signal);
16886         MEMCOPY_NO_WORDS(&logPagePtr.p->logPageWord[0],
16887                          &origLogPagePtr.p->logPageWord[0],
16888                          wordWritten + 1);
16889         ndbrequire(wordWritten < ZPAGE_SIZE);
16890         if (logFilePtr.p->noLogpagesInBuffer > 0) {
16891           jam();
16892           completedLogPage(signal, ZENFORCE_WRITE, __LINE__);
16893 /*---------------------------------------------------------------------------*/
16894 /*SINCE WE ARE ONLY WRITING PART OF THE LAST PAGE WE HAVE TO UPDATE THE WORD */
16895 /*WRITTEN TO REFLECT THE REAL LAST WORD WRITTEN. WE ALSO HAVE TO MOVE THE    */
16896 /*FILE POSITION ONE STEP BACKWARDS SINCE WE ARE NOT WRITING THE LAST PAGE    */
16897 /*COMPLETELY. IT WILL BE WRITTEN AGAIN.                                      */
16898 /*---------------------------------------------------------------------------*/
16899           lfoPtr.p->lfoWordWritten = wordWritten;
16900           logFilePtr.p->filePosition = logFilePtr.p->filePosition - 1;
16901         } else {
16902           if (wordWritten == (ZPAGE_HEADER_SIZE - 1)) {
16903 /*---------------------------------------------------------------------------*/
16904 /*THIS IS POSSIBLE BUT VERY UNLIKELY. IF THE PAGE WAS COMPLETED AFTER THE LAST*/
16905 /*WRITE TO DISK THEN NO_LOG_PAGES_IN_BUFFER > 0 AND IF NOT WRITTEN SINCE LAST*/
16906 /*WRITE TO DISK THEN THE PREVIOUS PAGE MUST HAVE BEEN WRITTEN BY SOME        */
16907 /*OPERATION AND THAT BECAME COMPLETELY FULL. IN ANY CASE WE NEED NOT WRITE AN*/
16908 /*EMPTY PAGE TO DISK.                                                        */
16909 /*---------------------------------------------------------------------------*/
16910             jam();
16911             releaseLogpage(signal);
16912           } else {
16913             jam();
16914             writeSinglePage(signal, logFilePtr.p->currentFilepage,
16915                             wordWritten, __LINE__);
16916             lfoPtr.p->lfoState = LogFileOperationRecord::ACTIVE_WRITE_LOG;
16917           }//if
16918         }//if
16919       }//if
16920     }
16921   }
16922 
16923   logPartPtr.p->logTimer++;
16924   return;
16925 }//Dblqh::timeSup()
16926 
writeLogfileLab(Signal * signal)16927 void Dblqh::writeLogfileLab(Signal* signal)
16928 {
16929 /*---------------------------------------------------------------------------*/
16930 /* CHECK IF ANY GLOBAL CHECKPOINTS ARE COMPLETED DUE TO THIS COMPLETED DISK  */
16931 /* WRITE.                                                                    */
16932 /*---------------------------------------------------------------------------*/
16933   switch (logFilePtr.p->fileChangeState) {
16934   case LogFileRecord::NOT_ONGOING:
16935     jam();
16936     checkGcpCompleted(signal,
16937                       ((lfoPtr.p->lfoPageNo + lfoPtr.p->noPagesRw) - 1),
16938                       lfoPtr.p->lfoWordWritten);
16939     break;
16940 #if 0
16941   case LogFileRecord::BOTH_WRITES_ONGOING:
16942     jam();
16943     ndbout_c("not crashing!!");
16944     // Fall-through
16945 #endif
16946   case LogFileRecord::WRITE_PAGE_ZERO_ONGOING:
16947   case LogFileRecord::LAST_WRITE_ONGOING:
16948     jam();
16949     logFilePtr.p->lastPageWritten = (lfoPtr.p->lfoPageNo + lfoPtr.p->noPagesRw) - 1;
16950     logFilePtr.p->lastWordWritten = lfoPtr.p->lfoWordWritten;
16951     break;
16952   default:
16953     jam();
16954     systemErrorLab(signal, __LINE__);
16955     return;
16956     break;
16957   }//switch
16958   releaseLfoPages(signal);
16959   releaseLfo(signal);
16960   return;
16961 }//Dblqh::writeLogfileLab()
16962 
closeWriteLogLab(Signal * signal)16963 void Dblqh::closeWriteLogLab(Signal* signal)
16964 {
16965   logFilePtr.p->logFileStatus = LogFileRecord::CLOSED;
16966   return;
16967 }//Dblqh::closeWriteLogLab()
16968 
16969 /* ######################################################################### */
16970 /*       FILE CHANGE MODULE                                                  */
16971 /*       THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING.            */
16972 /*                                                                           */
16973 /*THIS PART OF THE FILE MODULE HANDLES WHEN WE ARE CHANGING LOG FILE DURING  */
16974 /*NORMAL OPERATION. WE HAVE TO BE CAREFUL WHEN WE ARE CHANGING LOG FILE SO   */
16975 /*THAT WE DO NOT COMPLICATE THE SYSTEM RESTART PROCESS TOO MUCH.             */
16976 /*THE IDEA IS THAT WE START BY WRITING THE LAST WRITE IN THE OLD FILE AND WE */
16977 /*ALSO WRITE THE FIRST PAGE OF THE NEW FILE CONCURRENT WITH THAT. THIS FIRST */
16978 /*PAGE IN THE NEW FILE DO NOT CONTAIN ANY LOG RECORDS OTHER THAN A DESCRIPTOR*/
16979 /*CONTAINING INFORMATION ABOUT GCI'S NEEDED AT SYSTEM RESTART AND A NEXT LOG */
16980 /*RECORD.                                                                    */
16981 /*                                                                           */
16982 /*WHEN BOTH OF THOSE WRITES HAVE COMPLETED WE ALSO WRITE PAGE ZERO IN FILE   */
16983 /*ZERO. THE ONLY INFORMATION WHICH IS INTERESTING HERE IS THE NEW FILE NUMBER*/
16984 /*                                                                           */
16985 /*IF OPTIMISATIONS ARE NEEDED OF THE LOG HANDLING THEN IT IS POSSIBLE TO     */
16986 /*AVOID WRITING THE FIRST PAGE OF THE NEW PAGE IMMEDIATELY. THIS COMPLICATES */
16987 /*THE SYSTEM RESTART AND ONE HAS TO TAKE SPECIAL CARE WITH FILE ZERO. IT IS  */
16988 /*HOWEVER NO LARGE PROBLEM TO CHANGE INTO THIS SCENARIO. TO AVOID ALSO THE   */
16989 /*WRITING OF PAGE ZERO IS ALSO POSSIBLE BUT COMPLICATES THE DESIGN EVEN      */
16990 /*FURTHER. IT GETS FAIRLY COMPLEX TO FIND THE END OF THE LOG. SOME SORT OF   */
16991 /*BINARY SEARCH IS HOWEVER MOST LIKELY A GOOD METHODOLOGY FOR THIS.          */
16992 /* ######################################################################### */
firstPageWriteLab(Signal * signal)16993 void Dblqh::firstPageWriteLab(Signal* signal)
16994 {
16995   releaseLfo(signal);
16996 /*---------------------------------------------------------------------------*/
16997 /*       RELEASE PAGE ZERO IF THE FILE IS NOT FILE 0.                        */
16998 /*---------------------------------------------------------------------------*/
16999   Uint32 fileNo = logFilePtr.p->fileNo;
17000   if (fileNo != 0) {
17001     jam();
17002     releaseLogpage(signal);
17003   }//if
17004 /*---------------------------------------------------------------------------*/
17005 /* IF A NEW FILE HAS BEEN OPENED WE SHALL ALWAYS ALSO WRITE TO PAGE O IN     */
17006 /* FILE 0. THE AIM IS TO MAKE RESTARTS EASIER BY SPECIFYING WHICH IS THE     */
17007 /* LAST FILE WHERE LOGGING HAS STARTED.                                      */
17008 /*---------------------------------------------------------------------------*/
17009 /* FIRST CHECK WHETHER THE LAST WRITE IN THE PREVIOUS FILE HAVE COMPLETED    */
17010 /*---------------------------------------------------------------------------*/
17011   if (logFilePtr.p->fileChangeState == LogFileRecord::BOTH_WRITES_ONGOING) {
17012     jam();
17013 /*---------------------------------------------------------------------------*/
17014 /* THE LAST WRITE WAS STILL ONGOING.                                         */
17015 /*---------------------------------------------------------------------------*/
17016     logFilePtr.p->fileChangeState = LogFileRecord::LAST_WRITE_ONGOING;
17017     return;
17018   } else {
17019     jam();
17020     ndbrequire(logFilePtr.p->fileChangeState == LogFileRecord::FIRST_WRITE_ONGOING);
17021 /*---------------------------------------------------------------------------*/
17022 /* WRITE TO PAGE 0 IN IN FILE 0 NOW.                                         */
17023 /*---------------------------------------------------------------------------*/
17024     logFilePtr.p->fileChangeState = LogFileRecord::WRITE_PAGE_ZERO_ONGOING;
17025     if (fileNo == 0) {
17026       jam();
17027 /*---------------------------------------------------------------------------*/
17028 /* IF THE NEW FILE WAS 0 THEN WE HAVE ALREADY WRITTEN PAGE ZERO IN FILE 0.   */
17029 /*---------------------------------------------------------------------------*/
17030       // use writePageZeroLab to make sure that same code as normal is run
17031       writePageZeroLab(signal, __LINE__);
17032       return;
17033     } else {
17034       jam();
17035 /*---------------------------------------------------------------------------*/
17036 /* WRITE PAGE ZERO IN FILE ZERO. LOG_FILE_REC WILL REFER TO THE LOG FILE WE  */
17037 /* HAVE JUST WRITTEN PAGE ZERO IN TO GET HOLD OF LOG_FILE_PTR FOR THIS       */
17038 /* RECORD QUICKLY. THIS IS NEEDED TO GET HOLD OF THE FILE_CHANGE_STATE.      */
17039 /* THE ONLY INFORMATION WE WANT TO CHANGE IS THE LAST FILE NUMBER IN THE     */
17040 /* FILE DESCRIPTOR. THIS IS USED AT SYSTEM RESTART TO FIND THE END OF THE    */
17041 /* LOG PART.                                                                 */
17042 /*---------------------------------------------------------------------------*/
17043       Uint32 currLogFile = logFilePtr.i;
17044       logFilePtr.i = logPartPtr.p->firstLogfile;
17045       ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
17046       logPagePtr.i = logFilePtr.p->logPageZero;
17047       ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
17048       logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_FILE_NO] = fileNo;
17049       writeSinglePage(signal, 0, ZPAGE_SIZE - 1, __LINE__);
17050       lfoPtr.p->logFileRec = currLogFile;
17051       lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_PAGE_ZERO;
17052       return;
17053     }//if
17054   }//if
17055 }//Dblqh::firstPageWriteLab()
17056 
lastWriteInFileLab(Signal * signal)17057 void Dblqh::lastWriteInFileLab(Signal* signal)
17058 {
17059   LogFileRecordPtr locLogFilePtr;
17060 /*---------------------------------------------------------------------------*/
17061 /* CHECK IF ANY GLOBAL CHECKPOINTS ARE COMPLETED DUE TO THIS COMPLETED DISK  */
17062 /* WRITE.                                                                    */
17063 /*---------------------------------------------------------------------------*/
17064   checkGcpCompleted(signal,
17065                     ((lfoPtr.p->lfoPageNo + lfoPtr.p->noPagesRw) - 1),
17066                     (ZPAGE_SIZE - 1));
17067   releaseLfoPages(signal);
17068   releaseLfo(signal);
17069 /*---------------------------------------------------------------------------*/
17070 /* IF THE FILE IS NOT IN USE OR THE NEXT FILE TO BE USED WE WILL CLOSE IT.   */
17071 /*---------------------------------------------------------------------------*/
17072   locLogFilePtr.i = logPartPtr.p->currentLogfile;
17073   ptrCheckGuard(locLogFilePtr, clogFileFileSize, logFileRecord);
17074   if (logFilePtr.i != locLogFilePtr.i) {
17075     if (logFilePtr.i != locLogFilePtr.p->nextLogFile) {
17076       if (logFilePtr.p->fileNo != 0) {
17077         jam();
17078 /*---------------------------------------------------------------------------*/
17079 /* THE FILE IS NOT FILE ZERO EITHER. WE WILL NOT CLOSE FILE ZERO SINCE WE    */
17080 /* USE IT TO KEEP TRACK OF THE CURRENT LOG FILE BY WRITING PAGE ZERO IN      */
17081 /* FILE ZERO.                                                                */
17082 /*---------------------------------------------------------------------------*/
17083 /* WE WILL CLOSE THE FILE.                                                   */
17084 /*---------------------------------------------------------------------------*/
17085         logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_WRITE_LOG;
17086         closeFile(signal, logFilePtr, __LINE__);
17087       }//if
17088     }//if
17089   }//if
17090 /*---------------------------------------------------------------------------*/
17091 /* IF A NEW FILE HAS BEEN OPENED WE SHALL ALWAYS ALSO WRITE TO PAGE O IN     */
17092 /* FILE 0. THE AIM IS TO MAKE RESTARTS EASIER BY SPECIFYING WHICH IS THE     */
17093 /* LAST FILE WHERE LOGGING HAS STARTED.                                      */
17094 /*---------------------------------------------------------------------------*/
17095 /* FIRST CHECK WHETHER THE FIRST WRITE IN THE NEW FILE HAVE COMPLETED        */
17096 /* THIS STATE INFORMATION IS IN THE NEW LOG FILE AND THUS WE HAVE TO MOVE    */
17097 /* THE LOG FILE POINTER TO THIS LOG FILE.                                    */
17098 /*---------------------------------------------------------------------------*/
17099   logFilePtr.i = logFilePtr.p->nextLogFile;
17100   ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
17101   if (logFilePtr.p->fileChangeState == LogFileRecord::BOTH_WRITES_ONGOING) {
17102     jam();
17103 /*---------------------------------------------------------------------------*/
17104 /* THE FIRST WRITE WAS STILL ONGOING.                                        */
17105 /*---------------------------------------------------------------------------*/
17106     logFilePtr.p->fileChangeState = LogFileRecord::FIRST_WRITE_ONGOING;
17107     return;
17108   } else {
17109     ndbrequire(logFilePtr.p->fileChangeState == LogFileRecord::LAST_WRITE_ONGOING);
17110 /*---------------------------------------------------------------------------*/
17111 /* WRITE TO PAGE 0 IN IN FILE 0 NOW.                                         */
17112 /*---------------------------------------------------------------------------*/
17113     logFilePtr.p->fileChangeState = LogFileRecord::WRITE_PAGE_ZERO_ONGOING;
17114     Uint32 fileNo = logFilePtr.p->fileNo;
17115     if (fileNo == 0) {
17116       jam();
17117 /*---------------------------------------------------------------------------*/
17118 /* IF THE NEW FILE WAS 0 THEN WE HAVE ALREADY WRITTEN PAGE ZERO IN FILE 0.   */
17119 /*---------------------------------------------------------------------------*/
17120       // use writePageZeroLab to make sure that same code as normal is run
17121       writePageZeroLab(signal, __LINE__);
17122       return;
17123     } else {
17124       jam();
17125 /*---------------------------------------------------------------------------*/
17126 /* WRITE PAGE ZERO IN FILE ZERO. LOG_FILE_REC WILL REFER TO THE LOG FILE WE  */
17127 /* HAVE JUST WRITTEN PAGE ZERO IN TO GET HOLD OF LOG_FILE_PTR FOR THIS       */
17128 /* RECORD QUICKLY. THIS IS NEEDED TO GET HOLD OF THE FILE_CHANGE_STATE.      */
17129 /* THE ONLY INFORMATION WE WANT TO CHANGE IS THE LAST FILE NUMBER IN THE     */
17130 /* FILE DESCRIPTOR. THIS IS USED AT SYSTEM RESTART TO FIND THE END OF THE    */
17131 /* LOG PART.                                                                 */
17132 /*---------------------------------------------------------------------------*/
17133       Uint32 currLogFile = logFilePtr.i;
17134       logFilePtr.i = logPartPtr.p->firstLogfile;
17135       ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
17136       logPagePtr.i = logFilePtr.p->logPageZero;
17137       ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
17138       logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_FILE_NO] = fileNo;
17139       writeSinglePage(signal, 0, ZPAGE_SIZE - 1, __LINE__);
17140       lfoPtr.p->logFileRec = currLogFile;
17141       lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_PAGE_ZERO;
17142       return;
17143     }//if
17144   }//if
17145 }//Dblqh::lastWriteInFileLab()
17146 
writePageZeroLab(Signal * signal,Uint32 from)17147 void Dblqh::writePageZeroLab(Signal* signal, Uint32 from)
17148 {
17149   if ((logPartPtr.p->m_log_problems & LogPartRecord::P_FILE_CHANGE_PROBLEM)!= 0)
17150   {
17151     jam();
17152     update_log_problem(signal, logPartPtr,
17153                        LogPartRecord::P_FILE_CHANGE_PROBLEM,
17154                        /* clear */ false);
17155   }
17156 
17157   logFilePtr.p->fileChangeState = LogFileRecord::NOT_ONGOING;
17158 
17159 /*---------------------------------------------------------------------------*/
17160 /* IT COULD HAVE ARRIVED PAGE WRITES TO THE CURRENT FILE WHILE WE WERE       */
17161 /* WAITING FOR THIS DISK WRITE TO COMPLETE. THEY COULD NOT CHECK FOR         */
17162 /* COMPLETED GLOBAL CHECKPOINTS. THUS WE SHOULD DO THAT NOW INSTEAD.         */
17163 /*---------------------------------------------------------------------------*/
17164   bool res = checkGcpCompleted(signal,
17165                                logFilePtr.p->lastPageWritten,
17166                                logFilePtr.p->lastWordWritten);
17167   if (res && false)
17168   {
17169     gcpPtr.i = ccurrentGcprec;
17170     ptrCheckGuard(gcpPtr, cgcprecFileSize, gcpRecord);
17171 
17172     infoEvent("Completing GCP %u in writePageZeroLab from %u",
17173               gcpPtr.p->gcpId, from);
17174   }
17175   return;
17176 }//Dblqh::writePageZeroLab()
17177 
17178 /* ######################################################################### */
17179 /*       INITIAL START MODULE                                                */
17180 /*       THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING.            */
17181 /*                                                                           */
17182 /*THIS MODULE INITIALISES ALL THE LOG FILES THAT ARE NEEDED AT A SYSTEM      */
17183 /*RESTART AND WHICH ARE USED DURING NORMAL OPERATIONS. IT CREATES THE FILES  */
17184 /*AND SETS A PROPER SIZE OF THEM AND INITIALISES THE FIRST PAGE IN EACH FILE */
17185 /* ######################################################################### */
openFileInitLab(Signal * signal)17186 void Dblqh::openFileInitLab(Signal* signal)
17187 {
17188   logFilePtr.p->logFileStatus = LogFileRecord::OPEN_INIT;
17189   seizeLogpage(signal);
17190   if (m_use_om_init == 0)
17191   {
17192     jam();
17193     initLogpage(signal);
17194     writeSinglePage(signal, (clogFileSize * ZPAGES_IN_MBYTE) - 1,
17195                     ZPAGE_SIZE - 1, __LINE__, false);
17196     lfoPtr.p->lfoState = LogFileOperationRecord::INIT_WRITE_AT_END;
17197   }
17198   else
17199   {
17200     jam();
17201     seizeLfo(signal);
17202     initWriteEndLab(signal);
17203   }
17204   return;
17205 }//Dblqh::openFileInitLab()
17206 
initWriteEndLab(Signal * signal)17207 void Dblqh::initWriteEndLab(Signal* signal)
17208 {
17209   releaseLfo(signal);
17210   initLogpage(signal);
17211   if (logFilePtr.p->fileNo == 0) {
17212     jam();
17213 /*---------------------------------------------------------------------------*/
17214 /* PAGE ZERO IN FILE ZERO MUST SET LOG LAP TO ONE SINCE IT HAS STARTED       */
17215 /* WRITING TO THE LOG, ALSO GLOBAL CHECKPOINTS ARE SET TO ZERO.              */
17216 /* Set number of log parts used to ensure we use correct number of log parts */
17217 /* at system restart. Was previously hardcoded to 4.                         */
17218 /*---------------------------------------------------------------------------*/
17219     logPagePtr.p->logPageWord[ZPOS_NO_LOG_PARTS]= globalData.ndbLogParts;
17220     logPagePtr.p->logPageWord[ZPOS_LOG_LAP] = 1;
17221     logPagePtr.p->logPageWord[ZPOS_MAX_GCI_STARTED] = 0;
17222     logPagePtr.p->logPageWord[ZPOS_MAX_GCI_COMPLETED] = 0;
17223     logFilePtr.p->logMaxGciStarted[0] = 0;
17224     logFilePtr.p->logMaxGciCompleted[0] = 0;
17225   }//if
17226 /*---------------------------------------------------------------------------*/
17227 /* REUSE CODE FOR INITIALISATION OF FIRST PAGE IN ALL LOG FILES.             */
17228 /*---------------------------------------------------------------------------*/
17229   writeFileHeaderOpen(signal, ZINIT);
17230   return;
17231 }//Dblqh::initWriteEndLab()
17232 
initFirstPageLab(Signal * signal)17233 void Dblqh::initFirstPageLab(Signal* signal)
17234 {
17235   releaseLfo(signal);
17236   if (logFilePtr.p->fileNo == 0) {
17237     jam();
17238 /*---------------------------------------------------------------------------*/
17239 /* IN FILE ZERO WE WILL INSERT A PAGE ONE WHERE WE WILL INSERT A COMPLETED   */
17240 /* GCI RECORD FOR GCI = 0.                                                   */
17241 /*---------------------------------------------------------------------------*/
17242     initLogpage(signal);
17243     logPagePtr.p->logPageWord[ZPOS_LOG_LAP] = 1;
17244     logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE] = ZCOMPLETED_GCI_TYPE;
17245     logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + 1] = 1;
17246     writeSinglePage(signal, 1, ZPAGE_SIZE - 1, __LINE__, false);
17247     lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_GCI_ZERO;
17248     return;
17249   }//if
17250   logFilePtr.p->currentMbyte = 1;
17251   writeInitMbyte(signal);
17252   return;
17253 }//Dblqh::initFirstPageLab()
17254 
writeGciZeroLab(Signal * signal)17255 void Dblqh::writeGciZeroLab(Signal* signal)
17256 {
17257   releaseLfo(signal);
17258   logFilePtr.p->currentMbyte = 1;
17259   writeInitMbyte(signal);
17260   return;
17261 }//Dblqh::writeGciZeroLab()
17262 
writeInitMbyteLab(Signal * signal)17263 void Dblqh::writeInitMbyteLab(Signal* signal)
17264 {
17265   releaseLfo(signal);
17266   logFilePtr.p->currentMbyte = logFilePtr.p->currentMbyte + 1;
17267   if (logFilePtr.p->currentMbyte == clogFileSize) {
17268     jam();
17269     releaseLogpage(signal);
17270     logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_INIT;
17271     closeFile(signal, logFilePtr, __LINE__);
17272     return;
17273   }//if
17274   writeInitMbyte(signal);
17275   return;
17276 }//Dblqh::writeInitMbyteLab()
17277 
closingInitLab(Signal * signal)17278 void Dblqh::closingInitLab(Signal* signal)
17279 {
17280   logFilePtr.p->logFileStatus = LogFileRecord::CLOSED;
17281   logPartPtr.i = logFilePtr.p->logPartRec;
17282   ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
17283   if (logFilePtr.p->nextLogFile == logPartPtr.p->firstLogfile) {
17284     jam();
17285     checkInitCompletedLab(signal);
17286     return;
17287   } else {
17288     jam();
17289     logFilePtr.i = logFilePtr.p->nextLogFile;
17290     ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
17291     openLogfileInit(signal);
17292   }//if
17293   return;
17294 }//Dblqh::closingInitLab()
17295 
checkInitCompletedLab(Signal * signal)17296 void Dblqh::checkInitCompletedLab(Signal* signal)
17297 {
17298   logPartPtr.p->logPartState = LogPartRecord::SR_FIRST_PHASE_COMPLETED;
17299   g_eventLogger->info("LDM(%u): Completed REDO log initialisation of"
17300                       " logPart = %u",
17301                       instance(),
17302                       logPartPtr.i);
17303 /*---------------------------------------------------------------------------*/
17304 /* WE HAVE NOW INITIALISED ALL FILES IN THIS LOG PART. WE CAN NOW SET THE    */
17305 /* THE LOG LAP TO ONE SINCE WE WILL START WITH LOG LAP ONE. LOG LAP = ZERO   */
17306 /* MEANS THIS PART OF THE LOG IS NOT WRITTEN YET.                            */
17307 /*---------------------------------------------------------------------------*/
17308   logPartPtr.p->logLap = 1;
17309 
17310   if (m_use_om_init && ++logPartPtr.i != clogPartFileSize)
17311   {
17312     jam();
17313     ptrAss(logPartPtr, logPartRecord);
17314     logFilePtr.i = logPartPtr.p->firstLogfile;
17315     ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
17316     openLogfileInit(signal);
17317     return;
17318   }
17319 
17320   for (logPartPtr.i = 0; logPartPtr.i < clogPartFileSize; logPartPtr.i++)
17321   {
17322     jam();
17323     ptrAss(logPartPtr, logPartRecord);
17324     if (logPartPtr.p->logPartState != LogPartRecord::SR_FIRST_PHASE_COMPLETED)
17325     {
17326       jam();
17327 /*---------------------------------------------------------------------------*/
17328 /* THIS PART HAS STILL NOT COMPLETED. WAIT FOR THIS TO OCCUR.                */
17329 /*---------------------------------------------------------------------------*/
17330       return;
17331     }//if
17332   }
17333 
17334 #ifdef VM_TRACE
17335   enable_global_variables();
17336 #endif
17337   g_eventLogger->info("LDM(%u): Completed REDO initialisation",
17338                       instance());
17339   logfileInitCompleteReport(signal);
17340   sendNdbSttorryLab(signal);
17341 }
17342 
17343 /* ========================================================================= */
17344 /* =======       INITIATE LOG FILE OPERATION RECORD WHEN ALLOCATED   ======= */
17345 /*                                                                           */
17346 /* ========================================================================= */
initLfo(Signal * signal)17347 void Dblqh::initLfo(Signal* signal)
17348 {
17349   lfoPtr.p->firstLfoPage = RNIL;
17350   lfoPtr.p->lfoState = LogFileOperationRecord::IDLE;
17351   lfoPtr.p->logFileRec = logFilePtr.i;
17352   lfoPtr.p->noPagesRw = 0;
17353   lfoPtr.p->lfoPageNo = ZNIL;
17354 }//Dblqh::initLfo()
17355 
17356 /* ========================================================================= */
17357 /* =======              INITIATE LOG FILE WHEN ALLOCATED             ======= */
17358 /*                                                                           */
17359 /*       INPUT:  TFILE_NO        NUMBER OF THE FILE INITIATED                */
17360 /*               LOG_PART_PTR    NUMBER OF LOG PART                          */
17361 /*       SUBROUTINE SHORT NAME = IL                                          */
17362 /* ========================================================================= */
initLogfile(Signal * signal,Uint32 fileNo)17363 void Dblqh::initLogfile(Signal* signal, Uint32 fileNo)
17364 {
17365   UintR tilTmp;
17366   UintR tilIndex;
17367 
17368   logFilePtr.p->currentFilepage = 0;
17369   logFilePtr.p->currentLogpage = RNIL;
17370   logFilePtr.p->fileName[0] = (UintR)-1;
17371   logFilePtr.p->fileName[1] = (UintR)-1;	/* = H'FFFFFFFF = -1 */
17372   logFilePtr.p->fileName[2] = fileNo;	        /* Sfile_no */
17373   tilTmp = 1;	                        /* VERSION 1 OF FILE NAME */
17374   tilTmp = (tilTmp << 8) + 1;	    /* FRAGMENT LOG => .FRAGLOG AS EXTENSION */
17375   tilTmp = (tilTmp << 8) + (8 + logPartPtr.p->logPartNo); /* DIRECTORY = D(8+Part)/DBLQH */
17376   tilTmp = (tilTmp << 8) + 255;	              /* IGNORE Pxx PART OF FILE NAME */
17377   logFilePtr.p->fileName[3] = tilTmp;
17378 /* ========================================================================= */
17379 /*       FILE NAME BECOMES /D2/DBLQH/Tpart_no/Sfile_no.FRAGLOG               */
17380 /* ========================================================================= */
17381   logFilePtr.p->fileNo = fileNo;
17382   logFilePtr.p->filePosition = 0;
17383   logFilePtr.p->firstLfo = RNIL;
17384   logFilePtr.p->lastLfo = RNIL;
17385   logFilePtr.p->logFileStatus = LogFileRecord::CLOSED;
17386   logFilePtr.p->logPartRec = logPartPtr.i;
17387   logFilePtr.p->noLogpagesInBuffer = 0;
17388   logFilePtr.p->firstFilledPage = RNIL;
17389   logFilePtr.p->lastFilledPage = RNIL;
17390   logFilePtr.p->lastPageWritten = 0;
17391   logFilePtr.p->logPageZero = RNIL;
17392   logFilePtr.p->currentMbyte = 0;
17393   for (tilIndex = 0; tilIndex < clogFileSize; tilIndex++) {
17394     logFilePtr.p->logMaxGciCompleted[tilIndex] = (UintR)-1;
17395     logFilePtr.p->logMaxGciStarted[tilIndex] = (UintR)-1;
17396     logFilePtr.p->logLastPrepRef[tilIndex] = 0;
17397   }//for
17398 }//Dblqh::initLogfile()
17399 
17400 /* ========================================================================= */
17401 /* =======              INITIATE LOG PAGE WHEN ALLOCATED             ======= */
17402 /*                                                                           */
17403 /* ========================================================================= */
initLogpage(Signal * signal)17404 void Dblqh::initLogpage(Signal* signal)
17405 {
17406   TcConnectionrecPtr ilpTcConnectptr;
17407 
17408   /* Ensure all non-used header words are zero */
17409   bzero(logPagePtr.p, sizeof(Uint32) * ZPAGE_HEADER_SIZE);
17410   logPagePtr.p->logPageWord[ZPOS_LOG_LAP] = logPartPtr.p->logLap;
17411   logPagePtr.p->logPageWord[ZPOS_MAX_GCI_COMPLETED] =
17412         logPartPtr.p->logPartNewestCompletedGCI;
17413   logPagePtr.p->logPageWord[ZPOS_MAX_GCI_STARTED] = cnewestGci;
17414   logPagePtr.p->logPageWord[ZPOS_VERSION] = NDB_VERSION;
17415   logPagePtr.p->logPageWord[ZPOS_NO_LOG_FILES] = logPartPtr.p->noLogFiles;
17416   logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = ZPAGE_HEADER_SIZE;
17417   logPagePtr.p->logPageWord[ZPOS_NO_LOG_PARTS]= globalData.ndbLogParts;
17418   ilpTcConnectptr.i = logPartPtr.p->firstLogTcrec;
17419   if (ilpTcConnectptr.i != RNIL) {
17420     jam();
17421     ptrCheckGuard(ilpTcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
17422     logPagePtr.p->logPageWord[ZLAST_LOG_PREP_REF] =
17423       (ilpTcConnectptr.p->logStartFileNo << 16) +
17424       (ilpTcConnectptr.p->logStartPageNo >> ZTWOLOG_NO_PAGES_IN_MBYTE);
17425   } else {
17426     jam();
17427     logPagePtr.p->logPageWord[ZLAST_LOG_PREP_REF] =
17428       (logFilePtr.p->fileNo << 16) +
17429       (logFilePtr.p->currentFilepage >> ZTWOLOG_NO_PAGES_IN_MBYTE);
17430   }//if
17431 }//Dblqh::initLogpage()
17432 
17433 /* ------------------------------------------------------------------------- */
17434 /* -------               OPEN LOG FILE FOR READ AND WRITE            ------- */
17435 /*                                                                           */
17436 /*       SUBROUTINE SHORT NAME = OFR                                         */
17437 /* ------------------------------------------------------------------------- */
openFileRw(Signal * signal,LogFileRecordPtr olfLogFilePtr,bool writeBuffer)17438 void Dblqh::openFileRw(Signal* signal,
17439                        LogFileRecordPtr olfLogFilePtr,
17440                        bool writeBuffer)
17441 {
17442   FsOpenReq* req = (FsOpenReq*)signal->getDataPtrSend();
17443   signal->theData[0] = cownref;
17444   signal->theData[1] = olfLogFilePtr.i;
17445   signal->theData[2] = olfLogFilePtr.p->fileName[0];
17446   signal->theData[3] = olfLogFilePtr.p->fileName[1];
17447   signal->theData[4] = olfLogFilePtr.p->fileName[2];
17448   signal->theData[5] = olfLogFilePtr.p->fileName[3];
17449   signal->theData[6] = FsOpenReq::OM_READWRITE | FsOpenReq::OM_AUTOSYNC | FsOpenReq::OM_CHECK_SIZE;
17450   if (c_o_direct)
17451     signal->theData[6] |= FsOpenReq::OM_DIRECT;
17452   if (writeBuffer)
17453     signal->theData[6] |= FsOpenReq::OM_WRITE_BUFFER;
17454 
17455   req->auto_sync_size = MAX_REDO_PAGES_WITHOUT_SYNCH * sizeof(LogPageRecord);
17456   Uint64 sz = clogFileSize;
17457   sz *= 1024; sz *= 1024;
17458   req->file_size_hi = (Uint32)(sz >> 32);
17459   req->file_size_lo = (Uint32)(sz & 0xFFFFFFFF);
17460   sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, FsOpenReq::SignalLength, JBA);
17461 }//Dblqh::openFileRw()
17462 
17463 /* ------------------------------------------------------------------------- */
17464 /* -------               OPEN LOG FILE DURING INITIAL START          ------- */
17465 /*                                                                           */
17466 /*       SUBROUTINE SHORT NAME = OLI                                         */
17467 /* ------------------------------------------------------------------------- */
openLogfileInit(Signal * signal)17468 void Dblqh::openLogfileInit(Signal* signal)
17469 {
17470   logFilePtr.p->logFileStatus = LogFileRecord::OPENING_INIT;
17471   FsOpenReq* req = (FsOpenReq*)signal->getDataPtrSend();
17472   signal->theData[0] = cownref;
17473   signal->theData[1] = logFilePtr.i;
17474   signal->theData[2] = logFilePtr.p->fileName[0];
17475   signal->theData[3] = logFilePtr.p->fileName[1];
17476   signal->theData[4] = logFilePtr.p->fileName[2];
17477   signal->theData[5] = logFilePtr.p->fileName[3];
17478   signal->theData[6] = FsOpenReq::OM_READWRITE | FsOpenReq::OM_TRUNCATE | FsOpenReq::OM_CREATE | FsOpenReq::OM_AUTOSYNC | FsOpenReq::OM_WRITE_BUFFER;
17479   if (c_o_direct)
17480     signal->theData[6] |= FsOpenReq::OM_DIRECT;
17481 
17482   Uint64 sz = Uint64(clogFileSize) * 1024 * 1024;
17483   req->file_size_hi = Uint32(sz >> 32);
17484   req->file_size_lo = Uint32(sz);
17485   req->page_size = File_formats::NDB_PAGE_SIZE;
17486   if (m_use_om_init)
17487   {
17488     jam();
17489     signal->theData[6] |= FsOpenReq::OM_INIT;
17490   }
17491 
17492   req->auto_sync_size = MAX_REDO_PAGES_WITHOUT_SYNCH * sizeof(LogPageRecord);
17493   sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, FsOpenReq::SignalLength, JBA);
17494 }//Dblqh::openLogfileInit()
17495 
17496 void
execFSWRITEREQ(Signal * signal)17497 Dblqh::execFSWRITEREQ(Signal* signal)
17498 {
17499   /**
17500    * This is currently run in other thread -> no jam
17501    *   and no global variables
17502    *
17503    * This method is called from NDB file system while initialising a REDO log
17504    * file, so we need to ensure that we don't touch any block variables other
17505    * than to read stable variables. This is only called during initial
17506    * restart. The pages are allocated by NDBFS from DataMemory, so these can
17507    * be written to safely since they are owned by the file system thread.
17508    */
17509   Ptr<GlobalPage> page_ptr;
17510   FsReadWriteReq* req= (FsReadWriteReq*)signal->getDataPtr();
17511   m_shared_page_pool.getPtr(page_ptr, req->data.pageData[0]);
17512 
17513   LogFileRecordPtr currLogFilePtr;
17514   currLogFilePtr.i = req->userPointer;
17515   ptrCheckGuard(currLogFilePtr, clogFileFileSize, logFileRecord);
17516 
17517   LogPartRecordPtr currLogPartPtr;
17518   currLogPartPtr.i = currLogFilePtr.p->logPartRec;
17519   ptrCheckGuard(currLogPartPtr, clogPartFileSize, logPartRecord);
17520 
17521   Uint32 page_no = req->varIndex;
17522   LogPageRecordPtr currLogPagePtr;
17523   currLogPagePtr.p = (LogPageRecord*)page_ptr.p;
17524 
17525   bzero(page_ptr.p, sizeof(LogPageRecord));
17526   if (page_no == 0)
17527   {
17528     // keep writing these afterwards
17529   }
17530   else if (((page_no % ZPAGES_IN_MBYTE) == 0) ||
17531            (page_no == ((clogFileSize * ZPAGES_IN_MBYTE) - 1)))
17532   {
17533     currLogPagePtr.p->logPageWord[ZPOS_LOG_LAP] = currLogPartPtr.p->logLap;
17534     currLogPagePtr.p->logPageWord[ZPOS_MAX_GCI_COMPLETED] =
17535       currLogPartPtr.p->logPartNewestCompletedGCI;
17536     currLogPagePtr.p->logPageWord[ZPOS_MAX_GCI_STARTED] = cnewestGci;
17537     currLogPagePtr.p->logPageWord[ZPOS_VERSION] = NDB_VERSION;
17538     currLogPagePtr.p->logPageWord[ZPOS_NO_LOG_FILES] =
17539       currLogPartPtr.p->noLogFiles;
17540     currLogPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = ZPAGE_HEADER_SIZE;
17541     currLogPagePtr.p->logPageWord[ZLAST_LOG_PREP_REF] =
17542       (currLogFilePtr.p->fileNo << 16) +
17543       (currLogFilePtr.p->currentFilepage >> ZTWOLOG_NO_PAGES_IN_MBYTE);
17544 
17545     currLogPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL;
17546     currLogPagePtr.p->logPageWord[ZPOS_CHECKSUM] =
17547       calcPageCheckSum(currLogPagePtr);
17548   }
17549   else if (0)
17550   {
17551     currLogPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL;
17552     currLogPagePtr.p->logPageWord[ZPOS_CHECKSUM] =
17553       calcPageCheckSum(currLogPagePtr);
17554   }
17555 }
17556 
17557 /* OPEN FOR READ/WRITE, DO CREATE AND DO TRUNCATE FILE */
17558 /* ------------------------------------------------------------------------- */
17559 /* -------               OPEN NEXT LOG FILE                          ------- */
17560 /*                                                                           */
17561 /*       SUBROUTINE SHORT NAME = ONL                                         */
17562 /* ------------------------------------------------------------------------- */
openNextLogfile(Signal * signal)17563 void Dblqh::openNextLogfile(Signal* signal)
17564 {
17565   LogFileRecordPtr onlLogFilePtr;
17566 
17567   if (logPartPtr.p->noLogFiles > 2) {
17568     jam();
17569 /* -------------------------------------------------- */
17570 /*       IF ONLY 1 OR 2 LOG FILES EXIST THEN THEY ARE */
17571 /*       ALWAYS OPEN AND THUS IT IS NOT NECESSARY TO  */
17572 /*       OPEN THEM NOW.                               */
17573 /* -------------------------------------------------- */
17574     onlLogFilePtr.i = logFilePtr.p->nextLogFile;
17575     ptrCheckGuard(onlLogFilePtr, clogFileFileSize, logFileRecord);
17576     if (onlLogFilePtr.p->logFileStatus != LogFileRecord::CLOSED) {
17577       ndbrequire(onlLogFilePtr.p->fileNo == 0);
17578       return;
17579     }//if
17580     onlLogFilePtr.p->logFileStatus = LogFileRecord::OPENING_WRITE_LOG;
17581     FsOpenReq* req = (FsOpenReq*)signal->getDataPtrSend();
17582     signal->theData[0] = cownref;
17583     signal->theData[1] = onlLogFilePtr.i;
17584     signal->theData[2] = onlLogFilePtr.p->fileName[0];
17585     signal->theData[3] = onlLogFilePtr.p->fileName[1];
17586     signal->theData[4] = onlLogFilePtr.p->fileName[2];
17587     signal->theData[5] = onlLogFilePtr.p->fileName[3];
17588     signal->theData[6] = FsOpenReq::OM_READWRITE | FsOpenReq::OM_AUTOSYNC | FsOpenReq::OM_CHECK_SIZE | FsOpenReq::OM_WRITE_BUFFER;
17589     if (c_o_direct)
17590       signal->theData[6] |= FsOpenReq::OM_DIRECT;
17591     req->auto_sync_size = MAX_REDO_PAGES_WITHOUT_SYNCH * sizeof(LogPageRecord);
17592     Uint64 sz = clogFileSize;
17593     sz *= 1024; sz *= 1024;
17594     req->file_size_hi = (Uint32)(sz >> 32);
17595     req->file_size_lo = (Uint32)(sz & 0xFFFFFFFF);
17596     sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, FsOpenReq::SignalLength, JBA);
17597   }//if
17598 }//Dblqh::openNextLogfile()
17599 
17600         /* OPEN FOR READ/WRITE, DON'T CREATE AND DON'T TRUNCATE FILE */
17601 /* ------------------------------------------------------------------------- */
17602 /* -------                       RELEASE LFO RECORD                  ------- */
17603 /*                                                                           */
17604 /* ------------------------------------------------------------------------- */
releaseLfo(Signal * signal)17605 void Dblqh::releaseLfo(Signal* signal)
17606 {
17607 #ifdef VM_TRACE
17608   // Check that lfo record isn't already in free list
17609   LogFileOperationRecordPtr TlfoPtr;
17610   TlfoPtr.i = cfirstfreeLfo;
17611   while (TlfoPtr.i != RNIL){
17612     ptrCheckGuard(TlfoPtr, clfoFileSize, logFileOperationRecord);
17613     ndbrequire(TlfoPtr.i != lfoPtr.i);
17614     TlfoPtr.i = TlfoPtr.p->nextLfo;
17615   }
17616 #endif
17617   lfoPtr.p->nextLfo = cfirstfreeLfo;
17618   lfoPtr.p->lfoTimer = 0;
17619   cfirstfreeLfo = lfoPtr.i;
17620   lfoPtr.p->lfoState = LogFileOperationRecord::IDLE;
17621 }//Dblqh::releaseLfo()
17622 
17623 /* ------------------------------------------------------------------------- */
17624 /* ------- RELEASE ALL LOG PAGES CONNECTED TO A LFO RECORD           ------- */
17625 /*                                                                           */
17626 /*       SUBROUTINE SHORT NAME = RLP                                         */
17627 /* ------------------------------------------------------------------------- */
releaseLfoPages(Signal * signal)17628 void Dblqh::releaseLfoPages(Signal* signal)
17629 {
17630   logPagePtr.i = lfoPtr.p->firstLfoPage;
17631   while (logPagePtr.i != RNIL)
17632   {
17633     ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
17634     Uint32 tmp = logPagePtr.p->logPageWord[ZNEXT_PAGE];
17635     releaseLogpage(signal);
17636     logPagePtr.i = tmp;
17637   }
17638   lfoPtr.p->firstLfoPage = RNIL;
17639 }//Dblqh::releaseLfoPages()
17640 
17641 /* ------------------------------------------------------------------------- */
17642 /* -------                       RELEASE LOG PAGE                    ------- */
17643 /*                                                                           */
17644 /* ------------------------------------------------------------------------- */
releaseLogpage(Signal * signal)17645 void Dblqh::releaseLogpage(Signal* signal)
17646 {
17647 #ifdef VM_TRACE
17648   // Check that log page isn't already in free list
17649   ndbrequire(logPagePtr.p->logPageWord[ZPOS_IN_FREE_LIST] == 0);
17650 #endif
17651 
17652   cnoOfLogPages++;
17653   logPagePtr.p->logPageWord[ZNEXT_PAGE] = cfirstfreeLogPage;
17654   logPagePtr.p->logPageWord[ZPOS_IN_WRITING]= 0;
17655   logPagePtr.p->logPageWord[ZPOS_IN_FREE_LIST]= 1;
17656   cfirstfreeLogPage = logPagePtr.i;
17657 }//Dblqh::releaseLogpage()
17658 
17659 /* ------------------------------------------------------------------------- */
17660 /* -------       SEIZE LFO RECORD                                    ------- */
17661 /*                                                                           */
17662 /* ------------------------------------------------------------------------- */
seizeLfo(Signal * signal)17663 void Dblqh::seizeLfo(Signal* signal)
17664 {
17665   lfoPtr.i = cfirstfreeLfo;
17666   ptrCheckGuard(lfoPtr, clfoFileSize, logFileOperationRecord);
17667   cfirstfreeLfo = lfoPtr.p->nextLfo;
17668   lfoPtr.p->nextLfo = RNIL;
17669   lfoPtr.p->lfoTimer = cLqhTimeOutCount;
17670 }//Dblqh::seizeLfo()
17671 
17672 /* ------------------------------------------------------------------------- */
17673 /* -------       SEIZE LOG FILE RECORD                               ------- */
17674 /*                                                                           */
17675 /* ------------------------------------------------------------------------- */
seizeLogfile(Signal * signal)17676 void Dblqh::seizeLogfile(Signal* signal)
17677 {
17678   logFilePtr.i = cfirstfreeLogFile;
17679   ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
17680 /* ------------------------------------------------------------------------- */
17681 /*IF LIST IS EMPTY THEN A SYSTEM CRASH IS INVOKED SINCE LOG_FILE_PTR = RNIL  */
17682 /* ------------------------------------------------------------------------- */
17683   cfirstfreeLogFile = logFilePtr.p->nextLogFile;
17684   logFilePtr.p->nextLogFile = RNIL;
17685 }//Dblqh::seizeLogfile()
17686 
17687 /* ------------------------------------------------------------------------- */
17688 /* -------       SEIZE LOG PAGE RECORD                               ------- */
17689 /*                                                                           */
17690 /* ------------------------------------------------------------------------- */
seizeLogpage(Signal * signal)17691 void Dblqh::seizeLogpage(Signal* signal)
17692 {
17693   cnoOfLogPages--;
17694   logPagePtr.i = cfirstfreeLogPage;
17695   ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
17696 /* ------------------------------------------------------------------------- */
17697 /*IF LIST IS EMPTY THEN A SYSTEM CRASH IS INVOKED SINCE LOG_PAGE_PTR = RNIL  */
17698 /* ------------------------------------------------------------------------- */
17699   cfirstfreeLogPage = logPagePtr.p->logPageWord[ZNEXT_PAGE];
17700 #ifdef VM_TRACE
17701   bzero(logPagePtr.p, sizeof(LogPageRecord));
17702 #endif
17703   logPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL;
17704   logPagePtr.p->logPageWord[ZPOS_IN_FREE_LIST] = 0;
17705 }//Dblqh::seizeLogpage()
17706 
17707 /* ------------------------------------------------------------------------- */
17708 /* -------               WRITE FILE DESCRIPTOR INFORMATION           ------- */
17709 /*                                                                           */
17710 /*       SUBROUTINE SHORT NAME: WFD                                          */
17711 // Pointer handling:
17712 // logFilePtr in
17713 // logPartPtr in
17714 /* ------------------------------------------------------------------------- */
writeFileDescriptor(Signal * signal)17715 void Dblqh::writeFileDescriptor(Signal* signal)
17716 {
17717   TcConnectionrecPtr wfdTcConnectptr;
17718   UintR twfdFileNo;
17719   UintR twfdMbyte;
17720 
17721 /* -------------------------------------------------- */
17722 /*       START BY WRITING TO LOG FILE RECORD          */
17723 /* -------------------------------------------------- */
17724   arrGuard(logFilePtr.p->currentMbyte, clogFileSize);
17725   if (DEBUG_REDO)
17726   {
17727     printf("part: %u file: %u setting logMaxGciCompleted[%u] = %u logMaxGciStarted[%u]: %u lastPrepRef[%u]: ",
17728            logPartPtr.p->logPartNo,
17729            logFilePtr.p->fileNo,
17730            logFilePtr.p->currentMbyte,
17731            logPartPtr.p->logPartNewestCompletedGCI,
17732            logFilePtr.p->currentMbyte,
17733            cnewestGci,
17734            logFilePtr.p->currentMbyte);
17735     if (logPartPtr.p->firstLogTcrec == RNIL)
17736     {
17737       ndbout_c("file: %u mb: %u (RNIL)",
17738                logFilePtr.p->fileNo,
17739                logFilePtr.p->currentMbyte);
17740     }
17741     else
17742     {
17743       wfdTcConnectptr.i = logPartPtr.p->firstLogTcrec;
17744       ptrCheckGuard(wfdTcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
17745       ndbout_c("file: %u mb: %u",
17746                wfdTcConnectptr.p->logStartFileNo,
17747                wfdTcConnectptr.p->logStartPageNo >> ZTWOLOG_NO_PAGES_IN_MBYTE);
17748     }
17749   }
17750   logFilePtr.p->logMaxGciCompleted[logFilePtr.p->currentMbyte] =
17751     logPartPtr.p->logPartNewestCompletedGCI;
17752   logFilePtr.p->logMaxGciStarted[logFilePtr.p->currentMbyte] = cnewestGci;
17753   wfdTcConnectptr.i = logPartPtr.p->firstLogTcrec;
17754   if (wfdTcConnectptr.i != RNIL) {
17755     jam();
17756     ptrCheckGuard(wfdTcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
17757     twfdFileNo = wfdTcConnectptr.p->logStartFileNo;
17758     twfdMbyte = wfdTcConnectptr.p->logStartPageNo >> ZTWOLOG_NO_PAGES_IN_MBYTE;
17759     logFilePtr.p->logLastPrepRef[logFilePtr.p->currentMbyte] =
17760       (twfdFileNo << 16) + twfdMbyte;
17761   } else {
17762     jam();
17763     logFilePtr.p->logLastPrepRef[logFilePtr.p->currentMbyte] =
17764       (logFilePtr.p->fileNo << 16) + logFilePtr.p->currentMbyte;
17765   }//if
17766 }//Dblqh::writeFileDescriptor()
17767 
17768 /* ------------------------------------------------------------------------- */
17769 /* -------               WRITE THE HEADER PAGE OF A NEW FILE         ------- */
17770 /*                                                                           */
17771 /*       SUBROUTINE SHORT NAME:  WMO                                         */
17772 /* ------------------------------------------------------------------------- */
writeFileHeaderOpen(Signal * signal,Uint32 wmoType)17773 void Dblqh::writeFileHeaderOpen(Signal* signal, Uint32 wmoType)
17774 {
17775   UintR twmoNoLogDescriptors;
17776 
17777 /* -------------------------------------------------- */
17778 /*       WRITE HEADER INFORMATION IN THE NEW FILE.    */
17779 /* -------------------------------------------------- */
17780   logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_LOG_TYPE] = ZFD_TYPE;
17781   logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_FILE_NO] =
17782     logFilePtr.p->fileNo;
17783   /*
17784    * When writing a file header on open, we write cmaxLogFilesInPageZero,
17785    * though the entries for the first file (this file), will be invalid,
17786    * as we do not know e.g. which GCIs will be included by log records
17787    * in the MBs in this file.  On the first lap these will be initial values
17788    * on subsequent laps, they will be values from the previous lap.
17789    * We take care when reading these values back, not to use the values for
17790    * the current file.
17791    */
17792   if (logPartPtr.p->noLogFiles > cmaxLogFilesInPageZero) {
17793     jam();
17794     twmoNoLogDescriptors = cmaxLogFilesInPageZero;
17795   } else {
17796     jam();
17797     twmoNoLogDescriptors = logPartPtr.p->noLogFiles;
17798   }//if
17799   logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_NO_FD] =
17800     twmoNoLogDescriptors;
17801 
17802   {
17803     Uint32 pos = ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE;
17804     LogFileRecordPtr filePtr = logFilePtr;
17805     for (Uint32 fd = 0; fd < twmoNoLogDescriptors; fd++)
17806     {
17807       jam();
17808       ptrCheckGuard(filePtr, clogFileFileSize, logFileRecord);
17809       for (Uint32 mb = 0; mb < clogFileSize; mb ++)
17810       {
17811         jam();
17812         Uint32 pos0 = pos + fd * (ZFD_MBYTE_SIZE * clogFileSize) + mb;
17813         Uint32 pos1 = pos0 + clogFileSize;
17814         Uint32 pos2 = pos1 + clogFileSize;
17815         arrGuard(pos0, ZPAGE_SIZE);
17816         arrGuard(pos1, ZPAGE_SIZE);
17817         arrGuard(pos2, ZPAGE_SIZE);
17818         logPagePtr.p->logPageWord[pos0] = filePtr.p->logMaxGciCompleted[mb];
17819         logPagePtr.p->logPageWord[pos1] = filePtr.p->logMaxGciStarted[mb];
17820         logPagePtr.p->logPageWord[pos2] = filePtr.p->logLastPrepRef[mb];
17821       }
17822       filePtr.i = filePtr.p->prevLogFile;
17823     }
17824     pos += (twmoNoLogDescriptors * ZFD_MBYTE_SIZE * clogFileSize);
17825     arrGuard(pos, ZPAGE_SIZE);
17826     logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = pos;
17827     logPagePtr.p->logPageWord[pos] = ZNEXT_LOG_RECORD_TYPE;
17828   }
17829 
17830 /* ------------------------------------------------------- */
17831 /*       THIS IS A SPECIAL WRITE OF THE FIRST PAGE IN THE  */
17832 /*       LOG FILE. THIS HAS SPECIAL SIGNIFANCE TO FIND     */
17833 /*       THE END OF THE LOG AT SYSTEM RESTART.             */
17834 /* ------------------------------------------------------- */
17835   if (wmoType == ZINIT) {
17836     jam();
17837     writeSinglePage(signal, 0, ZPAGE_SIZE - 1, __LINE__, false);
17838     lfoPtr.p->lfoState = LogFileOperationRecord::INIT_FIRST_PAGE;
17839   } else {
17840     jam();
17841     writeSinglePage(signal, 0, ZPAGE_SIZE - 1, __LINE__, true);
17842     lfoPtr.p->lfoState = LogFileOperationRecord::FIRST_PAGE_WRITE_IN_LOGFILE;
17843   }//if
17844   logFilePtr.p->filePosition = 1;
17845   if (wmoType == ZNORMAL) {
17846     jam();
17847 /* -------------------------------------------------- */
17848 /*       ALLOCATE A NEW PAGE SINCE THE CURRENT IS     */
17849 /*       WRITTEN.                                     */
17850 /* -------------------------------------------------- */
17851     seizeLogpage(signal);
17852     initLogpage(signal);
17853     logFilePtr.p->currentLogpage = logPagePtr.i;
17854     logFilePtr.p->currentFilepage = logFilePtr.p->currentFilepage + 1;
17855   }//if
17856 }//Dblqh::writeFileHeaderOpen()
17857 
17858 /* -------------------------------------------------- */
17859 /*       THE NEW FILE POSITION WILL ALWAYS BE 1 SINCE */
17860 /*       WE JUST WROTE THE FIRST PAGE IN THE LOG FILE */
17861 /* -------------------------------------------------- */
17862 /* ------------------------------------------------------------------------- */
17863 /* -------               WRITE A MBYTE HEADER DURING INITIAL START   ------- */
17864 /*                                                                           */
17865 /*       SUBROUTINE SHORT NAME: WIM                                          */
17866 /* ------------------------------------------------------------------------- */
writeInitMbyte(Signal * signal)17867 void Dblqh::writeInitMbyte(Signal* signal)
17868 {
17869   if (m_use_om_init == 0)
17870   {
17871     jam();
17872     initLogpage(signal);
17873     writeSinglePage(signal, logFilePtr.p->currentMbyte * ZPAGES_IN_MBYTE,
17874                     ZPAGE_SIZE - 1, __LINE__, false);
17875     lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_INIT_MBYTE;
17876     checkReportStatus(signal);
17877   }
17878   else
17879   {
17880     jam();
17881     seizeLfo(signal);
17882     logFilePtr.p->currentMbyte = clogFileSize - 1;
17883     writeInitMbyteLab(signal);
17884   }
17885 }//Dblqh::writeInitMbyte()
17886 
17887 /* ------------------------------------------------------------------------- */
17888 /* -------               WRITE A SINGLE PAGE INTO A FILE             ------- */
17889 /*                                                                           */
17890 /*       INPUT:          TWSP_PAGE_NO    THE PAGE NUMBER WRITTEN             */
17891 /*       SUBROUTINE SHORT NAME:  WSP                                         */
17892 /* ------------------------------------------------------------------------- */
writeSinglePage(Signal * signal,Uint32 pageNo,Uint32 wordWritten,Uint32 place,bool sync)17893 void Dblqh::writeSinglePage(Signal* signal, Uint32 pageNo,
17894                             Uint32 wordWritten, Uint32 place,
17895                             bool sync)
17896 {
17897   seizeLfo(signal);
17898   initLfo(signal);
17899   lfoPtr.p->firstLfoPage = logPagePtr.i;
17900   logPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL;
17901 
17902   writeDbgInfoPageHeader(logPagePtr, place, pageNo, wordWritten);
17903   // Calculate checksum for page
17904   logPagePtr.p->logPageWord[ZPOS_CHECKSUM] = calcPageCheckSum(logPagePtr);
17905 
17906   lfoPtr.p->lfoPageNo = pageNo;
17907   lfoPtr.p->lfoWordWritten = wordWritten;
17908   lfoPtr.p->noPagesRw = 1;
17909 /* -------------------------------------------------- */
17910 /*       SET TIMER ON THIS LOG PART TO SIGNIFY THAT A */
17911 /*       LOG RECORD HAS BEEN SENT AT THIS TIME.       */
17912 /* -------------------------------------------------- */
17913   logPartPtr.p->logPartTimer = logPartPtr.p->logTimer;
17914   signal->theData[0] = logFilePtr.p->fileRef;
17915   signal->theData[1] = cownref;
17916   signal->theData[2] = lfoPtr.i;
17917   signal->theData[3] = sync ? ZLIST_OF_PAIRS_SYNCH : ZLIST_OF_PAIRS;
17918   signal->theData[4] = ZVAR_NO_LOG_PAGE_WORD;
17919   signal->theData[5] = 1;                     /* ONE PAGE WRITTEN */
17920   signal->theData[6] = logPagePtr.i;
17921   signal->theData[7] = pageNo;
17922   sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, 8, JBA);
17923 
17924   ndbrequire(logFilePtr.p->fileRef != RNIL);
17925 
17926   logPartPtr.p->m_io_tracker.send_io(32768);
17927 
17928   if (DEBUG_REDO)
17929   {
17930     ndbout_c("writeSingle 1 page at part: %u file: %u page: %u (mb: %u)",
17931              logPartPtr.p->logPartNo,
17932              logFilePtr.p->fileNo,
17933              pageNo,
17934              pageNo >> ZTWOLOG_NO_PAGES_IN_MBYTE);
17935   }
17936 }//Dblqh::writeSinglePage()
17937 
17938 /* ##########################################################################
17939  *     SYSTEM RESTART PHASE ONE MODULE
17940  *     THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING.
17941  *
17942  *     THIS MODULE CONTAINS THE CODE FOR THE FIRST PHASE OF THE SYSTEM RESTART.
17943  *     THE AIM OF THIS PHASE IS TO FIND THE END OF THE LOG AND TO FIND
17944  *     INFORMATION ABOUT WHERE GLOBAL CHECKPOINTS ARE COMPLETED AND STARTED
17945  *     IN THE LOG. THIS INFORMATION IS NEEDED TO START PHASE THREE OF
17946  *     THE SYSTEM RESTART.
17947  * ########################################################################## */
17948 /* --------------------------------------------------------------------------
17949  *     A SYSTEM RESTART OR NODE RESTART IS ONGOING. WE HAVE NOW OPENED FILE 0
17950  *     NOW WE NEED TO READ PAGE 0 TO FIND WHICH LOG FILE THAT WAS OPEN AT
17951  *     CRASH TIME.
17952  * -------------------------------------------------------------------------- */
openSrFrontpageLab(Signal * signal)17953 void Dblqh::openSrFrontpageLab(Signal* signal)
17954 {
17955   readSinglePage(signal, 0);
17956   lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_FRONTPAGE;
17957   return;
17958 }//Dblqh::openSrFrontpageLab()
17959 
17960 /* -------------------------------------------------------------------------
17961  * WE HAVE NOW READ PAGE 0 IN FILE 0. CHECK THE LAST OPEN FILE. ACTUALLY THE
17962  * LAST OPEN FILE COULD BE THE NEXT AFTER THAT. CHECK THAT FIRST. WHEN THE
17963  * LAST WAS FOUND WE CAN FIND ALL THE NEEDED INFORMATION WHERE TO START AND
17964  * STOP READING THE LOG.
17965  * -------------------------------------------------------------------------- */
readSrFrontpageLab(Signal * signal)17966 void Dblqh::readSrFrontpageLab(Signal* signal)
17967 {
17968   Uint32 num_parts_used;
17969   if (!ndb_configurable_log_parts(logPagePtr.p->logPageWord[ZPOS_VERSION])) {
17970     jam();
17971     num_parts_used= 4;
17972   }
17973   else
17974   {
17975     jam();
17976     num_parts_used = logPagePtr.p->logPageWord[ZPOS_NO_LOG_PARTS];
17977   }
17978   /* Verify that number of log parts >= number of LQH workers */
17979   if (globalData.ndbMtLqhWorkers > num_parts_used) {
17980     char buf[255];
17981     BaseString::snprintf(buf, sizeof(buf),
17982       "Trying to start %d LQH workers with only %d log parts, try initial"
17983       " node restart to be able to use more LQH workers.",
17984       globalData.ndbMtLqhWorkers, num_parts_used);
17985     progError(__LINE__, NDBD_EXIT_INVALID_CONFIG, buf);
17986   }
17987   if (num_parts_used != globalData.ndbLogParts)
17988   {
17989     char buf[255];
17990     BaseString::snprintf(buf, sizeof(buf),
17991       "Can only change NoOfLogParts through initial node restart, old"
17992       " value of NoOfLogParts = %d, tried using %d",
17993       num_parts_used, globalData.ndbLogParts);
17994     progError(__LINE__, NDBD_EXIT_INVALID_CONFIG, buf);
17995   }
17996 
17997   Uint32 fileNo = logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_FILE_NO];
17998   /* ------------------------------------------------------------------------
17999    *    CLOSE FILE 0 SO THAT WE HAVE CLOSED ALL FILES WHEN STARTING TO READ
18000    *    THE FRAGMENT LOG. ALSO RELEASE PAGE ZERO.
18001    * ------------------------------------------------------------------------ */
18002   releaseLogpage(signal);
18003   logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_SR_FRONTPAGE;
18004   closeFile(signal, logFilePtr, __LINE__);
18005   /* Lookup index of last file */
18006   LogFileRecordPtr locLogFilePtr;
18007   findLogfile(signal, fileNo, logPartPtr, &locLogFilePtr);
18008 
18009   /* Store in logPart record for use once file 0 is closed */
18010   logPartPtr.p->srLastFileIndex = locLogFilePtr.i;
18011   return;
18012 }//Dblqh::readSrFrontpageLab()
18013 
openSrLastFileLab(Signal * signal)18014 void Dblqh::openSrLastFileLab(Signal* signal)
18015 {
18016   readSinglePage(signal, 0);
18017   lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_LAST_FILE;
18018   return;
18019 }//Dblqh::openSrLastFileLab()
18020 
readSrLastFileLab(Signal * signal)18021 void Dblqh::readSrLastFileLab(Signal* signal)
18022 {
18023   logPartPtr.p->logLap = logPagePtr.p->logPageWord[ZPOS_LOG_LAP];
18024   if (DEBUG_REDO)
18025   {
18026     ndbout_c("readSrLastFileLab part: %u logExecState: %u logPartState: %u logLap: %u",
18027              logPartPtr.p->logPartNo,
18028              logPartPtr.p->logExecState,
18029              logPartPtr.p->logPartState,
18030              logPartPtr.p->logLap);
18031   }
18032   if (logPartPtr.p->noLogFiles > cmaxValidLogFilesInPageZero) {
18033     jam();
18034     initGciInLogFileRec(signal, cmaxValidLogFilesInPageZero);
18035   } else {
18036     jam();
18037     initGciInLogFileRec(signal, logPartPtr.p->noLogFiles);
18038   }//if
18039   /* ------------------------------------------------------------------------
18040    *    NOW WE HAVE FOUND THE LAST LOG FILE. WE ALSO NEED TO FIND THE LAST
18041    *    MBYTE THAT WAS LAST WRITTEN BEFORE THE SYSTEM CRASH.
18042    * ------------------------------------------------------------------------ */
18043   logPartPtr.p->lastLogfile = logFilePtr.i;
18044   /**
18045    * It is safe to read page 0 of the first MByte since we always ensure that
18046    * this page is up to date before we update current file number in page 0
18047    * of file 0. Given that we already have page 0 read, we can now call
18048    * readSrLastMbyteLab immediately, no need to reread page 0.
18049    */
18050   logFilePtr.p->currentMbyte = 0;
18051   readSrLastMbyteLab(signal);
18052   return;
18053 }//Dblqh::readSrLastFileLab()
18054 
readSrLastMbyteLab(Signal * signal)18055 void Dblqh::readSrLastMbyteLab(Signal* signal)
18056 {
18057   if (logPartPtr.p->lastMbyte == ZNIL)
18058   {
18059     if (logPagePtr.p->logPageWord[ZPOS_LOG_LAP] < logPartPtr.p->logLap) {
18060       jam();
18061       logPartPtr.p->lastMbyte = logFilePtr.p->currentMbyte - 1;
18062       if (DEBUG_REDO)
18063       {
18064         ndbout_c("readSrLastMbyteLab part: %u file: %u lastMbyte: %u",
18065                  logPartPtr.p->logPartNo,
18066                  logFilePtr.p->fileNo,
18067                  logPartPtr.p->lastMbyte);
18068       }
18069     }//if
18070   }//if
18071   arrGuard(logFilePtr.p->currentMbyte, clogFileSize);
18072   logFilePtr.p->logMaxGciCompleted[logFilePtr.p->currentMbyte] =
18073     logPagePtr.p->logPageWord[ZPOS_MAX_GCI_COMPLETED];
18074   logFilePtr.p->logMaxGciStarted[logFilePtr.p->currentMbyte] =
18075     logPagePtr.p->logPageWord[ZPOS_MAX_GCI_STARTED];
18076   logFilePtr.p->logLastPrepRef[logFilePtr.p->currentMbyte] =
18077     logPagePtr.p->logPageWord[ZLAST_LOG_PREP_REF];
18078   releaseLogpage(signal);
18079   if (logFilePtr.p->currentMbyte < (clogFileSize - 1)) {
18080     jam();
18081     logFilePtr.p->currentMbyte++;
18082     readSinglePage(signal, ZPAGES_IN_MBYTE * logFilePtr.p->currentMbyte);
18083     lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_LAST_MBYTE;
18084     return;
18085   } else {
18086     jam();
18087     /* ----------------------------------------------------------------------
18088      *    THE LOG WAS IN THE LAST MBYTE WHEN THE CRASH OCCURRED SINCE ALL
18089      *    LOG LAPS ARE EQUAL TO THE CURRENT LOG LAP.
18090      * ---------------------------------------------------------------------- */
18091     if (logPartPtr.p->lastMbyte == ZNIL) {
18092       jam();
18093       logPartPtr.p->lastMbyte = clogFileSize - 1;
18094     }//if
18095   }//if
18096   logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_SR;
18097   closeFile(signal, logFilePtr, __LINE__);
18098 
18099   /* Head file is initialised by reading per-MB headers rather than per-file
18100    * headers.  Therefore, when stepping back through the redo files to get
18101    * the previous file's metadata, we must be careful not to read the
18102    * per-file header info over the just-read per-MB headers, invalidating
18103    * the head metainfo.
18104    */
18105   Uint32 nonHeadFileCount = logPartPtr.p->noLogFiles - 1;
18106 
18107   if (logPartPtr.p->noLogFiles > cmaxValidLogFilesInPageZero) {
18108     /* Step back from head to get file:mb metadata from a
18109      * previous file's page zero
18110      */
18111     Uint32 fileNo;
18112     if (logFilePtr.p->fileNo >= cmaxValidLogFilesInPageZero) {
18113       jam();
18114       fileNo = logFilePtr.p->fileNo - cmaxValidLogFilesInPageZero;
18115     } else {
18116       /* Wrap at 0:0 */
18117       jam();
18118       fileNo =
18119 	(logPartPtr.p->noLogFiles + logFilePtr.p->fileNo) -
18120 	cmaxValidLogFilesInPageZero;
18121     }//if
18122 
18123     jam();
18124     logPartPtr.p->srRemainingFiles =
18125       nonHeadFileCount - cmaxValidLogFilesInPageZero;
18126 
18127     /* Check we're making progress */
18128     ndbrequire(fileNo != logFilePtr.p->fileNo);
18129     LogFileRecordPtr locLogFilePtr;
18130     findLogfile(signal, fileNo, logPartPtr, &locLogFilePtr);
18131     ndbrequire(locLogFilePtr.p->logFileStatus == LogFileRecord::CLOSED);
18132     locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_NEXT_FILE;
18133     openFileRw(signal, locLogFilePtr);
18134     return;
18135   }//if
18136   /* ------------------------------------------------------------------------
18137    *   THERE WERE NO NEED TO READ ANY MORE PAGE ZERO IN OTHER FILES.
18138    *   WE NOW HAVE ALL THE NEEDED INFORMATION ABOUT THE GCI'S THAT WE NEED.
18139    *   NOW JUST WAIT FOR CLOSE OPERATIONS TO COMPLETE.
18140    * ------------------------------------------------------------------------ */
18141   return;
18142 }//Dblqh::readSrLastMbyteLab()
18143 
openSrNextFileLab(Signal * signal)18144 void Dblqh::openSrNextFileLab(Signal* signal)
18145 {
18146   readSinglePage(signal, 0);
18147   lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_NEXT_FILE;
18148   return;
18149 }//Dblqh::openSrNextFileLab()
18150 
readSrNextFileLab(Signal * signal)18151 void Dblqh::readSrNextFileLab(Signal* signal)
18152 {
18153   if (logPartPtr.p->srRemainingFiles > cmaxValidLogFilesInPageZero) {
18154     jam();
18155     initGciInLogFileRec(signal, cmaxValidLogFilesInPageZero);
18156   } else {
18157     jam();
18158     initGciInLogFileRec(signal, logPartPtr.p->srRemainingFiles);
18159   }//if
18160   releaseLogpage(signal);
18161   logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_SR;
18162   closeFile(signal, logFilePtr, __LINE__);
18163   if (logPartPtr.p->srRemainingFiles > cmaxValidLogFilesInPageZero) {
18164     /* Step back from head to get file:mb metadata from a
18165      * previous file's page zero
18166      */
18167     Uint32 fileNo;
18168     if (logFilePtr.p->fileNo >= cmaxValidLogFilesInPageZero) {
18169       jam();
18170       fileNo = logFilePtr.p->fileNo - cmaxValidLogFilesInPageZero;
18171     } else {
18172       /* Wrap at 0:0 */
18173       jam();
18174       fileNo =
18175 	(logPartPtr.p->noLogFiles + logFilePtr.p->fileNo) -
18176 	cmaxValidLogFilesInPageZero;
18177     }//if
18178 
18179     jam();
18180     logPartPtr.p->srRemainingFiles =
18181       logPartPtr.p->srRemainingFiles - cmaxValidLogFilesInPageZero;
18182 
18183     /* Check we're making progress */
18184     ndbrequire(fileNo != logFilePtr.p->fileNo);
18185     LogFileRecordPtr locLogFilePtr;
18186     findLogfile(signal, fileNo, logPartPtr, &locLogFilePtr);
18187     ndbrequire(locLogFilePtr.p->logFileStatus == LogFileRecord::CLOSED);
18188     locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_NEXT_FILE;
18189     openFileRw(signal, locLogFilePtr);
18190   }//if
18191   /* ------------------------------------------------------------------------
18192    *   THERE WERE NO NEED TO READ ANY MORE PAGE ZERO IN OTHER FILES.
18193    *   WE NOW HAVE ALL THE NEEDED INFORMATION ABOUT THE GCI'S THAT WE NEED.
18194    *   NOW JUST WAIT FOR CLOSE OPERATIONS TO COMPLETE.
18195    * ------------------------------------------------------------------------ */
18196   return;
18197 }//Dblqh::readSrNextFileLab()
18198 
closingSrFrontPage(Signal * signal)18199 void Dblqh::closingSrFrontPage(Signal* signal)
18200 {
18201   jam();
18202   /* Front page (file 0) has closed, now it's safe to continue
18203    * to read any page (including file 0) as part of restoring
18204    * redo metadata
18205    */
18206   logFilePtr.p->logFileStatus = LogFileRecord::CLOSED;
18207   logPartPtr.i = logFilePtr.p->logPartRec;
18208   ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
18209   logFilePtr.i = logPartPtr.p->firstLogfile;
18210 
18211   /* Pre-restart head file index was stored in logPartPtr.p->srLastFileIndex
18212    * prior to closing this file, now let's use it...
18213    */
18214   ndbrequire(logPartPtr.p->srLastFileIndex != RNIL);
18215 
18216   LogFileRecordPtr oldHead;
18217   oldHead.i = logPartPtr.p->srLastFileIndex;
18218   ptrCheckGuard(oldHead, clogFileFileSize, logFileRecord);
18219 
18220   /* Reset srLastFileIndex */
18221   logPartPtr.p->srLastFileIndex = RNIL;
18222 
18223   /* And now open the head file to begin redo meta reload */
18224   oldHead.p->logFileStatus = LogFileRecord::OPEN_SR_LAST_FILE;
18225   openFileRw(signal, oldHead);
18226   return;
18227 }
18228 
closingSrLab(Signal * signal)18229 void Dblqh::closingSrLab(Signal* signal)
18230 {
18231   logFilePtr.p->logFileStatus = LogFileRecord::CLOSED;
18232   logPartPtr.i = logFilePtr.p->logPartRec;
18233   ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
18234   logFilePtr.i = logPartPtr.p->firstLogfile;
18235   do {
18236     jam();
18237     ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
18238     if (logFilePtr.p->logFileStatus != LogFileRecord::CLOSED) {
18239       jam();
18240       /* --------------------------------------------------------------------
18241        *  EXIT AND WAIT FOR REMAINING LOG FILES TO COMPLETE THEIR WORK.
18242        * -------------------------------------------------------------------- */
18243       return;
18244     }//if
18245     logFilePtr.i = logFilePtr.p->nextLogFile;
18246   } while (logFilePtr.i != logPartPtr.p->firstLogfile);
18247   /* ------------------------------------------------------------------------
18248    *  ALL FILES IN THIS PART HAVE BEEN CLOSED. THIS INDICATES THAT THE FIRST
18249    *  PHASE OF THE SYSTEM RESTART HAVE BEEN CONCLUDED FOR THIS LOG PART.
18250    *  CHECK IF ALL OTHER LOG PARTS ARE ALSO COMPLETED.
18251    * ------------------------------------------------------------------------ */
18252   logPartPtr.p->logPartState = LogPartRecord::SR_FIRST_PHASE_COMPLETED;
18253   for (logPartPtr.i = 0; logPartPtr.i < clogPartFileSize; logPartPtr.i++) {
18254     jam();
18255     ptrAss(logPartPtr, logPartRecord);
18256     if (logPartPtr.p->logPartState != LogPartRecord::SR_FIRST_PHASE_COMPLETED) {
18257       jam();
18258       /* --------------------------------------------------------------------
18259        * EXIT AND WAIT FOR THE REST OF THE LOG PARTS TO COMPLETE.
18260        * -------------------------------------------------------------------- */
18261       return;
18262     }//if
18263   }//for
18264   /* ------------------------------------------------------------------------
18265    *       THE FIRST PHASE HAVE BEEN COMPLETED.
18266    * ------------------------------------------------------------------------ */
18267   g_eventLogger->info("LDM(%u):"
18268                       "Ready to start execute REDO log phase,"
18269                       " prepare REDO log phase completed",
18270                       instance());
18271 
18272   signal->theData[0] = ZSR_PHASE3_START;
18273   signal->theData[1] = ZSR_PHASE1_COMPLETED;
18274   sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
18275   return;
18276 }//Dblqh::closingSrLab()
18277 
18278 /* ##########################################################################
18279  * #######                  SYSTEM RESTART PHASE TWO MODULE           #######
18280  *
18281  *  THIS MODULE HANDLES THE SYSTEM RESTART WHERE LQH CONTROLS TUP AND ACC TO
18282  *  ENSURE THAT THEY HAVE KNOWLEDGE OF ALL FRAGMENTS AND HAVE DONE THE NEEDED
18283  *  READING OF DATA FROM FILE AND EXECUTION OF LOCAL LOGS. THIS PROCESS
18284  *  EXECUTES CONCURRENTLY WITH PHASE ONE OF THE SYSTEM RESTART. THIS PHASE
18285  *  FINDS THE INFORMATION ABOUT THE FRAGMENT LOG NEEDED TO EXECUTE THE FRAGMENT
18286  *  LOG.
18287  *  WHEN TUP AND ACC HAVE PREPARED ALL FRAGMENTS THEN LQH ORDERS THOSE LQH'S
18288  *  THAT ARE RESPONSIBLE TO EXECUTE THE FRAGMENT LOGS TO DO SO. IT IS POSSIBLE
18289  *  THAT ANOTHER NODE EXECUTES THE LOG FOR A FRAGMENT RESIDING AT THIS NODE.
18290  * ########################################################################## */
18291 /* ***************>> */
18292 /*  START_FRAGREQ  > */
18293 /* ***************>> */
execSTART_FRAGREQ(Signal * signal)18294 void Dblqh::execSTART_FRAGREQ(Signal* signal)
18295 {
18296   const StartFragReq * const startFragReq = (StartFragReq *)&signal->theData[0];
18297   jamEntry();
18298 
18299   c_fragmentsStarted++;
18300 
18301   tabptr.i = startFragReq->tableId;
18302   Uint32 fragId = startFragReq->fragId;
18303 
18304   ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
18305   if (!getFragmentrec(signal, fragId)) {
18306     startFragRefLab(signal);
18307     return;
18308   }//if
18309   tabptr.p->tableStatus = Tablerec::TABLE_DEFINED;
18310 
18311   Uint32 lcpNo = startFragReq->lcpNo;
18312   Uint32 noOfLogNodes = startFragReq->noOfLogNodes;
18313   Uint32 lcpId = startFragReq->lcpId;
18314   Uint32 requestInfo = startFragReq->requestInfo;
18315   if (signal->getLength() < StartFragReq::SignalLength)
18316   {
18317     jam();
18318     requestInfo = StartFragReq::SFR_RESTORE_LCP;
18319   }
18320 
18321   bool doprint = false;
18322 #ifdef ERROR_INSERT
18323   /**
18324    * Always printSTART_FRAG_REQ (for debugging) if ERROR_INSERT is set
18325    */
18326   doprint = true;
18327 #endif
18328   if (doprint || noOfLogNodes > 1)
18329   {
18330     printSTART_FRAG_REQ(stdout, signal->getDataPtr(), signal->getLength(),
18331                         number());
18332   }
18333 
18334   ndbrequire(noOfLogNodes <= MAX_LOG_EXEC);
18335   fragptr.p->fragStatus = Fragrecord::CRASH_RECOVERING;
18336   fragptr.p->srBlockref = startFragReq->userRef;
18337   fragptr.p->srUserptr = startFragReq->userPtr;
18338   fragptr.p->srChkpnr = lcpNo;
18339   if (lcpNo == (MAX_LCP_STORED - 1)) {
18340     jam();
18341     fragptr.p->lcpId[lcpNo] = lcpId;
18342   } else if (lcpNo < (MAX_LCP_STORED - 1)) {
18343     jam();
18344     fragptr.p->lcpId[lcpNo] = lcpId;
18345   } else {
18346     ndbrequire(lcpNo == ZNIL);
18347     jam();
18348   }//if
18349   fragptr.p->srNoLognodes = noOfLogNodes;
18350   fragptr.p->logFlag = Fragrecord::STATE_FALSE;
18351   fragptr.p->srStatus = Fragrecord::SS_IDLE;
18352 
18353   if (requestInfo == StartFragReq::SFR_COPY_FRAG)
18354   {
18355     ndbrequire(lcpNo == ZNIL);
18356     Uint32 n = fragptr.p->srLqhLognode[0] = startFragReq->lqhLogNode[0]; // src
18357     ndbrequire(ndbd_non_trans_copy_frag_req(getNodeInfo(n).m_version));
18358 
18359     // Magic no, meaning to COPY_FRAGREQ instead of read from disk
18360     fragptr.p->srChkpnr = Z8NIL;
18361     c_fragmentsStartedWithCopy++;
18362   }
18363 
18364   if (noOfLogNodes > 0)
18365   {
18366     jam();
18367     for (Uint32 i = 0; i < noOfLogNodes; i++) {
18368       jam();
18369       fragptr.p->srStartGci[i] = startFragReq->startGci[i];
18370       fragptr.p->srLastGci[i] = startFragReq->lastGci[i];
18371       fragptr.p->srLqhLognode[i] = startFragReq->lqhLogNode[i];
18372     }//for
18373     fragptr.p->newestGci = startFragReq->lastGci[noOfLogNodes - 1];
18374   }
18375   else
18376   {
18377     jam();
18378     /**
18379      * This is a really weird piece of code
18380      *   it's probably incorrect, but seems to mask problems...
18381      */
18382     if (cnewestGci > fragptr.p->newestGci)
18383     {
18384       jam();
18385       fragptr.p->newestGci = cnewestGci;
18386     }
18387   }//if
18388 
18389   if (requestInfo == StartFragReq::SFR_COPY_FRAG)
18390   {
18391     jam();
18392   }
18393   else if (lcpNo == ZNIL)
18394   {
18395     jam();
18396     /**
18397      *  THERE WAS NO LOCAL CHECKPOINT AVAILABLE FOR THIS FRAGMENT. WE DO
18398      *  NOT NEED TO READ IN THE LOCAL FRAGMENT.
18399      */
18400     /**
18401      * Or this is not "first" fragment in table
18402      *   RESTORE_LCP_REQ will currently restore all fragments
18403      */
18404     c_lcp_complete_fragments.addLast(fragptr);
18405 
18406     c_tup->disk_restart_lcp_id(tabptr.i, fragId, RNIL);
18407     jamEntry();
18408     return;
18409   }
18410   else
18411   {
18412     jam();
18413     c_tup->disk_restart_lcp_id(tabptr.i, fragId, lcpId);
18414     jamEntry();
18415 
18416     if (ERROR_INSERTED(5055))
18417     {
18418       ndbrequire(c_lcpId == 0 || lcpId == 0 || c_lcpId == lcpId);
18419     }
18420 
18421     /**
18422      * Keep track of minimal lcp-id
18423      */
18424     c_lcpId = (c_lcpId == 0 ? lcpId : c_lcpId);
18425     c_lcpId = (c_lcpId < lcpId ? c_lcpId : lcpId);
18426   }
18427 
18428   c_lcp_waiting_fragments.addLast(fragptr);
18429   if(c_lcp_restoring_fragments.isEmpty())
18430     send_restore_lcp(signal);
18431 }//Dblqh::execSTART_FRAGREQ()
18432 
18433 void
send_restore_lcp(Signal * signal)18434 Dblqh::send_restore_lcp(Signal * signal)
18435 {
18436   c_lcp_waiting_fragments.first(fragptr);
18437   c_lcp_waiting_fragments.remove(fragptr);
18438   c_lcp_restoring_fragments.addLast(fragptr);
18439 
18440   if (fragptr.p->srChkpnr != Z8NIL)
18441   {
18442     jam();
18443     RestoreLcpReq* req= (RestoreLcpReq*)signal->getDataPtrSend();
18444     req->senderData = fragptr.i;
18445     req->senderRef = reference();
18446     req->tableId = fragptr.p->tabRef;
18447     req->fragmentId = fragptr.p->fragId;
18448     req->lcpNo = fragptr.p->srChkpnr;
18449     req->lcpId = fragptr.p->lcpId[fragptr.p->srChkpnr];
18450     BlockReference restoreRef = calcInstanceBlockRef(RESTORE);
18451     sendSignal(restoreRef, GSN_RESTORE_LCP_REQ, signal,
18452                RestoreLcpReq::SignalLength, JBB);
18453   }
18454   else
18455   {
18456     jam();
18457 
18458     tabptr.i = fragptr.p->tabRef;
18459     ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
18460 
18461     fragptr.p->fragStatus = Fragrecord::ACTIVE_CREATION;
18462     CopyFragReq * req = CAST_PTR(CopyFragReq, signal->getDataPtrSend());
18463     req->senderData = fragptr.i;
18464     req->senderRef = reference();
18465     req->tableId = fragptr.p->tabRef;
18466     req->fragId = fragptr.p->fragId;
18467     req->nodeId = getOwnNodeId();
18468     req->schemaVersion = tabptr.p->schemaVersion;
18469     req->distributionKey = 0;
18470     req->gci = fragptr.p->lcpId[0];
18471     req->nodeCount = 0;
18472     req->nodeList[1] = CopyFragReq::CFR_NON_TRANSACTIONAL;
18473     Uint32 instanceKey = fragptr.p->lqhInstanceKey;
18474     BlockReference ref = numberToRef(DBLQH, instanceKey,
18475                                      fragptr.p->srLqhLognode[0]);
18476 
18477     sendSignal(ref, GSN_COPY_FRAGREQ, signal,
18478                CopyFragReq::SignalLength, JBB);
18479   }
18480 }
18481 
18482 void
execCOPY_FRAGREF(Signal * signal)18483 Dblqh::execCOPY_FRAGREF(Signal* signal)
18484 {
18485   jamEntry();
18486 
18487   const CopyFragRef * ref = CAST_CONSTPTR(CopyFragRef, signal->getDataPtr());
18488   Uint32 errorCode = ref->errorCode;
18489 
18490   SystemError * sysErr = (SystemError*)&signal->theData[0];
18491   sysErr->errorCode = SystemError::CopyFragRefError;
18492   sysErr->errorRef = reference();
18493   sysErr->data[0] = errorCode;
18494   sysErr->data[1] = 0;
18495   sendSignal(NDBCNTR_REF, GSN_SYSTEM_ERROR, signal,
18496              SystemError::SignalLength, JBB);
18497 }
18498 
18499 void
execCOPY_FRAGCONF(Signal * signal)18500 Dblqh::execCOPY_FRAGCONF(Signal* signal)
18501 {
18502   jamEntry();
18503   {
18504     const CopyFragConf* conf = CAST_CONSTPTR(CopyFragConf,
18505                                              signal->getDataPtr());
18506     c_fragment_pool.getPtr(fragptr, conf->senderData);
18507     fragptr.p->fragStatus = Fragrecord::CRASH_RECOVERING;
18508 
18509     Uint32 rows_lo = conf->rows_lo;
18510     Uint32 bytes_lo = conf->bytes_lo;
18511     signal->theData[0] = NDB_LE_NR_CopyFragDone;
18512     signal->theData[1] = getOwnNodeId();
18513     signal->theData[2] = fragptr.p->tabRef;
18514     signal->theData[3] = fragptr.p->fragId;
18515     signal->theData[4] = rows_lo;
18516     signal->theData[5] = 0;
18517     signal->theData[6] = bytes_lo;
18518     signal->theData[7] = 0;
18519     sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 8, JBB);
18520   }
18521 
18522   {
18523     RestoreLcpConf* conf= (RestoreLcpConf*)signal->getDataPtr();
18524     conf->senderData = fragptr.i;
18525     execRESTORE_LCP_CONF(signal);
18526   }
18527 }
18528 
startFragRefLab(Signal * signal)18529 void Dblqh::startFragRefLab(Signal* signal)
18530 {
18531   const StartFragReq * const startFragReq = (StartFragReq *)&signal->theData[0];
18532   BlockReference userRef = startFragReq->userRef;
18533   Uint32 userPtr = startFragReq->userPtr;
18534   signal->theData[0] = userPtr;
18535   signal->theData[1] = terrorCode;
18536   signal->theData[2] = cownNodeid;
18537   sendSignal(userRef, GSN_START_FRAGREF, signal, 3, JBB);
18538   return;
18539 }//Dblqh::startFragRefLab()
18540 
execRESTORE_LCP_REF(Signal * signal)18541 void Dblqh::execRESTORE_LCP_REF(Signal* signal)
18542 {
18543   jamEntry();
18544   ndbrequire(false);
18545   return;
18546 }
18547 
execRESTORE_LCP_CONF(Signal * signal)18548 void Dblqh::execRESTORE_LCP_CONF(Signal* signal)
18549 {
18550   jamEntry();
18551   RestoreLcpConf* conf= (RestoreLcpConf*)signal->getDataPtr();
18552   fragptr.i = conf->senderData;
18553   c_fragment_pool.getPtr(fragptr);
18554 
18555   c_lcp_restoring_fragments.remove(fragptr);
18556   c_lcp_complete_fragments.addLast(fragptr);
18557 
18558   tabptr.i = fragptr.p->tabRef;
18559   ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
18560 
18561   if (!c_lcp_waiting_fragments.isEmpty())
18562   {
18563     send_restore_lcp(signal);
18564     return;
18565   }
18566 
18567   if (c_lcp_restoring_fragments.isEmpty() &&
18568       cstartRecReq == SRR_START_REC_REQ_ARRIVED)
18569   {
18570     jam();
18571     /* ----------------------------------------------------------------
18572      *  WE HAVE ALSO RECEIVED AN INDICATION THAT NO MORE FRAGMENTS
18573      *  NEEDS RESTART.
18574      *  NOW IT IS TIME TO START EXECUTING THE UNDO LOG.
18575      * ----------------------------------------------------------------
18576      *  WE ARE NOW IN A POSITION TO ORDER TUP TO START
18577      *  EXECUTING THEIR UNDO LOGS. THIS MUST BE DONE BEFORE THE
18578      *  FRAGMENT LOGS CAN BE EXECUTED.
18579      * ---------------------------------------------------------------- */
18580 
18581     mark_end_of_lcp_restore(signal);
18582 
18583     csrExecUndoLogState = EULS_STARTED;
18584     lcpPtr.i = 0;
18585     ptrAss(lcpPtr, lcpRecord);
18586     lcpPtr.p->m_outstanding = 1;
18587 
18588     if (cstartType == NodeState::ST_INITIAL_NODE_RESTART)
18589     {
18590       jam();
18591       /**
18592        * Skip lgman undo...
18593        */
18594       signal->theData[0] = LGMAN_REF;
18595       sendSignal(reference(), GSN_START_RECCONF, signal, 1, JBB);
18596       return;
18597     }
18598 
18599     if (!isNdbMtLqh())
18600     {
18601       jam();
18602       signal->theData[0] = c_lcpId;
18603       sendSignal(LGMAN_REF, GSN_START_RECREQ, signal, 1, JBB);
18604     }
18605     else
18606     {
18607       jam();
18608       signal->theData[0] = c_lcpId;
18609       signal->theData[1] = LGMAN;
18610       sendSignal(DBLQH_REF, GSN_START_RECREQ, signal, 2, JBB);
18611     }
18612     return;
18613   }
18614 }
18615 
18616 /* ***************> */
18617 /*  START_RECREQ  > */
18618 /* ***************> */
execSTART_RECREQ(Signal * signal)18619 void Dblqh::execSTART_RECREQ(Signal* signal)
18620 {
18621   CRASH_INSERTION(5027);
18622 
18623   jamEntry();
18624   StartRecReq * const req = (StartRecReq*)&signal->theData[0];
18625   cmasterDihBlockref = req->senderRef;
18626 
18627   crestartOldestGci = req->keepGci;
18628   crestartNewestGci = req->lastCompletedGci;
18629   cnewestGci = req->newestGci;
18630   cstartRecReqData = req->senderData;
18631 
18632   if (check_ndb_versions())
18633   {
18634     ndbrequire(crestartOldestGci <= crestartNewestGci);
18635   }
18636 
18637   ndbrequire(req->receivingNodeId == cownNodeid);
18638 
18639   cnewestCompletedGci = cnewestGci;
18640   cstartRecReq = SRR_START_REC_REQ_ARRIVED; // StartRecReq has arrived
18641 
18642   if (signal->getLength() == StartRecReq::SignalLength)
18643   {
18644     jam();
18645     NdbNodeBitmask tmp;
18646     tmp.assign(NdbNodeBitmask::Size, req->sr_nodes);
18647     if (!tmp.equal(m_sr_nodes))
18648     {
18649       char buf0[100], buf1[100];
18650       ndbout_c("execSTART_RECREQ changing srnodes from %s to %s",
18651                m_sr_nodes.getText(buf0),
18652                tmp.getText(buf1));
18653 
18654     }
18655     m_sr_nodes.assign(NdbNodeBitmask::Size, req->sr_nodes);
18656   }
18657   else
18658   {
18659     jam();
18660     cstartRecReqData = RNIL;
18661   }
18662 
18663   for (logPartPtr.i = 0; logPartPtr.i < clogPartFileSize; logPartPtr.i++) {
18664     ptrAss(logPartPtr, logPartRecord);
18665     logPartPtr.p->logPartNewestCompletedGCI = cnewestCompletedGci;
18666   }//for
18667   /* ------------------------------------------------------------------------
18668    *   WE HAVE TO SET THE OLDEST AND THE NEWEST GLOBAL CHECKPOINT IDENTITY
18669    *   THAT WILL SURVIVE THIS SYSTEM RESTART. THIS IS NEEDED SO THAT WE CAN
18670    *   SET THE LOG HEAD AND LOG TAIL PROPERLY BEFORE STARTING THE SYSTEM AGAIN.
18671    *   WE ALSO NEED TO SET CNEWEST_GCI TO ENSURE THAT LOG RECORDS ARE EXECUTED
18672    *   WITH A PROPER GCI.
18673    *------------------------------------------------------------------------ */
18674 
18675   if (c_lcp_restoring_fragments.isEmpty())
18676   {
18677     jam();
18678 
18679     mark_end_of_lcp_restore(signal);
18680 
18681     csrExecUndoLogState = EULS_STARTED;
18682 
18683     lcpPtr.i = 0;
18684     ptrAss(lcpPtr, lcpRecord);
18685     lcpPtr.p->m_outstanding = 1;
18686 
18687     if (cstartType == NodeState::ST_INITIAL_NODE_RESTART)
18688     {
18689       jam();
18690       /**
18691        * Skip lgman undo...
18692        */
18693       signal->theData[0] = LGMAN_REF;
18694       sendSignal(reference(), GSN_START_RECCONF, signal, 1, JBB);
18695       return;
18696     }
18697 
18698     if (!isNdbMtLqh())
18699     {
18700       jam();
18701       signal->theData[0] = c_lcpId;
18702       sendSignal(LGMAN_REF, GSN_START_RECREQ, signal, 1, JBB);
18703     }
18704     else
18705     {
18706       jam();
18707       signal->theData[0] = c_lcpId;
18708       signal->theData[1] = LGMAN;
18709       sendSignal(DBLQH_REF, GSN_START_RECREQ, signal, 2, JBB);
18710     }
18711   }//if
18712 }//Dblqh::execSTART_RECREQ()
18713 
18714 /* ***************>> */
18715 /*  START_RECCONF  > */
18716 /* ***************>> */
execSTART_RECCONF(Signal * signal)18717 void Dblqh::execSTART_RECCONF(Signal* signal)
18718 {
18719   jamEntry();
18720   lcpPtr.i = 0;
18721   ptrAss(lcpPtr, lcpRecord);
18722   ndbrequire(csrExecUndoLogState == EULS_STARTED);
18723   ndbrequire(lcpPtr.p->m_outstanding);
18724 
18725   Uint32 sender= signal->theData[0];
18726 
18727   if (ERROR_INSERTED(5055))
18728   {
18729     CLEAR_ERROR_INSERT_VALUE;
18730   }
18731 
18732   lcpPtr.p->m_outstanding--;
18733   if(lcpPtr.p->m_outstanding)
18734   {
18735     jam();
18736     return;
18737   }
18738 
18739   switch(refToBlock(sender)){
18740   case TSMAN:
18741     jam();
18742     break;
18743   case LGMAN:
18744     jam();
18745     lcpPtr.p->m_outstanding++;
18746     if (!isNdbMtLqh())
18747     {
18748       jam();
18749       signal->theData[0] = c_lcpId;
18750       sendSignal(TSMAN_REF, GSN_START_RECREQ, signal, 1, JBB);
18751     }
18752     else
18753     {
18754       jam();
18755       signal->theData[0] = c_lcpId;
18756       signal->theData[1] = TSMAN;
18757       sendSignal(DBLQH_REF, GSN_START_RECREQ, signal, 2, JBB);
18758     }
18759     return;
18760     break;
18761   default:
18762     ndbrequire(false);
18763   }
18764 
18765   jam();
18766   csrExecUndoLogState = EULS_COMPLETED;
18767 
18768   g_eventLogger->info("LDM(%u): Completed DD Undo log application",
18769                       instance());
18770 
18771   sendLOCAL_RECOVERY_COMPLETE_REP(signal,
18772            LocalRecoveryCompleteRep::UNDO_DD_COMPLETED);
18773   if (cstartType == NodeState::ST_INITIAL_NODE_RESTART)
18774   {
18775     jam();
18776     cstartRecReq = SRR_REDO_COMPLETE; // REDO complete
18777 
18778     rebuildOrderedIndexes(signal, 0);
18779     return;
18780   }
18781 
18782   g_eventLogger->info("LDM(%u): Starting REDO log execution"
18783                       " phase %u",
18784                       instance(),
18785                       csrPhasesCompleted);
18786   startExecSr(signal);
18787 }
18788 
sendLOCAL_RECOVERY_COMPLETE_REP(Signal * signal,LocalRecoveryCompleteRep::PhaseIds phaseId)18789 void Dblqh::sendLOCAL_RECOVERY_COMPLETE_REP(Signal *signal,
18790                                   LocalRecoveryCompleteRep::PhaseIds phaseId)
18791 {
18792   LocalRecoveryCompleteRep *rep =
18793     (LocalRecoveryCompleteRep*)signal->getDataPtrSend();
18794 
18795   rep->nodeId = getOwnNodeId();
18796   rep->phaseId = phaseId;
18797   if (isNdbMtLqh())
18798   {
18799     jam();
18800     rep->senderData = cstartRecReqData;
18801     rep->instanceId = instance();
18802     sendSignal(DBLQH_REF, GSN_LOCAL_RECOVERY_COMP_REP, signal,
18803                LocalRecoveryCompleteRep::SignalLengthLocal, JBB);
18804   }
18805   else
18806   {
18807     jam();
18808     Uint32 master_node_id = refToNode(cmasterDihBlockref);
18809     Uint32 master_version = getNodeInfo(master_node_id).m_version;
18810     if (master_version >= NDBD_NODE_RECOVERY_STATUS_VERSION)
18811     {
18812       jam();
18813       sendSignal(cmasterDihBlockref, GSN_LOCAL_RECOVERY_COMP_REP, signal,
18814                  LocalRecoveryCompleteRep::SignalLengthMaster, JBB);
18815     }
18816   }
18817 }
18818 
18819 /* ***************> */
18820 /*  START_RECREF  > */
18821 /* ***************> */
execSTART_RECREF(Signal * signal)18822 void Dblqh::execSTART_RECREF(Signal* signal)
18823 {
18824   jamEntry();
18825   ndbrequire(false);
18826 }//Dblqh::execSTART_RECREF()
18827 
18828 void
rebuildOrderedIndexes(Signal * signal,Uint32 tableId)18829 Dblqh::rebuildOrderedIndexes(Signal* signal, Uint32 tableId)
18830 {
18831   jamEntry();
18832 
18833   if (tableId == 0)
18834   {
18835     jam();
18836     g_eventLogger->info("LDM(%u): Starting to rebuild ordered indexes",
18837                         instance());
18838 
18839     sendLOCAL_RECOVERY_COMPLETE_REP(signal,
18840                     LocalRecoveryCompleteRep::EXECUTE_REDO_LOG_COMPLETED);
18841   }
18842   if (tableId >= ctabrecFileSize)
18843   {
18844     jam();
18845 
18846     for (logPartPtr.i = 0; logPartPtr.i < clogPartFileSize; logPartPtr.i++)
18847     {
18848       jam();
18849       ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
18850       LogFileRecordPtr logFile;
18851       logFile.i = logPartPtr.p->currentLogfile;
18852       ptrCheckGuard(logFile, clogFileFileSize, logFileRecord);
18853 
18854       LogPosition head = { logFile.p->fileNo, logFile.p->currentMbyte };
18855       LogPosition tail = { logPartPtr.p->logTailFileNo,
18856                            logPartPtr.p->logTailMbyte};
18857       Uint64 mb = free_log(head, tail, logPartPtr.p->noLogFiles, clogFileSize);
18858       if (mb <= c_free_mb_tail_problem_limit)
18859       {
18860         jam();
18861         update_log_problem(signal, logPartPtr,
18862                            LogPartRecord::P_TAIL_PROBLEM, true);
18863       }
18864     }
18865 
18866     if (!isNdbMtLqh())
18867     {
18868       /**
18869        * There should be no disk-ops in flight here...check it
18870        */
18871       signal->theData[0] = 12003;
18872       sendSignal(LGMAN_REF, GSN_DUMP_STATE_ORD, signal, 1, JBB);
18873     }
18874 
18875     StartRecConf * conf = (StartRecConf*)signal->getDataPtrSend();
18876     conf->startingNodeId = getOwnNodeId();
18877     conf->senderData = cstartRecReqData;
18878     sendSignal(cmasterDihBlockref, GSN_START_RECCONF, signal,
18879                StartRecConf::SignalLength, JBB);
18880 
18881     g_eventLogger->info("LDM(%u): We have completed restoring our"
18882                         " fragments and executed REDO log and rebuilt"
18883                         " ordered indexes",
18884                         instance());
18885     return;
18886   }
18887 
18888   tabptr.i = tableId;
18889   ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
18890   if (! (DictTabInfo::isOrderedIndex(tabptr.p->tableType) &&
18891          tabptr.p->tableStatus == Tablerec::TABLE_DEFINED))
18892   {
18893     jam();
18894     signal->theData[0] = ZREBUILD_ORDERED_INDEXES;
18895     signal->theData[1] = tableId + 1;
18896     sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
18897     return;
18898   }
18899 
18900   signal->theData[0] = NDB_LE_RebuildIndex;
18901   signal->theData[1] = instance();
18902   signal->theData[2] = tableId;
18903   sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 3, JBB);
18904 
18905   BuildIndxImplReq* const req = (BuildIndxImplReq*)signal->getDataPtrSend();
18906   req->senderRef = reference();
18907   req->senderData = tableId;
18908   req->requestType = BuildIndxImplReq::RF_BUILD_OFFLINE;
18909   req->buildId = 0;     // not yet..
18910   req->buildKey = 0;    // ..in use
18911   req->transId = 0;
18912   req->indexType = tabptr.p->tableType;
18913   req->indexId = tableId;
18914   req->tableId = tabptr.p->primaryTableId;
18915   req->parallelism = 0;
18916   sendSignal(calcInstanceBlockRef(DBTUP), GSN_BUILD_INDX_IMPL_REQ, signal,
18917              BuildIndxImplReq::SignalLength, JBB);
18918 }
18919 
18920 void
execBUILD_INDX_IMPL_REF(Signal * signal)18921 Dblqh::execBUILD_INDX_IMPL_REF(Signal * signal)
18922 {
18923   jamEntry();
18924   ndbrequire(false); // TODO error message
18925 }
18926 
18927 void
execBUILD_INDX_IMPL_CONF(Signal * signal)18928 Dblqh::execBUILD_INDX_IMPL_CONF(Signal* signal)
18929 {
18930   jamEntry();
18931   BuildIndxImplConf * conf = (BuildIndxImplConf*)signal->getDataPtr();
18932   Uint32 tableId = conf->senderData;
18933   rebuildOrderedIndexes(signal, tableId + 1);
18934   g_eventLogger->info("LDM(%u): index id %u rebuild done",
18935                       instance(),
18936                       tableId);
18937 }
18938 
18939 /* ***************>> */
18940 /*  START_EXEC_SR  > */
18941 /* ***************>> */
execSTART_EXEC_SR(Signal * signal)18942 void Dblqh::execSTART_EXEC_SR(Signal* signal)
18943 {
18944   jamEntry();
18945   fragptr.i = signal->theData[0];
18946   Uint32 next = RNIL;
18947 
18948   if (fragptr.i == RNIL)
18949   {
18950     jam();
18951     /* ----------------------------------------------------------------------
18952      *    NO MORE FRAGMENTS TO START EXECUTING THE LOG ON.
18953      *    SEND EXEC_SRREQ TO ALL LQH TO INDICATE THAT THIS NODE WILL
18954      *    NOT REQUEST ANY MORE FRAGMENTS TO EXECUTE THE FRAGMENT LOG ON.
18955      * ----------------------------------------------------------------------
18956      *    WE NEED TO SEND THOSE SIGNALS EVEN IF WE HAVE NOT REQUESTED
18957      *    ANY FRAGMENTS PARTICIPATE IN THIS PHASE.
18958      * --------------------------------------------------------------------- */
18959     signal->theData[0] = cownNodeid;
18960     if (!isNdbMtLqh())
18961     {
18962       jam();
18963       NodeReceiverGroup rg(DBLQH, m_sr_nodes);
18964       sendSignal(rg, GSN_EXEC_SRREQ, signal, 1, JBB);
18965     }
18966     else
18967     {
18968       jam();
18969       const Uint32 sz = NdbNodeBitmask::Size;
18970       m_sr_nodes.copyto(sz, &signal->theData[1]);
18971       sendSignal(DBLQH_REF, GSN_EXEC_SRREQ, signal, 1 + sz, JBB);
18972     }
18973     return;
18974   } else {
18975     jam();
18976     c_lcp_complete_fragments.getPtr(fragptr);
18977     next = fragptr.p->nextList;
18978 
18979     if (fragptr.p->srNoLognodes > csrPhasesCompleted)
18980     {
18981       jam();
18982       cnoOutstandingExecFragReq++;
18983 
18984       Uint32 index = csrPhasesCompleted;
18985       arrGuard(index, MAX_LOG_EXEC);
18986       Uint32 Tnode = fragptr.p->srLqhLognode[index];
18987       Uint32 instanceKey = fragptr.p->lqhInstanceKey;
18988       BlockReference ref = numberToRef(DBLQH, instanceKey, Tnode);
18989       fragptr.p->srStatus = Fragrecord::SS_STARTED;
18990 
18991       /* --------------------------------------------------------------------
18992        *  SINCE WE CAN HAVE SEVERAL LQH NODES PER FRAGMENT WE CALCULATE
18993        *  THE LQH POINTER IN SUCH A WAY THAT WE CAN DEDUCE WHICH OF THE
18994        *  LQH NODES THAT HAS RESPONDED WHEN EXEC_FRAGCONF IS RECEIVED.
18995        * ------------------------------------------------------------------- */
18996       ExecFragReq * const execFragReq = (ExecFragReq *)&signal->theData[0];
18997       execFragReq->userPtr = fragptr.i;
18998       execFragReq->userRef = cownref;
18999       execFragReq->tableId = fragptr.p->tabRef;
19000       execFragReq->fragId = fragptr.p->fragId;
19001       execFragReq->startGci = fragptr.p->srStartGci[index];
19002       execFragReq->lastGci = fragptr.p->srLastGci[index];
19003       execFragReq->dst = ref;
19004 
19005       if (isNdbMtLqh())
19006       {
19007         jam();
19008         // send via local proxy
19009         sendSignal(DBLQH_REF, GSN_EXEC_FRAGREQ, signal,
19010                    ExecFragReq::SignalLength, JBB);
19011       }
19012       else if (ndb_route_exec_frag(getNodeInfo(refToNode(ref)).m_version))
19013       {
19014         jam();
19015         // send via remote proxy
19016         sendSignal(numberToRef(DBLQH, refToNode(ref)), GSN_EXEC_FRAGREQ, signal,
19017                    ExecFragReq::SignalLength, JBB);
19018       }
19019       else
19020       {
19021         jam();
19022         // send direct
19023         sendSignal(ref, GSN_EXEC_FRAGREQ, signal,
19024                    ExecFragReq::SignalLength, JBB);
19025       }
19026     }
19027     signal->theData[0] = next;
19028     sendSignal(cownref, GSN_START_EXEC_SR, signal, 1, JBB);
19029   }//if
19030   return;
19031 }//Dblqh::execSTART_EXEC_SR()
19032 
19033 /* ***************> */
19034 /*  EXEC_FRAGREQ  > */
19035 /* ***************> */
19036 /* --------------------------------------------------------------------------
19037  *  THIS SIGNAL IS USED TO REQUEST THAT A FRAGMENT PARTICIPATES IN EXECUTING
19038  *  THE LOG IN THIS NODE.
19039  * ------------------------------------------------------------------------- */
execEXEC_FRAGREQ(Signal * signal)19040 void Dblqh::execEXEC_FRAGREQ(Signal* signal)
19041 {
19042   ExecFragReq * const execFragReq = (ExecFragReq *)&signal->theData[0];
19043   jamEntry();
19044   tabptr.i = execFragReq->tableId;
19045   Uint32 fragId = execFragReq->fragId;
19046   ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
19047   ndbrequire(getFragmentrec(signal, fragId));
19048 
19049   ndbrequire(fragptr.p->execSrNoReplicas < MAX_REPLICAS);
19050   fragptr.p->execSrBlockref[fragptr.p->execSrNoReplicas] = execFragReq->userRef;
19051   fragptr.p->execSrUserptr[fragptr.p->execSrNoReplicas] = execFragReq->userPtr;
19052   fragptr.p->execSrStartGci[fragptr.p->execSrNoReplicas] = execFragReq->startGci;
19053   fragptr.p->execSrLastGci[fragptr.p->execSrNoReplicas] = execFragReq->lastGci;
19054   fragptr.p->execSrStatus = Fragrecord::ACTIVE;
19055   fragptr.p->execSrNoReplicas++;
19056   cnoFragmentsExecSr++;
19057   return;
19058 }//Dblqh::execEXEC_FRAGREQ()
19059 
sendExecFragRefLab(Signal * signal)19060 void Dblqh::sendExecFragRefLab(Signal* signal)
19061 {
19062   ExecFragReq * const execFragReq = (ExecFragReq *)&signal->theData[0];
19063   BlockReference retRef = execFragReq->userRef;
19064   Uint32 retPtr = execFragReq->userPtr;
19065 
19066   signal->theData[0] = retPtr;
19067   signal->theData[1] = terrorCode;
19068   sendSignal(retRef, GSN_EXEC_FRAGREF, signal, 2, JBB);
19069   return;
19070 }//Dblqh::sendExecFragRefLab()
19071 
19072 /* ***************>> */
19073 /*  EXEC_FRAGCONF  > */
19074 /* ***************>> */
execEXEC_FRAGCONF(Signal * signal)19075 void Dblqh::execEXEC_FRAGCONF(Signal* signal)
19076 {
19077   jamEntry();
19078   fragptr.i = signal->theData[0];
19079   c_fragment_pool.getPtr(fragptr);
19080   fragptr.p->srStatus = Fragrecord::SS_COMPLETED;
19081 
19082   ndbrequire(cnoOutstandingExecFragReq);
19083   cnoOutstandingExecFragReq--;
19084   if (fragptr.p->srNoLognodes == csrPhasesCompleted + 1)
19085   {
19086     jam();
19087 
19088     fragptr.p->logFlag = Fragrecord::STATE_TRUE;
19089     fragptr.p->fragStatus = Fragrecord::FSACTIVE;
19090 
19091     signal->theData[0] = fragptr.p->srUserptr;
19092     signal->theData[1] = cownNodeid;
19093     sendSignal(fragptr.p->srBlockref, GSN_START_FRAGCONF, signal, 2, JBB);
19094   }
19095 
19096   return;
19097 }//Dblqh::execEXEC_FRAGCONF()
19098 
19099 /* ***************> */
19100 /*  EXEC_FRAGREF  > */
19101 /* ***************> */
execEXEC_FRAGREF(Signal * signal)19102 void Dblqh::execEXEC_FRAGREF(Signal* signal)
19103 {
19104   jamEntry();
19105   terrorCode = signal->theData[1];
19106   systemErrorLab(signal, __LINE__);
19107   return;
19108 }//Dblqh::execEXEC_FRAGREF()
19109 
19110 /* *************** */
19111 /*  EXEC_SRCONF  > */
19112 /* *************** */
execEXEC_SRCONF(Signal * signal)19113 void Dblqh::execEXEC_SRCONF(Signal* signal)
19114 {
19115   jamEntry();
19116   Uint32 nodeId = signal->theData[0];
19117   arrGuard(nodeId, MAX_NDB_NODES);
19118   g_eventLogger->info("LDM(%u): Node %u completed LDM restart"
19119                       " phase 3",
19120                       instance(),
19121                       nodeId);
19122   m_sr_exec_sr_conf.set(nodeId);
19123 
19124   if (!m_sr_nodes.equal(m_sr_exec_sr_conf))
19125   {
19126     jam();
19127     /* ------------------------------------------------------------------
19128      *  ALL NODES HAVE NOT REPORTED COMPLETION OF EXECUTING FRAGMENT
19129      *  LOGS YET.
19130      * ----------------------------------------------------------------- */
19131     return;
19132   }
19133 
19134   if (cnoOutstandingExecFragReq != 0)
19135   {
19136     /**
19137      * This should now have been fixed!
19138      *   but could occur during upgrade
19139      * old: wl4391_todo workaround until timing fixed
19140      */
19141     jam();
19142     ndbassert(false);
19143     m_sr_exec_sr_conf.clear(nodeId);
19144     ndbout << "delay: reqs=" << cnoOutstandingExecFragReq << endl;
19145     sendSignalWithDelay(reference(), GSN_EXEC_SRCONF,
19146                         signal, 10, signal->getLength());
19147     return;
19148   }
19149 
19150   /* ------------------------------------------------------------------------
19151    *  CLEAR NODE SYSTEM RESTART EXECUTION STATE TO PREPARE FOR NEXT PHASE OF
19152    *  LOG EXECUTION.
19153    * ----------------------------------------------------------------------- */
19154   m_sr_exec_sr_conf.clear();
19155   cnoFragmentsExecSr = 0;
19156 
19157   /* ------------------------------------------------------------------------
19158    *  NOW CHECK IF ALL FRAGMENTS IN THIS PHASE HAVE COMPLETED. IF SO START THE
19159    *  NEXT PHASE.
19160    * ----------------------------------------------------------------------- */
19161   ndbrequire(cnoOutstandingExecFragReq == 0);
19162 
19163   execSrCompletedLab(signal);
19164   return;
19165 }//Dblqh::execEXEC_SRCONF()
19166 
execSrCompletedLab(Signal * signal)19167 void Dblqh::execSrCompletedLab(Signal* signal)
19168 {
19169   csrPhasesCompleted++;
19170 
19171   /* ------------------------------------------------------------------------
19172    *  ALL FRAGMENTS WERE COMPLETED. THIS PHASE IS COMPLETED. IT IS NOW TIME TO
19173    *  START THE NEXT PHASE.
19174    * ----------------------------------------------------------------------- */
19175   if (csrPhasesCompleted >= MAX_LOG_EXEC) {
19176     jam();
19177     /* ----------------------------------------------------------------------
19178      *  THIS WAS THE LAST PHASE. WE HAVE NOW COMPLETED THE EXECUTION THE
19179      *  FRAGMENT LOGS IN ALL NODES. BEFORE WE SEND START_RECCONF TO THE
19180      *  MASTER DIH TO INDICATE A COMPLETED SYSTEM RESTART IT IS NECESSARY
19181      *  TO FIND THE HEAD AND THE TAIL OF THE LOG WHEN NEW OPERATIONS START
19182      *  TO COME AGAIN.
19183      *
19184      * THE FIRST STEP IS TO FIND THE HEAD AND TAIL MBYTE OF EACH LOG PART.
19185      * TO DO THIS WE REUSE THE CONTINUEB SIGNAL SR_LOG_LIMITS. THEN WE
19186      * HAVE TO FIND THE ACTUAL PAGE NUMBER AND PAGE INDEX WHERE TO
19187      * CONTINUE WRITING THE LOG AFTER THE SYSTEM RESTART.
19188      * --------------------------------------------------------------------- */
19189     g_eventLogger->info("LDM(%u): REDO log execution completed, now"
19190                         " finding the new log head + tail",
19191                         instance());
19192 
19193     for (logPartPtr.i = 0; logPartPtr.i < clogPartFileSize; logPartPtr.i++) {
19194       jam();
19195       ptrAss(logPartPtr, logPartRecord);
19196       logPartPtr.p->logPartState = LogPartRecord::SR_FOURTH_PHASE_STARTED;
19197       logPartPtr.p->logLastGci = crestartNewestGci;
19198       logPartPtr.p->logStartGci = crestartOldestGci;
19199       logPartPtr.p->logExecState = LogPartRecord::LES_SEARCH_STOP;
19200       if (logPartPtr.p->headFileNo == ZNIL) {
19201         jam();
19202 	/* -----------------------------------------------------------------
19203 	 *  IF WE HAVEN'T FOUND ANY HEAD OF THE LOG THEN WE ARE IN SERIOUS
19204 	 *  PROBLEM.  THIS SHOULD NOT OCCUR. IF IT OCCURS ANYWAY THEN WE
19205 	 *  HAVE TO FIND A CURE FOR THIS PROBLEM.
19206 	 * ----------------------------------------------------------------- */
19207         systemErrorLab(signal, __LINE__);
19208         return;
19209       }//if
19210 
19211       if (DEBUG_REDO)
19212       {
19213         ndbout_c("part: %u srLogLimits SR_FOURTH_PHASE %u-%u (file: %u mb: %u)",
19214                  logPartPtr.p->logPartNo,
19215                  logPartPtr.p->logStartGci,
19216                  logPartPtr.p->logLastGci,
19217                  logPartPtr.p->lastLogfile,
19218                  logPartPtr.p->lastMbyte);
19219       }
19220 
19221       signal->theData[0] = ZSR_LOG_LIMITS;
19222       signal->theData[1] = logPartPtr.i;
19223       signal->theData[2] = logPartPtr.p->lastLogfile;
19224       signal->theData[3] = logPartPtr.p->lastMbyte;
19225       sendSignal(cownref, GSN_CONTINUEB, signal, 4, JBB);
19226     }//for
19227     return;
19228   }
19229   else
19230   {
19231     jam();
19232     /* ----------------------------------------------------------------------
19233      *   THERE ARE YET MORE PHASES TO RESTART.
19234      *   WE MUST INITIALISE DATA FOR NEXT PHASE AND SEND START SIGNAL.
19235      * --------------------------------------------------------------------- */
19236     csrPhaseStarted = ZSR_PHASE1_COMPLETED; // Set correct state first...
19237     g_eventLogger->info("LDM(%u): Starting REDO log execution"
19238                         " phase %u",
19239                         instance(),
19240                         csrPhasesCompleted);
19241     startExecSr(signal);
19242   }//if
19243   return;
19244 }//Dblqh::execSrCompletedLab()
19245 
19246 /* ************>> */
19247 /*  EXEC_SRREQ  > */
19248 /* ************>> */
execEXEC_SRREQ(Signal * signal)19249 void Dblqh::execEXEC_SRREQ(Signal* signal)
19250 {
19251   jamEntry();
19252   Uint32 nodeId = signal->theData[0];
19253   ndbrequire(nodeId < MAX_NDB_NODES);
19254   g_eventLogger->info("LDM(%u): Node %u ready to execute REDO log",
19255                       instance(),
19256                       nodeId);
19257   m_sr_exec_sr_req.set(nodeId);
19258   if (!m_sr_exec_sr_req.equal(m_sr_nodes))
19259   {
19260     jam();
19261     return;
19262   }
19263 
19264   /* ------------------------------------------------------------------------
19265    *  CLEAR NODE SYSTEM RESTART STATE TO PREPARE FOR NEXT PHASE OF LOG
19266    *  EXECUTION
19267    * ----------------------------------------------------------------------- */
19268   m_sr_exec_sr_req.clear();
19269 
19270   g_eventLogger->info("LDM(%u): All starting nodes ready"
19271                       " to execute REDO log.  Phases completed = %u",
19272                       instance(),
19273                       csrPhasesCompleted);
19274 
19275   if (csrPhasesCompleted != 0) {
19276     /* ----------------------------------------------------------------------
19277      *       THE FIRST PHASE MUST ALWAYS EXECUTE THE LOG.
19278      * --------------------------------------------------------------------- */
19279     if (cnoFragmentsExecSr == 0) {
19280       jam();
19281       /* --------------------------------------------------------------------
19282        *  THERE WERE NO FRAGMENTS THAT NEEDED TO EXECUTE THE LOG IN THIS PHASE.
19283        * ------------------------------------------------------------------- */
19284       srPhase3Comp(signal);
19285       return;
19286     }//if
19287   }//if
19288   /* ------------------------------------------------------------------------
19289    *  NOW ALL NODES HAVE SENT ALL EXEC_FRAGREQ. NOW WE CAN START EXECUTING THE
19290    *  LOG FROM THE MINIMUM GCI NEEDED UNTIL THE MAXIMUM GCI NEEDED.
19291    *
19292    *  WE MUST FIRST CHECK IF THE FIRST PHASE OF THE SYSTEM RESTART HAS BEEN
19293    *  COMPLETED. THIS HANDLING IS PERFORMED IN THE FILE SYSTEM MODULE
19294    * ----------------------------------------------------------------------- */
19295 
19296   g_eventLogger->info("LDM(%u):"
19297                       "Ready to start execute REDO log phase,"
19298                       " collect REDO log execution info phase completed",
19299                       instance());
19300 
19301   signal->theData[0] = ZSR_PHASE3_START;
19302   signal->theData[1] = ZSR_PHASE2_COMPLETED;
19303   sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
19304   return;
19305 }//Dblqh::execEXEC_SRREQ()
19306 
19307 /* ######################################################################### */
19308 /*       SYSTEM RESTART PHASE THREE MODULE                                   */
19309 /*       THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING.            */
19310 /*                                                                           */
19311 /* THIS MODULE IS CONCERNED WITH EXECUTING THE FRAGMENT LOG. IT DOES ALSO    */
19312 /* CONTAIN SIGNAL RECEPTIONS LQHKEYCONF AND LQHKEYREF SINCE LQHKEYREQ IS USED*/
19313 /* TO EXECUTE THE LOG RECORDS.                                               */
19314 /*                                                                           */
19315 /* BEFORE IT STARTS IT HAS BEEN DECIDED WHERE TO START AND WHERE TO STOP     */
19316 /* READING THE FRAGMENT LOG BY USING THE INFORMATION ABOUT GCI DISCOVERED IN */
19317 /* PHASE ONE OF THE SYSTEM RESTART.                                          */
19318 /* ######################################################################### */
19319 /*---------------------------------------------------------------------------*/
19320 /* PHASE THREE OF THE SYSTEM RESTART CAN NOW START. ONE OF THE PHASES HAVE   */
19321 /* COMPLETED.                                                                */
19322 /*---------------------------------------------------------------------------*/
srPhase3Start(Signal * signal)19323 void Dblqh::srPhase3Start(Signal* signal)
19324 {
19325   UintR tsrPhaseStarted;
19326 
19327   jamEntry();
19328 
19329   tsrPhaseStarted = signal->theData[1];
19330   if (csrPhaseStarted == ZSR_NO_PHASE_STARTED) {
19331     jam();
19332     csrPhaseStarted = tsrPhaseStarted;
19333     return;
19334   }//if
19335   ndbrequire(csrPhaseStarted != tsrPhaseStarted);
19336   ndbrequire(csrPhaseStarted != ZSR_BOTH_PHASES_STARTED);
19337 
19338   csrPhaseStarted = ZSR_BOTH_PHASES_STARTED;
19339   for (logPartPtr.i = 0; logPartPtr.i < clogPartFileSize; logPartPtr.i++) {
19340     jam();
19341     ptrAss(logPartPtr, logPartRecord);
19342     logPartPtr.p->logPartState = LogPartRecord::SR_THIRD_PHASE_STARTED;
19343     logPartPtr.p->logStartGci = (UintR)-1;
19344     if (csrPhasesCompleted == 0) {
19345       jam();
19346       /* --------------------------------------------------------------------
19347        *  THE FIRST PHASE WE MUST ENSURE THAT IT REACHES THE END OF THE LOG.
19348        * ------------------------------------------------------------------- */
19349       logPartPtr.p->logLastGci = crestartNewestGci;
19350     } else {
19351       jam();
19352       logPartPtr.p->logLastGci = 2;
19353     }//if
19354   }//for
19355 
19356   jam();
19357   c_lcp_complete_fragments.first(fragptr);
19358   signal->theData[0] = ZSR_GCI_LIMITS;
19359   signal->theData[1] = fragptr.i;
19360   sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
19361   return;
19362 }//Dblqh::srPhase3Start()
19363 
19364 /* --------------------------------------------------------------------------
19365  *   WE NOW WE NEED TO FIND THE LIMITS WITHIN WHICH TO EXECUTE
19366  *   THE FRAGMENT LOG
19367  * ------------------------------------------------------------------------- */
srGciLimits(Signal * signal)19368 void Dblqh::srGciLimits(Signal* signal)
19369 {
19370   jamEntry();
19371   fragptr.i = signal->theData[0];
19372   Uint32 loopCount = 0;
19373   logPartPtr.i = 0;
19374   ptrAss(logPartPtr, logPartRecord);
19375   while (fragptr.i != RNIL){
19376     jam();
19377     c_lcp_complete_fragments.getPtr(fragptr);
19378     ndbrequire(fragptr.p->execSrNoReplicas - 1 < MAX_REPLICAS);
19379     for (Uint32 i = 0; i < fragptr.p->execSrNoReplicas; i++) {
19380       jam();
19381       if (fragptr.p->execSrStartGci[i] < logPartPtr.p->logStartGci) {
19382 	jam();
19383 	logPartPtr.p->logStartGci = fragptr.p->execSrStartGci[i];
19384       }//if
19385       if (fragptr.p->execSrLastGci[i] > logPartPtr.p->logLastGci) {
19386 	jam();
19387 	logPartPtr.p->logLastGci = fragptr.p->execSrLastGci[i];
19388       }
19389     }
19390 
19391     loopCount++;
19392     if (loopCount > 20) {
19393       jam();
19394       signal->theData[0] = ZSR_GCI_LIMITS;
19395       signal->theData[1] = fragptr.p->nextList;
19396       sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
19397       return;
19398     } else {
19399       jam();
19400       fragptr.i = fragptr.p->nextList;
19401     }//if
19402   }
19403 
19404   if (logPartPtr.p->logStartGci == (UintR)-1) {
19405     jam();
19406       /* --------------------------------------------------------------------
19407        *  THERE WERE NO FRAGMENTS TO INSTALL WE WILL EXECUTE THE LOG AS
19408        *  SHORT AS POSSIBLE TO REACH THE END OF THE LOG. THIS WE DO BY
19409        *  STARTING AT THE STOP GCI.
19410        * ------------------------------------------------------------------- */
19411     logPartPtr.p->logStartGci = logPartPtr.p->logLastGci;
19412   }//if
19413 
19414   for(Uint32 i = 1; i < clogPartFileSize; i++)
19415   {
19416     LogPartRecordPtr tmp;
19417     tmp.i = i;
19418     ptrAss(tmp, logPartRecord);
19419     tmp.p->logStartGci = logPartPtr.p->logStartGci;
19420     tmp.p->logLastGci = logPartPtr.p->logLastGci;
19421   }
19422 
19423   for (logPartPtr.i = 0; logPartPtr.i < clogPartFileSize; logPartPtr.i++) {
19424     jam();
19425     ptrAss(logPartPtr, logPartRecord);
19426     logPartPtr.p->logExecState = LogPartRecord::LES_SEARCH_STOP;
19427     if (DEBUG_REDO)
19428     {
19429       ndbout_c("part: %u srLogLimits (srGciLimits) %u-%u (file: %u mb: %u)",
19430                logPartPtr.p->logPartNo,
19431                logPartPtr.p->logStartGci,
19432                logPartPtr.p->logLastGci,
19433                logPartPtr.p->lastLogfile,
19434                logPartPtr.p->lastMbyte);
19435     }
19436     signal->theData[0] = ZSR_LOG_LIMITS;
19437     signal->theData[1] = logPartPtr.i;
19438     signal->theData[2] = logPartPtr.p->lastLogfile;
19439     signal->theData[3] = logPartPtr.p->lastMbyte;
19440     sendSignal(cownref, GSN_CONTINUEB, signal, 4, JBB);
19441 
19442     logFilePtr.i = logPartPtr.p->lastLogfile;
19443     ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
19444     g_eventLogger->info("LDM(%u): Log part %u will execute REDO log"
19445                         " records from GCI %u -> %u and last log file is "
19446                         "number %u and last MByte in this file is %u",
19447                         instance(),
19448                         logPartPtr.p->logPartNo,
19449                         logPartPtr.p->logStartGci,
19450                         logPartPtr.p->logLastGci,
19451                         logFilePtr.p->fileNo, /* fileNo of last log file */
19452                         logPartPtr.p->lastMbyte);
19453   }//for
19454 }//Dblqh::srGciLimits()
19455 
19456 /* --------------------------------------------------------------------------
19457  *       IT IS NOW TIME TO FIND WHERE TO START EXECUTING THE LOG.
19458  *       THIS SIGNAL IS SENT FOR EACH LOG PART AND STARTS THE EXECUTION
19459  *       OF THE LOG FOR THIS PART.
19460  *-------------------------------------------------------------------------- */
srLogLimits(Signal * signal)19461 void Dblqh::srLogLimits(Signal* signal)
19462 {
19463   Uint32 tlastPrepRef;
19464   Uint32 tmbyte;
19465 
19466   jamEntry();
19467   logPartPtr.i = signal->theData[0];
19468   ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
19469   logFilePtr.i = signal->theData[1];
19470   ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
19471   tmbyte = signal->theData[2];
19472   Uint32 loopCount = 0;
19473   /* ------------------------------------------------------------------------
19474    *   WE ARE SEARCHING FOR THE START AND STOP MBYTE OF THE LOG THAT IS TO BE
19475    *   EXECUTED.
19476    * ----------------------------------------------------------------------- */
19477   while(true) {
19478     ndbrequire(tmbyte < clogFileSize);
19479     if (logPartPtr.p->logExecState == LogPartRecord::LES_SEARCH_STOP)
19480     {
19481       if (logFilePtr.p->logMaxGciCompleted[tmbyte] <= logPartPtr.p->logLastGci)
19482       {
19483         jam();
19484         /* --------------------------------------------------------------------
19485          *  WE ARE STEPPING BACKWARDS FROM MBYTE TO MBYTE. THIS IS THE FIRST
19486          *  MBYTE WHICH IS TO BE INCLUDED IN THE LOG EXECUTION. THE STOP GCI
19487          *  HAS NOT BEEN COMPLETED BEFORE THIS MBYTE. THUS THIS MBYTE HAVE
19488          *  TO BE EXECUTED.
19489          * ------------------------------------------------------------------ */
19490         logPartPtr.p->stopLogfile = logFilePtr.i;
19491         logPartPtr.p->stopMbyte = tmbyte;
19492         logPartPtr.p->logExecState = LogPartRecord::LES_SEARCH_START;
19493         if (DEBUG_REDO)
19494         {
19495           ndbout_c("part: %u srLogLimits found stop pos file: %u mb: %u logMaxGciCompleted[tmbyte]: %u (lastGci: %u)",
19496                    logPartPtr.p->logPartNo,
19497                    logFilePtr.p->fileNo,
19498                    tmbyte,
19499                    logFilePtr.p->logMaxGciCompleted[tmbyte],
19500                    logPartPtr.p->logLastGci);
19501         }
19502       }//if
19503       else if (DEBUG_REDO)
19504       {
19505         ndbout_c("SEARCH STOP SKIP part: %u file: %u mb: %u "
19506                  "logMaxGciCompleted: %u > %u",
19507                  logPartPtr.p->logPartNo,
19508                  logFilePtr.p->fileNo,
19509                  tmbyte,
19510                  logFilePtr.p->logMaxGciCompleted[tmbyte],
19511                  logPartPtr.p->logLastGci);
19512       }
19513     }//if
19514     /* ------------------------------------------------------------------------
19515      *  WHEN WE HAVEN'T FOUND THE STOP MBYTE IT IS NOT NECESSARY TO LOOK FOR THE
19516      *  START MBYTE. THE REASON IS THE FOLLOWING LOGIC CHAIN:
19517      *    MAX_GCI_STARTED >= MAX_GCI_COMPLETED >= LAST_GCI >= START_GCI
19518      *  THUS MAX_GCI_STARTED >= START_GCI. THUS MAX_GCI_STARTED < START_GCI CAN
19519      *  NOT BE TRUE AS WE WILL CHECK OTHERWISE.
19520      * ---------------------------------------------------------------------- */
19521     if (logPartPtr.p->logExecState == LogPartRecord::LES_SEARCH_START)
19522     {
19523       if (logFilePtr.p->logMaxGciStarted[tmbyte] < logPartPtr.p->logStartGci)
19524       {
19525         jam();
19526         /* --------------------------------------------------------------------
19527          *  WE HAVE NOW FOUND THE START OF THE EXECUTION OF THE LOG.
19528          *  WE STILL HAVE TO MOVE IT BACKWARDS TO ALSO INCLUDE THE
19529          *  PREPARE RECORDS WHICH WERE STARTED IN A PREVIOUS MBYTE.
19530          * ------------------------------------------------------------------ */
19531         if (DEBUG_REDO)
19532         {
19533           ndbout_c("part: %u srLogLimits found start pos file: %u mb: %u logMaxGciStarted[tmbyte]: %u (startGci: %u)",
19534                    logPartPtr.p->logPartNo,
19535                    logFilePtr.p->fileNo,
19536                    tmbyte,
19537                    logFilePtr.p->logMaxGciCompleted[tmbyte],
19538                    logPartPtr.p->logStartGci);
19539           ndbout_c("part: %u srLogLimits lastPrepRef => file: %u mb: %u",
19540                    logPartPtr.p->logPartNo,
19541                    logFilePtr.p->logLastPrepRef[tmbyte] >> 16,
19542                    logFilePtr.p->logLastPrepRef[tmbyte] & 65535);
19543         }
19544         tlastPrepRef = logFilePtr.p->logLastPrepRef[tmbyte];
19545         logPartPtr.p->startMbyte = tlastPrepRef & 65535;
19546         LogFileRecordPtr locLogFilePtr;
19547         findLogfile(signal, tlastPrepRef >> 16, logPartPtr, &locLogFilePtr);
19548         logPartPtr.p->startLogfile = locLogFilePtr.i;
19549         logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG;
19550       }
19551       else if (DEBUG_REDO)
19552       {
19553         ndbout_c("SEARCH START SKIP part: %u file: %u mb: %u "
19554                  "logMaxGciCompleted: %u >= %u",
19555                  logPartPtr.p->logPartNo,
19556                  logFilePtr.p->fileNo,
19557                  tmbyte,
19558                  logFilePtr.p->logMaxGciStarted[tmbyte],
19559                  logPartPtr.p->logStartGci);
19560       }
19561     }//if
19562     if (logPartPtr.p->logExecState != LogPartRecord::LES_EXEC_LOG) {
19563       if (tmbyte == 0) {
19564         jam();
19565         tmbyte = clogFileSize - 1;
19566         logFilePtr.i = logFilePtr.p->prevLogFile;
19567         ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
19568       } else {
19569         jam();
19570         tmbyte--;
19571       }//if
19572       if (logPartPtr.p->lastLogfile == logFilePtr.i) {
19573         ndbrequire(logPartPtr.p->lastMbyte != tmbyte);
19574       }//if
19575       if (loopCount > 20) {
19576         jam();
19577         signal->theData[0] = ZSR_LOG_LIMITS;
19578         signal->theData[1] = logPartPtr.i;
19579         signal->theData[2] = logFilePtr.i;
19580         signal->theData[3] = tmbyte;
19581         sendSignal(cownref, GSN_CONTINUEB, signal, 4, JBB);
19582         return;
19583       }//if
19584       loopCount++;
19585     } else {
19586       jam();
19587       break;
19588     }//if
19589   }//while
19590 
19591   if (DEBUG_REDO)
19592   {
19593     LogFileRecordPtr tmp;
19594     tmp.i = logPartPtr.p->stopLogfile;
19595     ptrCheckGuard(tmp, clogFileFileSize, logFileRecord);
19596     ndbout_c("srLogLimits part: %u gci: %u-%u start file: %u mb: %u stop file: %u mb: %u",
19597              logPartPtr.p->logPartNo,
19598              logPartPtr.p->logStartGci,
19599              logPartPtr.p->logLastGci,
19600              tlastPrepRef >> 16,
19601              tlastPrepRef & 65535,
19602              tmp.p->fileNo,
19603              logPartPtr.p->stopMbyte);
19604   }
19605 
19606 
19607 
19608   /* ------------------------------------------------------------------------
19609    *  WE HAVE NOW FOUND BOTH THE START AND THE STOP OF THE LOG. NOW START
19610    *  EXECUTING THE LOG. THE FIRST ACTION IS TO OPEN THE LOG FILE WHERE TO
19611    *  START EXECUTING THE LOG.
19612    * ----------------------------------------------------------------------- */
19613   if (logPartPtr.p->logPartState == LogPartRecord::SR_THIRD_PHASE_STARTED) {
19614     jam();
19615     logFilePtr.i = logPartPtr.p->startLogfile;
19616     ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
19617     logFilePtr.p->logFileStatus = LogFileRecord::OPEN_EXEC_SR_START;
19618     openFileRw(signal, logFilePtr);
19619     g_eventLogger->info("LDM(%u): Start executing REDO log for"
19620                         " part %u",
19621                         instance(),
19622                         logPartPtr.p->logPartNo);
19623 
19624     send_runredo_event(signal, logPartPtr.p, logPartPtr.p->logStartGci);
19625   }
19626   else
19627   {
19628     jam();
19629 
19630     g_eventLogger->info("LDM(%u): Found log limits for REDO"
19631                         " post-restart for log part %u",
19632                         instance(),
19633                         logPartPtr.p->logPartNo);
19634 
19635     ndbrequire(logPartPtr.p->logPartState == LogPartRecord::SR_FOURTH_PHASE_STARTED);
19636       /* --------------------------------------------------------------------
19637        *  WE HAVE NOW FOUND THE TAIL MBYTE IN THE TAIL FILE.
19638        *  SET THOSE PARAMETERS IN THE LOG PART.
19639        *  WE HAVE ALSO FOUND THE HEAD MBYTE. WE STILL HAVE TO SEARCH
19640        *  FOR THE PAGE NUMBER AND PAGE INDEX WHERE TO SET THE HEAD.
19641        * ------------------------------------------------------------------- */
19642     logFilePtr.i = logPartPtr.p->startLogfile;
19643     ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
19644     logPartPtr.p->logTailFileNo = logFilePtr.p->fileNo;
19645     logPartPtr.p->logTailMbyte = logPartPtr.p->startMbyte;
19646       /* --------------------------------------------------------------------
19647        *  THE HEAD WE ACTUALLY FOUND DURING EXECUTION OF LOG SO WE USE
19648        *  THIS INFO HERE RATHER THAN THE MBYTE WE FOUND TO BE THE HEADER.
19649        * ------------------------------------------------------------------- */
19650     LogFileRecordPtr locLogFilePtr;
19651     findLogfile(signal, logPartPtr.p->headFileNo, logPartPtr, &locLogFilePtr);
19652     locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_FOURTH_PHASE;
19653     openFileRw(signal, locLogFilePtr);
19654   }//if
19655   return;
19656 }//Dblqh::srLogLimits()
19657 
openExecSrStartLab(Signal * signal)19658 void Dblqh::openExecSrStartLab(Signal* signal)
19659 {
19660   logPartPtr.p->currentLogfile = logFilePtr.i;
19661   logFilePtr.p->currentMbyte = logPartPtr.p->startMbyte;
19662   /* ------------------------------------------------------------------------
19663    *     WE NEED A TC CONNECT RECORD TO HANDLE EXECUTION OF LOG RECORDS.
19664    *     This will always succeed since we don't interact with user
19665    *     operations during recovery when we are applying the REDO log content.
19666    * ------------------------------------------------------------------------ */
19667   seizeTcrec();
19668   logPartPtr.p->logTcConrec = tcConnectptr.i;
19669   /* ------------------------------------------------------------------------
19670    *   THE FIRST LOG RECORD TO EXECUTE IS ALWAYS AT A NEW MBYTE.
19671    *   SET THE NUMBER OF PAGES IN THE MAIN MEMORY BUFFER TO ZERO AS AN INITIAL
19672    *   VALUE. THIS VALUE WILL BE UPDATED AND ENSURED THAT IT RELEASES PAGES IN
19673    *   THE SUBROUTINE READ_EXEC_SR.
19674    * ----------------------------------------------------------------------- */
19675   logPartPtr.p->mmBufferSize = 0;
19676   readExecSrNewMbyte(signal);
19677   return;
19678 }//Dblqh::openExecSrStartLab()
19679 
19680 /* ---------------------------------------------------------------------------
19681  *  WE WILL ALWAYS ENSURE THAT WE HAVE AT LEAST 16 KBYTE OF LOG PAGES WHEN WE
19682  *  START READING A LOG RECORD. THE ONLY EXCEPTION IS WHEN WE COME CLOSE TO A
19683  *  MBYTE BOUNDARY. SINCE WE KNOW THAT LOG RECORDS ARE NEVER WRITTEN ACROSS A
19684  *  MBYTE BOUNDARY THIS IS NOT A PROBLEM.
19685  *
19686  *  WE START BY READING 64 KBYTE BEFORE STARTING TO EXECUTE THE LOG RECORDS.
19687  *  WHEN WE COME BELOW 64 KBYTE WE READ ANOTHER SET OF LOG PAGES. WHEN WE
19688  *  GO BELOW 16 KBYTE WE WAIT UNTIL THE READ PAGES HAVE ENTERED THE BLOCK.
19689  * ------------------------------------------------------------------------- */
19690 /* --------------------------------------------------------------------------
19691  *       NEW PAGES FROM LOG FILE DURING EXECUTION OF LOG HAS ARRIVED.
19692  * ------------------------------------------------------------------------- */
readExecSrLab(Signal * signal)19693 void Dblqh::readExecSrLab(Signal* signal)
19694 {
19695   buildLinkedLogPageList(signal);
19696   /* ------------------------------------------------------------------------
19697    *   WE NEED TO SET THE CURRENT PAGE INDEX OF THE FIRST PAGE SINCE IT CAN BE
19698    *   USED IMMEDIATELY WITHOUT ANY OTHER INITIALISATION. THE REST OF THE PAGES
19699    *   WILL BE INITIALISED BY READ_LOGWORD.
19700    * ----------------------------------------------------------------------- */
19701   logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = ZPAGE_HEADER_SIZE;
19702   if (logPartPtr.p->logExecState ==
19703       LogPartRecord::LES_WAIT_READ_EXEC_SR_NEW_MBYTE) {
19704     jam();
19705     /* ----------------------------------------------------------------------
19706      *  THIS IS THE FIRST READ DURING THE EXECUTION OF THIS MBYTE. SET THE
19707      *  NEW CURRENT LOG PAGE TO THE FIRST OF THESE PAGES. CHANGE
19708      *  LOG_EXEC_STATE TO ENSURE THAT WE START EXECUTION OF THE LOG.
19709      * --------------------------------------------------------------------- */
19710     logFilePtr.p->currentFilepage = logFilePtr.p->currentMbyte *
19711                                     ZPAGES_IN_MBYTE;
19712     logPartPtr.p->prevFilepage = logFilePtr.p->currentFilepage;
19713     logFilePtr.p->currentLogpage = lfoPtr.p->firstLfoPage;
19714     logPartPtr.p->prevLogpage = logFilePtr.p->currentLogpage;
19715   }//if
19716   moveToPageRef(signal);
19717   releaseLfo(signal);
19718   /* ------------------------------------------------------------------------
19719    *  NOW WE HAVE COMPLETED THE RECEPTION OF THESE PAGES.
19720    *  NOW CHECK IF WE NEED TO READ MORE PAGES.
19721    * ----------------------------------------------------------------------- */
19722   checkReadExecSr(signal);
19723   if (logPartPtr.p->logExecState == LogPartRecord::LES_EXEC_LOG) {
19724     jam();
19725     signal->theData[0] = ZEXEC_SR;
19726     signal->theData[1] = logPartPtr.i;
19727     sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
19728     return;
19729   }//if
19730   return;
19731 }//Dblqh::readExecSrLab()
19732 
openExecSrNewMbyteLab(Signal * signal)19733 void Dblqh::openExecSrNewMbyteLab(Signal* signal)
19734 {
19735   readExecSrNewMbyte(signal);
19736   return;
19737 }//Dblqh::openExecSrNewMbyteLab()
19738 
closeExecSrLab(Signal * signal)19739 void Dblqh::closeExecSrLab(Signal* signal)
19740 {
19741   LogFileRecordPtr locLogFilePtr;
19742   logFilePtr.p->logFileStatus = LogFileRecord::CLOSED;
19743   logPartPtr.i = logFilePtr.p->logPartRec;
19744   ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
19745   locLogFilePtr.i = logPartPtr.p->currentLogfile;
19746   ptrCheckGuard(locLogFilePtr, clogFileFileSize, logFileRecord);
19747   locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_EXEC_SR_NEW_MBYTE;
19748   openFileRw(signal, locLogFilePtr);
19749   return;
19750 }//Dblqh::closeExecSrLab()
19751 
writeDirtyLab(Signal * signal)19752 void Dblqh::writeDirtyLab(Signal* signal)
19753 {
19754   releaseLfo(signal);
19755   signal->theData[0] = logPartPtr.i;
19756   execSr(signal);
19757   return;
19758 }//Dblqh::writeDirtyLab()
19759 
19760 /* --------------------------------------------------------------------------
19761  *       EXECUTE A LOG RECORD WITHIN THE CURRENT MBYTE.
19762  * ------------------------------------------------------------------------- */
execSr(Signal * signal)19763 void Dblqh::execSr(Signal* signal)
19764 {
19765   LogFileRecordPtr nextLogFilePtr;
19766   LogPageRecordPtr tmpLogPagePtr;
19767   Uint32 logWord;
19768   Uint32 line;
19769   const char * crash_msg = 0;
19770 
19771   jamEntry();
19772   logPartPtr.i = signal->theData[0];
19773   ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
19774 
19775   do {
19776     jam();
19777     logFilePtr.i = logPartPtr.p->currentLogfile;
19778     ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
19779     logPagePtr.i = logPartPtr.p->prevLogpage;
19780     ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
19781     if (logPagePtr.p->logPageWord[ZPOS_DIRTY] == ZDIRTY) {
19782       jam();
19783       switch (logPartPtr.p->logExecState) {
19784       case LogPartRecord::LES_EXEC_LOG_COMPLETED:
19785       case LogPartRecord::LES_EXEC_LOG_NEW_FILE:
19786       case LogPartRecord::LES_EXEC_LOG_NEW_MBYTE:
19787         jam();
19788 	/* ------------------------------------------------------------------
19789 	 *  IN THIS WE HAVE COMPLETED EXECUTION OF THE CURRENT LOG PAGE
19790 	 *  AND CAN WRITE IT TO DISK SINCE IT IS DIRTY.
19791 	 * ----------------------------------------------------------------- */
19792         writeDirty(signal, __LINE__);
19793         return;
19794         break;
19795       case LogPartRecord::LES_EXEC_LOG:
19796       jam();
19797       /* --------------------------------------------------------------------
19798        *  IN THIS CASE WE ONLY WRITE THE PAGE TO DISK IF WE HAVE COMPLETED
19799        *  EXECUTION OF LOG RECORDS BELONGING TO THIS LOG PAGE.
19800        * ------------------------------------------------------------------- */
19801         if (logFilePtr.p->currentLogpage != logPartPtr.p->prevLogpage) {
19802           jam();
19803           writeDirty(signal, __LINE__);
19804           return;
19805         }//if
19806         break;
19807       default:
19808         ndbrequire(false);
19809         break;
19810       }//switch
19811     }//if
19812     if (logFilePtr.p->currentLogpage != logPartPtr.p->prevLogpage) {
19813       jam();
19814       logPartPtr.p->prevLogpage = logPagePtr.p->logPageWord[ZNEXT_PAGE];
19815       logPartPtr.p->prevFilepage++;
19816       continue;
19817     }//if
19818     switch (logPartPtr.p->logExecState) {
19819     case LogPartRecord::LES_EXEC_LOG_COMPLETED:
19820       jam();
19821       releaseMmPages(signal);
19822       logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_EXEC_SR_COMPLETED;
19823       closeFile(signal, logFilePtr, __LINE__);
19824       return;
19825       break;
19826     case LogPartRecord::LES_EXEC_LOG_NEW_MBYTE:
19827       jam();
19828       logFilePtr.p->currentMbyte++;
19829       readExecSrNewMbyte(signal);
19830       return;
19831       break;
19832     case LogPartRecord::LES_EXEC_LOG_NEW_FILE:
19833       jam();
19834       nextLogFilePtr.i = logFilePtr.p->nextLogFile;
19835       logPartPtr.p->currentLogfile = nextLogFilePtr.i;
19836       ptrCheckGuard(nextLogFilePtr, clogFileFileSize, logFileRecord);
19837       nextLogFilePtr.p->currentMbyte = 0;
19838       logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_EXEC_SR;
19839       closeFile(signal, logFilePtr, __LINE__);
19840       return;
19841       break;
19842     case LogPartRecord::LES_EXEC_LOG:
19843       jam();
19844       /*empty*/;
19845       break;
19846     default:
19847       jam();
19848       systemErrorLab(signal, __LINE__);
19849       return;
19850       break;
19851     }//switch
19852     logPagePtr.i = logFilePtr.p->currentLogpage;
19853     ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
19854     logPartPtr.p->savePageIndex = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX];
19855     if (logPartPtr.p->execSrPagesRead < ZMIN_READ_BUFFER_SIZE) {
19856       /* --------------------------------------------------------------------
19857        *  THERE WERE LESS THAN 16 KBYTE OF LOG PAGES REMAINING. WE WAIT UNTIL
19858        *  THE NEXT 64 KBYTE ARRIVES UNTIL WE CONTINUE AGAIN.
19859        * ------------------------------------------------------------------- */
19860       if ((logPartPtr.p->execSrPagesRead +
19861 	   logPartPtr.p->execSrPagesExecuted) < ZPAGES_IN_MBYTE) {
19862         jam();
19863 	/* ------------------------------------------------------------------
19864 	 *  WE ONLY STOP AND WAIT IF THERE MORE PAGES TO READ. IF IT IS NOT
19865 	 *  THEN IT IS THE END OF THE MBYTE AND WE WILL CONTINUE. IT IS NO
19866 	 *  RISK THAT A LOG RECORD WE FIND WILL NOT BE READ AT THIS TIME
19867 	 *  SINCE THE LOG RECORDS NEVER SPAN OVER A MBYTE BOUNDARY.
19868 	 * ----------------------------------------------------------------- */
19869         readExecSr(signal);
19870         logPartPtr.p->logExecState = LogPartRecord::LES_WAIT_READ_EXEC_SR;
19871         return;
19872       }//if
19873     }//if
19874     logWord = readLogword(signal);
19875     switch (logWord) {
19876 /* ========================================================================= */
19877 /* ========================================================================= */
19878     case ZPREP_OP_TYPE:
19879     {
19880       logWord = readLogword(signal);
19881       stepAhead(signal, logWord - 2);
19882       logPartPtr.p->m_redoWorkStats.m_opsPrepared++;
19883       break;
19884     }
19885 /* ========================================================================= */
19886 /* ========================================================================= */
19887     case ZINVALID_COMMIT_TYPE:
19888       jam();
19889       stepAhead(signal, ZCOMMIT_LOG_SIZE - 1);
19890       break;
19891 /* ========================================================================= */
19892 /* ========================================================================= */
19893     case ZCOMMIT_TYPE:
19894     {
19895       CommitLogRecord commitLogRecord;
19896       jam();
19897       tcConnectptr.i = logPartPtr.p->logTcConrec;
19898       ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
19899       readCommitLog(signal, &commitLogRecord);
19900       if (tcConnectptr.p->gci_hi > crestartNewestGci) {
19901         jam();
19902 /*---------------------------------------------------------------------------*/
19903 /* THIS LOG RECORD MUST BE IGNORED. IT IS PART OF A GLOBAL CHECKPOINT WHICH  */
19904 /* WILL BE INVALIDATED BY THE SYSTEM RESTART. IF NOT INVALIDATED IT MIGHT BE */
19905 /* EXECUTED IN A FUTURE SYSTEM RESTART.                                      */
19906 /*---------------------------------------------------------------------------*/
19907         tmpLogPagePtr.i = logPartPtr.p->prevLogpage;
19908         ptrCheckGuard(tmpLogPagePtr, clogPageFileSize, logPageRecord);
19909         arrGuard(logPartPtr.p->savePageIndex, ZPAGE_SIZE);
19910         tmpLogPagePtr.p->logPageWord[logPartPtr.p->savePageIndex] =
19911                                                   ZINVALID_COMMIT_TYPE;
19912         tmpLogPagePtr.p->logPageWord[ZPOS_DIRTY] = ZDIRTY;
19913       }
19914       else
19915       {
19916         jam();
19917 /*---------------------------------------------------------------------------*/
19918 /* CHECK IF I AM SUPPOSED TO EXECUTE THIS LOG RECORD. IF I AM THEN SAVE PAGE */
19919 /* INDEX IN CURRENT LOG PAGE SINCE IT WILL BE OVERWRITTEN WHEN EXECUTING THE */
19920 /* LOG RECORD.                                                               */
19921 /*---------------------------------------------------------------------------*/
19922         logPartPtr.p->execSrExecuteIndex = 0;
19923         Uint32 result = checkIfExecLog(signal);
19924         if (result == ZOK) {
19925           jam();
19926 //*---------------------------------------------------------------------------*/
19927 /* IN A NODE RESTART WE WILL NEVER END UP HERE SINCE NO FRAGMENTS HAVE BEEN  */
19928 /* DEFINED YET. THUS NO EXTRA CHECKING FOR NODE RESTART IS NECESSARY.        */
19929 /*---------------------------------------------------------------------------*/
19930           logPartPtr.p->savePageIndex =
19931              logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX];
19932           tcConnectptr.p->fragmentptr = fragptr.i;
19933           findPageRef(signal, &commitLogRecord);
19934           logPartPtr.p->execSrLogPageIndex = commitLogRecord.startPageIndex;
19935           if (logPagePtr.i != RNIL) {
19936             jam();
19937             logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = commitLogRecord.startPageIndex;
19938             logPartPtr.p->execSrLogPage = logPagePtr.i;
19939             execLogRecord(signal);
19940             return;
19941           }//if
19942           logPartPtr.p->execSrStartPageNo = commitLogRecord.startPageNo;
19943           logPartPtr.p->execSrStopPageNo = commitLogRecord.stopPageNo;
19944           findLogfile(signal, commitLogRecord.fileNo, logPartPtr, &logFilePtr);
19945           logPartPtr.p->execSrExecLogFile = logFilePtr.i;
19946           if (logFilePtr.i == logPartPtr.p->currentLogfile) {
19947             jam();
19948 #ifndef NO_REDO_PAGE_CACHE
19949             Uint32 cnt = 1 +
19950               logPartPtr.p->execSrStopPageNo - logPartPtr.p->execSrStartPageNo;
19951             evict(m_redo_page_cache, cnt);
19952 #endif
19953             readExecLog(signal);
19954             lfoPtr.p->lfoState = LogFileOperationRecord::READ_EXEC_LOG;
19955             return;
19956           } else {
19957             jam();
19958 /*---------------------------------------------------------------------------*/
19959 /* THE FILE IS CURRENTLY NOT OPEN. WE MUST OPEN IT BEFORE WE CAN READ FROM   */
19960 /* THE FILE.                                                                 */
19961 /*---------------------------------------------------------------------------*/
19962 #ifndef NO_REDO_OPEN_FILE_CACHE
19963             openFileRw_cache(signal, logFilePtr);
19964 #else
19965             logFilePtr.p->logFileStatus = LogFileRecord::OPEN_EXEC_LOG;
19966             openFileRw(signal, logFilePtr);
19967 #endif
19968             return;
19969           }//if
19970         }//if
19971         else
19972         {
19973           logPartPtr.p->m_redoWorkStats.m_opsSkipped++;
19974         }
19975       }//if
19976       break;
19977     }
19978 /* ========================================================================= */
19979 /* ========================================================================= */
19980     case ZABORT_TYPE:
19981       jam();
19982       stepAhead(signal, ZABORT_LOG_SIZE - 1);
19983       logPartPtr.p->m_redoWorkStats.m_opsSkipped++;
19984       break;
19985 /* ========================================================================= */
19986 /* ========================================================================= */
19987     case ZFD_TYPE:
19988       jam();
19989 /*---------------------------------------------------------------------------*/
19990 /* THIS IS THE FIRST ITEM WE ENCOUNTER IN A NEW FILE. AT THIS MOMENT WE SHALL*/
19991 /* SIMPLY BYPASS IT. IT HAS NO SIGNIFANCE WHEN EXECUTING THE LOG. IT HAS ITS */
19992 /* SIGNIFANCE WHEN FINDING THE START END THE END OF THE LOG.                 */
19993 /* WE HARDCODE THE PAGE INDEX SINCE THIS SHOULD NEVER BE FOUND AT ANY OTHER  */
19994 /* PLACE THAN IN THE FIRST PAGE OF A NEW FILE IN THE FIRST POSITION AFTER THE*/
19995 /* HEADER.                                                                   */
19996 /*---------------------------------------------------------------------------*/
19997       if (unlikely(logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] !=
19998 		   (ZPAGE_HEADER_SIZE + ZPOS_NO_FD)))
19999       {
20000 	line = __LINE__;
20001 	logWord = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX];
20002 	crash_msg = "ZFD_TYPE at incorrect position!";
20003 	goto crash;
20004       }
20005       {
20006         Uint32 noFdDescriptors =
20007 	  logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_NO_FD];
20008           logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] =
20009 	      (ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) +
20010 	      (noFdDescriptors * ZFD_MBYTE_SIZE * clogFileSize);
20011       }
20012       break;
20013 /* ========================================================================= */
20014 /* ========================================================================= */
20015     case ZNEXT_LOG_RECORD_TYPE:
20016       jam();
20017       stepAhead(signal, ZPAGE_SIZE - logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]);
20018       break;
20019 /* ========================================================================= */
20020 /* ========================================================================= */
20021     case ZNEXT_MBYTE_TYPE:
20022 /*---------------------------------------------------------------------------*/
20023 /* WE WILL SKIP A PART OF THE LOG FILE. ACTUALLY THE NEXT POINTER IS TO      */
20024 /* A NEW MBYTE. THEREFORE WE WILL START UP A NEW MBYTE. THIS NEW MBYTE IS    */
20025 /* HOWEVER ONLY STARTED IF IT IS NOT AFTER THE STOP MBYTE.                   */
20026 /* IF WE HAVE REACHED THE END OF THE STOP MBYTE THEN THE EXECUTION OF THE LOG*/
20027 /* IS COMPLETED.                                                             */
20028 /*---------------------------------------------------------------------------*/
20029       if (logPartPtr.p->currentLogfile == logPartPtr.p->stopLogfile) {
20030         if (logFilePtr.p->currentMbyte == logPartPtr.p->stopMbyte) {
20031           jam();
20032 /*---------------------------------------------------------------------------*/
20033 /* THIS WAS THE LAST MBYTE TO EXECUTE IN THIS LOG PART. WE SHOULD HAVE FOUND */
20034 /* A COMPLETED GCI RECORD OF THE LAST GCI BEFORE THIS. FOR SOME REASON THIS  */
20035 /* RECORD WAS NOT AVAILABLE ON THE LOG. CRASH THE SYSTEM, A VERY SERIOUS     */
20036 /* ERROR WHICH WE MUST REALLY WORK HARD TO AVOID.                            */
20037 /*---------------------------------------------------------------------------*/
20038 /*---------------------------------------------------------------------------*/
20039 /* SEND A SIGNAL TO THE SIGNAL LOG AND THEN CRASH THE SYSTEM.                */
20040 /*---------------------------------------------------------------------------*/
20041 	  line = __LINE__;
20042 	  logWord = ZNEXT_MBYTE_TYPE;
20043 	  crash_msg = "end of log wo/ having found last GCI";
20044 	  goto crash;
20045         }//if
20046       }//if
20047 /*---------------------------------------------------------------------------*/
20048 /* START EXECUTION OF A NEW MBYTE IN THE LOG.                                */
20049 /*---------------------------------------------------------------------------*/
20050       if (logFilePtr.p->currentMbyte < (clogFileSize - 1)) {
20051         jam();
20052         logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG_NEW_MBYTE;
20053       } else {
20054         ndbrequire(logFilePtr.p->currentMbyte == (clogFileSize - 1));
20055         jam();
20056 /*---------------------------------------------------------------------------*/
20057 /* WE HAVE TO CHANGE FILE. CLOSE THIS ONE AND THEN OPEN THE NEXT.            */
20058 /*---------------------------------------------------------------------------*/
20059         logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG_NEW_FILE;
20060       }//if
20061       break;
20062 /* ========================================================================= */
20063 /* ========================================================================= */
20064     case ZCOMPLETED_GCI_TYPE:
20065       jam();
20066       logWord = readLogword(signal);
20067       if (DEBUG_REDO)
20068       {
20069         ndbout_c("found gci: %u part: %u file: %u page: %u (mb: %u)",
20070                  logWord,
20071                  logPartPtr.p->logPartNo,
20072                  logFilePtr.p->fileNo,
20073                  logFilePtr.p->currentFilepage,
20074                  logFilePtr.p->currentFilepage >> ZTWOLOG_NO_PAGES_IN_MBYTE);
20075       }
20076       logPartPtr.p->m_redoWorkStats.m_gcisExecuted++;
20077       if (logWord == logPartPtr.p->logLastGci)
20078       {
20079         jam();
20080 /*---------------------------------------------------------------------------*/
20081 /* IF IT IS THE LAST GCI TO LIVE AFTER SYSTEM RESTART THEN WE RECORD THE NEXT*/
20082 /* WORD AS THE NEW HEADER OF THE LOG FILE. OTHERWISE WE SIMPLY IGNORE THIS   */
20083 /* LOG RECORD.                                                               */
20084 /*---------------------------------------------------------------------------*/
20085         if (csrPhasesCompleted == 0) {
20086           jam();
20087 /*---------------------------------------------------------------------------*/
20088 /*WE ONLY RECORD THE HEAD OF THE LOG IN THE FIRST LOG ROUND OF LOG EXECUTION.*/
20089 /*---------------------------------------------------------------------------*/
20090           logPartPtr.p->headFileNo = logFilePtr.p->fileNo;
20091           logPartPtr.p->headPageNo = logFilePtr.p->currentFilepage;
20092           logPartPtr.p->headPageIndex =
20093                   logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX];
20094 	  logPartPtr.p->logLap = logPagePtr.p->logPageWord[ZPOS_LOG_LAP];
20095           if (DEBUG_REDO)
20096           {
20097             ndbout_c("execSr part: %u logLap: %u",
20098                      logPartPtr.p->logPartNo, logPartPtr.p->logLap);
20099           }
20100         }//if
20101 /*---------------------------------------------------------------------------*/
20102 /* THERE IS NO NEED OF EXECUTING PAST THIS LINE SINCE THERE WILL ONLY BE LOG */
20103 /* RECORDS THAT WILL BE OF NO INTEREST. THUS CLOSE THE FILE AND START THE    */
20104 /* NEXT PHASE OF THE SYSTEM RESTART.                                         */
20105 /*---------------------------------------------------------------------------*/
20106         logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG_COMPLETED;
20107         send_runredo_event(signal, logPartPtr.p, logPartPtr.p->logLastGci);
20108       }//if
20109       break;
20110     default:
20111       jam();
20112 /* ========================================================================= */
20113 /* ========================================================================= */
20114 /*---------------------------------------------------------------------------*/
20115 /* SEND A SIGNAL TO THE SIGNAL LOG AND THEN CRASH THE SYSTEM.                */
20116 /*---------------------------------------------------------------------------*/
20117       line = __LINE__;
20118       crash_msg = "Invalid logword";
20119       goto crash;
20120       break;
20121     }//switch
20122 /*---------------------------------------------------------------------------*/
20123 // We continue to execute log records until we find a proper one to execute or
20124 // that we reach a new page.
20125 /*---------------------------------------------------------------------------*/
20126   } while (1);
20127   return;
20128 
20129 crash:
20130   signal->theData[0] = RNIL;
20131   signal->theData[1] = logPartPtr.i;
20132   Uint32 tmp = logFilePtr.p->fileName[3];
20133   tmp = (tmp >> 8) & 0xff;// To get the Directory, DXX.
20134   signal->theData[2] = tmp;
20135   signal->theData[3] = logFilePtr.p->fileNo;
20136   signal->theData[4] = logFilePtr.p->currentMbyte;
20137   signal->theData[5] = logFilePtr.p->currentFilepage;
20138   signal->theData[6] = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX];
20139   signal->theData[7] = logWord;
20140   signal->theData[8] = line;
20141 
20142   char buf[255];
20143   BaseString::snprintf(buf, sizeof(buf),
20144 		       "Error while reading REDO log. from %d\n"
20145 		       "part: %u D=%d, F=%d Mb=%d FP=%d W1=%d W2=%d : %s gci: %u",
20146 		       signal->theData[8],
20147                        logPartPtr.p->logPartNo,
20148 		       signal->theData[2],
20149 		       signal->theData[3],
20150 		       signal->theData[4],
20151 		       signal->theData[5],
20152 		       signal->theData[6],
20153 		       signal->theData[7],
20154 		       crash_msg ? crash_msg : "",
20155 		       logPartPtr.p->logLastGci);
20156 
20157   ndbout_c("%s", buf);
20158   ndbout_c("logPartPtr.p->logExecState: %u", logPartPtr.p->logExecState);
20159   ndbout_c("crestartOldestGci: %u", crestartOldestGci);
20160   ndbout_c("crestartNewestGci: %u", crestartNewestGci);
20161   ndbout_c("csrPhasesCompleted: %u", csrPhasesCompleted);
20162   ndbout_c("logPartPtr.p->logStartGci: %u", logPartPtr.p->logStartGci);
20163   ndbout_c("logPartPtr.p->logLastGci: %u", logPartPtr.p->logLastGci);
20164 
20165   progError(__LINE__, NDBD_EXIT_SR_REDOLOG, buf);
20166 }//Dblqh::execSr()
20167 
20168 /*---------------------------------------------------------------------------*/
20169 /* THIS SIGNAL IS ONLY RECEIVED TO BE CAPTURED IN THE SIGNAL LOG. IT IS      */
20170 /* ALSO USED TO CRASH THE SYSTEM AFTER SENDING A SIGNAL TO THE LOG.          */
20171 /*---------------------------------------------------------------------------*/
execDEBUG_SIG(Signal * signal)20172 void Dblqh::execDEBUG_SIG(Signal* signal)
20173 {
20174 /*
20175 2.5 TEMPORARY VARIABLES
20176 -----------------------
20177 */
20178   jamEntry();
20179   //logPagePtr.i = signal->theData[0];
20180   //tdebug = logPagePtr.p->logPageWord[0];
20181 
20182   char buf[100];
20183   BaseString::snprintf(buf, 100,
20184 	   "Error while reading REDO log. from %d\n"
20185 	   "D=%d, F=%d Mb=%d FP=%d W1=%d W2=%d",
20186 	   signal->theData[8],
20187 	   signal->theData[2], signal->theData[3], signal->theData[4],
20188 	   signal->theData[5], signal->theData[6], signal->theData[7]);
20189 
20190   progError(__LINE__, NDBD_EXIT_SR_REDOLOG, buf);
20191 
20192   return;
20193 }//Dblqh::execDEBUG_SIG()
20194 
20195 /*---------------------------------------------------------------------------*/
20196 /*---------------------------------------------------------------------------*/
closeExecLogLab(Signal * signal)20197 void Dblqh::closeExecLogLab(Signal* signal)
20198 {
20199   logFilePtr.p->logFileStatus = LogFileRecord::CLOSED;
20200   signal->theData[0] = ZEXEC_SR;
20201   signal->theData[1] = logFilePtr.p->logPartRec;
20202   sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
20203   return;
20204 }//Dblqh::closeExecLogLab()
20205 
openExecLogLab(Signal * signal)20206 void Dblqh::openExecLogLab(Signal* signal)
20207 {
20208 #ifndef NO_REDO_PAGE_CACHE
20209   Uint32 cnt = 1 +
20210     logPartPtr.p->execSrStopPageNo - logPartPtr.p->execSrStartPageNo;
20211 
20212 #if 0
20213   Uint32 MAX_EXTRA_READ = 9; // can be max 9 due to FSREADREQ formatting
20214   while (cnt < maxextraread && (logPartPtr.p->execSrStopPageNo % 32) != 31)
20215   {
20216     jam();
20217     cnt++;
20218     logPartPtr.p->execSrStopPageNo++;
20219   }
20220 #endif
20221 
20222   evict(m_redo_page_cache, cnt);
20223 #endif
20224 
20225   readExecLog(signal);
20226   lfoPtr.p->lfoState = LogFileOperationRecord::READ_EXEC_LOG;
20227   return;
20228 }//Dblqh::openExecLogLab()
20229 
readExecLogLab(Signal * signal)20230 void Dblqh::readExecLogLab(Signal* signal)
20231 {
20232   buildLinkedLogPageList(signal);
20233 #ifndef NO_REDO_PAGE_CACHE
20234   addCachePages(m_redo_page_cache,
20235                 logPartPtr.p->logPartNo,
20236                 logPartPtr.p->execSrStartPageNo,
20237                 lfoPtr.p);
20238 #endif
20239   logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOGREC_FROM_FILE;
20240   logPartPtr.p->execSrLfoRec = lfoPtr.i;
20241   logPartPtr.p->execSrLogPage = logPagePtr.i;
20242   logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] =
20243     logPartPtr.p->execSrLogPageIndex;
20244   execLogRecord(signal);
20245   return;
20246 }//Dblqh::readExecLogLab()
20247 
20248 /*---------------------------------------------------------------------------*/
20249 /* THIS CODE IS USED TO EXECUTE A LOG RECORD WHEN IT'S DATA HAVE BEEN LOCATED*/
20250 /* AND TRANSFERRED INTO MEMORY.                                              */
20251 /*---------------------------------------------------------------------------*/
execLogRecord(Signal * signal)20252 void Dblqh::execLogRecord(Signal* signal)
20253 {
20254   jamEntry();
20255 
20256   tcConnectptr.i = logPartPtr.p->logTcConrec;
20257   ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
20258   fragptr.i = tcConnectptr.p->fragmentptr;
20259   c_fragment_pool.getPtr(fragptr);
20260   tcConnectptr.p->m_log_part_ptr_i = fragptr.p->m_log_part_ptr_i;
20261 
20262   // Read a log record and prepare it for execution
20263   readLogHeader(signal);
20264   readKey(signal);
20265   readAttrinfo(signal);
20266   initReqinfoExecSr(signal);
20267   arrGuard(logPartPtr.p->execSrExecuteIndex, MAX_REPLICAS);
20268   BlockReference ref = fragptr.p->execSrBlockref[logPartPtr.p->execSrExecuteIndex];
20269   tcConnectptr.p->nextReplica = refToNode(ref);
20270   tcConnectptr.p->connectState = TcConnectionrec::LOG_CONNECTED;
20271   tcConnectptr.p->tcOprec = tcConnectptr.i;
20272   tcConnectptr.p->tcHashKeyHi = 0;
20273   packLqhkeyreqLab(signal);
20274 
20275   logPartPtr.p->m_redoWorkStats.m_opsExecuted++;
20276   logPartPtr.p->m_redoWorkStats.m_bytesExecuted+=
20277     (tcConnectptr.p->primKeyLen + tcConnectptr.p->totSendlenAi) << 2;
20278   return;
20279 }//Dblqh::execLogRecord()
20280 
20281 //----------------------------------------------------------------------------
20282 // This function invalidates log pages after the last GCI record in a
20283 // system/node restart. This is to ensure that the end of the log is
20284 // consistent. This function is executed last in start phase 3.
20285 // RT 450. EDTJAMO.
20286 //----------------------------------------------------------------------------
20287 Uint32
nextLogFilePtr(Uint32 logFilePtrI)20288 Dblqh::nextLogFilePtr(Uint32 logFilePtrI)
20289 {
20290   LogFileRecordPtr tmp;
20291   tmp.i = logFilePtrI;
20292   ptrCheckGuard(tmp, clogFileFileSize, logFileRecord);
20293   return tmp.p->nextLogFile;
20294 }
20295 
20296 void
invalidateLogAfterLastGCI(Signal * signal)20297 Dblqh::invalidateLogAfterLastGCI(Signal* signal)
20298 {
20299   jam();
20300   if (logPartPtr.p->logExecState != LogPartRecord::LES_EXEC_LOG_INVALIDATE) {
20301     jam();
20302     systemError(signal, __LINE__);
20303   }
20304 
20305   if (logFilePtr.p->fileNo != logPartPtr.p->invalidateFileNo) {
20306     jam();
20307     systemError(signal, __LINE__);
20308   }
20309 
20310   switch (lfoPtr.p->lfoState) {
20311   case LogFileOperationRecord::READ_SR_INVALIDATE_SEARCH_FILES:
20312   {
20313     jam();
20314     // Check if this file contains pages needing to be invalidated
20315     ndbrequire(logPartPtr.p->invalidatePageNo == 1);
20316     bool ok = logPagePtr.p->logPageWord[ZPOS_LOG_LAP] == logPartPtr.p->logLap;
20317     releaseLfo(signal);
20318     releaseLogpage(signal);
20319     if (ok)
20320     {
20321       jam();
20322       // This page must be invalidated.
20323       // We search next file
20324       readFileInInvalidate(signal, 3);
20325       return;
20326     }
20327     else
20328     {
20329       jam();
20330       /**
20331        * This file doest not need to be invalidated...move to previous
20332        *   file and search forward linear
20333        */
20334       readFileInInvalidate(signal, 6);
20335       return;
20336     }
20337     break;
20338   }
20339   case LogFileOperationRecord::READ_SR_INVALIDATE_PAGES:
20340     jam();
20341     /**
20342      * Check if this page must be invalidated.
20343      *
20344      * If the log lap number on a page after the head of the log is the same
20345      * as the actual log lap number we must invalidate this page. Otherwise it
20346      * could be impossible to find the end of the log in a later system/node
20347      * restart.
20348      *
20349      * After a restart, the log lap is used to find the old head (last written
20350      * part) of the redo log. In some cases recovery may complete by applying
20351      * up to some point long before the old head of the redo log, creating a
20352      * new head at an earlier position.  In this case, it is important to
20353      * invalidate the 'trimmed' part up to the old head, so that a future
20354      * recovery does not accidentally include it based on the log lap.  This
20355      * invalidation must itself be repeatable in case it fails part-way through.
20356      *
20357      * In addition we have the following conditions that give us an end to the
20358      * search. If it were not for these conditions when we find the first log
20359      * page with the wrong log lap.
20360      *
20361      * 1) Redo log writing can skip over pages to the next MByte start, this
20362      * means that pages can contain an old log lap although they are in the
20363      * part of REDO log which should be invalidated unless we search forward
20364      * at least until the next MByte start. We can have at most 1 MByte minus
20365      * one page of such pages with old log lap. When we skip major chunks like
20366      * this we set the synch flag to ensure that we can have an upper bound of
20367      * how far ahead in the REDO log we need to search until we have found the
20368      * end of it.
20369      *
20370      * 2) We can at most have 1 MByte of log writes outstanding.
20371      *    This is ensured by NDBFS through the use of the auto_sync_size
20372      *    parameter when calling NDBFS to open the file.
20373      *
20374      * 3) In worst case scenarios we get the last of those 1 MByte of pages
20375      *    written by NDBFS ending up on disk, but no other page.
20376      *
20377      * Given these facts we need to search onwards for a page with a current
20378      * log lap for at least 1 MByte plus the maximum skip size at MByte change
20379      * until we stop the search and decide we actually found the last page with
20380      * the current log lap number. The maximum skip size at normal MByte change
20381      * is equal to the largest size of a REDO log record. At the moment this
20382      * should never be bigger than one REDO log page at the moment. But this
20383      * can and will change in the future most likely.
20384      *
20385      * As an additional safety measure and to align the algorithm searching
20386      * for the first page to start invalidate from (invalidation happens
20387      * in a backward fashion) and the algorithm searching for the log end
20388      * at restart, we will not stop the search until we have found an
20389      * unwritten page 0 of a MByte (or page 1 for the first MByte in a file).
20390      *
20391      * This means that if we check one entire MByte from the first unwritten
20392      * page we find then we are always safe that we have found the end of the
20393      * REDO log.
20394      *
20395      * If we don't invalidate all REDO log pages that are invalid we can
20396      * easily run into problems in later restarts by connecting new log
20397      * pages to old invalid log pages which makes the finding of the start
20398      * and end of log impossible.
20399      */
20400 
20401     do
20402     {
20403       if (logPagePtr.p->logPageWord[ZPOS_LOG_LAP] < logPartPtr.p->logLap)
20404       {
20405         /**
20406          * We have found an old page which haven't been written in this log
20407          * lap. We need however to continue searching for pages to invalidate
20408          * a bit further. We need to actually find a page 0 within a
20409          * MByte that is old before we can quit the search and for the first
20410          * MByte this is actually page 1 since we never invalidate page 0 of
20411          * a log file.
20412          *
20413          * We will still track the old pages to provide some printouts of
20414          * that this happened so that we can gain better understanding of
20415          * how the REDO log writing actually works.
20416          */
20417         if (!logPartPtr.p->firstInvalidatePageFound)
20418         {
20419           Uint32 firstInvalidMByte = logPartPtr.p->invalidatePageNo /
20420                                      ZPAGES_IN_MBYTE;
20421           if ((firstInvalidMByte + 2) >= clogFileSize)
20422           {
20423             jam();
20424             logPartPtr.p->endInvalidMByteSearch =
20425               (firstInvalidMByte + 2) - clogFileSize;
20426           }
20427           else
20428           {
20429             jam();
20430             logPartPtr.p->endInvalidMByteSearch = firstInvalidMByte + 2;
20431           }
20432           logPartPtr.p->firstInvalidatePageFound = true;
20433           logPartPtr.p->firstInvalidatePageNo = logPartPtr.p->invalidatePageNo;
20434           logPartPtr.p->firstInvalidateFileNo = logPartPtr.p->invalidateFileNo;
20435         }
20436         else
20437         {
20438           jam();
20439           if (((logPartPtr.p->invalidatePageNo % ZPAGES_IN_MBYTE) == 0) ||
20440                (logPartPtr.p->invalidatePageNo == 1))
20441           {
20442             jam();
20443             Uint32 currentMByte = logPartPtr.p->invalidatePageNo /
20444                                   ZPAGES_IN_MBYTE;
20445             if (currentMByte == logPartPtr.p->endInvalidMByteSearch)
20446             {
20447               jam();
20448               /* No need to search any longer */
20449               break;
20450             }
20451           }
20452         }
20453       }
20454       else
20455       {
20456         ndbrequire(logPagePtr.p->logPageWord[ZPOS_LOG_LAP] ==
20457                    logPartPtr.p->logLap);
20458         if (logPartPtr.p->firstInvalidatePageFound)
20459         {
20460           jam();
20461           logPartPtr.p->firstInvalidatePageFound = false;
20462           g_eventLogger->info("Found a block of unwritten log pages in part %u"
20463                               ", followed by a written page, First unwritten:"
20464                               " file: %u, page: %u, Written: file: %u,"
20465                               " page: %u",
20466                               logPartPtr.p->logPartNo,
20467                               logPartPtr.p->firstInvalidateFileNo,
20468                               logPartPtr.p->firstInvalidatePageNo,
20469                               logPartPtr.p->invalidateFileNo,
20470                               logPartPtr.p->invalidatePageNo);
20471         }
20472       }
20473       jam();
20474       // This page must be invalidated.
20475       // We search for end
20476       // read next
20477       releaseLfo(signal);
20478       releaseLogpage(signal);
20479       readFileInInvalidate(signal, 1);
20480       return;
20481     } while (0);
20482 
20483     /**
20484      * We found the "last" page to invalidate...
20485      *
20486      * We now need to start the invalidation from firstInvalidatePageNo - 1.
20487      * We invalidate backwards to ensure that we make progress even in the
20488      * presence of multiple restarts.
20489      *
20490      * We could however have already stepped into a new file, in this case
20491      * we will start the invalidation writes from page 1 to ensure that
20492      * integrate this stepping ahead nicely with the file change code.
20493      * This is a harmless side effect since invalidating an invalid page
20494      * is not a problem.
20495      */
20496 
20497     if (logPartPtr.p->invalidateFileNo != logPartPtr.p->firstInvalidateFileNo)
20498     {
20499       jam();
20500       logPartPtr.p->invalidatePageNo = 1;
20501     }
20502     else
20503     {
20504       jam();
20505       logPartPtr.p->invalidatePageNo = logPartPtr.p->firstInvalidatePageNo;
20506     }
20507     g_eventLogger->info("Start invalidating: Part %u, Head: file: %u,"
20508                         " page: %u, Invalidation start: file: %u,"
20509                         " page: %u, actual start invalidate: file: %u"
20510                         " page: %u",
20511                         logPartPtr.p->logPartNo,
20512                         logPartPtr.p->headFileNo,
20513                         logPartPtr.p->headPageNo,
20514                         logPartPtr.p->firstInvalidateFileNo,
20515                         logPartPtr.p->firstInvalidatePageNo - 1,
20516                         logPartPtr.p->invalidateFileNo,
20517                         logPartPtr.p->invalidatePageNo - 1);
20518 
20519     // Fall through...
20520   case LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES:
20521     jam();
20522 
20523     releaseLfo(signal);
20524     releaseLogpage(signal);
20525 
20526     // Step backwards...
20527     logPartPtr.p->invalidatePageNo--;
20528 
20529     if (logPartPtr.p->invalidatePageNo == 0)
20530     {
20531       jam();
20532 
20533       if (logFilePtr.p->fileNo == 0)
20534       {
20535         jam();
20536         /**
20537          * We're wrapping in the log...
20538          *   update logLap
20539          */
20540         logPartPtr.p->logLap--;
20541 	ndbrequire(logPartPtr.p->logLap); // Should always be > 0
20542         if (DEBUG_REDO)
20543         {
20544           ndbout_c("invalidateLogAfterLastGCI part: %u wrap from file 0 -> logLap: %u",
20545                    logPartPtr.p->logPartNo, logPartPtr.p->logLap);
20546         }
20547       }
20548 
20549       if (invalidateCloseFile(signal, logPartPtr, logFilePtr,
20550                               LogFileRecord::CLOSE_SR_WRITE_INVALIDATE_PAGES))
20551       {
20552         jam();
20553         return;
20554       }
20555       writeFileInInvalidate(signal, 1); // step prev
20556       return;
20557     }
20558     writeFileInInvalidate(signal, 0);
20559     return;
20560   default:
20561     jamLine(lfoPtr.p->lfoState);
20562     ndbrequire(false);
20563   }
20564 }
20565 
20566 void
writeFileInInvalidate(Signal * signal,int stepPrev)20567 Dblqh::writeFileInInvalidate(Signal* signal, int stepPrev)
20568 {
20569   /**
20570    * Move to prev file
20571    */
20572   if (stepPrev == 1)
20573   {
20574     jam();
20575     logFilePtr.i = logFilePtr.p->prevLogFile;
20576     ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
20577     logPartPtr.p->invalidateFileNo = logFilePtr.p->fileNo;
20578     logPartPtr.p->invalidatePageNo = clogFileSize * ZPAGES_IN_MBYTE - 1;
20579   }
20580 
20581   if (logPartPtr.p->invalidateFileNo == logPartPtr.p->headFileNo &&
20582       logPartPtr.p->invalidatePageNo == logPartPtr.p->headPageNo)
20583   {
20584     jam();
20585     /**
20586      * Done...
20587      */
20588     logFilePtr.i = logPartPtr.p->currentLogfile;
20589     ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
20590 
20591     logFilePtr.i = logFilePtr.p->nextLogFile;
20592     ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
20593 
20594     exitFromInvalidate(signal);
20595     return;
20596   }
20597 
20598   if (stepPrev == 1 && logFilePtr.p->logFileStatus != LogFileRecord::OPEN)
20599   {
20600     jam();
20601     if (DEBUG_REDO)
20602     {
20603       ndbout_c("invalidate part: %u open for write %u",
20604                logPartPtr.p->logPartNo, logFilePtr.p->fileNo);
20605     }
20606     logFilePtr.p->logFileStatus =LogFileRecord::OPEN_SR_WRITE_INVALIDATE_PAGES;
20607     openFileRw(signal, logFilePtr);
20608     return;
20609   }
20610 
20611   seizeLogpage(signal);
20612 
20613   bool sync = false;
20614   const bool isLastPageToInvalidateInPart =
20615     ((logPartPtr.p->invalidatePageNo - 1) == logPartPtr.p->headPageNo) &&
20616      (logPartPtr.p->invalidateFileNo == logPartPtr.p->headFileNo);
20617   const bool isLastPageToInvalidateInFile =
20618     logPartPtr.p->invalidatePageNo == 1;
20619   const bool isLastPageToInvalidateInMByte =
20620     (logPartPtr.p->invalidatePageNo % ZPAGES_IN_MBYTE) == 0;
20621   if (isLastPageToInvalidateInPart ||
20622       isLastPageToInvalidateInFile ||
20623       isLastPageToInvalidateInMByte)
20624   {
20625     /**
20626      * In some cases we could end up with thousands of log pages to
20627      * to invalidate, to speed up this processing, only sync at file
20628      * switch, at the last page to write in a MByte. This will decrease
20629      * invalidation times in those cases from minutes to seconds.
20630      *
20631      * We keep the maximum size of invalidation writes to 1MByte and at
20632      * boundaries of MBytes to ensure that we don't allow for ways to
20633      * increase the set of unwritten pages in multiple restarts.
20634      */
20635     jam();
20636     sync = true;
20637   }
20638   /**
20639    * Make page really empty
20640    */
20641   bzero(logPagePtr.p, sizeof(LogPageRecord));
20642   writeSinglePage(signal,
20643                   logPartPtr.p->invalidatePageNo,
20644                   ZPAGE_SIZE - 1,
20645                   __LINE__,
20646                   sync);
20647 
20648   lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES;
20649   return;
20650 }//Dblqh::invalidateLogAfterLastGCI
20651 
20652 bool
invalidateCloseFile(Signal * signal,Ptr<LogPartRecord> partPtr,Ptr<LogFileRecord> filePtr,LogFileRecord::LogFileStatus status)20653 Dblqh::invalidateCloseFile(Signal* signal,
20654                            Ptr<LogPartRecord> partPtr,
20655                            Ptr<LogFileRecord> filePtr,
20656                            LogFileRecord::LogFileStatus status)
20657 {
20658   jam();
20659   if (filePtr.p->fileNo != 0 &&
20660       filePtr.i != partPtr.p->currentLogfile &&
20661       filePtr.i != nextLogFilePtr(logPartPtr.p->currentLogfile))
20662   {
20663     jam();
20664     if (DEBUG_REDO)
20665     {
20666       ndbout_c("invalidate part: %u close %u(%u) state: %u (%u)",
20667                logPartPtr.p->logPartNo,
20668                logFilePtr.p->fileNo,
20669                logFilePtr.i,
20670                (Uint32)status,
20671                logPartPtr.p->currentLogfile);
20672     }
20673     filePtr.p->logFileStatus = status;
20674     closeFile(signal, filePtr, __LINE__);
20675     return true;
20676   }
20677   return false;
20678 }
20679 
readFileInInvalidate(Signal * signal,int stepNext)20680 void Dblqh::readFileInInvalidate(Signal* signal, int stepNext)
20681 {
20682   jam();
20683 
20684   if (DEBUG_REDO)
20685   {
20686     ndbout_c("readFileInInvalidate part: %u file: %u stepNext: %u",
20687              logPartPtr.p->logPartNo, logFilePtr.p->fileNo, stepNext);
20688   }
20689 
20690   if (stepNext == 0)
20691   {
20692     jam();
20693     // Contact NDBFS. Real time break.
20694     readSinglePage(signal, logPartPtr.p->invalidatePageNo);
20695     lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_INVALIDATE_PAGES;
20696     return;
20697   }
20698 
20699   if (stepNext == 1)
20700   {
20701     jam();
20702     logPartPtr.p->invalidatePageNo++;
20703     if (logPartPtr.p->invalidatePageNo == (clogFileSize * ZPAGES_IN_MBYTE))
20704     {
20705       if (invalidateCloseFile(signal, logPartPtr, logFilePtr,
20706                               LogFileRecord::CLOSE_SR_READ_INVALIDATE_PAGES))
20707       {
20708         jam();
20709         return;
20710       }
20711       else
20712       {
20713         jam();
20714         stepNext = 2; // After close
20715       }
20716     }
20717     else
20718     {
20719       jam();
20720       // Contact NDBFS. Real time break.
20721       readSinglePage(signal, logPartPtr.p->invalidatePageNo);
20722       lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_INVALIDATE_PAGES;
20723       return;
20724     }
20725   }
20726 
20727   if (stepNext == 2)
20728   {
20729     jam();
20730     // We continue in the next file.
20731     logFilePtr.i = logFilePtr.p->nextLogFile;
20732     ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
20733     logPartPtr.p->invalidateFileNo = logFilePtr.p->fileNo;
20734     // Page 0 is used for file descriptors.
20735     logPartPtr.p->invalidatePageNo = 1;
20736 
20737     if (logFilePtr.p->fileNo == 0)
20738     {
20739       /**
20740        * We're wrapping in the log...
20741        *   update logLap
20742        */
20743       logPartPtr.p->logLap++;
20744       if (DEBUG_REDO)
20745       {
20746         ndbout_c("readFileInInvalidate part: %u step: %u wrap to file 0 -> logLap: %u",
20747                  logPartPtr.p->logPartNo, stepNext, logPartPtr.p->logLap);
20748       }
20749     }
20750 
20751 stepNext_2:
20752     if (logFilePtr.p->logFileStatus != LogFileRecord::OPEN)
20753     {
20754       jam();
20755       if (DEBUG_REDO)
20756       {
20757         ndbout_c("invalidate part: %u step: %u open for read %u",
20758                  logPartPtr.p->logPartNo, stepNext, logFilePtr.p->fileNo);
20759       }
20760       logFilePtr.p->logFileStatus =LogFileRecord::OPEN_SR_READ_INVALIDATE_PAGES;
20761       openFileRw(signal, logFilePtr);
20762       return;
20763     }
20764 
20765     // Contact NDBFS. Real time break.
20766     readSinglePage(signal, logPartPtr.p->invalidatePageNo);
20767     lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_INVALIDATE_PAGES;
20768     return;
20769   }
20770 
20771   if (stepNext == 3)
20772   {
20773     jam();
20774     if (invalidateCloseFile
20775         (signal, logPartPtr, logFilePtr,
20776          LogFileRecord::CLOSE_SR_READ_INVALIDATE_SEARCH_FILES))
20777     {
20778       jam();
20779       return;
20780     }
20781     stepNext = 4;
20782   }
20783 
20784   if (stepNext == 4)
20785   {
20786     jam();
20787     logFilePtr.i = logFilePtr.p->nextLogFile;
20788     ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
20789     logPartPtr.p->invalidateFileNo = logFilePtr.p->fileNo;
20790     // Page 0 is used for file descriptors.
20791     logPartPtr.p->invalidatePageNo = 1;
20792 
20793     if (logFilePtr.p->fileNo == 0)
20794     {
20795       /**
20796        * We're wrapping in the log...
20797        *   update logLap
20798        */
20799       logPartPtr.p->logLap++;
20800       if (DEBUG_REDO)
20801       {
20802         ndbout_c("readFileInInvalidate part: %u step: %u wrap to file 0 -> logLap: %u",
20803                  logPartPtr.p->logPartNo, stepNext, logPartPtr.p->logLap);
20804       }
20805     }
20806 
20807     if (logFilePtr.p->logFileStatus != LogFileRecord::OPEN)
20808     {
20809       jam();
20810       if (DEBUG_REDO)
20811       {
20812         ndbout_c("invalidate part: %u step: %u open for read %u",
20813                  logPartPtr.p->logPartNo, stepNext, logFilePtr.p->fileNo);
20814       }
20815       logFilePtr.p->logFileStatus =
20816         LogFileRecord::OPEN_SR_READ_INVALIDATE_SEARCH_FILES;
20817       openFileRw(signal, logFilePtr);
20818       return;
20819     }
20820     stepNext = 5;
20821   }
20822 
20823   if (stepNext == 5)
20824   {
20825     jam();
20826     // Contact NDBFS. Real time break.
20827     readSinglePage(signal, logPartPtr.p->invalidatePageNo);
20828     lfoPtr.p->lfoState =
20829       LogFileOperationRecord::READ_SR_INVALIDATE_SEARCH_FILES;
20830     return;
20831   }
20832 
20833   if (stepNext == 6)
20834   {
20835     jam();
20836     if (invalidateCloseFile
20837         (signal, logPartPtr, logFilePtr,
20838          LogFileRecord::CLOSE_SR_READ_INVALIDATE_SEARCH_LAST_FILE))
20839     {
20840       jam();
20841       return;
20842     }
20843     stepNext = 7;
20844   }
20845 
20846   if (stepNext == 7)
20847   {
20848     jam();
20849 
20850     if (logFilePtr.p->fileNo == 0)
20851     {
20852       jam();
20853       /**
20854        * We're wrapping in the log...
20855        *   update logLap
20856        */
20857       logPartPtr.p->logLap--;
20858       ndbrequire(logPartPtr.p->logLap); // Should always be > 0
20859       if (DEBUG_REDO)
20860       {
20861         ndbout_c("invalidateLogAfterLastGCI part: %u step: %u wrap from file 0 -> logLap: %u",
20862                  logPartPtr.p->logPartNo, stepNext, logPartPtr.p->logLap);
20863       }
20864     }
20865 
20866     logFilePtr.i = logFilePtr.p->prevLogFile;
20867     ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
20868 
20869     logPartPtr.p->invalidateFileNo = logFilePtr.p->fileNo;
20870     // Page 0 is used for file descriptors.
20871     logPartPtr.p->invalidatePageNo = 1;
20872 
20873     if (logPartPtr.p->invalidateFileNo == logPartPtr.p->headFileNo)
20874     {
20875       jam();
20876       logPartPtr.p->invalidatePageNo = logPartPtr.p->headPageNo;
20877 
20878       if (! ((cstartType == NodeState::ST_INITIAL_START) ||
20879              (cstartType == NodeState::ST_INITIAL_NODE_RESTART)))
20880       {
20881         jam();
20882         if (logFilePtr.i == logPartPtr.p->lastLogfile)
20883         {
20884           jam();
20885           Uint32 lastMbytePageNo =
20886             logPartPtr.p->lastMbyte << ZTWOLOG_NO_PAGES_IN_MBYTE;
20887           if (logPartPtr.p->invalidatePageNo < lastMbytePageNo)
20888           {
20889             jam();
20890             if (DEBUG_REDO)
20891             {
20892               ndbout_c("readFileInInvalidate part: %u step: %u moving invalidatePageNo from %u to %u (lastMbyte)",
20893                        logPartPtr.p->logPartNo, stepNext,
20894                        logPartPtr.p->invalidatePageNo,
20895                        lastMbytePageNo);
20896             }
20897             logPartPtr.p->invalidatePageNo = lastMbytePageNo;
20898           }
20899         }
20900       }
20901       readFileInInvalidate(signal, 1);
20902       return;
20903     }
20904 
20905     goto stepNext_2;
20906   }
20907   ndbrequire(false);
20908 }
20909 
exitFromInvalidate(Signal * signal)20910 void Dblqh::exitFromInvalidate(Signal* signal)
20911 {
20912   jam();
20913 
20914   if (DEBUG_REDO)
20915   {
20916     jam();
20917     printf("exitFromInvalidate part: %u head file: %u page: %u open: ",
20918            logPartPtr.p->logPartNo,
20919            logPartPtr.p->headFileNo,
20920            logPartPtr.p->headPageNo);
20921 
20922     LogFileRecordPtr tmp;
20923     tmp.i = logPartPtr.p->currentLogfile;
20924     do
20925     {
20926       jam();
20927       ptrCheckGuard(tmp, clogFileFileSize, logFileRecord);
20928       if (tmp.p->logFileStatus != LogFileRecord::LFS_IDLE &&
20929           tmp.p->logFileStatus != LogFileRecord::CLOSED)
20930       {
20931         jam();
20932         printf("%u ", tmp.p->fileNo);
20933       }
20934       tmp.i = tmp.p->nextLogFile;
20935     } while (tmp.i != logPartPtr.p->currentLogfile && tmp.i != RNIL);
20936     printf("\n");
20937 
20938     tmp.i = logPartPtr.p->currentLogfile;
20939     ptrCheckGuard(tmp, clogFileFileSize, logFileRecord);
20940 
20941     LogPosition head = { tmp.p->fileNo, tmp.p->currentMbyte };
20942     LogPosition tail = { logPartPtr.p->logTailFileNo,
20943                          logPartPtr.p->logTailMbyte};
20944     Uint64 mb = free_log(head, tail, logPartPtr.p->noLogFiles, clogFileSize);
20945     Uint64 total = logPartPtr.p->noLogFiles * Uint64(clogFileSize);
20946     ndbout_c("head: [ %u %u ] tail: [ %u %u ] free: %llu total: %llu",
20947              head.m_file_no, head.m_mbyte,
20948              tail.m_file_no, tail.m_mbyte,
20949              mb, total);
20950   }
20951 
20952   logFilePtr.i = logPartPtr.p->firstLogfile;
20953   ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
20954   logPagePtr.i = logFilePtr.p->logPageZero;
20955   ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
20956   logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_FILE_NO] =
20957     logPartPtr.p->headFileNo;
20958   writeSinglePage(signal, 0, ZPAGE_SIZE - 1, __LINE__);
20959 
20960   lfoPtr.p->logFileRec = logFilePtr.i;
20961   lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES_UPDATE_PAGE0;
20962   return;
20963 }
20964 
20965 /*---------------------------------------------------------------------------*/
20966 /* THE EXECUTION OF A LOG RECORD IS COMPLETED. RELEASE PAGES IF THEY WERE    */
20967 /* READ FROM DISK FOR THIS PARTICULAR OPERATION.                             */
20968 /*---------------------------------------------------------------------------*/
completedLab(Signal * signal)20969 void Dblqh::completedLab(Signal* signal)
20970 {
20971   Uint32 result = returnExecLog(signal);
20972 /*---------------------------------------------------------------------------*/
20973 /*       ENTER COMPLETED WITH                                                */
20974 /*         LQH_CONNECTPTR                                                    */
20975 /*---------------------------------------------------------------------------*/
20976   if (result == ZOK) {
20977     jam();
20978     execLogRecord(signal);
20979     return;
20980   } else if (result == ZNOT_OK) {
20981     jam();
20982     signal->theData[0] = ZEXEC_SR;
20983     signal->theData[1] = logPartPtr.i;
20984     sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
20985   } else {
20986     jam();
20987     /*empty*/;
20988   }//if
20989 /*---------------------------------------------------------------------------*/
20990 /* WE HAVE TO WAIT FOR CLOSING OF THE EXECUTED LOG FILE BEFORE PROCEEDING IN */
20991 /* RARE CASES.                                                               */
20992 /*---------------------------------------------------------------------------*/
20993   return;
20994 }//Dblqh::completedLab()
20995 
20996 /*---------------------------------------------------------------------------*/
20997 /* EXECUTION OF LOG RECORD WAS NOT SUCCESSFUL. CHECK IF IT IS OK ANYWAY,     */
20998 /* THEN EXECUTE THE NEXT LOG RECORD.                                         */
20999 /*---------------------------------------------------------------------------*/
logLqhkeyrefLab(Signal * signal)21000 void Dblqh::logLqhkeyrefLab(Signal* signal)
21001 {
21002   Uint32 result = returnExecLog(signal);
21003   switch (tcConnectptr.p->operation) {
21004   case ZUPDATE:
21005   case ZDELETE:
21006     jam();
21007     if (unlikely(terrorCode != ZNO_TUPLE_FOUND))
21008       goto error;
21009     break;
21010   case ZINSERT:
21011     jam();
21012     if (unlikely(terrorCode != ZTUPLE_ALREADY_EXIST && terrorCode != 899))
21013       goto error;
21014 
21015     break;
21016   default:
21017     goto error;
21018   }
21019 
21020   if (result == ZOK) {
21021     jam();
21022     execLogRecord(signal);
21023     return;
21024   } else if (result == ZNOT_OK) {
21025     jam();
21026     signal->theData[0] = ZEXEC_SR;
21027     signal->theData[1] = logPartPtr.i;
21028     sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
21029   } else {
21030     jam();
21031     /*empty*/;
21032   }//if
21033   /* ------------------------------------------------------------------------
21034    *  WE HAVE TO WAIT FOR CLOSING OF THE EXECUTED LOG FILE BEFORE
21035    *  PROCEEDING IN RARE CASES.
21036    * ----------------------------------------------------------------------- */
21037   return;
21038 error:
21039   BaseString tmp;
21040   tmp.appfmt("You have found a bug!"
21041 	     " Failed op (%s) during REDO table: %d fragment: %d err: %d",
21042 	     tcConnectptr.p->operation == ZINSERT ? "INSERT" :
21043 	     tcConnectptr.p->operation == ZUPDATE ? "UPDATE" :
21044 	     tcConnectptr.p->operation == ZDELETE ? "DELETE" :
21045 	     tcConnectptr.p->operation == ZWRITE ? "WRITE" : "<unknown>",
21046 	     tcConnectptr.p->tableref,
21047 	     tcConnectptr.p->fragmentid,
21048 	     terrorCode);
21049   progError(__LINE__, NDBD_EXIT_SYSTEM_ERROR,
21050 	    tmp.c_str());
21051 }//Dblqh::logLqhkeyrefLab()
21052 
closeExecSrCompletedLab(Signal * signal)21053 void Dblqh::closeExecSrCompletedLab(Signal* signal)
21054 {
21055   logFilePtr.p->logFileStatus = LogFileRecord::CLOSED;
21056   signal->theData[0] = logFilePtr.p->logPartRec;
21057   execLogComp(signal);
21058   return;
21059 }//Dblqh::closeExecSrCompletedLab()
21060 
21061 /* --------------------------------------------------------------------------
21062  *  ONE OF THE LOG PARTS HAVE COMPLETED EXECUTING THE LOG. CHECK IF ALL LOG
21063  *  PARTS ARE COMPLETED. IF SO START SENDING EXEC_FRAGCONF AND EXEC_SRCONF.
21064  * ------------------------------------------------------------------------- */
execLogComp(Signal * signal)21065 void Dblqh::execLogComp(Signal* signal)
21066 {
21067   logPartPtr.i = signal->theData[0];
21068   ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
21069   logPartPtr.p->logPartState = LogPartRecord::SR_THIRD_PHASE_COMPLETED;
21070   /* ------------------------------------------------------------------------
21071    *  WE MUST RELEASE THE TC CONNECT RECORD HERE SO THAT IT CAN BE REUSED.
21072    * ----------------------------------------------------------------------- */
21073   tcConnectptr.i = logPartPtr.p->logTcConrec;
21074   ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
21075   logPartPtr.p->logTcConrec = RNIL;
21076   releaseTcrecLog(signal, tcConnectptr);
21077   g_eventLogger->info("LDM(%u): Completed REDO log execution on"
21078                       " part %u, ops executed = %llu, bytes executed = %llu,",
21079                       instance(),
21080                       logPartPtr.p->logPartNo,
21081                       logPartPtr.p->m_redoWorkStats.m_opsExecuted,
21082                       logPartPtr.p->m_redoWorkStats.m_bytesExecuted);
21083   g_eventLogger->info("LDM(%u): Log part %u stats:"
21084                       " ops skipped = %llu, ops prepared %llu,"
21085                       " pages read = %llu,"
21086                       " GCIs executed = %u",
21087                       instance(),
21088                       logPartPtr.p->logPartNo,
21089                       logPartPtr.p->m_redoWorkStats.m_opsSkipped,
21090                       logPartPtr.p->m_redoWorkStats.m_opsPrepared,
21091                       logPartPtr.p->m_redoWorkStats.m_pagesRead,
21092                       logPartPtr.p->m_redoWorkStats.m_gcisExecuted);
21093   for (logPartPtr.i = 0; logPartPtr.i < clogPartFileSize; logPartPtr.i++) {
21094     jam();
21095     ptrAss(logPartPtr, logPartRecord);
21096     if (logPartPtr.p->logPartState != LogPartRecord::SR_THIRD_PHASE_COMPLETED) {
21097       if (logPartPtr.p->logPartState != LogPartRecord::SR_THIRD_PHASE_STARTED) {
21098         jam();
21099         systemErrorLab(signal, __LINE__);
21100         return;
21101       } else {
21102         jam();
21103 	/* ------------------------------------------------------------------
21104 	 *  THIS LOG PART WAS NOT COMPLETED YET. EXIT AND WAIT FOR IT
21105 	 *  TO COMPLETE
21106 	 * ----------------------------------------------------------------- */
21107         return;
21108       }//if
21109     }//if
21110   }//for
21111   /* ------------------------------------------------------------------------
21112    *   ALL LOG PARTS HAVE COMPLETED THE EXECUTION OF THE LOG. WE CAN NOW START
21113    *   SENDING THE EXEC_FRAGCONF SIGNALS TO ALL INVOLVED FRAGMENTS.
21114    * ----------------------------------------------------------------------- */
21115   jam();
21116 
21117 #ifndef NO_REDO_PAGE_CACHE
21118   release(m_redo_page_cache);
21119 #endif
21120 
21121 #ifndef NO_REDO_OPEN_FILE_CACHE
21122   release(signal, m_redo_open_file_cache);
21123 #else
21124   execLogComp_extra_files_closed(signal);
21125 #endif
21126 }
21127 
21128 void
execLogComp_extra_files_closed(Signal * signal)21129 Dblqh::execLogComp_extra_files_closed(Signal * signal)
21130 {
21131   c_lcp_complete_fragments.first(fragptr);
21132   signal->theData[0] = ZSEND_EXEC_CONF;
21133   signal->theData[1] = fragptr.i;
21134   sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
21135   return;
21136 }
21137 
21138 /* --------------------------------------------------------------------------
21139  *  GO THROUGH THE FRAGMENT RECORDS TO DEDUCE TO WHICH SHALL BE SENT
21140  *  EXEC_FRAGCONF AFTER COMPLETING THE EXECUTION OF THE LOG.
21141  * ------------------------------------------------------------------------- */
sendExecConf(Signal * signal)21142 void Dblqh::sendExecConf(Signal* signal)
21143 {
21144   jamEntry();
21145   fragptr.i = signal->theData[0];
21146   Uint32 loopCount = 0;
21147   while (fragptr.i != RNIL) {
21148     c_lcp_complete_fragments.getPtr(fragptr);
21149     Uint32 next = fragptr.p->nextList;
21150     if (fragptr.p->execSrStatus != Fragrecord::IDLE) {
21151       jam();
21152       ndbrequire(fragptr.p->execSrNoReplicas - 1 < MAX_REPLICAS);
21153       for (Uint32 i = 0; i < fragptr.p->execSrNoReplicas; i++) {
21154         jam();
21155         Uint32 ref = fragptr.p->execSrBlockref[i];
21156         signal->theData[0] = fragptr.p->execSrUserptr[i];
21157 
21158         if (isNdbMtLqh())
21159         {
21160           jam();
21161           // send via own proxy
21162           signal->theData[1] = ref;
21163           sendSignal(DBLQH_REF, GSN_EXEC_FRAGCONF, signal, 2, JBB);
21164         }
21165         else if (refToInstance(ref) != 0 &&
21166                  ndb_route_exec_frag(getNodeInfo(refToNode(ref)).m_version))
21167         {
21168           jam();
21169           // send via remote proxy
21170           signal->theData[1] = ref;
21171           sendSignal(numberToRef(refToMain(ref), refToNode(ref)),
21172                      GSN_EXEC_FRAGCONF, signal, 2, JBB);
21173         }
21174         else
21175         {
21176           jam();
21177           // send direct
21178           sendSignal(ref, GSN_EXEC_FRAGCONF, signal, 1, JBB);
21179         }
21180       }//for
21181       fragptr.p->execSrNoReplicas = 0;
21182     }//if
21183     loopCount++;
21184     if (loopCount > 20) {
21185       jam();
21186       signal->theData[0] = ZSEND_EXEC_CONF;
21187       signal->theData[1] = next;
21188       sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
21189       return;
21190     } else {
21191       jam();
21192       fragptr.i = next;
21193     }//if
21194   }//while
21195   /* ----------------------------------------------------------------------
21196    *  WE HAVE NOW SENT ALL EXEC_FRAGCONF. NOW IT IS TIME TO SEND
21197    *  EXEC_SRCONF TO ALL NODES.
21198    * --------------------------------------------------------------------- */
21199   srPhase3Comp(signal);
21200 }//Dblqh::sendExecConf()
21201 
21202 /* --------------------------------------------------------------------------
21203  *       PHASE 3 HAS NOW COMPLETED. INFORM ALL OTHER NODES OF THIS EVENT.
21204  * ------------------------------------------------------------------------- */
srPhase3Comp(Signal * signal)21205 void Dblqh::srPhase3Comp(Signal* signal)
21206 {
21207   jamEntry();
21208 
21209   g_eventLogger->info("LDM(%u): Completed LDM start phase 3",
21210                       instance());
21211 
21212   signal->theData[0] = cownNodeid;
21213   if (!isNdbMtLqh())
21214   {
21215     jam();
21216     NodeReceiverGroup rg(DBLQH, m_sr_nodes);
21217     sendSignal(rg, GSN_EXEC_SRCONF, signal, 1, JBB);
21218   }
21219   else
21220   {
21221     jam();
21222     const Uint32 sz = NdbNodeBitmask::Size;
21223     m_sr_nodes.copyto(sz, &signal->theData[1]);
21224     sendSignal(DBLQH_REF, GSN_EXEC_SRCONF, signal, 1 + sz, JBB);
21225   }
21226   return;
21227 }//Dblqh::srPhase3Comp()
21228 
21229 /* ##########################################################################
21230  *    SYSTEM RESTART PHASE FOUR MODULE
21231  *    THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING.
21232  *
21233  *    THIS MODULE SETS UP THE HEAD AND TAIL POINTERS OF THE LOG PARTS IN THE
21234  *    FRAGMENT LOG. WHEN IT IS COMPLETED IT REPORTS TO THE MASTER DIH THAT
21235  *    IT HAS COMPLETED THE PART OF THE SYSTEM RESTART WHERE THE DATABASE IS
21236  *    LOADED.
21237  *    IT ALSO OPENS THE CURRENT LOG FILE AND THE NEXT AND SETS UP THE FIRST
21238  *    LOG PAGE WHERE NEW LOG DATA IS TO BE INSERTED WHEN THE SYSTEM STARTS
21239  *    AGAIN.
21240  *
21241  *    THIS PART IS ACTUALLY EXECUTED FOR ALL RESTART TYPES.
21242  * ######################################################################### */
initFourth(Signal * signal)21243 void Dblqh::initFourth(Signal* signal)
21244 {
21245   LogFileRecordPtr locLogFilePtr;
21246   jamEntry();
21247   logPartPtr.i = signal->theData[0];
21248   ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
21249   crestartNewestGci = 1;
21250   crestartOldestGci = 1;
21251   /* ------------------------------------------------------------------------
21252    *       INITIALISE LOG PART AND LOG FILES AS NEEDED.
21253    * ----------------------------------------------------------------------- */
21254   logPartPtr.p->headFileNo = 0;
21255   logPartPtr.p->headPageNo = 1;
21256   logPartPtr.p->headPageIndex = ZPAGE_HEADER_SIZE + 2;
21257   logPartPtr.p->logPartState = LogPartRecord::SR_FOURTH_PHASE_STARTED;
21258   logPartPtr.p->logTailFileNo = 0;
21259   logPartPtr.p->logTailMbyte = 0;
21260   locLogFilePtr.i = logPartPtr.p->firstLogfile;
21261   ptrCheckGuard(locLogFilePtr, clogFileFileSize, logFileRecord);
21262   locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_FOURTH_PHASE;
21263   openFileRw(signal, locLogFilePtr);
21264   return;
21265 }//Dblqh::initFourth()
21266 
openSrFourthPhaseLab(Signal * signal)21267 void Dblqh::openSrFourthPhaseLab(Signal* signal)
21268 {
21269   /* ------------------------------------------------------------------------
21270    *  WE HAVE NOW OPENED THE HEAD LOG FILE WE WILL NOW START READING IT
21271    *  FROM THE HEAD MBYTE TO FIND THE NEW HEAD OF THE LOG.
21272    * ----------------------------------------------------------------------- */
21273   readSinglePage(signal, logPartPtr.p->headPageNo);
21274   lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_FOURTH_PHASE;
21275   return;
21276 }//Dblqh::openSrFourthPhaseLab()
21277 
readSrFourthPhaseLab(Signal * signal)21278 void Dblqh::readSrFourthPhaseLab(Signal* signal)
21279 {
21280   if(c_diskless){
21281     jam();
21282     logPagePtr.p->logPageWord[ZPOS_LOG_LAP] = 1;
21283   }
21284 
21285   /* ------------------------------------------------------------------------
21286    *  INITIALISE ALL LOG PART INFO AND LOG FILE INFO THAT IS NEEDED TO
21287    *  START UP THE SYSTEM.
21288    * ------------------------------------------------------------------------
21289    *  INITIALISE THE NEWEST GLOBAL CHECKPOINT IDENTITY AND THE NEWEST
21290    *  COMPLETED GLOBAL CHECKPOINT IDENITY AS THE NEWEST THAT WAS RESTARTED.
21291    * ------------------------------------------------------------------------
21292    *  INITIALISE THE HEAD PAGE INDEX IN THIS PAGE.
21293    *  ASSIGN IT AS THE CURRENT LOGPAGE.
21294    *  ASSIGN THE FILE AS THE CURRENT LOG FILE.
21295    *  ASSIGN THE CURRENT FILE NUMBER FROM THE CURRENT LOG FILE AND THE NEXT
21296    *  FILE NUMBER FROM THE NEXT LOG FILE.
21297    *  ASSIGN THE CURRENT FILEPAGE FROM HEAD PAGE NUMBER.
21298    *  ASSIGN THE CURRENT MBYTE BY DIVIDING PAGE NUMBER BY 128.
21299    *  INITIALISE LOG LAP TO BE THE LOG LAP AS FOUND IN THE HEAD PAGE.
21300    *  WE HAVE TO CALCULATE THE NUMBER OF REMAINING WORDS IN THIS MBYTE.
21301    * ----------------------------------------------------------------------- */
21302   Uint32 gci = crestartNewestGci;
21303   if (crestartOldestGci > gci)
21304   {
21305     jam();
21306     /**
21307      * If "keepGci" is bigger than latest-completed-gci
21308      *   move cnewest/cnewestCompletedGci forward
21309      */
21310     ndbout_c("readSrFourthPhaseLab: gci %u => %u",
21311              gci, crestartOldestGci);
21312     gci = crestartOldestGci;
21313   }
21314   cnewestGci = gci;
21315   cnewestCompletedGci = gci;
21316   logPartPtr.p->logPartNewestCompletedGCI = cnewestCompletedGci;
21317   logPartPtr.p->currentLogfile = logFilePtr.i;
21318   logFilePtr.p->filePosition = logPartPtr.p->headPageNo;
21319   logFilePtr.p->currentMbyte =
21320                   logPartPtr.p->headPageNo >> ZTWOLOG_NO_PAGES_IN_MBYTE;
21321   logFilePtr.p->fileChangeState = LogFileRecord::NOT_ONGOING;
21322   logPartPtr.p->logLap = logPagePtr.p->logPageWord[ZPOS_LOG_LAP];
21323   logFilePtr.p->currentFilepage = logPartPtr.p->headPageNo;
21324   logFilePtr.p->currentLogpage = logPagePtr.i;
21325 
21326   initLogpage(signal);
21327   logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPartPtr.p->headPageIndex;
21328   logFilePtr.p->remainingWordsInMbyte =
21329     ((
21330       ((logFilePtr.p->currentMbyte + 1) * ZPAGES_IN_MBYTE) -
21331      logFilePtr.p->currentFilepage) *
21332     (ZPAGE_SIZE - ZPAGE_HEADER_SIZE)) -
21333       (logPartPtr.p->headPageIndex - ZPAGE_HEADER_SIZE);
21334   /* ------------------------------------------------------------------------
21335    *     THE NEXT STEP IS TO OPEN THE NEXT LOG FILE (IF THERE IS ONE).
21336    * ----------------------------------------------------------------------- */
21337   if (logFilePtr.p->nextLogFile != logFilePtr.i) {
21338     LogFileRecordPtr locLogFilePtr;
21339     jam();
21340     locLogFilePtr.i = logFilePtr.p->nextLogFile;
21341     ptrCheckGuard(locLogFilePtr, clogFileFileSize, logFileRecord);
21342     locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_FOURTH_NEXT;
21343     openFileRw(signal, locLogFilePtr);
21344   } else {
21345     jam();
21346     /* ----------------------------------------------------------------------
21347      *  THIS CAN ONLY OCCUR IF WE HAVE ONLY ONE LOG FILE. THIS LOG FILE MUST
21348      *  BE LOG FILE ZERO AND THAT IS THE FILE WE CURRENTLY HAVE READ.
21349      *  THUS WE CAN CONTINUE IMMEDIATELY TO READ PAGE ZERO IN FILE ZERO.
21350      * --------------------------------------------------------------------- */
21351     openSrFourthZeroSkipInitLab(signal);
21352     return;
21353   }//if
21354   return;
21355 }//Dblqh::readSrFourthPhaseLab()
21356 
openSrFourthNextLab(Signal * signal)21357 void Dblqh::openSrFourthNextLab(Signal* signal)
21358 {
21359   /* ------------------------------------------------------------------------
21360    *       WE MUST ALSO HAVE FILE 0 OPEN ALL THE TIME.
21361    * ----------------------------------------------------------------------- */
21362   logFilePtr.i = logPartPtr.p->firstLogfile;
21363   ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
21364   if (logFilePtr.p->logFileStatus == LogFileRecord::OPEN) {
21365     jam();
21366     openSrFourthZeroSkipInitLab(signal);
21367     return;
21368   } else {
21369     jam();
21370     logFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_FOURTH_ZERO;
21371     openFileRw(signal, logFilePtr);
21372   }//if
21373   return;
21374 }//Dblqh::openSrFourthNextLab()
21375 
openSrFourthZeroLab(Signal * signal)21376 void Dblqh::openSrFourthZeroLab(Signal* signal)
21377 {
21378   openSrFourthZeroSkipInitLab(signal);
21379   return;
21380 }//Dblqh::openSrFourthZeroLab()
21381 
openSrFourthZeroSkipInitLab(Signal * signal)21382 void Dblqh::openSrFourthZeroSkipInitLab(Signal* signal)
21383 {
21384   if (logFilePtr.i == logPartPtr.p->currentLogfile) {
21385     if (logFilePtr.p->currentFilepage == 0) {
21386       jam();
21387       /* -------------------------------------------------------------------
21388        *  THE HEADER PAGE IN THE LOG IS PAGE ZERO IN FILE ZERO.
21389        *  THIS SHOULD NEVER OCCUR.
21390        * ------------------------------------------------------------------- */
21391       systemErrorLab(signal, __LINE__);
21392       return;
21393     }//if
21394   }//if
21395   readSinglePage(signal, 0);
21396   lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_FOURTH_ZERO;
21397   return;
21398 }//Dblqh::openSrFourthZeroSkipInitLab()
21399 
readSrFourthZeroLab(Signal * signal)21400 void Dblqh::readSrFourthZeroLab(Signal* signal)
21401 {
21402   logFilePtr.p->logPageZero = logPagePtr.i;
21403   // --------------------------------------------------------------------
21404   //   This is moved to invalidateLogAfterLastGCI(), RT453.
21405   //   signal->theData[0] = ZSR_FOURTH_COMP;
21406   //   signal->theData[1] = logPartPtr.i;
21407   //   sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
21408   // --------------------------------------------------------------------
21409 
21410   // Need to invalidate log pages after the head of the log. RT 453. EDTJAMO.
21411   // Set the start of the invalidation.
21412   logFilePtr.i = logPartPtr.p->currentLogfile;
21413   ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
21414   logPartPtr.p->invalidateFileNo = logPartPtr.p->headFileNo;
21415   logPartPtr.p->invalidatePageNo = logPartPtr.p->headPageNo;
21416   logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG_INVALIDATE;
21417   logPartPtr.p->firstInvalidatePageFound = false;
21418 
21419   readFileInInvalidate(signal, 3);
21420   return;
21421 }//Dblqh::readSrFourthZeroLab()
21422 
21423 /* --------------------------------------------------------------------------
21424  *     ONE OF THE LOG PARTS HAVE COMPLETED PHASE FOUR OF THE SYSTEM RESTART.
21425  *     CHECK IF ALL LOG PARTS ARE COMPLETED. IF SO SEND START_RECCONF
21426  * ------------------------------------------------------------------------- */
srFourthComp(Signal * signal)21427 void Dblqh::srFourthComp(Signal* signal)
21428 {
21429   jamEntry();
21430   logPartPtr.i = signal->theData[0];
21431   ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
21432   logPartPtr.p->logPartState = LogPartRecord::SR_FOURTH_PHASE_COMPLETED;
21433 
21434   g_eventLogger->info("LDM(%u): Completed old Redo head invalidation"
21435                       " on log part %u",
21436                       instance(),
21437                       logPartPtr.p->logPartNo);
21438 
21439   for (logPartPtr.i = 0; logPartPtr.i < clogPartFileSize; logPartPtr.i++) {
21440     jam();
21441     ptrAss(logPartPtr, logPartRecord);
21442     if (logPartPtr.p->logPartState != LogPartRecord::SR_FOURTH_PHASE_COMPLETED) {
21443       if (logPartPtr.p->logPartState != LogPartRecord::SR_FOURTH_PHASE_STARTED) {
21444         jam();
21445         systemErrorLab(signal, __LINE__);
21446         return;
21447       } else {
21448         jam();
21449 	/* ------------------------------------------------------------------
21450 	 *  THIS LOG PART WAS NOT COMPLETED YET.
21451 	 *  EXIT AND WAIT FOR IT TO COMPLETE
21452 	 * ----------------------------------------------------------------- */
21453         return;
21454       }//if
21455     }//if
21456   }//for
21457   /* ------------------------------------------------------------------------
21458    *  ALL LOG PARTS HAVE COMPLETED PHASE FOUR OF THE SYSTEM RESTART.
21459    *  WE CAN NOW SEND START_RECCONF TO THE MASTER DIH IF IT WAS A
21460    *  SYSTEM RESTART. OTHERWISE WE WILL CONTINUE WITH AN INITIAL START.
21461    *  SET LOG PART STATE TO IDLE TO
21462    *  INDICATE THAT NOTHING IS GOING ON IN THE LOG PART.
21463    * ----------------------------------------------------------------------- */
21464   for (logPartPtr.i = 0; logPartPtr.i < clogPartFileSize; logPartPtr.i++) {
21465     ptrAss(logPartPtr, logPartRecord);
21466     logPartPtr.p->logPartState = LogPartRecord::IDLE;
21467   }//for
21468 
21469   g_eventLogger->info("LDM(%u): All redo actions complete (apply,"
21470                       " invalidate)",
21471                       instance());
21472 
21473   if ((cstartType == NodeState::ST_INITIAL_START) ||
21474       (cstartType == NodeState::ST_INITIAL_NODE_RESTART)) {
21475     jam();
21476 
21477     ndbrequire(cinitialStartOngoing == ZTRUE);
21478     cinitialStartOngoing = ZFALSE;
21479     cstartRecReq = SRR_REDO_COMPLETE;
21480     checkStartCompletedLab(signal);
21481     return;
21482   } else if ((cstartType == NodeState::ST_NODE_RESTART) ||
21483              (cstartType == NodeState::ST_SYSTEM_RESTART)) {
21484     jam();
21485 
21486     if(cstartType == NodeState::ST_SYSTEM_RESTART)
21487     {
21488       jam();
21489       if (c_lcp_complete_fragments.first(fragptr))
21490       {
21491 	jam();
21492         signal->theData[0] = ZENABLE_EXPAND_CHECK;
21493         signal->theData[1] = fragptr.i;
21494         sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
21495 	return;
21496       }
21497     }
21498 
21499     cstartRecReq = SRR_REDO_COMPLETE; // REDO complete
21500 
21501     rebuildOrderedIndexes(signal, 0);
21502     return;
21503   } else {
21504     ndbrequire(false);
21505   }//if
21506   return;
21507 }//Dblqh::srFourthComp()
21508 
21509 /* ######################################################################### */
21510 /* #######                            ERROR MODULE                   ####### */
21511 /*                                                                           */
21512 /* ######################################################################### */
21513 
21514 /*---------------------------------------------------------------------------*/
21515 /* AN ERROR OCCURRED THAT WE WILL NOT TREAT AS SYSTEM ERROR. MOST OFTEN THIS */
21516 /* WAS CAUSED BY AN ERRONEUS SIGNAL SENT BY ANOTHER NODE. WE DO NOT WISH TO  */
21517 /* CRASH BECAUSE OF FAULTS IN OTHER NODES. THUS WE ONLY REPORT A WARNING.    */
21518 /* THIS IS CURRENTLY NOT IMPLEMENTED AND FOR THE MOMENT WE GENERATE A SYSTEM */
21519 /* ERROR SINCE WE WANT TO FIND FAULTS AS QUICKLY AS POSSIBLE IN A TEST PHASE.*/
21520 /* IN A LATER PHASE WE WILL CHANGE THIS TO BE A WARNING MESSAGE INSTEAD.     */
21521 /*---------------------------------------------------------------------------*/
21522 /*---------------------------------------------------------------------------*/
21523 /*      THIS TYPE OF ERROR SHOULD NOT GENERATE A SYSTEM ERROR IN A PRODUCT   */
21524 /*      RELEASE. THIS IS A TEMPORARY SOLUTION DURING TEST PHASE TO QUICKLY   */
21525 /*      FIND ERRORS. NORMALLY THIS SHOULD GENERATE A WARNING MESSAGE ONTO    */
21526 /*      SOME ERROR LOGGER. THIS WILL LATER BE IMPLEMENTED BY SOME SIGNAL.    */
21527 /*---------------------------------------------------------------------------*/
21528 /* ------ SYSTEM ERROR SITUATIONS ------- */
21529 /*      IN SITUATIONS WHERE THE STATE IS ERRONEOUS OR IF THE ERROR OCCURS IN */
21530 /*      THE COMMIT, COMPLETE OR ABORT PHASE, WE PERFORM A CRASH OF THE AXE VM*/
21531 /*---------------------------------------------------------------------------*/
21532 
systemErrorLab(Signal * signal,int line)21533 void Dblqh::systemErrorLab(Signal* signal, int line)
21534 {
21535   systemError(signal, line);
21536   progError(line, NDBD_EXIT_NDBREQUIRE);
21537 /*************************************************************************>*/
21538 /*       WE WANT TO INVOKE AN IMMEDIATE ERROR HERE SO WE GET THAT BY       */
21539 /*       INSERTING A CERTAIN POINTER OUT OF RANGE.                         */
21540 /*************************************************************************>*/
21541 }//Dblqh::systemErrorLab()
21542 
21543 /* ------- ERROR SITUATIONS ------- */
21544 
aiStateErrorCheckLab(Signal * signal,Uint32 * dataPtr,Uint32 length)21545 void Dblqh::aiStateErrorCheckLab(Signal* signal, Uint32* dataPtr, Uint32 length)
21546 {
21547   ndbrequire(tcConnectptr.p->abortState != TcConnectionrec::ABORT_IDLE);
21548   if (tcConnectptr.p->transactionState != TcConnectionrec::IDLE) {
21549       jam();
21550 /*************************************************************************>*/
21551 /*       TRANSACTION ABORT IS ONGOING. IT CAN STILL BE A PART OF AN        */
21552 /*       OPERATION THAT SHOULD CONTINUE SINCE THE TUPLE HAS NOT ARRIVED    */
21553 /*       YET. THIS IS POSSIBLE IF ACTIVE CREATION OF THE FRAGMENT IS       */
21554 /*       ONGOING.                                                          */
21555 /*************************************************************************>*/
21556     if (tcConnectptr.p->activeCreat == Fragrecord::AC_IGNORED) {
21557         jam();
21558 /*************************************************************************>*/
21559 /*       ONGOING ABORTS DURING ACTIVE CREATION MUST SAVE THE ATTRIBUTE INFO*/
21560 /*       SO THAT IT CAN BE SENT TO THE NEXT NODE IN THE COMMIT CHAIN. THIS */
21561 /*       IS NEEDED SINCE ALL ABORTS DURING CREATION OF A FRAGMENT ARE NOT  */
21562 /*       REALLY ERRORS. A MISSING TUPLE TO BE UPDATED SIMPLY MEANS THAT    */
21563 /*       IT HASN'T BEEN TRANSFERRED TO THE NEW REPLICA YET.                */
21564 /*************************************************************************>*/
21565 /*************************************************************************>*/
21566 /*       AFTER THIS ERROR THE ABORT MUST BE COMPLETED. TO ENSURE THIS SET  */
21567 /*       ACTIVE CREATION TO FALSE. THIS WILL ENSURE THAT THE ABORT IS      */
21568 /*       COMPLETED.                                                        */
21569 /*************************************************************************>*/
21570       if (saveAttrInfoInSection(dataPtr, length) == ZOK) {
21571         jam();
21572         if (tcConnectptr.p->transactionState ==
21573             TcConnectionrec::WAIT_AI_AFTER_ABORT) {
21574           if (tcConnectptr.p->currTupAiLen == tcConnectptr.p->totReclenAi) {
21575             jam();
21576 /*************************************************************************>*/
21577 /*       WE WERE WAITING FOR MORE ATTRIBUTE INFO AFTER A SUCCESSFUL ABORT  */
21578 /*       IN ACTIVE CREATION STATE. THE TRANSACTION SHOULD CONTINUE AS IF   */
21579 /*       IT WAS COMMITTED. NOW ALL INFO HAS ARRIVED AND WE CAN CONTINUE    */
21580 /*       WITH NORMAL PROCESSING AS IF THE TRANSACTION WAS PREPARED.        */
21581 /*       SINCE THE FRAGMENT IS UNDER CREATION WE KNOW THAT LOGGING IS      */
21582 /*       DISABLED. WE STILL HAVE TO CATER FOR DIRTY OPERATION OR NOT.      */
21583 /*************************************************************************>*/
21584             tcConnectptr.p->abortState = TcConnectionrec::ABORT_IDLE;
21585             rwConcludedAiLab(signal);
21586             return;
21587           } else {
21588             ndbrequire(tcConnectptr.p->currTupAiLen < tcConnectptr.p->totReclenAi);
21589             jam();
21590             return;	/* STILL WAITING FOR MORE ATTRIBUTE INFO */
21591           }//if
21592         }//if
21593       } else {
21594         jam();
21595 /*************************************************************************>*/
21596 /*       AFTER THIS ERROR THE ABORT MUST BE COMPLETED. TO ENSURE THIS SET  */
21597 /*       ACTIVE CREATION TO ABORT. THIS WILL ENSURE THAT THE ABORT IS      */
21598 /*       COMPLETED AND THAT THE ERROR CODE IS PROPERLY SET                 */
21599 /*************************************************************************>*/
21600         tcConnectptr.p->errorCode = terrorCode;
21601         tcConnectptr.p->activeCreat = Fragrecord::AC_NORMAL;
21602         if (tcConnectptr.p->transactionState ==
21603 	    TcConnectionrec::WAIT_AI_AFTER_ABORT) {
21604           jam();
21605 /*************************************************************************>*/
21606 /*       ABORT IS ALREADY COMPLETED. WE NEED TO RESTART IT FROM WHERE IT   */
21607 /*       WAS INTERRUPTED.                                                  */
21608 /*************************************************************************>*/
21609           continueAbortLab(signal);
21610           return;
21611         } else {
21612           jam();
21613           return;
21614 /*************************************************************************>*/
21615 // Abort is ongoing. It will complete since we set the activeCreat = ZFALSE
21616 /*************************************************************************>*/
21617         }//if
21618       }//if
21619     }//if
21620   }//if
21621 /*************************************************************************>*/
21622 /* TRANSACTION HAVE BEEN ABORTED. THUS IGNORE ALL SIGNALS BELONGING TO IT. */
21623 /*************************************************************************>*/
21624   return;
21625 }//Dblqh::aiStateErrorCheckLab()
21626 
takeOverErrorLab(Signal * signal)21627 void Dblqh::takeOverErrorLab(Signal* signal)
21628 {
21629   terrorCode = ZTAKE_OVER_ERROR;
21630   abortErrorLab(signal);
21631   return;
21632 }//Dblqh::takeOverErrorLab()
21633 
21634 /* ##########################################################################
21635  *               TEST MODULE
21636  * ######################################################################### */
21637 #ifdef VM_TRACE
execTESTSIG(Signal * signal)21638 void Dblqh::execTESTSIG(Signal* signal)
21639 {
21640   jamEntry();
21641   Uint32 userpointer = signal->theData[0];
21642   BlockReference userblockref = signal->theData[1];
21643   Uint32 testcase = signal->theData[2];
21644 
21645   signal->theData[0] = userpointer;
21646   signal->theData[1] = cownref;
21647   signal->theData[2] = testcase;
21648   sendSignal(userblockref, GSN_TESTSIG, signal, 25, JBB);
21649   return;
21650 }//Dblqh::execTESTSIG()
21651 
21652 /* *************** */
21653 /*  MEMCHECKREQ  > */
21654 /* *************** */
21655 /* ************************************************************************>>
21656  * THIS SIGNAL IS PURELY FOR TESTING PURPOSES. IT CHECKS THE FREE LIST
21657  * AND REPORTS THE NUMBER OF FREE RECORDS.
21658  * THIS CAN BE DONE TO ENSURE THAT NO RECORDS HAS BEEN LOST
21659  * ************************************************************************> */
execMEMCHECKREQ(Signal * signal)21660 void Dblqh::execMEMCHECKREQ(Signal* signal)
21661 {
21662   Uint32* dataPtr = &signal->theData[0];
21663   jamEntry();
21664   BlockReference userblockref = signal->theData[0];
21665   Uint32 index = 0;
21666   for (Uint32 i = 0; i < 7; i++)
21667     dataPtr[i] = 0;
21668   addfragptr.i = cfirstfreeAddfragrec;
21669   while (addfragptr.i != RNIL) {
21670     ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord);
21671     addfragptr.i = addfragptr.p->nextAddfragrec;
21672     dataPtr[index]++;
21673   }//while
21674   index++;
21675   dataPtr[index]= 0;
21676   index++;
21677   dataPtr[index]= 0;
21678   index++;
21679   for (tabptr.i = 0;
21680        tabptr.i < ctabrecFileSize;
21681        tabptr.i++) {
21682     ptrAss(tabptr, tablerec);
21683     if (tabptr.p->tableStatus == Tablerec::NOT_DEFINED) {
21684       dataPtr[index]++;
21685     }//if
21686   }//for
21687   index++;
21688   tcConnectptr.i = cfirstfreeTcConrec;
21689   dataPtr[index] = ctcNumFree;
21690   sendSignal(userblockref, GSN_MEMCHECKCONF, signal, 10, JBB);
21691   return;
21692 }//Dblqh::execMEMCHECKREQ()
21693 
21694 #endif
21695 
21696 /* ************************************************************************* */
21697 /* ************************* STATEMENT BLOCKS ****************************** */
21698 /* ************************************************************************* */
21699 /* ========================================================================= */
21700 /* ====== BUILD LINKED LIST OF LOG PAGES AFTER RECEIVING FSREADCONF  ======= */
21701 /*                                                                           */
21702 /* ========================================================================= */
buildLinkedLogPageList(Signal * signal)21703 void Dblqh::buildLinkedLogPageList(Signal* signal)
21704 {
21705   LogPageRecordPtr bllLogPagePtr;
21706 
21707   arrGuard(lfoPtr.p->noPagesRw - 1, 16);
21708   arrGuard(lfoPtr.p->noPagesRw, 16);
21709   Uint32 prev = RNIL;
21710   for (UintR tbllIndex = 0; tbllIndex < lfoPtr.p->noPagesRw; tbllIndex++) {
21711     jam();
21712     /* ----------------------------------------------------------------------
21713      *  BUILD LINKED LIST BUT ALSO ENSURE THAT PAGE IS NOT SEEN AS DIRTY
21714      *  INITIALLY.
21715      * --------------------------------------------------------------------- */
21716     bllLogPagePtr.i = lfoPtr.p->logPageArray[tbllIndex];
21717     ptrCheckGuard(bllLogPagePtr, clogPageFileSize, logPageRecord);
21718 
21719 // #if VM_TRACE
21720 //     // Check logPage checksum before modifying it
21721 //     Uint32 calcCheckSum = calcPageCheckSum(bllLogPagePtr);
21722 //     Uint32 checkSum = bllLogPagePtr.p->logPageWord[ZPOS_CHECKSUM];
21723 //     if (checkSum != calcCheckSum) {
21724 //       ndbout << "Redolog: Checksum failure." << endl;
21725 //       progError(__LINE__, NDBD_EXIT_NDBREQUIRE, "Redolog: Checksum failure.");
21726 //     }
21727 // #endif
21728 
21729     bllLogPagePtr.p->logPageWord[ZPREV_PAGE] = prev;
21730     bllLogPagePtr.p->logPageWord[ZNEXT_PAGE] =
21731       lfoPtr.p->logPageArray[tbllIndex + 1];
21732     bllLogPagePtr.p->logPageWord[ZPOS_DIRTY] = ZNOT_DIRTY;
21733     prev = bllLogPagePtr.i;
21734   }//for
21735   bllLogPagePtr.i = lfoPtr.p->logPageArray[lfoPtr.p->noPagesRw - 1];
21736   ptrCheckGuard(bllLogPagePtr, clogPageFileSize, logPageRecord);
21737   bllLogPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL;
21738 }//Dblqh::buildLinkedLogPageList()
21739 
21740 /* =========================================================================
21741  * =======                      CHANGE TO NEXT MBYTE IN LOG           =======
21742  *
21743  * ========================================================================= */
changeMbyte(Signal * signal)21744 void Dblqh::changeMbyte(Signal* signal)
21745 {
21746   writeNextLog(signal);
21747   writeFileDescriptor(signal);
21748 }//Dblqh::changeMbyte()
21749 
21750 /* ========================================================================= */
21751 /* ======       CHECK IF THIS COMMIT LOG RECORD IS TO BE EXECUTED    ======= */
21752 /*                                                                           */
21753 /*      SUBROUTINE SHORT NAME = CEL                                          */
21754 /* ========================================================================= */
checkIfExecLog(Signal * signal)21755 Uint32 Dblqh::checkIfExecLog(Signal* signal)
21756 {
21757   tabptr.i = tcConnectptr.p->tableref;
21758   ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
21759   if (getFragmentrec(signal, tcConnectptr.p->fragmentid) &&
21760       (table_version_major(tabptr.p->schemaVersion) == table_version_major(tcConnectptr.p->schemaVersion))) {
21761     if (fragptr.p->execSrStatus != Fragrecord::IDLE) {
21762       if (fragptr.p->execSrNoReplicas > logPartPtr.p->execSrExecuteIndex) {
21763         ndbrequire((fragptr.p->execSrNoReplicas - 1) < MAX_REPLICAS);
21764         for (Uint32 i = logPartPtr.p->execSrExecuteIndex;
21765 	     i < fragptr.p->execSrNoReplicas;
21766 	     i++) {
21767           jam();
21768           if (tcConnectptr.p->gci_hi >= fragptr.p->execSrStartGci[i]) {
21769             if (tcConnectptr.p->gci_hi <= fragptr.p->execSrLastGci[i]) {
21770               jam();
21771               logPartPtr.p->execSrExecuteIndex = i;
21772               return ZOK;
21773             }//if
21774           }//if
21775         }//for
21776       }//if
21777     }//if
21778   }//if
21779   return ZNOT_OK;
21780 }//Dblqh::checkIfExecLog()
21781 
21782 /* ========================================================================= */
21783 /* == CHECK IF THERE IS LESS THAN 192 KBYTE IN THE BUFFER PLUS INCOMING  === */
21784 /*      READS ALREADY STARTED. IF SO IS THE CASE THEN START ANOTHER READ IF  */
21785 /*      THERE ARE MORE PAGES IN THIS MBYTE.                                  */
21786 /*                                                                           */
21787 /* ========================================================================= */
checkReadExecSr(Signal * signal)21788 void Dblqh::checkReadExecSr(Signal* signal)
21789 {
21790   logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG;
21791   logPartPtr.p->execSrPagesRead = logPartPtr.p->execSrPagesRead + 8;
21792   logPartPtr.p->execSrPagesReading = logPartPtr.p->execSrPagesReading - 8;
21793   if ((logPartPtr.p->execSrPagesRead + logPartPtr.p->execSrPagesReading) <
21794       ZREAD_AHEAD_SIZE) {
21795     jam();
21796     /* ----------------------------------------------------------------------
21797      *  WE HAVE LESS THAN 64 KBYTE OF LOG PAGES REMAINING IN MEMORY OR ON
21798      *  ITS WAY TO MAIN MEMORY. READ IN 8 MORE PAGES.
21799      * --------------------------------------------------------------------- */
21800     if ((logPartPtr.p->execSrPagesRead + logPartPtr.p->execSrPagesExecuted) <
21801 	ZPAGES_IN_MBYTE) {
21802       jam();
21803       /* --------------------------------------------------------------------
21804        *  THERE ARE MORE PAGES TO READ IN THIS MBYTE. READ THOSE FIRST
21805        *  IF >= ZPAGES_IN_MBYTE THEN THERE ARE NO MORE PAGES TO READ. THUS
21806        *  WE PROCEED WITH EXECUTION OF THE LOG.
21807        * ------------------------------------------------------------------- */
21808       readExecSr(signal);
21809       logPartPtr.p->logExecState = LogPartRecord::LES_WAIT_READ_EXEC_SR;
21810     }//if
21811   }//if
21812 }//Dblqh::checkReadExecSr()
21813 
21814 /* ========================================================================= */
21815 /* ==== CHECK IF START OF NEW FRAGMENT IS COMPLETED AND WE CAN       ======= */
21816 /* ==== GET THE START GCI                                            ======= */
21817 /*                                                                           */
21818 /*      SUBROUTINE SHORT NAME = CTC                                          */
21819 /* ========================================================================= */
checkScanTcCompleted(Signal * signal)21820 void Dblqh::checkScanTcCompleted(Signal* signal)
21821 {
21822   tcConnectptr.p->logWriteState = TcConnectionrec::NOT_STARTED;
21823   fragptr.i = tcConnectptr.p->fragmentptr;
21824   c_fragment_pool.getPtr(fragptr);
21825   fragptr.p->activeTcCounter = fragptr.p->activeTcCounter - 1;
21826   if (fragptr.p->activeTcCounter == 0) {
21827     jam();
21828     fragptr.p->startGci = cnewestGci + 1;
21829     tabptr.i = tcConnectptr.p->tableref;
21830     ptrCheckGuard(tabptr, ctabrecFileSize, tablerec);
21831     sendCopyActiveConf(signal, tcConnectptr.p->tableref);
21832   }//if
21833 }//Dblqh::checkScanTcCompleted()
21834 
21835 /* ------------------------------------------------------------------------- */
21836 /* ------       CLOSE A FILE DURING EXECUTION OF FRAGMENT LOG        ------- */
21837 /*                                                                           */
21838 /* ------------------------------------------------------------------------- */
closeFile(Signal * signal,LogFileRecordPtr clfLogFilePtr,Uint32 line)21839 void Dblqh::closeFile(Signal* signal,
21840 		      LogFileRecordPtr clfLogFilePtr, Uint32 line)
21841 {
21842   signal->theData[0] = clfLogFilePtr.p->fileRef;
21843   signal->theData[1] = cownref;
21844   signal->theData[2] = clfLogFilePtr.i;
21845   signal->theData[3] = ZCLOSE_NO_DELETE;
21846   signal->theData[4] = line;
21847   sendSignal(NDBFS_REF, GSN_FSCLOSEREQ, signal, 5, JBA);
21848 }//Dblqh::closeFile()
21849 
21850 
21851 /* ---------------------------------------------------------------- */
21852 /* ---------------- A LOG PAGE HAVE BEEN COMPLETED ---------------- */
21853 /*                                                                  */
21854 /*       SUBROUTINE SHORT NAME = CLP                                */
21855 // Input Pointers:
21856 // logFilePtr
21857 // logPagePtr
21858 // logPartPtr
21859 // Defines lfoPtr
21860 /* ---------------------------------------------------------------- */
completedLogPage(Signal * signal,Uint32 clpType,Uint32 place,bool sync_flag)21861 void Dblqh::completedLogPage(Signal* signal,
21862                              Uint32 clpType,
21863                              Uint32 place,
21864                              bool sync_flag)
21865 {
21866   LogPageRecordPtr clpLogPagePtr;
21867   LogPageRecordPtr wlpLogPagePtr;
21868   UintR twlpNoPages;
21869   UintR twlpType;
21870 
21871   if (logFilePtr.p->firstFilledPage == RNIL) {
21872     jam();
21873     logFilePtr.p->firstFilledPage = logPagePtr.i;
21874   } else {
21875     jam();
21876     clpLogPagePtr.i = logFilePtr.p->lastFilledPage;
21877     ptrCheckGuard(clpLogPagePtr, clogPageFileSize, logPageRecord);
21878     clpLogPagePtr.p->logPageWord[ZNEXT_PAGE] = logPagePtr.i;
21879   }//if
21880   logFilePtr.p->lastFilledPage = logPagePtr.i;
21881   logPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL;
21882   logFilePtr.p->noLogpagesInBuffer = logFilePtr.p->noLogpagesInBuffer + 1;
21883   if (logFilePtr.p->noLogpagesInBuffer != ZMAX_PAGES_WRITTEN) {
21884     if (clpType != ZLAST_WRITE_IN_FILE) {
21885       if (clpType != ZENFORCE_WRITE) {
21886         jam();
21887         return;
21888       }//if
21889     }//if
21890   }//if
21891   twlpType = clpType;
21892 /* ------------------------------------------------------------------------- */
21893 /* ------               WRITE A SET OF LOG PAGES TO DISK             ------- */
21894 /*                                                                           */
21895 /*      SUBROUTINE SHORT NAME: WLP                                           */
21896 /* ------------------------------------------------------------------------- */
21897   seizeLfo(signal);
21898   initLfo(signal);
21899   Uint32* dataPtr = &signal->theData[6];
21900   twlpNoPages = 0;
21901   wlpLogPagePtr.i = logFilePtr.p->firstFilledPage;
21902   do {
21903     dataPtr[twlpNoPages] = wlpLogPagePtr.i;
21904     twlpNoPages++;
21905     ptrCheckGuard(wlpLogPagePtr, clogPageFileSize, logPageRecord);
21906 
21907     writeDbgInfoPageHeader(wlpLogPagePtr, place,
21908                            logFilePtr.p->filePosition + twlpNoPages - 1,
21909                            ZPAGE_SIZE);
21910     // Calculate checksum for page
21911     wlpLogPagePtr.p->logPageWord[ZPOS_CHECKSUM] = calcPageCheckSum(wlpLogPagePtr);
21912     wlpLogPagePtr.i = wlpLogPagePtr.p->logPageWord[ZNEXT_PAGE];
21913   } while (wlpLogPagePtr.i != RNIL);
21914   ndbrequire(twlpNoPages < 9);
21915   dataPtr[twlpNoPages] = logFilePtr.p->filePosition;
21916 /* -------------------------------------------------- */
21917 /*       SET TIMER ON THIS LOG PART TO SIGNIFY THAT A */
21918 /*       LOG RECORD HAS BEEN SENT AT THIS TIME.       */
21919 /* -------------------------------------------------- */
21920   logPartPtr.p->logPartTimer = logPartPtr.p->logTimer;
21921   signal->theData[0] = logFilePtr.p->fileRef;
21922   signal->theData[1] = cownref;
21923   signal->theData[2] = lfoPtr.i;
21924   if (twlpType == ZLAST_WRITE_IN_FILE || sync_flag) {
21925     jam();
21926     signal->theData[3] = ZLIST_OF_MEM_PAGES_SYNCH;
21927   } else {
21928     jam();
21929     signal->theData[3] = ZLIST_OF_MEM_PAGES;
21930   }//if
21931   signal->theData[4] = ZVAR_NO_LOG_PAGE_WORD;
21932   signal->theData[5] = twlpNoPages;
21933   sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, 15, JBA);
21934 
21935   ndbrequire(logFilePtr.p->fileRef != RNIL);
21936 
21937   logPartPtr.p->m_io_tracker.send_io(32768*twlpNoPages);
21938 
21939   if (DEBUG_REDO)
21940   {
21941     ndbout_c("writing %d pages at part: %u file: %u page: %u (mb: %u)",
21942              twlpNoPages,
21943              logPartPtr.p->logPartNo,
21944              logFilePtr.p->fileNo,
21945              logFilePtr.p->filePosition,
21946              logFilePtr.p->filePosition >> ZTWOLOG_NO_PAGES_IN_MBYTE);
21947   }
21948 
21949   if (twlpType == ZNORMAL) {
21950     jam();
21951     lfoPtr.p->lfoState = LogFileOperationRecord::ACTIVE_WRITE_LOG;
21952   } else if (twlpType == ZLAST_WRITE_IN_FILE) {
21953     jam();
21954     lfoPtr.p->lfoState = LogFileOperationRecord::LAST_WRITE_IN_FILE;
21955   } else {
21956     ndbrequire(twlpType == ZENFORCE_WRITE);
21957     jam();
21958     lfoPtr.p->lfoState = LogFileOperationRecord::ACTIVE_WRITE_LOG;
21959   }//if
21960   /* ----------------------------------------------------------------------- */
21961   /* ------       MOVE PAGES FROM LOG FILE TO LFO RECORD             ------- */
21962   /*                                                                         */
21963   /* ----------------------------------------------------------------------- */
21964   /* -------------------------------------------------- */
21965   /*       MOVE PAGES TO LFO RECORD AND REMOVE THEM     */
21966   /*       FROM LOG FILE RECORD.                        */
21967   /* -------------------------------------------------- */
21968   lfoPtr.p->firstLfoPage = logFilePtr.p->firstFilledPage;
21969   logFilePtr.p->firstFilledPage = RNIL;
21970   logFilePtr.p->lastFilledPage = RNIL;
21971   logFilePtr.p->noLogpagesInBuffer = 0;
21972 
21973   lfoPtr.p->noPagesRw = twlpNoPages;
21974   lfoPtr.p->lfoPageNo = logFilePtr.p->filePosition;
21975   lfoPtr.p->lfoWordWritten = ZPAGE_SIZE - 1;
21976   logFilePtr.p->filePosition += twlpNoPages;
21977 }//Dblqh::completedLogPage()
21978 
21979 /* ---------------------------------------------------------------- */
21980 /* ---------------- DELETE FRAGMENT RECORD ------------------------ */
21981 /*                                                                  */
21982 /*       SUBROUTINE SHORT NAME = DFR                                */
21983 /* ---------------------------------------------------------------- */
deleteFragrec(Uint32 fragId)21984 void Dblqh::deleteFragrec(Uint32 fragId)
21985 {
21986   Uint32 indexFound= RNIL;
21987   fragptr.i = RNIL;
21988   for (Uint32 i = 0; i < NDB_ARRAY_SIZE(tabptr.p->fragid); i++) {
21989     jam();
21990     if (tabptr.p->fragid[i] == fragId) {
21991       fragptr.i = tabptr.p->fragrec[i];
21992       indexFound = i;
21993       break;
21994     }//if
21995   }//for
21996   if (fragptr.i != RNIL) {
21997     jam();
21998     c_fragment_pool.getPtr(fragptr);
21999     tabptr.p->fragid[indexFound] = ZNIL;
22000     tabptr.p->fragrec[indexFound] = RNIL;
22001     fragptr.p->fragStatus = Fragrecord::FREE;
22002     c_fragment_pool.release(fragptr);
22003   }//if
22004 }//Dblqh::deleteFragrec()
22005 
22006 /* ------------------------------------------------------------------------- */
22007 /* -------          FIND LOG FILE RECORD GIVEN FILE NUMBER           ------- */
22008 /*                                                                           */
22009 /*       INPUT:          TFLF_FILE_NO    THE FILE NUMBER                     */
22010 /*                       FLF_LOG_PART_PTR THE LOG PART RECORD                */
22011 /*       OUTPUT:         FLF_LOG_FILE_PTR THE FOUND LOG FILE RECORD          */
22012 /*       SUBROUTINE SHORT NAME = FLF                                         */
22013 /* ------------------------------------------------------------------------- */
findLogfile(Signal * signal,Uint32 fileNo,LogPartRecordPtr flfLogPartPtr,LogFileRecordPtr * parLogFilePtr)22014 void Dblqh::findLogfile(Signal* signal,
22015                         Uint32 fileNo,
22016                         LogPartRecordPtr flfLogPartPtr,
22017                         LogFileRecordPtr* parLogFilePtr)
22018 {
22019   LogFileRecordPtr locLogFilePtr;
22020   locLogFilePtr.i = flfLogPartPtr.p->firstLogfile;
22021   Uint32 loopCount = 0;
22022   while (true) {
22023     ptrCheckGuard(locLogFilePtr, clogFileFileSize, logFileRecord);
22024     if (locLogFilePtr.p->fileNo == fileNo) {
22025       jam();
22026       ndbrequire(loopCount == fileNo);
22027       parLogFilePtr->i = locLogFilePtr.i;
22028       parLogFilePtr->p = locLogFilePtr.p;
22029       return;
22030     }//if
22031     locLogFilePtr.i = locLogFilePtr.p->nextLogFile;
22032     loopCount++;
22033     if (loopCount >= flfLogPartPtr.p->noLogFiles &&
22034 	getNodeState().startLevel != NodeState::SL_STARTED)
22035     {
22036       goto error;
22037     }
22038     ndbrequire(loopCount < flfLogPartPtr.p->noLogFiles);
22039   }//while
22040 
22041 error:
22042   char buf[255];
22043   BaseString::snprintf(buf, sizeof(buf),
22044 		       "Unable to restart, failed while reading redo."
22045 		       " Likely invalid change of configuration");
22046   progError(__LINE__,
22047 	    NDBD_EXIT_INVALID_CONFIG,
22048 	    buf);
22049 }//Dblqh::findLogfile()
22050 
22051 /* ------------------------------------------------------------------------- */
22052 /* ------     FIND PAGE REFERENCE IN MEMORY BUFFER AT LOG EXECUTION  ------- */
22053 /*                                                                           */
22054 /* ------------------------------------------------------------------------- */
findPageRef(Signal * signal,CommitLogRecord * commitLogRecord)22055 void Dblqh::findPageRef(Signal* signal, CommitLogRecord* commitLogRecord)
22056 {
22057   UintR tfprIndex;
22058 
22059   logPagePtr.i = RNIL;
22060   if (ERROR_INSERTED(5020)) {
22061     // Force system to read page from disk
22062     return;
22063   }
22064   pageRefPtr.i = logPartPtr.p->lastPageRef;
22065   do {
22066     ptrCheckGuard(pageRefPtr, cpageRefFileSize, pageRefRecord);
22067     if (commitLogRecord->fileNo == pageRefPtr.p->prFileNo) {
22068       if (commitLogRecord->startPageNo >= pageRefPtr.p->prPageNo) {
22069         if (commitLogRecord->startPageNo < (Uint16) (pageRefPtr.p->prPageNo + 8)) {
22070           jam();
22071           tfprIndex = commitLogRecord->startPageNo - pageRefPtr.p->prPageNo;
22072           logPagePtr.i = pageRefPtr.p->pageRef[tfprIndex];
22073           ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
22074           return;
22075         }//if
22076       }//if
22077     }//if
22078     pageRefPtr.i = pageRefPtr.p->prPrev;
22079   } while (pageRefPtr.i != RNIL);
22080 
22081 #ifndef NO_REDO_PAGE_CACHE
22082   RedoPageCache& cache = m_redo_page_cache;
22083   RedoCacheLogPageRecord key;
22084   key.m_part_no = logPartPtr.p->logPartNo;
22085   key.m_file_no = commitLogRecord->fileNo;
22086   key.m_page_no = commitLogRecord->startPageNo;
22087   Ptr<RedoCacheLogPageRecord> pagePtr;
22088   if (cache.m_hash.find(pagePtr, key))
22089   {
22090     jam();
22091     if (cache.m_lru.hasPrev(pagePtr))
22092     {
22093       jam();
22094       cache.m_lru.remove(pagePtr);
22095       cache.m_lru.addFirst(pagePtr);
22096     }
22097     logPagePtr.i = pagePtr.i;
22098     ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
22099 
22100     Ptr<LogPageRecord> loopPtr = logPagePtr;
22101     Uint32 extra = commitLogRecord->stopPageNo - commitLogRecord->startPageNo;
22102     for (Uint32 i = 0; i<extra; i++)
22103     {
22104       jam();
22105       Uint32 prevPtrI = loopPtr.i;
22106       loopPtr.i = loopPtr.p->logPageWord[ZNEXT_PAGE];
22107       if (loopPtr.i == RNIL)
22108       {
22109         jam();
22110         /**
22111          * next page is not linked
22112          *   check if it's added as a "single" page
22113          */
22114         key.m_page_no = commitLogRecord->startPageNo + i + 1;
22115         if (cache.m_hash.find(pagePtr, key))
22116         {
22117           jam();
22118           /**
22119            * Yes it is...link them
22120            */
22121           Ptr<LogPageRecord> tmp;
22122           tmp.i = pagePtr.i;
22123           tmp.p = reinterpret_cast<LogPageRecord*>(pagePtr.p);
22124           tmp.p->logPageWord[ZPREV_PAGE] = prevPtrI;
22125           loopPtr.p->logPageWord[ZNEXT_PAGE] = tmp.i;
22126           loopPtr.i = tmp.i;
22127         }
22128         else
22129         {
22130           jam();
22131           logPagePtr.i = RNIL;
22132           cache.m_multi_miss++;
22133           if (0)
22134           ndbout_c("Found part: %u file: %u page: %u but not next page(%u) %u",
22135                    key.m_part_no,
22136                    commitLogRecord->fileNo,
22137                    commitLogRecord->startPageNo,
22138                    (i + 1),
22139                    commitLogRecord->startPageNo + i + 1);
22140           return;
22141         }
22142       }
22143 
22144       ptrCheckGuard(loopPtr, clogPageFileSize, logPageRecord);
22145       pagePtr.i = loopPtr.i;
22146       pagePtr.p = reinterpret_cast<RedoCacheLogPageRecord*>(loopPtr.p);
22147       if (cache.m_lru.hasPrev(pagePtr))
22148       {
22149         jam();
22150         cache.m_lru.remove(pagePtr);
22151         cache.m_lru.addFirst(pagePtr);
22152       }
22153     }
22154     cache.m_hits++;
22155     if (extra)
22156     {
22157       jam();
22158       cache.m_multi_page++;
22159     }
22160   }
22161 #endif
22162 }//Dblqh::findPageRef()
22163 
22164 /* ------------------------------------------------------------------------- */
22165 /* ------         GET FIRST OPERATION QUEUED FOR LOGGING             ------- */
22166 /*                                                                           */
22167 /*      SUBROUTINE SHORT NAME = GFL                                          */
22168 /* ------------------------------------------------------------------------- */
22169 void
getFirstInLogQueue(Signal * signal,Ptr<TcConnectionrec> & dst)22170 Dblqh::getFirstInLogQueue(Signal* signal,
22171                           Ptr<TcConnectionrec> & dst)
22172 {
22173   TcConnectionrecPtr tmp;
22174 /* -------------------------------------------------- */
22175 /*       GET THE FIRST FROM THE LOG QUEUE AND REMOVE  */
22176 /*       IT FROM THE QUEUE.                           */
22177 /* -------------------------------------------------- */
22178   LogPartRecord::OperationQueue * queue = &logPartPtr.p->m_log_complete_queue;
22179   tmp.i = queue->firstElement;
22180   if (tmp.i == RNIL)
22181   {
22182     jam();
22183     queue = &logPartPtr.p->m_log_prepare_queue;
22184     tmp.i = queue->firstElement;
22185   }
22186   ptrCheckGuard(tmp, ctcConnectrecFileSize, tcConnectionrec);
22187   queue->firstElement = tmp.p->nextTcLogQueue;
22188   if (queue->firstElement == RNIL) {
22189     jam();
22190     queue->lastElement = RNIL;
22191   }
22192   else
22193   {
22194     /**
22195      * Also needs to set the prev pointer of the new first
22196      * element to RNIL to indicate it is now first in the
22197      * list.
22198      */
22199     TcConnectionrecPtr new_first;
22200     new_first.i = tmp.p->nextTcLogQueue;
22201     ptrCheckGuard(new_first, ctcConnectrecFileSize, tcConnectionrec);
22202     new_first.p->prevTcLogQueue = RNIL;
22203   }
22204   tmp.p->nextTcLogQueue = RNIL;
22205   tmp.p->prevTcLogQueue = RNIL;
22206   dst = tmp;
22207 }//Dblqh::getFirstInLogQueue()
22208 
22209 void
remove_from_prepare_log_queue(Signal * signal,TcConnectionrecPtr tcPtr)22210 Dblqh::remove_from_prepare_log_queue(Signal *signal,
22211                                      TcConnectionrecPtr tcPtr)
22212 {
22213   TcConnectionrecPtr tmp;
22214   LogPartRecordPtr regLogPartPtr;
22215   regLogPartPtr.i = tcPtr.p->m_log_part_ptr_i;
22216   ptrCheckGuard(regLogPartPtr, clogPartFileSize, logPartRecord);
22217   LogPartRecord::OperationQueue *queue = &regLogPartPtr.p->m_log_prepare_queue;
22218 
22219   if (tcPtr.p->prevTcLogQueue == RNIL)
22220   {
22221     jam();
22222     ndbrequire(queue->firstElement == tcPtr.i);
22223     queue->firstElement = tcPtr.p->nextTcLogQueue;
22224   }
22225   else
22226   {
22227     jam();
22228     tmp.i = tcPtr.p->prevTcLogQueue;
22229     ptrCheckGuard(tmp, ctcConnectrecFileSize, tcConnectionrec);
22230     tmp.p->nextTcLogQueue = tcPtr.p->nextTcLogQueue;
22231   }
22232 
22233   if (tcPtr.p->nextTcLogQueue == RNIL)
22234   {
22235     jam();
22236     ndbrequire(queue->lastElement == tcPtr.i);
22237     queue->lastElement = tcPtr.p->prevTcLogQueue;
22238   }
22239   else
22240   {
22241     jam();
22242     tmp.i = tcPtr.p->nextTcLogQueue;
22243     ptrCheckGuard(tmp, ctcConnectrecFileSize, tcConnectionrec);
22244     tmp.p->prevTcLogQueue = tcPtr.p->prevTcLogQueue;
22245   }
22246 
22247   tcPtr.p->prevTcLogQueue = RNIL;
22248   tcPtr.p->nextTcLogQueue = RNIL;
22249 }
22250 
22251 /* ---------------------------------------------------------------- */
22252 /* ---------------- GET FRAGMENT RECORD --------------------------- */
22253 /*       INPUT:          TFRAGID         FRAGMENT ID LOOKING FOR    */
22254 /*                       TABPTR          TABLE ID                   */
22255 /*       SUBROUTINE SHORT NAME = GFR                                */
22256 /* ---------------------------------------------------------------- */
getFragmentrec(Signal * signal,Uint32 fragId)22257 bool Dblqh::getFragmentrec(Signal* signal, Uint32 fragId)
22258 {
22259   for (Uint32 i = 0; i < NDB_ARRAY_SIZE(tabptr.p->fragid); i++) {
22260     jam();
22261     if (tabptr.p->fragid[i] == fragId) {
22262       fragptr.i = tabptr.p->fragrec[i];
22263       c_fragment_pool.getPtr(fragptr);
22264       return true;
22265     }//if
22266   }//for
22267   return false;
22268 }//Dblqh::getFragmentrec()
22269 
22270 /* ========================================================================= */
22271 /* ======                      INITIATE FRAGMENT RECORD              ======= */
22272 /*                                                                           */
22273 /* ========================================================================= */
initialiseAddfragrec(Signal * signal)22274 void Dblqh::initialiseAddfragrec(Signal* signal)
22275 {
22276   if (caddfragrecFileSize != 0) {
22277     for (addfragptr.i = 0; addfragptr.i < caddfragrecFileSize; addfragptr.i++) {
22278       ptrAss(addfragptr, addFragRecord);
22279       addfragptr.p->addfragStatus = AddFragRecord::FREE;
22280       addfragptr.p->nextAddfragrec = addfragptr.i + 1;
22281     }//for
22282     addfragptr.i = caddfragrecFileSize - 1;
22283     ptrAss(addfragptr, addFragRecord);
22284     addfragptr.p->nextAddfragrec = RNIL;
22285     cfirstfreeAddfragrec = 0;
22286   } else {
22287     jam();
22288     cfirstfreeAddfragrec = RNIL;
22289   }//if
22290 }//Dblqh::initialiseAddfragrec()
22291 
22292 /* ========================================================================= */
22293 /* ======                INITIATE FRAGMENT RECORD                    ======= */
22294 /*                                                                           */
22295 /* ========================================================================= */
initialiseFragrec(Signal * signal)22296 void Dblqh::initialiseFragrec(Signal* signal)
22297 {
22298 
22299   SLList<Fragrecord> tmp(c_fragment_pool);
22300   while (tmp.seizeFirst(fragptr))
22301   {
22302     refresh_watch_dog();
22303     new (fragptr.p) Fragrecord();
22304     fragptr.p->fragStatus = Fragrecord::FREE;
22305     fragptr.p->execSrStatus = Fragrecord::IDLE;
22306     fragptr.p->srStatus = Fragrecord::SS_IDLE;
22307   }
22308   while (tmp.releaseFirst());
22309 }//Dblqh::initialiseFragrec()
22310 
22311 /* ========================================================================= */
22312 /* ======                INITIATE FRAGMENT RECORD                    ======= */
22313 /*                                                                           */
22314 /* ========================================================================= */
initialiseGcprec(Signal * signal)22315 void Dblqh::initialiseGcprec(Signal* signal)
22316 {
22317   UintR tigpIndex;
22318 
22319   if (cgcprecFileSize != 0) {
22320     for (gcpPtr.i = 0; gcpPtr.i < cgcprecFileSize; gcpPtr.i++) {
22321       ptrAss(gcpPtr, gcpRecord);
22322       for (tigpIndex = 0; tigpIndex < NDB_MAX_LOG_PARTS; tigpIndex++) {
22323         gcpPtr.p->gcpLogPartState[tigpIndex] = ZIDLE;
22324         gcpPtr.p->gcpSyncReady[tigpIndex] = ZFALSE;
22325       }//for
22326     }//for
22327   }//if
22328 }//Dblqh::initialiseGcprec()
22329 
22330 /* ========================================================================= */
22331 /* ======                INITIATE LCP RECORD                         ======= */
22332 /*                                                                           */
22333 /* ========================================================================= */
initialiseLcpRec(Signal * signal)22334 void Dblqh::initialiseLcpRec(Signal* signal)
22335 {
22336   if (clcpFileSize != 0) {
22337     for (lcpPtr.i = 0; lcpPtr.i < clcpFileSize; lcpPtr.i++) {
22338       ptrAss(lcpPtr, lcpRecord);
22339       lcpPtr.p->lcpState = LcpRecord::LCP_IDLE;
22340       lcpPtr.p->reportEmpty = false;
22341       lcpPtr.p->firstFragmentFlag = false;
22342       lcpPtr.p->lastFragmentFlag = false;
22343     }//for
22344   }//if
22345 }//Dblqh::initialiseLcpRec()
22346 
22347 /* ========================================================================= */
22348 /* ======         INITIATE LOG FILE OPERATION RECORD                 ======= */
22349 /*                                                                           */
22350 /* ========================================================================= */
initialiseLfo(Signal * signal)22351 void Dblqh::initialiseLfo(Signal* signal)
22352 {
22353   if (clfoFileSize != 0) {
22354     for (lfoPtr.i = 0; lfoPtr.i < clfoFileSize; lfoPtr.i++) {
22355       ptrAss(lfoPtr, logFileOperationRecord);
22356       lfoPtr.p->lfoState = LogFileOperationRecord::IDLE;
22357       lfoPtr.p->lfoTimer = 0;
22358       lfoPtr.p->nextLfo = lfoPtr.i + 1;
22359     }//for
22360     lfoPtr.i = clfoFileSize - 1;
22361     ptrAss(lfoPtr, logFileOperationRecord);
22362     lfoPtr.p->nextLfo = RNIL;
22363     cfirstfreeLfo = 0;
22364   } else {
22365     jam();
22366     cfirstfreeLfo = RNIL;
22367   }//if
22368 }//Dblqh::initialiseLfo()
22369 
22370 /* ========================================================================= */
22371 /* ======                 INITIATE LOG FILE RECORD                   ======= */
22372 /*                                                                           */
22373 /* ========================================================================= */
initialiseLogFile(Signal * signal)22374 void Dblqh::initialiseLogFile(Signal* signal)
22375 {
22376   if (clogFileFileSize != 0) {
22377     for (logFilePtr.i = 0; logFilePtr.i < clogFileFileSize; logFilePtr.i++) {
22378       ptrAss(logFilePtr, logFileRecord);
22379       logFilePtr.p->nextLogFile = logFilePtr.i + 1;
22380       logFilePtr.p->logFileStatus = LogFileRecord::LFS_IDLE;
22381 
22382       logFilePtr.p->logLastPrepRef = new Uint32[clogFileSize];
22383       logFilePtr.p->logMaxGciCompleted = new Uint32[clogFileSize];
22384       logFilePtr.p->logMaxGciStarted = new Uint32[clogFileSize];
22385 
22386       if (logFilePtr.p->logLastPrepRef == 0 ||
22387           logFilePtr.p->logMaxGciCompleted == 0 ||
22388           logFilePtr.p->logMaxGciStarted == 0)
22389       {
22390         char buf[256];
22391         BaseString::snprintf(buf, sizeof(buf),
22392                              "Failed to alloc mbyte(%u) arrays for logfile %u",
22393                              clogFileSize, logFilePtr.i);
22394         progError(__LINE__, NDBD_EXIT_MEMALLOC, buf);
22395       }
22396 
22397     }//for
22398     logFilePtr.i = clogFileFileSize - 1;
22399     ptrAss(logFilePtr, logFileRecord);
22400     logFilePtr.p->nextLogFile = RNIL;
22401     cfirstfreeLogFile = 0;
22402   } else {
22403     jam();
22404     cfirstfreeLogFile = RNIL;
22405   }//if
22406 }//Dblqh::initialiseLogFile()
22407 
22408 /* ========================================================================= */
22409 /* ======                  INITIATE LOG PAGES                        ======= */
22410 /*                                                                           */
22411 /* ========================================================================= */
initialiseLogPage(Signal * signal)22412 void Dblqh::initialiseLogPage(Signal* signal)
22413 {
22414   /**
22415    * Moved into initRecords()
22416    */
22417 }//Dblqh::initialiseLogPage()
22418 
22419 /* =========================================================================
22420  * ======                       INITIATE LOG PART RECORD             =======
22421  *
22422  * ========================================================================= */
initialiseLogPart(Signal * signal)22423 void Dblqh::initialiseLogPart(Signal* signal)
22424 {
22425   for (logPartPtr.i = 0; logPartPtr.i < clogPartFileSize; logPartPtr.i++) {
22426     ptrAss(logPartPtr, logPartRecord);
22427     logPartPtr.p->waitWriteGciLog = LogPartRecord::WWGL_FALSE;
22428     logPartPtr.p->LogLqhKeyReqSent = ZFALSE;
22429     logPartPtr.p->logPartNewestCompletedGCI = (UintR)-1;
22430     logPartPtr.p->logTcConrec = RNIL;
22431   }//for
22432 }//Dblqh::initialiseLogPart()
22433 
initialisePageRef(Signal * signal)22434 void Dblqh::initialisePageRef(Signal* signal)
22435 {
22436   if (cpageRefFileSize != 0) {
22437     for (pageRefPtr.i = 0;
22438 	 pageRefPtr.i < cpageRefFileSize;
22439 	 pageRefPtr.i++) {
22440       ptrAss(pageRefPtr, pageRefRecord);
22441       pageRefPtr.p->prNext = pageRefPtr.i + 1;
22442     }//for
22443     pageRefPtr.i = cpageRefFileSize - 1;
22444     ptrAss(pageRefPtr, pageRefRecord);
22445     pageRefPtr.p->prNext = RNIL;
22446     cfirstfreePageRef = 0;
22447   } else {
22448     jam();
22449     cfirstfreePageRef = RNIL;
22450   }//if
22451 }//Dblqh::initialisePageRef()
22452 
22453 /* ==========================================================================
22454  * =======                        INITIATE RECORDS                    =======
22455  *
22456  *       TAKES CARE OF INITIATION OF ALL RECORDS IN THIS BLOCK.
22457  * ========================================================================= */
initialiseRecordsLab(Signal * signal,Uint32 data,Uint32 retRef,Uint32 retData)22458 void Dblqh::initialiseRecordsLab(Signal* signal, Uint32 data,
22459 				 Uint32 retRef, Uint32 retData)
22460 {
22461   Uint32 i;
22462   switch (data) {
22463   case 0:
22464     jam();
22465     m_sr_nodes.clear();
22466     m_sr_exec_sr_req.clear();
22467     m_sr_exec_sr_conf.clear();
22468     for (i = 0; i < 4; i++) {
22469       cactiveCopy[i] = RNIL;
22470     }//for
22471     cnoActiveCopy = 0;
22472     ccurrentGcprec = RNIL;
22473     caddNodeState = ZFALSE;
22474     cstartRecReq = SRR_INITIAL; // Initial
22475     cnewestGci = 0;
22476     cnewestCompletedGci = 0;
22477     crestartOldestGci = 0;
22478     crestartNewestGci = 0;
22479     csrPhaseStarted = ZSR_NO_PHASE_STARTED;
22480     csrPhasesCompleted = 0;
22481     cmasterDihBlockref = 0;
22482     cnoFragmentsExecSr = 0;
22483     cnoOutstandingExecFragReq = 0;
22484     clcpCompletedState = LCP_IDLE;
22485     csrExecUndoLogState = EULS_IDLE;
22486     c_lcpId = 0;
22487     cnoOfFragsCheckpointed = 0;
22488     break;
22489   case 1:
22490     jam();
22491     initialiseAddfragrec(signal);
22492     break;
22493   case 2:
22494     jam();
22495     /* Unused */
22496     break;
22497   case 3:
22498     jam();
22499     /* Unused */
22500     break;
22501   case 4:
22502     jam();
22503     initialiseFragrec(signal);
22504     break;
22505   case 5:
22506     jam();
22507     initialiseGcprec(signal);
22508     initialiseLcpRec(signal);
22509     break;
22510   case 6:
22511     jam();
22512     initialiseLogPage(signal);
22513     break;
22514   case 7:
22515     jam();
22516     initialiseLfo(signal);
22517     break;
22518   case 8:
22519     jam();
22520     initialiseLogFile(signal);
22521     initialiseLogPart(signal);
22522     break;
22523   case 9:
22524     jam();
22525     initialisePageRef(signal);
22526     break;
22527   case 10:
22528     jam();
22529     initialiseScanrec(signal);
22530     break;
22531   case 11:
22532     jam();
22533     initialiseTabrec(signal);
22534     break;
22535   case 12:
22536     jam();
22537     initialiseTcNodeFailRec(signal);
22538     initialiseTcrec(signal);
22539     {
22540       ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend();
22541       conf->senderRef = reference();
22542       conf->senderData = retData;
22543       sendSignal(retRef, GSN_READ_CONFIG_CONF, signal,
22544 		 ReadConfigConf::SignalLength, JBB);
22545     }
22546     return;
22547     break;
22548   default:
22549     ndbrequire(false);
22550     break;
22551   }//switch
22552 
22553   signal->theData[0] = ZINITIALISE_RECORDS;
22554   signal->theData[1] = data + 1;
22555   signal->theData[2] = 0;
22556   signal->theData[3] = retRef;
22557   signal->theData[4] = retData;
22558   sendSignal(reference(), GSN_CONTINUEB, signal, 5, JBB);
22559 
22560   return;
22561 }//Dblqh::initialiseRecordsLab()
22562 
22563 /* ==========================================================================
22564  * =======                      INITIATE TC CONNECTION RECORD         =======
22565  *
22566  * ========================================================================= */
initialiseScanrec(Signal * signal)22567 void Dblqh::initialiseScanrec(Signal* signal)
22568 {
22569   ndbrequire(cscanrecFileSize > 1);
22570   DLList<ScanRecord> tmp(c_scanRecordPool);
22571   while (tmp.seizeFirst(scanptr)){
22572     //new (scanptr.p) ScanRecord();
22573     refresh_watch_dog();
22574     scanptr.p->scanType = ScanRecord::ST_IDLE;
22575     scanptr.p->scanState = ScanRecord::SCAN_FREE;
22576     scanptr.p->scanTcWaiting = 0;
22577     scanptr.p->nextHash = RNIL;
22578     scanptr.p->prevHash = RNIL;
22579     scanptr.p->scan_acc_index= 0;
22580     scanptr.p->scan_acc_segments= 0;
22581     scanptr.p->m_reserved = 0;
22582   }
22583   while (tmp.releaseFirst());
22584 
22585   /**
22586    * just seize records from pool and put into
22587    *   dedicated list
22588    *
22589    * We need to allocate an ACC pointer list that fits
22590    * all reserved since we can use the LCP record for NR or Backup and
22591    * vice versa for NR scans and Backup scans.
22592    */
22593   m_reserved_scans.seizeFirst(scanptr); // LCP
22594   scanptr.p->m_reserved = 1;
22595   ndbrequire(seize_acc_ptr_list(scanptr.p, 0, ZRESERVED_SCAN_BATCH_SIZE));
22596   m_reserved_scans.seizeFirst(scanptr); // NR
22597   scanptr.p->m_reserved = 1;
22598   ndbrequire(seize_acc_ptr_list(scanptr.p, 0, ZRESERVED_SCAN_BATCH_SIZE));
22599   m_reserved_scans.seizeFirst(scanptr); // Backup
22600   scanptr.p->m_reserved = 1;
22601   ndbrequire(seize_acc_ptr_list(scanptr.p, 0, ZRESERVED_SCAN_BATCH_SIZE));
22602 
22603 }//Dblqh::initialiseScanrec()
22604 
22605 /* ==========================================================================
22606  * =======                      INITIATE TABLE RECORD                 =======
22607  *
22608  * ========================================================================= */
initialiseTabrec(Signal * signal)22609 void Dblqh::initialiseTabrec(Signal* signal)
22610 {
22611   if (ctabrecFileSize != 0) {
22612     for (tabptr.i = 0; tabptr.i < ctabrecFileSize; tabptr.i++) {
22613       refresh_watch_dog();
22614       ptrAss(tabptr, tablerec);
22615       tabptr.p->tableStatus = Tablerec::NOT_DEFINED;
22616       tabptr.p->usageCountR = 0;
22617       tabptr.p->usageCountW = 0;
22618       for (Uint32 i = 0; i < NDB_ARRAY_SIZE(tabptr.p->fragid); i++) {
22619         tabptr.p->fragid[i] = ZNIL;
22620         tabptr.p->fragrec[i] = RNIL;
22621       }//for
22622     }//for
22623   }//if
22624 }//Dblqh::initialiseTabrec()
22625 
22626 /* ==========================================================================
22627  * =======                      INITIATE TC CONNECTION RECORD         =======
22628  *
22629  * ========================================================================= */
initialiseTcrec(Signal * signal)22630 void Dblqh::initialiseTcrec(Signal* signal)
22631 {
22632   if (ctcConnectrecFileSize != 0) {
22633     for (tcConnectptr.i = 0;
22634 	 tcConnectptr.i < ctcConnectrecFileSize;
22635 	 tcConnectptr.i++) {
22636       refresh_watch_dog();
22637       ptrAss(tcConnectptr, tcConnectionrec);
22638       tcConnectptr.p->transactionState = TcConnectionrec::TC_NOT_CONNECTED;
22639       tcConnectptr.p->tcScanRec = RNIL;
22640       tcConnectptr.p->logWriteState = TcConnectionrec::NOT_STARTED;
22641       tcConnectptr.p->keyInfoIVal = RNIL;
22642       tcConnectptr.p->attrInfoIVal = RNIL;
22643       tcConnectptr.p->m_flags= 0;
22644       tcConnectptr.p->tcTimer = 0;
22645       tcConnectptr.p->nextLogTcrec = RNIL;
22646       tcConnectptr.p->prevLogTcrec = RNIL;
22647       tcConnectptr.p->nextHashRec = RNIL;
22648       tcConnectptr.p->prevHashRec = RNIL;
22649       tcConnectptr.p->nextTcLogQueue = RNIL;
22650       tcConnectptr.p->prevTcLogQueue = RNIL;
22651       tcConnectptr.p->nextTcConnectrec = tcConnectptr.i + 1;
22652     }//for
22653     tcConnectptr.i = ctcConnectrecFileSize - 1;
22654     ptrAss(tcConnectptr, tcConnectionrec);
22655     tcConnectptr.p->nextTcConnectrec = RNIL;
22656     cfirstfreeTcConrec = 0;
22657     ctcNumFree = ctcConnectrecFileSize;
22658   } else {
22659     jam();
22660     cfirstfreeTcConrec = RNIL;
22661   }//if
22662 }//Dblqh::initialiseTcrec()
22663 
22664 /* ==========================================================================
22665  * =======                      INITIATE TC CONNECTION RECORD         =======
22666  *
22667  * ========================================================================= */
initialiseTcNodeFailRec(Signal * signal)22668 void Dblqh::initialiseTcNodeFailRec(Signal* signal)
22669 {
22670   TcNodeFailRecordPtr tcNodeFailPtr;
22671   if (ctcNodeFailrecFileSize != 0) {
22672     for (tcNodeFailPtr.i = 0;
22673 	 tcNodeFailPtr.i < ctcNodeFailrecFileSize;
22674 	 tcNodeFailPtr.i++) {
22675       ptrAss(tcNodeFailPtr, tcNodeFailRecord);
22676       tcNodeFailPtr.p->tcFailStatus = TcNodeFailRecord::TC_STATE_FALSE;
22677     }//for
22678   }//if
22679 }//Dblqh::initialiseTcNodeFailRec()
22680 
22681 /* ==========================================================================
22682  * =======              INITIATE FRAGMENT RECORD                      =======
22683  *
22684  *       SUBROUTINE SHORT NAME = IF
22685  * ========================================================================= */
initFragrec(Signal * signal,Uint32 tableId,Uint32 fragId,Uint32 copyType)22686 void Dblqh::initFragrec(Signal* signal,
22687                         Uint32 tableId,
22688                         Uint32 fragId,
22689                         Uint32 copyType)
22690 {
22691   new (fragptr.p) Fragrecord();
22692   fragptr.p->m_scanNumberMask.set(); // All is free
22693   fragptr.p->accBlockref = caccBlockref;
22694   fragptr.p->fragStatus = Fragrecord::DEFINED;
22695   fragptr.p->fragCopy = copyType;
22696   fragptr.p->tupBlockref = ctupBlockref;
22697   fragptr.p->tuxBlockref = ctuxBlockref;
22698   fragptr.p->logFlag = Fragrecord::STATE_TRUE;
22699   fragptr.p->lcpFlag = Fragrecord::LCP_STATE_TRUE;
22700   for (Uint32 i = 0; i < MAX_LCP_STORED; i++) {
22701     fragptr.p->lcpId[i] = 0;
22702   }//for
22703   fragptr.p->maxGciCompletedInLcp = 0;
22704   fragptr.p->accFragptr = RNIL;
22705   fragptr.p->maxGciInLcp = 0;
22706   fragptr.p->copyFragState = ZIDLE;
22707   fragptr.p->newestGci = cnewestGci;
22708   fragptr.p->tabRef = tableId;
22709   fragptr.p->fragId = fragId;
22710   fragptr.p->srStatus = Fragrecord::SS_IDLE;
22711   fragptr.p->execSrStatus = Fragrecord::IDLE;
22712   fragptr.p->execSrNoReplicas = 0;
22713   fragptr.p->fragDistributionKey = 0;
22714   fragptr.p->activeTcCounter = 0;
22715   fragptr.p->tableFragptr = RNIL;
22716   fragptr.p->m_copy_started_state = 0;
22717   fragptr.p->lcp_frag_ord_state = Fragrecord::LCP_EXECUTED;
22718   fragptr.p->lcp_frag_ord_lcp_no = 0;
22719   fragptr.p->lcp_frag_ord_lcp_id = 0;
22720 }//Dblqh::initFragrec()
22721 
22722 /* ==========================================================================
22723  * =======       INITIATE FRAGMENT RECORD FOR SYSTEM RESTART          =======
22724  *
22725  *       SUBROUTINE SHORT NAME = IFS
22726  * ========================================================================= */
22727 
22728 /* ==========================================================================
22729  * =======       INITIATE INFORMATION ABOUT GLOBAL CHECKPOINTS        =======
22730  *               IN LOG FILE RECORDS
22731  *
22732  *       INPUT:     LOG_FILE_PTR            CURRENT LOG FILE
22733  *                  TNO_FD_DESCRIPTORS      THE NUMBER OF FILE DESCRIPTORS
22734  *                                          TO READ FROM THE LOG PAGE
22735  *                  LOG_PAGE_PTR            PAGE ZERO IN LOG FILE
22736  *       SUBROUTINE SHORT NAME = IGL
22737  * ========================================================================= */
initGciInLogFileRec(Signal * signal,Uint32 noFdDescriptors)22738 void Dblqh::initGciInLogFileRec(Signal* signal, Uint32 noFdDescriptors)
22739 {
22740   /* We are reading the per file:mb metadata from page zero in this file
22741    * We cannot use the data for this file (fd 0), but the data for
22742    * previous files is valid.
22743    * So we start reading at fd 1.
22744    * The metadata for this file (fd 0) is set either reading the next file,
22745    * or by probing the last megabytes.
22746    */
22747   LogFileRecordPtr filePtr = logFilePtr;
22748   Uint32 pos = ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE;
22749   ndbrequire(noFdDescriptors <= cmaxValidLogFilesInPageZero);
22750 
22751   /* We start by initialising the previous file's metadata,
22752    * so lets move there now...
22753    */
22754   filePtr.i = filePtr.p->prevLogFile;
22755   ptrCheckGuard(filePtr, clogFileFileSize, logFileRecord);
22756 
22757 
22758   for (Uint32 fd = 1; fd <= noFdDescriptors; fd++)
22759   {
22760     jam();
22761     for (Uint32 mb = 0; mb < clogFileSize; mb++)
22762     {
22763       jam();
22764       Uint32 pos0 = pos + fd * (ZFD_MBYTE_SIZE * clogFileSize) + mb;
22765       Uint32 pos1 = pos0 + clogFileSize;
22766       Uint32 pos2 = pos1 + clogFileSize;
22767       arrGuard(pos0, ZPAGE_SIZE);
22768       arrGuard(pos1, ZPAGE_SIZE);
22769       arrGuard(pos2, ZPAGE_SIZE);
22770       filePtr.p->logMaxGciCompleted[mb] = logPagePtr.p->logPageWord[pos0];
22771       filePtr.p->logMaxGciStarted[mb] = logPagePtr.p->logPageWord[pos1];
22772       filePtr.p->logLastPrepRef[mb] = logPagePtr.p->logPageWord[pos2];
22773     }
22774     if (fd + 1 <= noFdDescriptors)
22775     {
22776       jam();
22777       filePtr.i = filePtr.p->prevLogFile;
22778       ptrCheckGuard(filePtr, clogFileFileSize, logFileRecord);
22779     }
22780   }
22781 }//Dblqh::initGciInLogFileRec()
22782 
22783 /* ==========================================================================
22784  * =======        INITIATE LCP RECORD WHEN USED FOR SYSTEM RESTART    =======
22785  *
22786  *       SUBROUTINE SHORT NAME = ILS
22787  * ========================================================================= */
initLcpSr(Signal * signal,Uint32 lcpNo,Uint32 lcpId,Uint32 tableId,Uint32 fragId,Uint32 fragPtr)22788 void Dblqh::initLcpSr(Signal* signal,
22789                       Uint32 lcpNo,
22790                       Uint32 lcpId,
22791                       Uint32 tableId,
22792                       Uint32 fragId,
22793                       Uint32 fragPtr)
22794 {
22795   lcpPtr.p->currentFragment.fragPtrI = fragPtr;
22796   lcpPtr.p->currentFragment.lcpFragOrd.lcpNo = lcpNo;
22797   lcpPtr.p->currentFragment.lcpFragOrd.lcpId = lcpId;
22798   lcpPtr.p->currentFragment.lcpFragOrd.tableId = tableId;
22799   lcpPtr.p->currentFragment.lcpFragOrd.fragmentId = fragId;
22800   lcpPtr.p->lcpState = LcpRecord::LCP_SR_WAIT_FRAGID;
22801 }//Dblqh::initLcpSr()
22802 
22803 /* ==========================================================================
22804  * =======              INITIATE LOG PART                             =======
22805  *
22806  * ========================================================================= */
initLogpart(Signal * signal)22807 void Dblqh::initLogpart(Signal* signal)
22808 {
22809   logPartPtr.p->execSrLogPage = RNIL;
22810   logPartPtr.p->execSrLogPageIndex = ZNIL;
22811   logPartPtr.p->execSrExecuteIndex = 0;
22812   logPartPtr.p->noLogFiles = cnoLogFiles;
22813   logPartPtr.p->logLap = 0;
22814   logPartPtr.p->logTailFileNo = 0;
22815   logPartPtr.p->logTailMbyte = 0;
22816   logPartPtr.p->lastMbyte = ZNIL;
22817   logPartPtr.p->logPartState = LogPartRecord::SR_FIRST_PHASE;
22818   logPartPtr.p->logExecState = LogPartRecord::LES_IDLE;
22819   logPartPtr.p->firstLogTcrec = RNIL;
22820   logPartPtr.p->lastLogTcrec = RNIL;
22821   logPartPtr.p->gcprec = RNIL;
22822   logPartPtr.p->firstPageRef = RNIL;
22823   logPartPtr.p->lastPageRef = RNIL;
22824   logPartPtr.p->headFileNo = ZNIL;
22825   logPartPtr.p->headPageNo = ZNIL;
22826   logPartPtr.p->headPageIndex = ZNIL;
22827   logPartPtr.p->firstInvalidatePageNo = ZNIL;
22828   logPartPtr.p->firstInvalidateFileNo = ZNIL;
22829   logPartPtr.p->endInvalidMByteSearch = ZNIL;
22830   logPartPtr.p->firstInvalidatePageFound = false;
22831   logPartPtr.p->m_log_problems = 0;
22832   NdbLogPartInfo lpinfo(instance());
22833   ndbrequire(lpinfo.partCount == clogPartFileSize);
22834   logPartPtr.p->logPartNo = lpinfo.partNo[logPartPtr.i];
22835   logPartPtr.p->m_io_tracker.init(logPartPtr.p->logPartNo);
22836   logPartPtr.p->m_log_prepare_queue.init();
22837   logPartPtr.p->m_log_complete_queue.init();
22838 }//Dblqh::initLogpart()
22839 
22840 /* ==========================================================================
22841  * =======              INITIATE LOG POINTERS                         =======
22842  *
22843  * ========================================================================= */
initLogPointers(Signal * signal)22844 void Dblqh::initLogPointers(Signal* signal)
22845 {
22846   logPartPtr.i = tcConnectptr.p->m_log_part_ptr_i;
22847   ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
22848   logFilePtr.i = logPartPtr.p->currentLogfile;
22849   ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
22850   logPagePtr.i = logFilePtr.p->currentLogpage;
22851   ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
22852 }//Dblqh::initLogPointers()
22853 
22854 /* ------------------------------------------------------------------------- */
22855 /* -------    INIT REQUEST INFO BEFORE EXECUTING A LOG RECORD        ------- */
22856 /*                                                                           */
22857 /* ------------------------------------------------------------------------- */
initReqinfoExecSr(Signal * signal)22858 void Dblqh::initReqinfoExecSr(Signal* signal)
22859 {
22860   UintR Treqinfo = 0;
22861   TcConnectionrec * const regTcPtr = tcConnectptr.p;
22862   LqhKeyReq::setKeyLen(Treqinfo, regTcPtr->primKeyLen);
22863 /* ------------------------------------------------------------------------- */
22864 /* NUMBER OF BACKUPS AND STANDBYS ARE ZERO AND NEED NOT BE SET.              */
22865 /* REPLICA TYPE IS CLEARED BY SEND_LQHKEYREQ.                                */
22866 /* ------------------------------------------------------------------------- */
22867 /* ------------------------------------------------------------------------- */
22868 /*       SET LAST REPLICA NUMBER TO ZERO (BIT 10-11)                         */
22869 /* ------------------------------------------------------------------------- */
22870 /* ------------------------------------------------------------------------- */
22871 /*       SET DIRTY FLAG                                                      */
22872 /* ------------------------------------------------------------------------- */
22873   LqhKeyReq::setDirtyFlag(Treqinfo, 1);
22874 /* ------------------------------------------------------------------------- */
22875 /*       SET SIMPLE TRANSACTION                                              */
22876 /* ------------------------------------------------------------------------- */
22877   LqhKeyReq::setSimpleFlag(Treqinfo, 1);
22878   LqhKeyReq::setGCIFlag(Treqinfo, 1);
22879 /* ------------------------------------------------------------------------- */
22880 /* SET OPERATION TYPE AND LOCK MODE (NEVER READ OPERATION OR SCAN IN LOG)    */
22881 /* ------------------------------------------------------------------------- */
22882   LqhKeyReq::setOperation(Treqinfo, regTcPtr->operation);
22883   regTcPtr->reqinfo = Treqinfo;
22884 /* ------------------------------------------------------------------------ */
22885 /* NO OF BACKUP IS SET TO ONE AND NUMBER OF STANDBY NODES IS SET TO ZERO.   */
22886 /* THUS THE RECEIVING NODE WILL EXPECT THAT IT IS THE LAST NODE AND WILL    */
22887 /* SEND COMPLETED AS THE RESPONSE SIGNAL SINCE DIRTY_OP BIT IS SET.         */
22888 /* ------------------------------------------------------------------------ */
22889 /* ------------------------------------------------------------------------- */
22890 /*       SET REPLICA TYPE TO PRIMARY AND NUMBER OF REPLICA TO ONE            */
22891 /* ------------------------------------------------------------------------- */
22892   regTcPtr->lastReplicaNo = 0;
22893   regTcPtr->nextSeqNoReplica = 0;
22894   regTcPtr->opExec = 0;
22895   regTcPtr->storedProcId = ZNIL;
22896   regTcPtr->readlenAi = 0;
22897   regTcPtr->nodeAfterNext[0] = ZNIL;
22898   regTcPtr->nodeAfterNext[1] = ZNIL;
22899   regTcPtr->dirtyOp = ZFALSE;
22900   regTcPtr->tcBlockref = cownref;
22901   regTcPtr->m_reorg = ScanFragReq::REORG_ALL;
22902 }//Dblqh::initReqinfoExecSr()
22903 
22904 /* --------------------------------------------------------------------------
22905  * -------               INSERT FRAGMENT                              -------
22906  *
22907  * ------------------------------------------------------------------------- */
insertFragrec(Signal * signal,Uint32 fragId)22908 bool Dblqh::insertFragrec(Signal* signal, Uint32 fragId)
22909 {
22910   terrorCode = ZOK;
22911   if(c_fragment_pool.seize(fragptr) == false)
22912   {
22913     terrorCode = ZNO_FREE_FRAGMENTREC;
22914     return false;
22915   }
22916   for (Uint32 i = 0; i < NDB_ARRAY_SIZE(tabptr.p->fragid); i++) {
22917     jam();
22918     if (tabptr.p->fragid[i] == ZNIL) {
22919       jam();
22920       tabptr.p->fragid[i] = fragId;
22921       tabptr.p->fragrec[i] = fragptr.i;
22922       return true;
22923     }//if
22924   }//for
22925   c_fragment_pool.release(fragptr);
22926   terrorCode = ZTOO_MANY_FRAGMENTS;
22927   return false;
22928 }//Dblqh::insertFragrec()
22929 
22930 /* -------------------------------------------------------------------------
22931  * -------               LINK OPERATION INTO WAITING FOR LOGGING     -------
22932  *
22933  *       SUBROUTINE SHORT NAME = LWL
22934 // Input Pointers:
22935 // tcConnectptr
22936 // logPartPtr
22937  * ------------------------------------------------------------------------- */
22938 void
linkWaitLog(Signal * signal,LogPartRecordPtr regLogPartPtr,LogPartRecord::OperationQueue & queue)22939 Dblqh::linkWaitLog(Signal* signal,
22940                    LogPartRecordPtr regLogPartPtr,
22941                    LogPartRecord::OperationQueue & queue)
22942 {
22943   TcConnectionrecPtr lwlTcConnectptr;
22944 /* -------------------------------------------------- */
22945 /*       LINK ACTIVE OPERATION INTO QUEUE WAITING FOR */
22946 /*       ACCESS TO THE LOG PART.                      */
22947 /* -------------------------------------------------- */
22948   lwlTcConnectptr.i = queue.lastElement;
22949   if (lwlTcConnectptr.i == RNIL) {
22950     jam();
22951     queue.firstElement = tcConnectptr.i;
22952     tcConnectptr.p->prevTcLogQueue = RNIL;
22953   } else {
22954     jam();
22955     ptrCheckGuard(lwlTcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
22956     lwlTcConnectptr.p->nextTcLogQueue = tcConnectptr.i;
22957     tcConnectptr.p->prevTcLogQueue = lwlTcConnectptr.i;
22958   }//if
22959   queue.lastElement = tcConnectptr.i;
22960   tcConnectptr.p->nextTcLogQueue = RNIL;
22961   regLogPartPtr.p->logPartState = LogPartRecord::ACTIVE;
22962   if (regLogPartPtr.p->LogLqhKeyReqSent == ZFALSE)
22963   {
22964     jam();
22965     regLogPartPtr.p->LogLqhKeyReqSent = ZTRUE;
22966     signal->theData[0] = ZLOG_LQHKEYREQ;
22967     signal->theData[1] = regLogPartPtr.i;
22968     sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
22969   }//if
22970 }//Dblqh::linkWaitLog()
22971 
22972 /* --------------------------------------------------------------------------
22973  * -------          START THE NEXT OPERATION ON THIS LOG PART IF ANY  -------
22974  * -------               OPERATIONS ARE QUEUED.                       -------
22975  *
22976  *       SUBROUTINE SHORT NAME = LNS
22977 // Input Pointers:
22978 // tcConnectptr
22979 // logPartPtr
22980  * ------------------------------------------------------------------------- */
logNextStart(Signal * signal)22981 void Dblqh::logNextStart(Signal* signal)
22982 {
22983   LogPartRecordPtr lnsLogPartPtr;
22984   UintR tlnsStillWaiting;
22985   LogPartRecord * const regLogPartPtr = logPartPtr.p;
22986 
22987   if (regLogPartPtr->m_log_prepare_queue.isEmpty() &&
22988       regLogPartPtr->m_log_complete_queue.isEmpty() &&
22989       (regLogPartPtr->waitWriteGciLog != LogPartRecord::WWGL_TRUE))
22990   {
22991 // --------------------------------------------------------------------------
22992 // Optimised route for the common case
22993 // --------------------------------------------------------------------------
22994     return;
22995   }//if
22996 
22997   if (!regLogPartPtr->m_log_prepare_queue.isEmpty() ||
22998       !regLogPartPtr->m_log_complete_queue.isEmpty())
22999   {
23000     jam();
23001     regLogPartPtr->logPartState = LogPartRecord::ACTIVE;
23002     if (regLogPartPtr->LogLqhKeyReqSent == ZFALSE)
23003     {
23004       jam();
23005       regLogPartPtr->LogLqhKeyReqSent = ZTRUE;
23006       signal->theData[0] = ZLOG_LQHKEYREQ;
23007       signal->theData[1] = logPartPtr.i;
23008       sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
23009     }//if
23010   }
23011 
23012   if (regLogPartPtr->waitWriteGciLog != LogPartRecord::WWGL_TRUE)
23013   {
23014     jam();
23015     return;
23016   }
23017   else
23018   {
23019     jam();
23020 /* --------------------------------------------------------------------------
23021  *   A COMPLETE GCI LOG RECORD IS WAITING TO BE WRITTEN. WE GIVE THIS HIGHEST
23022  *   PRIORITY AND WRITE IT IMMEDIATELY. AFTER WRITING IT WE CHECK IF ANY MORE
23023  *   LOG PARTS ARE WAITING. IF NOT WE SEND A SIGNAL THAT INITIALISES THE GCP
23024  *   RECORD TO WAIT UNTIL ALL COMPLETE GCI LOG RECORDS HAVE REACHED TO DISK.
23025  * -------------------------------------------------------------------------- */
23026     writeCompletedGciLog(signal);
23027     logPartPtr.p->waitWriteGciLog = LogPartRecord::WWGL_FALSE;
23028     tlnsStillWaiting = ZFALSE;
23029     for (lnsLogPartPtr.i = 0; lnsLogPartPtr.i < clogPartFileSize; lnsLogPartPtr.i++) {
23030       jam();
23031       ptrAss(lnsLogPartPtr, logPartRecord);
23032       if (lnsLogPartPtr.p->waitWriteGciLog == LogPartRecord::WWGL_TRUE) {
23033         jam();
23034         tlnsStillWaiting = ZTRUE;
23035       }//if
23036     }//for
23037     if (tlnsStillWaiting == ZFALSE) {
23038       jam();
23039       signal->theData[0] = ZINIT_GCP_REC;
23040       sendSignal(cownref, GSN_CONTINUEB, signal, 1, JBB);
23041     }//if
23042   }//if
23043 }//Dblqh::logNextStart()
23044 
23045 /* --------------------------------------------------------------------------
23046  * -------       MOVE PAGES FROM LFO RECORD TO PAGE REFERENCE RECORD  -------
23047  *               WILL ALWAYS MOVE 8 PAGES TO A PAGE REFERENCE RECORD.
23048  *
23049  *       SUBROUTINE SHORT NAME = MPR
23050  * ------------------------------------------------------------------------- */
moveToPageRef(Signal * signal)23051 void Dblqh::moveToPageRef(Signal* signal)
23052 {
23053   LogPageRecordPtr mprLogPagePtr;
23054   PageRefRecordPtr mprPageRefPtr;
23055   UintR tmprIndex;
23056 
23057 /* --------------------------------------------------------------------------
23058  * -------       INSERT PAGE REFERENCE RECORD                         -------
23059  *
23060  *       INPUT:  LFO_PTR         LOG FILE OPERATION RECORD
23061  *               LOG_PART_PTR    LOG PART RECORD
23062  *               PAGE_REF_PTR    THE PAGE REFERENCE RECORD TO BE INSERTED.
23063  * ------------------------------------------------------------------------- */
23064   PageRefRecordPtr iprPageRefPtr;
23065 
23066   if ((logPartPtr.p->mmBufferSize + 8) >= ZMAX_MM_BUFFER_SIZE) {
23067     jam();
23068     pageRefPtr.i = logPartPtr.p->firstPageRef;
23069     ptrCheckGuard(pageRefPtr, cpageRefFileSize, pageRefRecord);
23070     releasePrPages(signal);
23071     removePageRef(signal);
23072   } else {
23073     jam();
23074     logPartPtr.p->mmBufferSize = logPartPtr.p->mmBufferSize + 8;
23075   }//if
23076   seizePageRef(signal);
23077   if (logPartPtr.p->firstPageRef == RNIL) {
23078     jam();
23079     logPartPtr.p->firstPageRef = pageRefPtr.i;
23080   } else {
23081     jam();
23082     iprPageRefPtr.i = logPartPtr.p->lastPageRef;
23083     ptrCheckGuard(iprPageRefPtr, cpageRefFileSize, pageRefRecord);
23084     iprPageRefPtr.p->prNext = pageRefPtr.i;
23085   }//if
23086   pageRefPtr.p->prPrev = logPartPtr.p->lastPageRef;
23087   logPartPtr.p->lastPageRef = pageRefPtr.i;
23088 
23089   pageRefPtr.p->prFileNo = logFilePtr.p->fileNo;
23090   pageRefPtr.p->prPageNo = lfoPtr.p->lfoPageNo;
23091   tmprIndex = 0;
23092   mprLogPagePtr.i = lfoPtr.p->firstLfoPage;
23093 MPR_LOOP:
23094   arrGuard(tmprIndex, 8);
23095   pageRefPtr.p->pageRef[tmprIndex] = mprLogPagePtr.i;
23096   tmprIndex = tmprIndex + 1;
23097   ptrCheckGuard(mprLogPagePtr, clogPageFileSize, logPageRecord);
23098   mprLogPagePtr.i = mprLogPagePtr.p->logPageWord[ZNEXT_PAGE];
23099   if (mprLogPagePtr.i != RNIL) {
23100     jam();
23101     goto MPR_LOOP;
23102   }//if
23103   mprPageRefPtr.i = pageRefPtr.p->prPrev;
23104   if (mprPageRefPtr.i != RNIL) {
23105     jam();
23106     ptrCheckGuard(mprPageRefPtr, cpageRefFileSize, pageRefRecord);
23107     mprLogPagePtr.i = mprPageRefPtr.p->pageRef[7];
23108     ptrCheckGuard(mprLogPagePtr, clogPageFileSize, logPageRecord);
23109     mprLogPagePtr.p->logPageWord[ZNEXT_PAGE] = pageRefPtr.p->pageRef[0];
23110   }//if
23111 }//Dblqh::moveToPageRef()
23112 
23113 /* ------------------------------------------------------------------------- */
23114 /* -------               READ THE ATTRINFO FROM THE LOG              ------- */
23115 /*                                                                           */
23116 /*       SUBROUTINE SHORT NAME = RA                                          */
23117 /* ------------------------------------------------------------------------- */
readAttrinfo(Signal * signal)23118 void Dblqh::readAttrinfo(Signal* signal)
23119 {
23120   Uint32 remainingLen = tcConnectptr.p->totSendlenAi;
23121   tcConnectptr.p->reclenAiLqhkey = 0;
23122   if (remainingLen == 0) {
23123     jam();
23124     return;
23125   }//if
23126 
23127   readLogData(signal, remainingLen, tcConnectptr.p->attrInfoIVal);
23128 }//Dblqh::readAttrinfo()
23129 
23130 /* ------------------------------------------------------------------------- */
23131 /* -------               READ COMMIT LOG                             ------- */
23132 /*                                                                           */
23133 /*       SUBROUTINE SHORT NAME = RCL                                         */
23134 /* ------------------------------------------------------------------------- */
readCommitLog(Signal * signal,CommitLogRecord * commitLogRecord)23135 void Dblqh::readCommitLog(Signal* signal, CommitLogRecord* commitLogRecord)
23136 {
23137   Uint32 trclPageIndex = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX];
23138   if ((trclPageIndex + (ZCOMMIT_LOG_SIZE - 1)) < ZPAGE_SIZE) {
23139     jam();
23140     tcConnectptr.p->tableref = logPagePtr.p->logPageWord[trclPageIndex + 0];
23141     tcConnectptr.p->schemaVersion = logPagePtr.p->logPageWord[trclPageIndex + 1];
23142     tcConnectptr.p->fragmentid = logPagePtr.p->logPageWord[trclPageIndex + 2];
23143     commitLogRecord->fileNo = logPagePtr.p->logPageWord[trclPageIndex + 3];
23144     commitLogRecord->startPageNo = logPagePtr.p->logPageWord[trclPageIndex + 4];
23145     commitLogRecord->startPageIndex = logPagePtr.p->logPageWord[trclPageIndex + 5];
23146     commitLogRecord->stopPageNo = logPagePtr.p->logPageWord[trclPageIndex + 6];
23147     tcConnectptr.p->gci_hi = logPagePtr.p->logPageWord[trclPageIndex + 7];
23148     tcConnectptr.p->gci_lo = 0;
23149     logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] =
23150                             (trclPageIndex + ZCOMMIT_LOG_SIZE) - 1;
23151   } else {
23152     jam();
23153     tcConnectptr.p->tableref = readLogword(signal);
23154     tcConnectptr.p->schemaVersion = readLogword(signal);
23155     tcConnectptr.p->fragmentid = readLogword(signal);
23156     commitLogRecord->fileNo = readLogword(signal);
23157     commitLogRecord->startPageNo = readLogword(signal);
23158     commitLogRecord->startPageIndex = readLogword(signal);
23159     commitLogRecord->stopPageNo = readLogword(signal);
23160     tcConnectptr.p->gci_hi = readLogword(signal);
23161     tcConnectptr.p->gci_lo = 0;
23162   }//if
23163   tcConnectptr.p->transid[0] = logPartPtr.i + 65536;
23164   tcConnectptr.p->transid[1] = (DBLQH << 20) + (cownNodeid << 8);
23165 }//Dblqh::readCommitLog()
23166 
23167 /* ------------------------------------------------------------------------- */
23168 /* -------        READ LOG PAGES FROM DISK IN ORDER TO EXECUTE A LOG ------- */
23169 /*                RECORD WHICH WAS NOT FOUND IN MAIN MEMORY.                 */
23170 /*                                                                           */
23171 /*       SUBROUTINE SHORT NAME = REL                                         */
23172 /* ------------------------------------------------------------------------- */
readExecLog(Signal * signal)23173 void Dblqh::readExecLog(Signal* signal)
23174 {
23175   UintR trelIndex;
23176   UintR trelI;
23177 
23178   seizeLfo(signal);
23179   initLfo(signal);
23180   trelI = logPartPtr.p->execSrStopPageNo - logPartPtr.p->execSrStartPageNo;
23181   arrGuard(trelI + 1, 16);
23182   lfoPtr.p->logPageArray[trelI + 1] = logPartPtr.p->execSrStartPageNo;
23183   for (trelIndex = logPartPtr.p->execSrStopPageNo; (trelIndex >= logPartPtr.p->execSrStartPageNo) &&
23184        (UintR)~trelIndex; trelIndex--) {
23185     jam();
23186     seizeLogpage(signal);
23187     arrGuard(trelI, 16);
23188     lfoPtr.p->logPageArray[trelI] = logPagePtr.i;
23189     trelI--;
23190   }//for
23191   lfoPtr.p->lfoPageNo = logPartPtr.p->execSrStartPageNo;
23192   lfoPtr.p->noPagesRw = (logPartPtr.p->execSrStopPageNo -
23193 			 logPartPtr.p->execSrStartPageNo) + 1;
23194   lfoPtr.p->firstLfoPage = lfoPtr.p->logPageArray[0];
23195   signal->theData[0] = logFilePtr.p->fileRef;
23196   signal->theData[1] = cownref;
23197   signal->theData[2] = lfoPtr.i;
23198   signal->theData[3] = ZLIST_OF_MEM_PAGES; // edtjamo TR509 //ZLIST_OF_PAIRS;
23199   signal->theData[4] = ZVAR_NO_LOG_PAGE_WORD;
23200   signal->theData[5] = lfoPtr.p->noPagesRw;
23201   signal->theData[6] = lfoPtr.p->logPageArray[0];
23202   signal->theData[7] = lfoPtr.p->logPageArray[1];
23203   signal->theData[8] = lfoPtr.p->logPageArray[2];
23204   signal->theData[9] = lfoPtr.p->logPageArray[3];
23205   signal->theData[10] = lfoPtr.p->logPageArray[4];
23206   signal->theData[11] = lfoPtr.p->logPageArray[5];
23207   signal->theData[12] = lfoPtr.p->logPageArray[6];
23208   signal->theData[13] = lfoPtr.p->logPageArray[7];
23209   signal->theData[14] = lfoPtr.p->logPageArray[8];
23210   signal->theData[15] = lfoPtr.p->logPageArray[9];
23211   sendSignal(NDBFS_REF, GSN_FSREADREQ, signal, 16, JBA);
23212 
23213   logPartPtr.p->m_redoWorkStats.m_pagesRead+= lfoPtr.p->noPagesRw;
23214 
23215 
23216   if (DEBUG_REDO)
23217   {
23218     ndbout_c("readExecLog %u page at part: %u file: %u page: %u (mb: %u)",
23219              lfoPtr.p->noPagesRw,
23220              logPartPtr.p->logPartNo,
23221              logFilePtr.p->fileNo,
23222              logPartPtr.p->execSrStartPageNo,
23223              logPartPtr.p->execSrStartPageNo >> ZTWOLOG_NO_PAGES_IN_MBYTE);
23224   }
23225 }//Dblqh::readExecLog()
23226 
23227 /* ------------------------------------------------------------------------- */
23228 /* -------        READ 64 KBYTES WHEN EXECUTING THE FRAGMENT LOG     ------- */
23229 /*                                                                           */
23230 /*       SUBROUTINE SHORT NAME = RES                                         */
23231 /* ------------------------------------------------------------------------- */
readExecSrNewMbyte(Signal * signal)23232 void Dblqh::readExecSrNewMbyte(Signal* signal)
23233 {
23234   logFilePtr.p->currentFilepage = logFilePtr.p->currentMbyte * ZPAGES_IN_MBYTE;
23235   logFilePtr.p->filePosition = logFilePtr.p->currentMbyte * ZPAGES_IN_MBYTE;
23236   logPartPtr.p->execSrPagesRead = 0;
23237   logPartPtr.p->execSrPagesReading = 0;
23238   logPartPtr.p->execSrPagesExecuted = 0;
23239   readExecSr(signal);
23240   logPartPtr.p->logExecState = LogPartRecord::LES_WAIT_READ_EXEC_SR_NEW_MBYTE;
23241 }//Dblqh::readExecSrNewMbyte()
23242 
23243 /* ------------------------------------------------------------------------- */
23244 /* -------        READ 64 KBYTES WHEN EXECUTING THE FRAGMENT LOG     ------- */
23245 /*                                                                           */
23246 /*       SUBROUTINE SHORT NAME = RES                                         */
23247 /* ------------------------------------------------------------------------- */
readExecSr(Signal * signal)23248 void Dblqh::readExecSr(Signal* signal)
23249 {
23250   UintR tresPageid;
23251   UintR tresIndex;
23252 
23253   tresPageid = logFilePtr.p->filePosition;
23254   seizeLfo(signal);
23255   initLfo(signal);
23256   for (tresIndex = 7; (UintR)~tresIndex; tresIndex--) {
23257     jam();
23258 /* ------------------------------------------------------------------------- */
23259 /* GO BACKWARDS SINCE WE INSERT AT THE BEGINNING AND WE WANT THAT FIRST PAGE */
23260 /* SHALL BE FIRST AND LAST PAGE LAST.                                        */
23261 /* ------------------------------------------------------------------------- */
23262     seizeLogpage(signal);
23263     lfoPtr.p->logPageArray[tresIndex] = logPagePtr.i;
23264   }//for
23265   lfoPtr.p->lfoState = LogFileOperationRecord::READ_EXEC_SR;
23266   lfoPtr.p->lfoPageNo = tresPageid;
23267   logFilePtr.p->filePosition = logFilePtr.p->filePosition + 8;
23268   logPartPtr.p->execSrPagesReading = logPartPtr.p->execSrPagesReading + 8;
23269   lfoPtr.p->noPagesRw = 8;
23270   lfoPtr.p->firstLfoPage = lfoPtr.p->logPageArray[0];
23271   signal->theData[0] = logFilePtr.p->fileRef;
23272   signal->theData[1] = cownref;
23273   signal->theData[2] = lfoPtr.i;
23274   signal->theData[3] = ZLIST_OF_MEM_PAGES;
23275   signal->theData[4] = ZVAR_NO_LOG_PAGE_WORD;
23276   signal->theData[5] = 8;
23277   signal->theData[6] = lfoPtr.p->logPageArray[0];
23278   signal->theData[7] = lfoPtr.p->logPageArray[1];
23279   signal->theData[8] = lfoPtr.p->logPageArray[2];
23280   signal->theData[9] = lfoPtr.p->logPageArray[3];
23281   signal->theData[10] = lfoPtr.p->logPageArray[4];
23282   signal->theData[11] = lfoPtr.p->logPageArray[5];
23283   signal->theData[12] = lfoPtr.p->logPageArray[6];
23284   signal->theData[13] = lfoPtr.p->logPageArray[7];
23285   signal->theData[14] = tresPageid;
23286   sendSignal(NDBFS_REF, GSN_FSREADREQ, signal, 15, JBA);
23287 
23288   logPartPtr.p->m_redoWorkStats.m_pagesRead +=8;
23289 
23290   if (DEBUG_REDO)
23291   {
23292     ndbout_c("readExecSr %u page at part: %u file: %u page: %u (mb: %u)",
23293              8,
23294              logPartPtr.p->logPartNo,
23295              logFilePtr.p->fileNo,
23296              tresPageid,
23297              tresPageid >> ZTWOLOG_NO_PAGES_IN_MBYTE);
23298   }
23299 }//Dblqh::readExecSr()
23300 
23301 /* ------------------------------------------------------------------------- */
23302 /* ------------ READ THE PRIMARY KEY FROM THE LOG           ---------------- */
23303 /*                                                                           */
23304 /*       SUBROUTINE SHORT NAME = RK                                          */
23305 /* --------------------------------------------------------------------------*/
readKey(Signal * signal)23306 void Dblqh::readKey(Signal* signal)
23307 {
23308   Uint32 remainingLen = tcConnectptr.p->primKeyLen;
23309   ndbrequire(remainingLen != 0);
23310 
23311   readLogData(signal, remainingLen, tcConnectptr.p->keyInfoIVal);
23312 }//Dblqh::readKey()
23313 
23314 /* ------------------------------------------------------------------------- */
23315 /* ------------ READ A NUMBER OF WORDS FROM LOG INTO CDATA  ---------------- */
23316 /*                                                                           */
23317 /*       SUBROUTINE SHORT NAME = RLD                                         */
23318 /* --------------------------------------------------------------------------*/
readLogData(Signal * signal,Uint32 noOfWords,Uint32 & sectionIVal)23319 void Dblqh::readLogData(Signal* signal, Uint32 noOfWords, Uint32& sectionIVal)
23320 {
23321   Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX];
23322   if ((logPos + noOfWords) >= ZPAGE_SIZE) {
23323     for (Uint32 i = 0; i < noOfWords; i++)
23324     {
23325       /* Todo : Consider reading > 1 word at a time */
23326       Uint32 word= readLogwordExec(signal);
23327       bool ok= appendToSection(sectionIVal,
23328                                &word,
23329                                1);
23330       ndbrequire(ok);
23331     }
23332   } else {
23333     /* In one bite */
23334     bool ok= appendToSection(sectionIVal,
23335                              &logPagePtr.p->logPageWord[logPos],
23336                              noOfWords);
23337     ndbrequire(ok);
23338     logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos + noOfWords;
23339   }//if
23340 }//Dblqh::readLogData()
23341 
23342 /* ------------------------------------------------------------------------- */
23343 /* ------------ READ THE LOG HEADER OF A PREPARE LOG HEADER ---------------- */
23344 /*                                                                           */
23345 /*       SUBROUTINE SHORT NAME = RLH                                         */
23346 /* --------------------------------------------------------------------------*/
readLogHeader(Signal * signal)23347 void Dblqh::readLogHeader(Signal* signal)
23348 {
23349   Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX];
23350   if ((logPos + ZLOG_HEAD_SIZE) < ZPAGE_SIZE) {
23351     jam();
23352     tcConnectptr.p->hashValue = logPagePtr.p->logPageWord[logPos + 2];
23353     tcConnectptr.p->operation = logPagePtr.p->logPageWord[logPos + 3];
23354     tcConnectptr.p->totSendlenAi = logPagePtr.p->logPageWord[logPos + 4];
23355     tcConnectptr.p->primKeyLen = logPagePtr.p->logPageWord[logPos + 5];
23356     tcConnectptr.p->m_row_id.m_page_no = logPagePtr.p->logPageWord[logPos + 6];
23357     tcConnectptr.p->m_row_id.m_page_idx = logPagePtr.p->logPageWord[logPos+ 7];
23358     logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos + ZLOG_HEAD_SIZE;
23359   } else {
23360     jam();
23361     readLogwordExec(signal);	/* IGNORE PREPARE LOG RECORD TYPE */
23362     readLogwordExec(signal);	/* IGNORE LOG RECORD SIZE         */
23363     tcConnectptr.p->hashValue = readLogwordExec(signal);
23364     tcConnectptr.p->operation = readLogwordExec(signal);
23365     tcConnectptr.p->totSendlenAi = readLogwordExec(signal);
23366     tcConnectptr.p->primKeyLen = readLogwordExec(signal);
23367     tcConnectptr.p->m_row_id.m_page_no = readLogwordExec(signal);
23368     tcConnectptr.p->m_row_id.m_page_idx = readLogwordExec(signal);
23369   }//if
23370 
23371   tcConnectptr.p->m_use_rowid = (tcConnectptr.p->operation == ZINSERT);
23372 }//Dblqh::readLogHeader()
23373 
23374 /* ------------------------------------------------------------------------- */
23375 /* -------               READ A WORD FROM THE LOG                    ------- */
23376 /*                                                                           */
23377 /*       OUTPUT:         TLOG_WORD                                           */
23378 /*       SUBROUTINE SHORT NAME = RLW                                         */
23379 /* ------------------------------------------------------------------------- */
readLogword(Signal * signal)23380 Uint32 Dblqh::readLogword(Signal* signal)
23381 {
23382   Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX];
23383   ndbrequire(logPos < ZPAGE_SIZE);
23384   Uint32 logWord = logPagePtr.p->logPageWord[logPos];
23385   logPos++;
23386   logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos;
23387   if (logPos >= ZPAGE_SIZE) {
23388     jam();
23389     logPagePtr.i = logPagePtr.p->logPageWord[ZNEXT_PAGE];
23390     ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
23391     logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = ZPAGE_HEADER_SIZE;
23392     logFilePtr.p->currentLogpage = logPagePtr.i;
23393     logFilePtr.p->currentFilepage++;
23394     logPartPtr.p->execSrPagesRead--;
23395     logPartPtr.p->execSrPagesExecuted++;
23396   }//if
23397   return logWord;
23398 }//Dblqh::readLogword()
23399 
23400 /* ------------------------------------------------------------------------- */
23401 /* -------   READ A WORD FROM THE LOG WHEN EXECUTING A LOG RECORD    ------- */
23402 /*                                                                           */
23403 /*       OUTPUT:         TLOG_WORD                                           */
23404 /*       SUBROUTINE SHORT NAME = RWE                                         */
23405 /* ------------------------------------------------------------------------- */
readLogwordExec(Signal * signal)23406 Uint32 Dblqh::readLogwordExec(Signal* signal)
23407 {
23408   Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX];
23409   ndbrequire(logPos < ZPAGE_SIZE);
23410   Uint32 logWord = logPagePtr.p->logPageWord[logPos];
23411   logPos++;
23412   logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos;
23413   if (logPos >= ZPAGE_SIZE) {
23414     jam();
23415     logPagePtr.i = logPagePtr.p->logPageWord[ZNEXT_PAGE];
23416     if (logPagePtr.i != RNIL){
23417       ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
23418       logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = ZPAGE_HEADER_SIZE;
23419     } else {
23420       // Reading word at the last pos in the last page
23421       // Don't step forward to next page!
23422       jam();
23423       logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]++;
23424     }
23425   }//if
23426   return logWord;
23427 }//Dblqh::readLogwordExec()
23428 
23429 /* ------------------------------------------------------------------------- */
23430 /* -------               READ A SINGLE PAGE FROM THE LOG             ------- */
23431 /*                                                                           */
23432 /*       INPUT:          TRSP_PAGE_NO                                        */
23433 /*       SUBROUTINE SHORT NAME = RSP                                         */
23434 /* ------------------------------------------------------------------------- */
readSinglePage(Signal * signal,Uint32 pageNo)23435 void Dblqh::readSinglePage(Signal* signal, Uint32 pageNo)
23436 {
23437   seizeLfo(signal);
23438   initLfo(signal);
23439   seizeLogpage(signal);
23440   lfoPtr.p->firstLfoPage = logPagePtr.i;
23441   lfoPtr.p->lfoPageNo = pageNo;
23442   lfoPtr.p->noPagesRw = 1;
23443   signal->theData[0] = logFilePtr.p->fileRef;
23444   signal->theData[1] = cownref;
23445   signal->theData[2] = lfoPtr.i;
23446   signal->theData[3] = ZLIST_OF_PAIRS;
23447   signal->theData[4] = ZVAR_NO_LOG_PAGE_WORD;
23448   signal->theData[5] = 1;
23449   signal->theData[6] = logPagePtr.i;
23450   signal->theData[7] = pageNo;
23451   sendSignal(NDBFS_REF, GSN_FSREADREQ, signal, 8, JBA);
23452 
23453   if (DEBUG_REDO)
23454   {
23455     ndbout_c("readSinglePage 1 page at part: %u file: %u page: %u (mb: %u)",
23456              logPartPtr.p->logPartNo,
23457              logFilePtr.p->fileNo,
23458              pageNo,
23459              pageNo >> ZTWOLOG_NO_PAGES_IN_MBYTE);
23460   }
23461 }//Dblqh::readSinglePage()
23462 
23463 /* --------------------------------------------------------------------------
23464  * -------       REMOVE COPY FRAGMENT FROM ACTIVE COPY LIST           -------
23465  *
23466  * ------------------------------------------------------------------------- */
releaseActiveCopy(Signal * signal)23467 void Dblqh::releaseActiveCopy(Signal* signal)
23468 {
23469   UintR tracFlag;
23470   UintR tracIndex;
23471 
23472   tracFlag = ZFALSE;
23473   for (tracIndex = 0; tracIndex < 4; tracIndex++) {
23474     if (tracFlag == ZFALSE) {
23475       jam();
23476       if (cactiveCopy[tracIndex] == fragptr.i) {
23477         jam();
23478         tracFlag = ZTRUE;
23479       }//if
23480     } else {
23481       if (tracIndex < 3) {
23482         jam();
23483         cactiveCopy[tracIndex - 1] = cactiveCopy[tracIndex];
23484       } else {
23485         jam();
23486         cactiveCopy[3] = RNIL;
23487       }//if
23488     }//if
23489   }//for
23490   ndbrequire(tracFlag == ZTRUE);
23491   cnoActiveCopy--;
23492 }//Dblqh::releaseActiveCopy()
23493 
23494 
23495 /* --------------------------------------------------------------------------
23496  * -------       RELEASE ADD FRAGMENT RECORD                          -------
23497  *
23498  * ------------------------------------------------------------------------- */
releaseAddfragrec(Signal * signal)23499 void Dblqh::releaseAddfragrec(Signal* signal)
23500 {
23501   addfragptr.p->addfragStatus = AddFragRecord::FREE;
23502   addfragptr.p->nextAddfragrec = cfirstfreeAddfragrec;
23503   cfirstfreeAddfragrec = addfragptr.i;
23504 }//Dblqh::releaseAddfragrec()
23505 
23506 /* --------------------------------------------------------------------------
23507  * -------     RELEASE A PAGE REFERENCE RECORD.                       -------
23508  *
23509  * ------------------------------------------------------------------------- */
releasePageRef(Signal * signal)23510 void Dblqh::releasePageRef(Signal* signal)
23511 {
23512   pageRefPtr.p->prNext = cfirstfreePageRef;
23513   cfirstfreePageRef = pageRefPtr.i;
23514 }//Dblqh::releasePageRef()
23515 
23516 /* --------------------------------------------------------------------------
23517  * --- RELEASE ALL PAGES IN THE MM BUFFER AFTER EXECUTING THE LOG ON IT. ----
23518  *
23519  * ------------------------------------------------------------------------- */
releaseMmPages(Signal * signal)23520 void Dblqh::releaseMmPages(Signal* signal)
23521 {
23522 RMP_LOOP:
23523   jam();
23524   pageRefPtr.i = logPartPtr.p->firstPageRef;
23525   if (pageRefPtr.i != RNIL) {
23526     jam();
23527     ptrCheckGuard(pageRefPtr, cpageRefFileSize, pageRefRecord);
23528     releasePrPages(signal);
23529     removePageRef(signal);
23530     goto RMP_LOOP;
23531   }//if
23532 }//Dblqh::releaseMmPages()
23533 
23534 /* --------------------------------------------------------------------------
23535  * -------     RELEASE A SET OF PAGES AFTER EXECUTING THE LOG ON IT.  -------
23536  *
23537  * ------------------------------------------------------------------------- */
releasePrPages(Signal * signal)23538 void Dblqh::releasePrPages(Signal* signal)
23539 {
23540   UintR trppIndex;
23541 
23542   for (trppIndex = 0; trppIndex <= 7; trppIndex++) {
23543     jam();
23544     logPagePtr.i = pageRefPtr.p->pageRef[trppIndex];
23545     ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
23546     releaseLogpage(signal);
23547   }//for
23548 }//Dblqh::releasePrPages()
23549 
23550 /* --------------------------------------------------------------------------
23551  * -------  REMOVE OPERATION RECORD FROM LIST ON LOG PART OF NOT      -------
23552  *               COMPLETED OPERATIONS IN THE LOG.
23553  *
23554  *       SUBROUTINE SHORT NAME = RLO
23555  * ------------------------------------------------------------------------- */
removeLogTcrec(Signal * signal)23556 void Dblqh::removeLogTcrec(Signal* signal)
23557 {
23558   TcConnectionrecPtr rloTcNextConnectptr;
23559   TcConnectionrecPtr rloTcPrevConnectptr;
23560   rloTcPrevConnectptr.i = tcConnectptr.p->prevLogTcrec;
23561   rloTcNextConnectptr.i = tcConnectptr.p->nextLogTcrec;
23562   if (rloTcNextConnectptr.i != RNIL) {
23563     jam();
23564     ptrCheckGuard(rloTcNextConnectptr, ctcConnectrecFileSize, tcConnectionrec);
23565     rloTcNextConnectptr.p->prevLogTcrec = rloTcPrevConnectptr.i;
23566   } else {
23567     jam();
23568     logPartPtr.p->lastLogTcrec = rloTcPrevConnectptr.i;
23569   }//if
23570   if (rloTcPrevConnectptr.i != RNIL) {
23571     jam();
23572     ptrCheckGuard(rloTcPrevConnectptr, ctcConnectrecFileSize, tcConnectionrec);
23573     rloTcPrevConnectptr.p->nextLogTcrec = rloTcNextConnectptr.i;
23574   } else {
23575     jam();
23576     logPartPtr.p->firstLogTcrec = rloTcNextConnectptr.i;
23577   }//if
23578 }//Dblqh::removeLogTcrec()
23579 
23580 /* --------------------------------------------------------------------------
23581  * -------  REMOVE PAGE REFERENCE RECORD FROM LIST IN THIS LOG PART   -------
23582  *
23583  *       SUBROUTINE SHORT NAME = RPR
23584  * ------------------------------------------------------------------------- */
removePageRef(Signal * signal)23585 void Dblqh::removePageRef(Signal* signal)
23586 {
23587   PageRefRecordPtr rprPageRefPtr;
23588 
23589   pageRefPtr.i = logPartPtr.p->firstPageRef;
23590   if (pageRefPtr.i != RNIL) {
23591     jam();
23592     ptrCheckGuard(pageRefPtr, cpageRefFileSize, pageRefRecord);
23593     if (pageRefPtr.p->prNext == RNIL) {
23594       jam();
23595       logPartPtr.p->lastPageRef = RNIL;
23596       logPartPtr.p->firstPageRef = RNIL;
23597     } else {
23598       jam();
23599       logPartPtr.p->firstPageRef = pageRefPtr.p->prNext;
23600       rprPageRefPtr.i = pageRefPtr.p->prNext;
23601       ptrCheckGuard(rprPageRefPtr, cpageRefFileSize, pageRefRecord);
23602       rprPageRefPtr.p->prPrev = RNIL;
23603     }//if
23604     releasePageRef(signal);
23605   }//if
23606 }//Dblqh::removePageRef()
23607 
23608 /* ------------------------------------------------------------------------- */
23609 /* -------       RETURN FROM EXECUTION OF LOG                        ------- */
23610 /*                                                                           */
23611 /* ------------------------------------------------------------------------- */
returnExecLog(Signal * signal)23612 Uint32 Dblqh::returnExecLog(Signal* signal)
23613 {
23614   tcConnectptr.p->connectState = TcConnectionrec::CONNECTED;
23615   initLogPointers(signal);
23616   logPartPtr.p->execSrExecuteIndex++;
23617   Uint32 result = checkIfExecLog(signal);
23618   if (result == ZOK) {
23619     jam();
23620 /* ------------------------------------------------------------------------- */
23621 /* THIS LOG RECORD WILL BE EXECUTED AGAIN TOWARDS ANOTHER NODE.              */
23622 /* ------------------------------------------------------------------------- */
23623     logPagePtr.i = logPartPtr.p->execSrLogPage;
23624     ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
23625     logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] =
23626                   logPartPtr.p->execSrLogPageIndex;
23627   } else {
23628     jam();
23629 /* ------------------------------------------------------------------------- */
23630 /*       NO MORE EXECUTION OF THIS LOG RECORD.                               */
23631 /* ------------------------------------------------------------------------- */
23632     if (logPartPtr.p->logExecState ==
23633 	LogPartRecord::LES_EXEC_LOGREC_FROM_FILE) {
23634       jam();
23635 /* ------------------------------------------------------------------------- */
23636 /* THE LOG RECORD WAS READ FROM DISK. RELEASE ITS PAGES IMMEDIATELY.         */
23637 /* ------------------------------------------------------------------------- */
23638       lfoPtr.i = logPartPtr.p->execSrLfoRec;
23639       ptrCheckGuard(lfoPtr, clfoFileSize, logFileOperationRecord);
23640       releaseLfoPages(signal);
23641       releaseLfo(signal);
23642       logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG;
23643       if (logPartPtr.p->execSrExecLogFile != logPartPtr.p->currentLogfile) {
23644         jam();
23645         LogFileRecordPtr clfLogFilePtr;
23646         clfLogFilePtr.i = logPartPtr.p->execSrExecLogFile;
23647         ptrCheckGuard(clfLogFilePtr, clogFileFileSize, logFileRecord);
23648 #ifndef NO_REDO_OPEN_FILE_CACHE
23649         closeFile_cache(signal, clfLogFilePtr, __LINE__);
23650 #else
23651         clfLogFilePtr.p->logFileStatus = LogFileRecord::CLOSING_EXEC_LOG;
23652         closeFile(signal, clfLogFilePtr, __LINE__);
23653 #endif
23654         result = ZCLOSE_FILE;
23655       }//if
23656     }//if
23657     logPartPtr.p->execSrExecuteIndex = 0;
23658     logPartPtr.p->execSrLogPage = RNIL;
23659     logPartPtr.p->execSrLogPageIndex = ZNIL;
23660     logPagePtr.i = logFilePtr.p->currentLogpage;
23661     ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
23662     logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPartPtr.p->savePageIndex;
23663   }//if
23664   return result;
23665 }//Dblqh::returnExecLog()
23666 
23667 /* --------------------------------------------------------------------------
23668  * -------       SEIZE ADD FRAGMENT RECORD                             ------
23669  *
23670  * ------------------------------------------------------------------------- */
seizeAddfragrec(Signal * signal)23671 void Dblqh::seizeAddfragrec(Signal* signal)
23672 {
23673   addfragptr.i = cfirstfreeAddfragrec;
23674   ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord);
23675   cfirstfreeAddfragrec = addfragptr.p->nextAddfragrec;
23676 
23677   addfragptr.p->accConnectptr = RNIL;
23678   addfragptr.p->tupConnectptr = RNIL;
23679   addfragptr.p->tuxConnectptr = RNIL;
23680   addfragptr.p->defValSectionI = RNIL;
23681   addfragptr.p->defValNextPos = 0;
23682   bzero(&addfragptr.p->m_createTabReq, sizeof(addfragptr.p->m_createTabReq));
23683   bzero(&addfragptr.p->m_lqhFragReq, sizeof(addfragptr.p->m_lqhFragReq));
23684   bzero(&addfragptr.p->m_addAttrReq, sizeof(addfragptr.p->m_addAttrReq));
23685   bzero(&addfragptr.p->m_dropFragReq, sizeof(addfragptr.p->m_dropFragReq));
23686   bzero(&addfragptr.p->m_dropTabReq, sizeof(addfragptr.p->m_dropTabReq));
23687   addfragptr.p->addfragErrorCode = 0;
23688   addfragptr.p->attrSentToTup = 0;
23689   addfragptr.p->attrReceived = 0;
23690   addfragptr.p->totalAttrReceived = 0;
23691 }//Dblqh::seizeAddfragrec()
23692 
23693 /* --------------------------------------------------------------------------
23694  * -------       SEIZE FRAGMENT RECORD                                -------
23695  *
23696  * ------------------------------------------------------------------------- */
23697 /* ------------------------------------------------------------------------- */
23698 /* -------     SEIZE A PAGE REFERENCE RECORD.                        ------- */
23699 /*                                                                           */
23700 /* ------------------------------------------------------------------------- */
seizePageRef(Signal * signal)23701 void Dblqh::seizePageRef(Signal* signal)
23702 {
23703   pageRefPtr.i = cfirstfreePageRef;
23704   ptrCheckGuard(pageRefPtr, cpageRefFileSize, pageRefRecord);
23705   cfirstfreePageRef = pageRefPtr.p->prNext;
23706   pageRefPtr.p->prNext = RNIL;
23707 }//Dblqh::seizePageRef()
23708 
23709 /* --------------------------------------------------------------------------
23710  * -------               SEND ABORTED                                 -------
23711  *
23712  * ------------------------------------------------------------------------- */
sendAborted(Signal * signal)23713 void Dblqh::sendAborted(Signal* signal)
23714 {
23715   UintR TlastInd;
23716   if (tcConnectptr.p->nextReplica == ZNIL) {
23717     TlastInd = ZTRUE;
23718   } else {
23719     TlastInd = ZFALSE;
23720   }//if
23721   signal->theData[0] = tcConnectptr.p->tcOprec;
23722   signal->theData[1] = tcConnectptr.p->transid[0];
23723   signal->theData[2] = tcConnectptr.p->transid[1];
23724   signal->theData[3] = cownNodeid;
23725   signal->theData[4] = TlastInd;
23726   sendSignal(tcConnectptr.p->tcBlockref, GSN_ABORTED, signal, 5, JBB);
23727   return;
23728 }//Dblqh::sendAborted()
23729 
23730 /* --------------------------------------------------------------------------
23731  * -------               SEND LQH_TRANSCONF                           -------
23732  *
23733  * ------------------------------------------------------------------------- */
sendLqhTransconf(Signal * signal,LqhTransConf::OperationStatus stat)23734 void Dblqh::sendLqhTransconf(Signal* signal, LqhTransConf::OperationStatus stat)
23735 {
23736   TcNodeFailRecordPtr tcNodeFailPtr;
23737   tcNodeFailPtr.i = tcConnectptr.p->tcNodeFailrec;
23738   ptrCheckGuard(tcNodeFailPtr, ctcNodeFailrecFileSize, tcNodeFailRecord);
23739 
23740   Uint32 reqInfo = 0;
23741   LqhTransConf::setReplicaType(reqInfo, tcConnectptr.p->replicaType);
23742   LqhTransConf::setReplicaNo(reqInfo, tcConnectptr.p->seqNoReplica);
23743   LqhTransConf::setLastReplicaNo(reqInfo, tcConnectptr.p->lastReplicaNo);
23744   LqhTransConf::setSimpleFlag(reqInfo, tcConnectptr.p->opSimple);
23745   LqhTransConf::setDirtyFlag(reqInfo, tcConnectptr.p->dirtyOp);
23746   LqhTransConf::setOperation(reqInfo, tcConnectptr.p->operation);
23747 
23748   LqhTransConf * const lqhTransConf = (LqhTransConf *)&signal->theData[0];
23749   lqhTransConf->tcRef           = tcNodeFailPtr.p->newTcRef;
23750   lqhTransConf->lqhNodeId       = cownNodeid;
23751   lqhTransConf->operationStatus = stat;
23752   lqhTransConf->lqhConnectPtr   = tcConnectptr.i;
23753   lqhTransConf->transId1        = tcConnectptr.p->transid[0];
23754   lqhTransConf->transId2        = tcConnectptr.p->transid[1];
23755   lqhTransConf->oldTcOpRec      = tcConnectptr.p->tcOprec;
23756   lqhTransConf->requestInfo     = reqInfo;
23757   lqhTransConf->gci_hi          = tcConnectptr.p->gci_hi;
23758   lqhTransConf->nextNodeId1     = tcConnectptr.p->nextReplica;
23759   lqhTransConf->nextNodeId2     = tcConnectptr.p->nodeAfterNext[0];
23760   lqhTransConf->nextNodeId3     = tcConnectptr.p->nodeAfterNext[1];
23761   lqhTransConf->apiRef          = tcConnectptr.p->applRef;
23762   lqhTransConf->apiOpRec        = tcConnectptr.p->applOprec;
23763   lqhTransConf->tableId         = tcConnectptr.p->tableref;
23764   lqhTransConf->gci_lo          = tcConnectptr.p->gci_lo;
23765   lqhTransConf->fragId          = tcConnectptr.p->fragmentid;
23766   /**
23767     maxInstanceId is ignored for all LQH_TRANSCONF except the last one sent with
23768     LqhTransConf::LastTransConf as the state. This state is never called in this
23769     function. We set the value to the TC instance that handled this transaction.
23770     It's not needed but better set it to something useful than to something
23771     not useful.
23772   */
23773   ndbassert(stat != LqhTransConf::LastTransConf);
23774   lqhTransConf->maxInstanceId = refToInstance(tcConnectptr.p->tcBlockref);
23775   sendSignal(tcNodeFailPtr.p->newTcBlockref, GSN_LQH_TRANSCONF,
23776 	     signal, LqhTransConf::SignalLength, JBB);
23777   tcNodeFailPtr.p->tcRecNow = tcConnectptr.i + 1;
23778   signal->theData[0] = ZLQH_TRANS_NEXT;
23779   signal->theData[1] = tcNodeFailPtr.i;
23780   sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
23781 
23782   if (0)
23783   {
23784     ndbout_c("sending LQH_TRANSCONF %u transid: H'%.8x, H'%.8x op: %u state: %u(%u) marker: %u",
23785              tcConnectptr.i,
23786              tcConnectptr.p->transid[0],
23787              tcConnectptr.p->transid[1],
23788              tcConnectptr.p->operation,
23789              tcConnectptr.p->transactionState,
23790              stat,
23791              tcConnectptr.p->commitAckMarker);
23792   }
23793 }//Dblqh::sendLqhTransconf()
23794 
23795 /* --------------------------------------------------------------------------
23796  * -------               START ANOTHER PHASE OF LOG EXECUTION         -------
23797  *       RESET THE VARIABLES NEEDED BY THIS PROCESS AND SEND THE START SIGNAL
23798  *
23799  * ------------------------------------------------------------------------- */
startExecSr(Signal * signal)23800 void Dblqh::startExecSr(Signal* signal)
23801 {
23802   c_lcp_complete_fragments.first(fragptr);
23803   signal->theData[0] = fragptr.i;
23804   sendSignal(cownref, GSN_START_EXEC_SR, signal, 1, JBB);
23805 }//Dblqh::startExecSr()
23806 
23807 /* ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
23808  * ¤¤¤¤¤¤¤                            LOG MODULE                      ¤¤¤¤¤¤¤
23809  * ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ */
23810 /* --------------------------------------------------------------------------
23811  * -------       STEP FORWARD IN FRAGMENT LOG DURING LOG EXECUTION    -------
23812  *
23813  * ------------------------------------------------------------------------- */
stepAhead(Signal * signal,Uint32 stepAheadWords)23814 void Dblqh::stepAhead(Signal* signal, Uint32 stepAheadWords)
23815 {
23816   UintR tsaPos;
23817 
23818   tsaPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX];
23819   while ((stepAheadWords + tsaPos) >= ZPAGE_SIZE) {
23820     jam();
23821     logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = ZPAGE_SIZE;
23822     stepAheadWords = stepAheadWords - (ZPAGE_SIZE - tsaPos);
23823     logFilePtr.p->currentLogpage = logPagePtr.p->logPageWord[ZNEXT_PAGE];
23824     logPagePtr.i = logPagePtr.p->logPageWord[ZNEXT_PAGE];
23825     logFilePtr.p->currentFilepage++;
23826     ptrCheckGuardErr(logPagePtr, clogPageFileSize, logPageRecord,
23827                      NDBD_EXIT_SR_REDOLOG);
23828     logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = ZPAGE_HEADER_SIZE;
23829     logPartPtr.p->execSrPagesRead--;
23830     logPartPtr.p->execSrPagesExecuted++;
23831     tsaPos = ZPAGE_HEADER_SIZE;
23832   }//while
23833   logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = stepAheadWords + tsaPos;
23834 }//Dblqh::stepAhead()
23835 
23836 /* --------------------------------------------------------------------------
23837  * -------               WRITE A ABORT LOG RECORD                     -------
23838  *
23839  *       SUBROUTINE SHORT NAME: WAL
23840  * ------------------------------------------------------------------------- */
writeAbortLog(Signal * signal)23841 void Dblqh::writeAbortLog(Signal* signal)
23842 {
23843   if ((ZABORT_LOG_SIZE + ZNEXT_LOG_SIZE) >
23844       logFilePtr.p->remainingWordsInMbyte) {
23845     jam();
23846     changeMbyte(signal);
23847   }//if
23848   logFilePtr.p->remainingWordsInMbyte =
23849     logFilePtr.p->remainingWordsInMbyte - ZABORT_LOG_SIZE;
23850   writeLogWord(signal, ZABORT_TYPE);
23851   writeLogWord(signal, tcConnectptr.p->transid[0]);
23852   writeLogWord(signal, tcConnectptr.p->transid[1]);
23853 }//Dblqh::writeAbortLog()
23854 
23855 /* --------------------------------------------------------------------------
23856  * -------               WRITE A COMMIT LOG RECORD                    -------
23857  *
23858  *       SUBROUTINE SHORT NAME: WCL
23859  * ------------------------------------------------------------------------- */
writeCommitLog(Signal * signal,LogPartRecordPtr regLogPartPtr)23860 void Dblqh::writeCommitLog(Signal* signal, LogPartRecordPtr regLogPartPtr)
23861 {
23862   LogFileRecordPtr regLogFilePtr;
23863   LogPageRecordPtr regLogPagePtr;
23864   TcConnectionrec * const regTcPtr = tcConnectptr.p;
23865   regLogFilePtr.i = regLogPartPtr.p->currentLogfile;
23866   ptrCheckGuard(regLogFilePtr, clogFileFileSize, logFileRecord);
23867   regLogPagePtr.i = regLogFilePtr.p->currentLogpage;
23868   Uint32 twclTmp = regLogFilePtr.p->remainingWordsInMbyte;
23869   ptrCheckGuard(regLogPagePtr, clogPageFileSize, logPageRecord);
23870   logPartPtr = regLogPartPtr;
23871   logFilePtr = regLogFilePtr;
23872   logPagePtr = regLogPagePtr;
23873   if ((ZCOMMIT_LOG_SIZE + ZNEXT_LOG_SIZE) > twclTmp) {
23874     jam();
23875     changeMbyte(signal);
23876     twclTmp = logFilePtr.p->remainingWordsInMbyte;
23877   }//if
23878 
23879   Uint32 twclLogPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX];
23880   Uint32 tableId = regTcPtr->tableref;
23881   Uint32 schemaVersion = regTcPtr->schemaVersion;
23882   Uint32 fragId = regTcPtr->fragmentid;
23883   Uint32 fileNo = regTcPtr->logStartFileNo;
23884   Uint32 startPageNo = regTcPtr->logStartPageNo;
23885   Uint32 pageIndex = regTcPtr->logStartPageIndex;
23886   Uint32 stopPageNo = regTcPtr->logStopPageNo;
23887   Uint32 gci = regTcPtr->gci_hi;
23888   logFilePtr.p->remainingWordsInMbyte = twclTmp - ZCOMMIT_LOG_SIZE;
23889 
23890   if ((twclLogPos + ZCOMMIT_LOG_SIZE) >= ZPAGE_SIZE) {
23891     writeLogWord(signal, ZCOMMIT_TYPE);
23892     writeLogWord(signal, tableId);
23893     writeLogWord(signal, schemaVersion);
23894     writeLogWord(signal, fragId);
23895     writeLogWord(signal, fileNo);
23896     writeLogWord(signal, startPageNo);
23897     writeLogWord(signal, pageIndex);
23898     writeLogWord(signal, stopPageNo);
23899     writeLogWord(signal, gci);
23900   } else {
23901     Uint32* dataPtr = &logPagePtr.p->logPageWord[twclLogPos];
23902     logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = twclLogPos + ZCOMMIT_LOG_SIZE;
23903     dataPtr[0] = ZCOMMIT_TYPE;
23904     dataPtr[1] = tableId;
23905     dataPtr[2] = schemaVersion;
23906     dataPtr[3] = fragId;
23907     dataPtr[4] = fileNo;
23908     dataPtr[5] = startPageNo;
23909     dataPtr[6] = pageIndex;
23910     dataPtr[7] = stopPageNo;
23911     dataPtr[8] = gci;
23912   }//if
23913   TcConnectionrecPtr rloTcNextConnectptr;
23914   TcConnectionrecPtr rloTcPrevConnectptr;
23915   rloTcPrevConnectptr.i = regTcPtr->prevLogTcrec;
23916   rloTcNextConnectptr.i = regTcPtr->nextLogTcrec;
23917   if (rloTcNextConnectptr.i != RNIL) {
23918     jam();
23919     ptrCheckGuard(rloTcNextConnectptr, ctcConnectrecFileSize, tcConnectionrec);
23920     rloTcNextConnectptr.p->prevLogTcrec = rloTcPrevConnectptr.i;
23921   } else {
23922     regLogPartPtr.p->lastLogTcrec = rloTcPrevConnectptr.i;
23923   }//if
23924   if (rloTcPrevConnectptr.i != RNIL) {
23925     jam();
23926     ptrCheckGuard(rloTcPrevConnectptr, ctcConnectrecFileSize, tcConnectionrec);
23927     rloTcPrevConnectptr.p->nextLogTcrec = rloTcNextConnectptr.i;
23928   } else {
23929     regLogPartPtr.p->firstLogTcrec = rloTcNextConnectptr.i;
23930   }//if
23931 }//Dblqh::writeCommitLog()
23932 
23933 /* --------------------------------------------------------------------------
23934  * -------               WRITE A COMPLETED GCI LOG RECORD             -------
23935  *
23936  *       SUBROUTINE SHORT NAME: WCG
23937 // Input Pointers:
23938 // logFilePtr
23939 // logPartPtr
23940  * ------------------------------------------------------------------------- */
writeCompletedGciLog(Signal * signal)23941 void Dblqh::writeCompletedGciLog(Signal* signal)
23942 {
23943   if ((ZCOMPLETED_GCI_LOG_SIZE + ZNEXT_LOG_SIZE) >
23944       logFilePtr.p->remainingWordsInMbyte) {
23945     jam();
23946     changeMbyte(signal);
23947   }//if
23948 
23949   if (ERROR_INSERTED(5051) && (logFilePtr.p->currentFilepage > 0) &&
23950       (logFilePtr.p->currentFilepage % 32) == 0)
23951   {
23952     SET_ERROR_INSERT_VALUE(5000);
23953   }
23954 
23955   logFilePtr.p->remainingWordsInMbyte =
23956     logFilePtr.p->remainingWordsInMbyte - ZCOMPLETED_GCI_LOG_SIZE;
23957 
23958   if (DEBUG_REDO)
23959   {
23960     ndbout_c("writeCompletedGciLog gci: %u part: %u file: %u page: %u (mb: %u)",
23961              cnewestCompletedGci,
23962              logPartPtr.p->logPartNo,
23963              logFilePtr.p->fileNo,
23964              logFilePtr.p->currentFilepage,
23965              logFilePtr.p->currentFilepage >> ZTWOLOG_NO_PAGES_IN_MBYTE);
23966   }
23967 
23968   writeLogWord(signal, ZCOMPLETED_GCI_TYPE);
23969   writeLogWord(signal, cnewestCompletedGci);
23970   logPartPtr.p->logPartNewestCompletedGCI = cnewestCompletedGci;
23971 }//Dblqh::writeCompletedGciLog()
23972 
23973 /* --------------------------------------------------------------------------
23974  * -------         WRITE A DIRTY PAGE DURING LOG EXECUTION            -------
23975  *
23976  *     SUBROUTINE SHORT NAME: WD
23977  * ------------------------------------------------------------------------- */
writeDirty(Signal * signal,Uint32 place)23978 void Dblqh::writeDirty(Signal* signal, Uint32 place)
23979 {
23980   logPagePtr.p->logPageWord[ZPOS_DIRTY] = ZNOT_DIRTY;
23981 
23982   ndbassert(logPartPtr.p->prevFilepage ==
23983             logPagePtr.p->logPageWord[ZPOS_PAGE_NO]);
23984   writeDbgInfoPageHeader(logPagePtr, place, logPartPtr.p->prevFilepage,
23985                          ZPAGE_SIZE);
23986   // Calculate checksum for page
23987   logPagePtr.p->logPageWord[ZPOS_CHECKSUM] = calcPageCheckSum(logPagePtr);
23988 
23989   seizeLfo(signal);
23990   initLfo(signal);
23991   lfoPtr.p->lfoPageNo = logPartPtr.p->prevFilepage;
23992   lfoPtr.p->noPagesRw = 1;
23993   lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_DIRTY;
23994   lfoPtr.p->firstLfoPage = logPagePtr.i;
23995   signal->theData[0] = logFilePtr.p->fileRef;
23996   signal->theData[1] = cownref;
23997   signal->theData[2] = lfoPtr.i;
23998   signal->theData[3] = ZLIST_OF_PAIRS_SYNCH;
23999   signal->theData[4] = ZVAR_NO_LOG_PAGE_WORD;
24000   signal->theData[5] = 1;
24001   signal->theData[6] = logPagePtr.i;
24002   signal->theData[7] = logPartPtr.p->prevFilepage;
24003   sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, 8, JBA);
24004 
24005   ndbrequire(logFilePtr.p->fileRef != RNIL);
24006 
24007   logPartPtr.p->m_io_tracker.send_io(32768);
24008 
24009   if (DEBUG_REDO)
24010   {
24011     ndbout_c("writeDirty 1 page at part: %u file: %u page: %u (mb: %u)",
24012              logPartPtr.p->logPartNo,
24013              logFilePtr.p->fileNo,
24014              logPartPtr.p->prevFilepage,
24015              logPartPtr.p->prevFilepage >> ZTWOLOG_NO_PAGES_IN_MBYTE);
24016   }
24017 }//Dblqh::writeDirty()
24018 
24019 /* --------------------------------------------------------------------------
24020  * -------          WRITE A WORD INTO THE LOG, CHECK FOR NEW PAGE     -------
24021  *
24022  *       SUBROUTINE SHORT NAME:  WLW
24023  * ------------------------------------------------------------------------- */
writeLogWord(Signal * signal,Uint32 data)24024 void Dblqh::writeLogWord(Signal* signal, Uint32 data)
24025 {
24026   Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX];
24027   ndbrequire(logPos < ZPAGE_SIZE);
24028   logPagePtr.p->logPageWord[logPos] = data;
24029   logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos + 1;
24030   if ((logPos + 1) == ZPAGE_SIZE) {
24031     jam();
24032     completedLogPage(signal, ZNORMAL, __LINE__);
24033     seizeLogpage(signal);
24034     initLogpage(signal);
24035     logFilePtr.p->currentLogpage = logPagePtr.i;
24036     logFilePtr.p->currentFilepage++;
24037   }//if
24038 }//Dblqh::writeLogWord()
24039 
24040 /* --------------------------------------------------------------------------
24041  * -------   WRITE MULTIPLE WORDS INTO THE LOG, CHECK FOR NEW PAGES   -------
24042  *
24043  * ------------------------------------------------------------------------- */
24044 
writeLogWords(Signal * signal,const Uint32 * data,Uint32 len)24045 void Dblqh::writeLogWords(Signal* signal, const Uint32* data, Uint32 len)
24046 {
24047   Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX];
24048   ndbrequire(logPos < ZPAGE_SIZE);
24049   Uint32 wordsThisPage= ZPAGE_SIZE - logPos;
24050 
24051   while (len >= wordsThisPage)
24052   {
24053     /* Fill rest of the log page */
24054     MEMCOPY_NO_WORDS(&logPagePtr.p->logPageWord[logPos],
24055                      data,
24056                      wordsThisPage);
24057     logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = ZPAGE_SIZE;
24058     data+= wordsThisPage;
24059     len-= wordsThisPage;
24060 
24061     /* Mark page completed and get a new one */
24062     jam();
24063     completedLogPage(signal, ZNORMAL, __LINE__);
24064     seizeLogpage(signal);
24065     initLogpage(signal);
24066     logFilePtr.p->currentLogpage = logPagePtr.i;
24067     logFilePtr.p->currentFilepage++;
24068 
24069     logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX];
24070     ndbrequire(logPos < ZPAGE_SIZE);
24071     wordsThisPage= ZPAGE_SIZE - logPos;
24072   }
24073 
24074   if (len > 0)
24075   {
24076     /* No need to worry about next page */
24077     ndbassert( len < wordsThisPage );
24078     /* Write partial log page */
24079     MEMCOPY_NO_WORDS(&logPagePtr.p->logPageWord[logPos],
24080                      data,
24081                      len);
24082     logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos + len;
24083   }
24084 
24085   ndbassert( logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] < ZPAGE_SIZE );
24086 }
24087 
24088 /* --------------------------------------------------------------------------
24089  * -------         WRITE A NEXT LOG RECORD AND CHANGE TO NEXT MBYTE   -------
24090  *
24091  *       SUBROUTINE SHORT NAME:  WNL
24092  * Input Pointers:
24093  * logFilePtr(Redefines)
24094  * logPagePtr (Redefines)
24095  * logPartPtr
24096  * When changing to a new MByte we always ensure that we sync the REDO log.
24097  * This more or less annuls the sync once per 1 MByte maintained by NDBFS,
24098  * it does however make it easier to reason around recovery and also makes
24099  * it less likely of future bugs due to changes in NDBFS. This is why we
24100  * use true on completedLogPage in this function.
24101  * ------------------------------------------------------------------------- */
writeNextLog(Signal * signal)24102 void Dblqh::writeNextLog(Signal* signal)
24103 {
24104   LogFileRecordPtr wnlNextLogFilePtr;
24105   UintR twnlNextFileNo;
24106   UintR twnlNewMbyte;
24107   UintR twnlRemWords;
24108   UintR twnlNextMbyte;
24109 
24110 /* -------------------------------------------------- */
24111 /*       CALCULATE THE NEW NUMBER OF REMAINING WORDS  */
24112 /*       AS 128*2036 WHERE 128 * 8 KBYTE = 1 MBYTE    */
24113 /*       AND 2036 IS THE NUMBER OF WORDS IN A PAGE    */
24114 /*       THAT IS USED FOR LOG INFORMATION.            */
24115 /* -------------------------------------------------- */
24116   twnlRemWords = ZPAGE_SIZE - ZPAGE_HEADER_SIZE;
24117   twnlRemWords = twnlRemWords * ZPAGES_IN_MBYTE;
24118   wnlNextLogFilePtr.i = logFilePtr.p->nextLogFile;
24119   ptrCheckGuard(wnlNextLogFilePtr, clogFileFileSize, logFileRecord);
24120 /* -------------------------------------------------- */
24121 /*       WRITE THE NEXT LOG RECORD.                   */
24122 /* -------------------------------------------------- */
24123   ndbrequire(logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] < ZPAGE_SIZE);
24124   logPagePtr.p->logPageWord[logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]] =
24125     ZNEXT_MBYTE_TYPE;
24126   if (logFilePtr.p->currentMbyte == (clogFileSize - 1)) {
24127     jam();
24128 /* -------------------------------------------------- */
24129 /*       CALCULATE THE NEW REMAINING WORDS WHEN       */
24130 /*       CHANGING LOG FILE IS PERFORMED               */
24131 /* -------------------------------------------------- */
24132     twnlRemWords = twnlRemWords - (ZPAGE_SIZE - ZPAGE_HEADER_SIZE);
24133 /* -------------------------------------------------- */
24134 /*       ENSURE THAT THE LOG PAGES ARE WRITTEN AFTER  */
24135 /*       WE HAVE CHANGED MBYTE.                       */
24136 /* -------------------------------------------------- */
24137 /*       ENSURE LAST PAGE IN PREVIOUS MBYTE IS        */
24138 /*       WRITTEN AND THAT THE STATE OF THE WRITE IS   */
24139 /*       PROPERLY SET.                                */
24140 /* -------------------------------------------------- */
24141 /*       WE HAVE TO CHANGE LOG FILE                   */
24142 /* -------------------------------------------------- */
24143     completedLogPage(signal, ZLAST_WRITE_IN_FILE, __LINE__, true);
24144     if (wnlNextLogFilePtr.p->fileNo == 0) {
24145       jam();
24146 /* -------------------------------------------------- */
24147 /*       WE HAVE FINALISED A LOG LAP, START FROM LOG  */
24148 /*       FILE 0 AGAIN                                 */
24149 /* -------------------------------------------------- */
24150       logPartPtr.p->logLap++;
24151     }//if
24152     logPartPtr.p->currentLogfile = wnlNextLogFilePtr.i;
24153     logFilePtr.i = wnlNextLogFilePtr.i;
24154     logFilePtr.p = wnlNextLogFilePtr.p;
24155     twnlNewMbyte = 0;
24156   } else {
24157     jam();
24158 /* -------------------------------------------------- */
24159 /*       INCREMENT THE CURRENT MBYTE                  */
24160 /*       SET PAGE INDEX TO PAGE HEADER SIZE           */
24161 /* -------------------------------------------------- */
24162     completedLogPage(signal, ZENFORCE_WRITE, __LINE__, true);
24163     twnlNewMbyte = logFilePtr.p->currentMbyte + 1;
24164   }//if
24165 /* -------------------------------------------------- */
24166 /*       CHANGE TO NEW LOG FILE IF NECESSARY          */
24167 /*       UPDATE THE FILE POSITION TO THE NEW MBYTE    */
24168 /*       FOUND IN PAGE PART OF TNEXT_LOG_PTR          */
24169 /*       ALLOCATE AND INITIATE A NEW PAGE SINCE WE    */
24170 /*       HAVE SENT THE PREVIOUS PAGE TO DISK.         */
24171 /*       SET THE NEW NUMBER OF REMAINING WORDS IN THE */
24172 /*       NEW MBYTE ALLOCATED.                         */
24173 /* -------------------------------------------------- */
24174   logFilePtr.p->currentMbyte = twnlNewMbyte;
24175   logFilePtr.p->filePosition = twnlNewMbyte * ZPAGES_IN_MBYTE;
24176   logFilePtr.p->currentFilepage = twnlNewMbyte * ZPAGES_IN_MBYTE;
24177   logFilePtr.p->remainingWordsInMbyte = twnlRemWords;
24178   seizeLogpage(signal);
24179   if (logFilePtr.p->currentMbyte == 0) {
24180     jam();
24181     logFilePtr.p->lastPageWritten = 0;
24182     if (logFilePtr.p->fileNo == 0) {
24183       jam();
24184       releaseLogpage(signal);
24185       logPagePtr.i = logFilePtr.p->logPageZero;
24186       ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
24187     }//if
24188   }//if
24189   initLogpage(signal);
24190   logFilePtr.p->currentLogpage = logPagePtr.i;
24191   if (logFilePtr.p->currentMbyte == 0) {
24192     jam();
24193 /* -------------------------------------------------- */
24194 /*       THIS IS A NEW FILE, WRITE THE FILE DESCRIPTOR*/
24195 /*       ALSO OPEN THE NEXT LOG FILE TO ENSURE THAT   */
24196 /*       THIS FILE IS OPEN WHEN ITS TURN COMES.       */
24197 /* -------------------------------------------------- */
24198     writeFileHeaderOpen(signal, ZNORMAL);
24199     openNextLogfile(signal);
24200     logFilePtr.p->fileChangeState = LogFileRecord::BOTH_WRITES_ONGOING;
24201   }//if
24202   if (logFilePtr.p->fileNo == logPartPtr.p->logTailFileNo)
24203   {
24204     if (logFilePtr.p->currentMbyte == logPartPtr.p->logTailMbyte)
24205     {
24206       jam();
24207 /* -------------------------------------------------- */
24208 /*       THE HEAD AND TAIL HAS MET. THIS SHOULD NEVER */
24209 /*       OCCUR. CAN HAPPEN IF THE LOCAL CHECKPOINTS   */
24210 /*       TAKE FAR TOO LONG TIME. SO TIMING PROBLEMS   */
24211 /*       CAN INVOKE THIS SYSTEM CRASH. HOWEVER ONLY   */
24212 /*       VERY SERIOUS TIMING PROBLEMS.                */
24213 /* -------------------------------------------------- */
24214       char buf[100];
24215       BaseString::snprintf(buf, sizeof(buf),
24216                            "Head/Tail met in REDO log, logpart: %u"
24217                            " file: %u mbyte: %u state: %u log-problem: %u",
24218                            logPartPtr.p->logPartNo,
24219                            logFilePtr.p->fileNo,
24220                            logFilePtr.p->currentMbyte,
24221                            logPartPtr.p->logPartState,
24222                            logPartPtr.p->m_log_problems);
24223 
24224 
24225       signal->theData[0] = 2398;
24226       execDUMP_STATE_ORD(signal);
24227       progError(__LINE__, NDBD_EXIT_NO_MORE_REDOLOG, buf);
24228       systemError(signal, __LINE__);
24229     }//if
24230   }//if
24231   if (logFilePtr.p->currentMbyte == (clogFileSize - 1)) {
24232     jam();
24233     twnlNextMbyte = 0;
24234     if (logFilePtr.p->fileChangeState != LogFileRecord::NOT_ONGOING)
24235     {
24236       jam();
24237       update_log_problem(signal, logPartPtr,
24238                          LogPartRecord::P_FILE_CHANGE_PROBLEM,
24239                          /* set */ true);
24240     }//if
24241     twnlNextFileNo = wnlNextLogFilePtr.p->fileNo;
24242   } else {
24243     jam();
24244     twnlNextMbyte = logFilePtr.p->currentMbyte + 1;
24245     twnlNextFileNo = logFilePtr.p->fileNo;
24246   }//if
24247 
24248   LogPosition head = { twnlNextFileNo, twnlNextMbyte };
24249   LogPosition tail = { logPartPtr.p->logTailFileNo, logPartPtr.p->logTailMbyte};
24250   Uint64 free_mb = free_log(head, tail, logPartPtr.p->noLogFiles, clogFileSize);
24251   if (free_mb <= c_free_mb_force_lcp_limit)
24252   {
24253     jam();
24254     force_lcp(signal);
24255   }
24256 
24257   if (free_mb <= c_free_mb_tail_problem_limit)
24258   {
24259     jam();
24260     update_log_problem(signal, logPartPtr, LogPartRecord::P_TAIL_PROBLEM, true);
24261   }
24262 
24263   if (ERROR_INSERTED(5058) &&
24264       (twnlNextMbyte + 3 >= clogFileSize) &&
24265       logFilePtr.p->fileNo != 0 &&
24266       logFilePtr.p->nextLogFile != logPartPtr.p->firstLogfile)
24267   {
24268     jam();
24269     srand((int)time(0));
24270     Uint32 wait = 3 + (rand() % 5);
24271 
24272     suspendFile(signal, logFilePtr, /* forever */ 0);
24273     suspendFile(signal, logPartPtr.p->firstLogfile, /* forever */ 0);
24274     signal->theData[0] = 9999;
24275     sendSignalWithDelay(CMVMI_REF, GSN_NDB_TAMPER, signal, wait * 1000, 1);
24276     CLEAR_ERROR_INSERT_VALUE;
24277   }
24278 
24279   if (ERROR_INSERTED(5059) &&
24280       twnlNextMbyte == 4 &&
24281       logFilePtr.p->fileNo != 0)
24282   {
24283     signal->theData[0] = 9999;
24284     sendSignal(CMVMI_REF, GSN_NDB_TAMPER, signal, 1, JBA);
24285   }
24286 
24287 }//Dblqh::writeNextLog()
24288 
24289 bool
validate_filter(Signal * signal)24290 Dblqh::validate_filter(Signal* signal)
24291 {
24292   Uint32 * start = signal->theData + 1;
24293   Uint32 * end = signal->theData + signal->getLength();
24294   if (start == end)
24295   {
24296     infoEvent("No filter specified, not listing...");
24297     if (!ERROR_INSERTED(4002))
24298       return false;
24299     else
24300       return true;
24301   }
24302 
24303   while(start < end)
24304   {
24305     switch(* start){
24306     case 0: // Table
24307     case 1: // API Node
24308     case 3: // TC Node
24309       start += 2;
24310       break;
24311     case 2: // Transid
24312       start += 3;
24313       break;
24314     default:
24315       infoEvent("Invalid filter op: 0x%x pos: %ld",
24316 		* start,
24317 		(long int)(start - (signal->theData + 1)));
24318       return false;
24319     }
24320   }
24321 
24322   if (start != end)
24323   {
24324     infoEvent("Invalid filter, unexpected end");
24325     return false;
24326   }
24327 
24328   return true;
24329 }
24330 
24331 bool
match_and_print(Signal * signal,Ptr<TcConnectionrec> tcRec)24332 Dblqh::match_and_print(Signal* signal, Ptr<TcConnectionrec> tcRec)
24333 {
24334   Uint32 len = signal->getLength();
24335   Uint32* start = signal->theData + 3;
24336   Uint32* end = signal->theData + len;
24337   while (start < end)
24338   {
24339     switch(* start){
24340     case 0:
24341       if (tcRec.p->tableref != * (start + 1))
24342 	return false;
24343       start += 2;
24344       break;
24345     case 1:
24346       if (refToNode(tcRec.p->applRef) != * (start + 1))
24347 	return false;
24348       start += 2;
24349       break;
24350     case 2:
24351       if (tcRec.p->transid[0] != * (start + 1) ||
24352 	  tcRec.p->transid[1] != * (start + 2))
24353 	return false;
24354       start += 3;
24355       break;
24356     case 3:
24357       if (refToNode(tcRec.p->tcBlockref) != * (start + 1))
24358 	return false;
24359       start += 2;
24360       break;
24361     default:
24362       ndbassert(false);
24363       return false;
24364     }
24365   }
24366 
24367   if (start != end)
24368   {
24369     ndbassert(false);
24370     return false;
24371   }
24372 
24373   /**
24374    * Do print
24375    */
24376   Uint32 *temp = signal->theData + 25;
24377   memcpy(temp, signal->theData, 4 * len);
24378 
24379   char state[20];
24380   const char* op = "<Unknown>";
24381   if (tcRec.p->tcScanRec != RNIL)
24382   {
24383     ScanRecordPtr sp;
24384     sp.i = tcRec.p->tcScanRec;
24385     c_scanRecordPool.getPtr(sp);
24386 
24387     if (sp.p->scanLockMode)
24388       op = "SCAN-EX";
24389     else if(sp.p->scanLockHold)
24390       op = "SCAN-SH";
24391     else
24392       op = "SCAN";
24393 
24394     switch(sp.p->scanState){
24395     case ScanRecord::WAIT_NEXT_SCAN:
24396       BaseString::snprintf(state, sizeof(state), "WaitNextScan");
24397       break;
24398     case ScanRecord::IN_QUEUE:
24399       BaseString::snprintf(state, sizeof(state), "InQueue");
24400       break;
24401     case ScanRecord::SCAN_FREE:
24402     case ScanRecord::WAIT_NEXT_SCAN_COPY:
24403     case ScanRecord::WAIT_ACC_COPY:
24404     case ScanRecord::WAIT_ACC_SCAN:
24405     case ScanRecord::WAIT_SCAN_NEXTREQ:
24406     case ScanRecord::WAIT_CLOSE_SCAN:
24407     case ScanRecord::WAIT_CLOSE_COPY:
24408     case ScanRecord::WAIT_TUPKEY_COPY:
24409     case ScanRecord::WAIT_LQHKEY_COPY:
24410       BaseString::snprintf(state, sizeof(state), "%u", sp.p->scanState);
24411       break;
24412     }
24413   }
24414   else
24415   {
24416     switch(tcRec.p->operation){
24417     case ZREAD:
24418       if (tcRec.p->lockType)
24419 	op = "READ-EX";
24420       else if(!tcRec.p->dirtyOp)
24421 	op = "READ-SH";
24422       else
24423 	op = "READ";
24424       break;
24425     case ZINSERT: op = "INSERT"; break;
24426     case ZUPDATE: op = "UPDATE"; break;
24427     case ZDELETE: op = "DELETE"; break;
24428     case ZWRITE: op = "WRITE"; break;
24429     case ZUNLOCK: op = "UNLOCK"; break;
24430     }
24431 
24432     switch(tcRec.p->transactionState){
24433     case TcConnectionrec::IDLE:
24434     case TcConnectionrec::WAIT_ACC:
24435       BaseString::snprintf(state, sizeof(state), "In lock queue");
24436       break;
24437     case TcConnectionrec::WAIT_TUPKEYINFO:
24438     case TcConnectionrec::WAIT_ATTR:
24439       BaseString::snprintf(state, sizeof(state), "WaitData");
24440       break;
24441     case TcConnectionrec::WAIT_TUP:
24442       BaseString::snprintf(state, sizeof(state), "Running");
24443       break;
24444     case TcConnectionrec::WAIT_TUP_COMMIT:
24445       BaseString::snprintf(state, sizeof(state), "Committing");
24446       break;
24447     case TcConnectionrec::PREPARED:
24448       BaseString::snprintf(state, sizeof(state), "Prepared");
24449       break;
24450     case TcConnectionrec::COMMITTED:
24451       BaseString::snprintf(state, sizeof(state), "Committed");
24452       break;
24453     case TcConnectionrec::LOG_QUEUED:
24454     case TcConnectionrec::LOG_COMMIT_WRITTEN_WAIT_SIGNAL:
24455     case TcConnectionrec::LOG_COMMIT_QUEUED_WAIT_SIGNAL:
24456     case TcConnectionrec::LOG_COMMIT_QUEUED:
24457     case TcConnectionrec::COMMIT_QUEUED:
24458     case TcConnectionrec::WAIT_ACC_ABORT:
24459     case TcConnectionrec::ABORT_QUEUED:
24460     case TcConnectionrec::WAIT_AI_AFTER_ABORT:
24461     case TcConnectionrec::LOG_ABORT_QUEUED:
24462     case TcConnectionrec::WAIT_TUP_TO_ABORT:
24463     case TcConnectionrec::WAIT_SCAN_AI:
24464     case TcConnectionrec::SCAN_STATE_USED:
24465     case TcConnectionrec::SCAN_TUPKEY:
24466     case TcConnectionrec::COPY_TUPKEY:
24467     case TcConnectionrec::TC_NOT_CONNECTED:
24468     case TcConnectionrec::PREPARED_RECEIVED_COMMIT:
24469     case TcConnectionrec::LOG_COMMIT_WRITTEN:
24470       BaseString::snprintf(state, sizeof(state), "%u",
24471 			   tcRec.p->transactionState);
24472     }
24473   }
24474 
24475   char buf[100];
24476   BaseString::snprintf(buf, sizeof(buf),
24477 		       "OP[%u]: Tab: %d frag: %d TC: %u API: %d(0x%x)"
24478 		       "transid: H'%.8x H'%.8x op: %s state: %s",
24479 		       tcRec.i,
24480 		       tcRec.p->tableref,
24481 		       tcRec.p->fragmentid,
24482 		       refToNode(tcRec.p->tcBlockref),
24483 		       refToNode(tcRec.p->applRef),
24484 		       refToBlock(tcRec.p->applRef),
24485 		       tcRec.p->transid[0], tcRec.p->transid[1],
24486 		       op,
24487 		       state);
24488 
24489   if (!ERROR_INSERTED(4002))
24490     infoEvent("%s", buf);
24491   else
24492     ndbout_c("%s", buf);
24493 
24494   memcpy(signal->theData, temp, 4*len);
24495   return true;
24496 }
24497 
24498 void
execDUMP_STATE_ORD(Signal * signal)24499 Dblqh::execDUMP_STATE_ORD(Signal* signal)
24500 {
24501   jamEntry();
24502   DumpStateOrd * const dumpState = (DumpStateOrd *)&signal->theData[0];
24503   Uint32 arg= dumpState->args[0];
24504 
24505   if(dumpState->args[0] == DumpStateOrd::CommitAckMarkersSize){
24506     infoEvent("LQH: m_commitAckMarkerPool: %d free size: %d",
24507 	      m_commitAckMarkerPool.getNoOfFree(),
24508 	      m_commitAckMarkerPool.getSize());
24509   }
24510   if(dumpState->args[0] == DumpStateOrd::CommitAckMarkersDump){
24511     infoEvent("LQH: m_commitAckMarkerPool: %d free size: %d",
24512 	      m_commitAckMarkerPool.getNoOfFree(),
24513 	      m_commitAckMarkerPool.getSize());
24514 
24515     CommitAckMarkerIterator iter;
24516     for(m_commitAckMarkerHash.first(iter); iter.curr.i != RNIL;
24517 	m_commitAckMarkerHash.next(iter)){
24518       infoEvent("CommitAckMarker: i = %d (H'%.8x, H'%.8x)"
24519 		" ApiRef: 0x%x apiOprec: 0x%x TcRef: %x, ref_count: %u",
24520 		iter.curr.i,
24521 		iter.curr.p->transid1,
24522 		iter.curr.p->transid2,
24523 		iter.curr.p->apiRef,
24524 		iter.curr.p->apiOprec,
24525 		iter.curr.p->tcRef,
24526                 iter.curr.p->reference_count);
24527     }
24528   }
24529 
24530   // Dump info about number of log pages
24531   if(dumpState->args[0] == DumpStateOrd::LqhDumpNoLogPages){
24532     infoEvent("LQH: Log pages : %d Free: %d",
24533 	      clogPageFileSize,
24534 	      cnoOfLogPages);
24535   }
24536 
24537   // Dump all defined tables that LQH knowns about
24538   if(dumpState->args[0] == DumpStateOrd::LqhDumpAllDefinedTabs){
24539     for(Uint32 i = 0; i<ctabrecFileSize; i++){
24540       TablerecPtr tabPtr;
24541       tabPtr.i = i;
24542       ptrAss(tabPtr, tablerec);
24543       if(tabPtr.p->tableStatus != Tablerec::NOT_DEFINED){
24544 	infoEvent("Table %d Status: %d Usage: [ r: %u w: %u ]",
24545 		  i, tabPtr.p->tableStatus,
24546                   tabPtr.p->usageCountR, tabPtr.p->usageCountW);
24547 
24548 	for (Uint32 j = 0; j<NDB_ARRAY_SIZE(tabPtr.p->fragrec); j++)
24549 	{
24550 	  FragrecordPtr fragPtr;
24551 	  if ((fragPtr.i = tabPtr.p->fragrec[j]) != RNIL)
24552 	  {
24553 	    c_fragment_pool.getPtr(fragPtr);
24554 	    infoEvent("  frag: %d distKey: %u",
24555 		      tabPtr.p->fragid[j],
24556 		      fragPtr.p->fragDistributionKey);
24557 	  }
24558 	}
24559       }
24560     }
24561     return;
24562   }
24563 
24564   // Dump all ScanRecords
24565   if (dumpState->args[0] == DumpStateOrd::LqhDumpAllScanRec){
24566     Uint32 recordNo = 0;
24567     if (signal->length() == 1)
24568       infoEvent("LQH: Dump all ScanRecords - size: %d",
24569 		cscanrecFileSize);
24570     else if (signal->length() == 2)
24571       recordNo = dumpState->args[1];
24572     else
24573       return;
24574 
24575     dumpState->args[0] = DumpStateOrd::LqhDumpOneScanRec;
24576     dumpState->args[1] = recordNo;
24577     execDUMP_STATE_ORD(signal);
24578 
24579     if (recordNo < cscanrecFileSize-1){
24580       dumpState->args[0] = DumpStateOrd::LqhDumpAllScanRec;
24581       dumpState->args[1] = recordNo+1;
24582       sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 2, JBB);
24583     }
24584     return;
24585   }
24586 
24587   // Dump all active ScanRecords
24588   if (dumpState->args[0] == DumpStateOrd::LqhDumpAllActiveScanRec){
24589     Uint32 recordNo = 0;
24590     if (signal->length() == 1)
24591       infoEvent("LQH: Dump active ScanRecord - size: %d",
24592 		cscanrecFileSize);
24593     else if (signal->length() == 2)
24594       recordNo = dumpState->args[1];
24595     else
24596       return;
24597 
24598     ScanRecordPtr sp;
24599     sp.i = recordNo;
24600     c_scanRecordPool.getPtr(sp);
24601     if (sp.p->scanState != ScanRecord::SCAN_FREE){
24602       dumpState->args[0] = DumpStateOrd::LqhDumpOneScanRec;
24603       dumpState->args[1] = recordNo;
24604       execDUMP_STATE_ORD(signal);
24605     }
24606 
24607     if (recordNo < cscanrecFileSize-1){
24608       dumpState->args[0] = DumpStateOrd::LqhDumpAllActiveScanRec;
24609       dumpState->args[1] = recordNo+1;
24610       sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 2, JBB);
24611     }
24612     return;
24613   }
24614 
24615   if(dumpState->args[0] == DumpStateOrd::LqhDumpOneScanRec){
24616     Uint32 recordNo = RNIL;
24617     if (signal->length() == 2)
24618       recordNo = dumpState->args[1];
24619     else
24620       return;
24621 
24622     if (recordNo >= cscanrecFileSize)
24623       return;
24624 
24625     ScanRecordPtr sp;
24626     sp.i = recordNo;
24627     c_scanRecordPool.getPtrIgnoreAlloc(sp);
24628     infoEvent("Dblqh::ScanRecord[%d]: state=%d, type=%d, "
24629 	      "complStatus=%d, scanNodeId=%d",
24630 	      sp.i,
24631 	      sp.p->scanState,
24632 	      sp.p->scanType,
24633 	      sp.p->scanCompletedStatus,
24634 	      sp.p->scanNodeId);
24635     infoEvent(" apiBref=0x%x, scanAccPtr=%d",
24636 	      sp.p->scanApiBlockref,
24637 	      sp.p->scanAccPtr);
24638     infoEvent(" copyptr=%d, ailen=%d, complOps=%d, concurrOps=%d",
24639 	      sp.p->copyPtr,
24640 	      sp.p->scanAiLength,
24641 	      sp.p->m_curr_batch_size_rows,
24642 	      sp.p->m_max_batch_size_rows);
24643     infoEvent(" errCnt=%d, schV=%d",
24644 	      sp.p->scanErrorCounter,
24645 	      sp.p->scanSchemaVersion);
24646     infoEvent(" stpid=%d, flag=%d, lhold=%d, lmode=%d, num=%d",
24647 	      sp.p->scanStoredProcId,
24648 	      sp.p->scanFlag,
24649 	      sp.p->scanLockHold,
24650 	      sp.p->scanLockMode,
24651 	      sp.p->scanNumber);
24652     infoEvent(" relCount=%d, TCwait=%d, TCRec=%d, KIflag=%d",
24653 	      sp.p->scanReleaseCounter,
24654 	      sp.p->scanTcWaiting,
24655 	      sp.p->scanTcrec,
24656 	      sp.p->scanKeyinfoFlag);
24657     infoEvent(" LcpScan=%d  RowId(%u:%u)",
24658               sp.p->lcpScan,
24659               sp.p->m_row_id.m_page_no,
24660               sp.p->m_row_id.m_page_idx);
24661     return;
24662   }
24663   if(dumpState->args[0] == DumpStateOrd::LqhDumpLcpState){
24664 
24665     infoEvent("== LQH LCP STATE ==");
24666     infoEvent(" clcpCompletedState=%d, c_lcpId=%d, cnoOfFragsCheckpointed=%d",
24667 	      clcpCompletedState,
24668 	      c_lcpId,
24669 	      cnoOfFragsCheckpointed);
24670 
24671     LcpRecordPtr TlcpPtr;
24672     // Print information about the current local checkpoint
24673     TlcpPtr.i = 0;
24674     ptrAss(TlcpPtr, lcpRecord);
24675     infoEvent(" lcpState=%d lastFragmentFlag=%d",
24676 	      TlcpPtr.p->lcpState, TlcpPtr.p->lastFragmentFlag);
24677     infoEvent("currentFragment.fragPtrI=%d",
24678 	      TlcpPtr.p->currentFragment.fragPtrI);
24679     infoEvent("currentFragment.lcpFragOrd.tableId=%d",
24680 	      TlcpPtr.p->currentFragment.lcpFragOrd.tableId);
24681     infoEvent(" reportEmpty=%d",
24682 	      TlcpPtr.p->reportEmpty);
24683     char buf[8*_NDB_NODE_BITMASK_SIZE+1];
24684     infoEvent(" m_EMPTY_LCP_REQ=%s",
24685 	      TlcpPtr.p->m_EMPTY_LCP_REQ.getText(buf));
24686 
24687     if ((signal->length() == 2) &&
24688         (dumpState->args[1] == 0))
24689     {
24690       /* Dump reserved LCP scan rec */
24691       /* As there's only one, we'll do a tight loop here */
24692       infoEvent(" dumping reserved scan records");
24693       for (Uint32 rec=0; rec < cscanrecFileSize; rec++)
24694       {
24695         ScanRecordPtr sp;
24696         sp.i = rec;
24697         c_scanRecordPool.getPtrIgnoreAlloc(sp);
24698 
24699         if (sp.p->m_reserved &&
24700             sp.p->lcpScan)
24701         {
24702           dumpState->args[0] = DumpStateOrd::LqhDumpOneScanRec;
24703           dumpState->args[1] = rec;
24704           execDUMP_STATE_ORD(signal);
24705         }
24706       }
24707     }
24708 
24709     return;
24710   }
24711   if (dumpState->args[0] == DumpStateOrd::LQHLogFileInitStatus){
24712      reportStatus(signal);
24713      return;
24714   }
24715 
24716 #ifdef ERROR_INSERT
24717 #ifdef NDB_DEBUG_FULL
24718   if(dumpState->args[0] == DumpStateOrd::LCPContinue){
24719     switch(cerrorInsert){
24720     case 5904:
24721       CLEAR_ERROR_INSERT_VALUE;
24722       g_trace_lcp.restore(*globalData.getBlock(BACKUP), signal);
24723       return;
24724     default:
24725       return;
24726     }
24727   }
24728 #endif
24729 #endif
24730 
24731   if(arg == 2304 || arg == 2305)
24732   {
24733     jam();
24734 
24735     // logPartRecord is initialised in start phase 1
24736     if ((getNodeState().startLevel < NodeState::SL_STARTING) ||
24737         ((getNodeState().startLevel == NodeState::SL_STARTING) && (getNodeState().starting.startPhase < 2)))
24738     {
24739       jam();
24740       return ;
24741     }
24742 
24743     Uint32 i;
24744     void * logPartPtr = 0;
24745     (void)logPartPtr;
24746     GcpRecordPtr gcp; gcp.i = RNIL;
24747     for(i = 0; i < clogPartFileSize; i++)
24748     {
24749       Ptr<LogPartRecord> lp;
24750       lp.i = i;
24751       ptrCheckGuard(lp, clogPartFileSize, logPartRecord);
24752       ndbout_c("LP %d blockInstance: %d partNo: %d state: %d WW_Gci: %d gcprec: %d flq: %u %u currfile: %d tailFileNo: %d logTailMbyte: %d cnoOfLogPages: %u problems: 0x%x",
24753                i,
24754                instance(),
24755                lp.p->logPartNo,
24756 	       lp.p->logPartState,
24757 	       lp.p->waitWriteGciLog,
24758 	       lp.p->gcprec,
24759 	       lp.p->m_log_prepare_queue.firstElement,
24760 	       lp.p->m_log_complete_queue.firstElement,
24761 	       lp.p->currentLogfile,
24762 	       lp.p->logTailFileNo,
24763 	       lp.p->logTailMbyte,
24764                cnoOfLogPages,
24765                lp.p->m_log_problems);
24766 
24767       if(gcp.i == RNIL && lp.p->gcprec != RNIL)
24768 	gcp.i = lp.p->gcprec;
24769 
24770       LogFileRecordPtr logFilePtr;
24771       Uint32 first= logFilePtr.i= lp.p->firstLogfile;
24772       do
24773       {
24774 	ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord);
24775 	ndbout_c("  file %d(%d)  FileChangeState: %d  logFileStatus: %d  currentMbyte: %d  currentFilepage %d",
24776 		 logFilePtr.p->fileNo,
24777 		 logFilePtr.i,
24778 		 logFilePtr.p->fileChangeState,
24779 		 logFilePtr.p->logFileStatus,
24780 		 logFilePtr.p->currentMbyte,
24781 		 logFilePtr.p->currentFilepage);
24782 	logFilePtr.i = logFilePtr.p->nextLogFile;
24783       } while(logFilePtr.i != first);
24784     }
24785 
24786     if(gcp.i != RNIL)
24787     {
24788       ptrCheckGuard(gcp, cgcprecFileSize, gcpRecord);
24789       for(i = 0; i<4; i++)
24790       {
24791 	ndbout_c("  GCP %d file: %d state: %d sync: %d page: %d word: %d",
24792 		 i, gcp.p->gcpFilePtr[i], gcp.p->gcpLogPartState[i],
24793 		 gcp.p->gcpSyncReady[i],
24794 		 gcp.p->gcpPageNo[i],
24795 		 gcp.p->gcpWordNo[i]);
24796       }
24797     }
24798 
24799     if(arg== 2305)
24800     {
24801       if (ERROR_INSERTED(5085))
24802       {
24803         g_eventLogger->info("LQH instance %u ignoring DUMP 2305 (GCP_STOP kill)",
24804                             instance());
24805         return;
24806       }
24807       CRASH_INSERTION(5087);
24808       progError(__LINE__, NDBD_EXIT_SYSTEM_ERROR,
24809 		"Please report this as a bug. "
24810 		"Provide as much info as possible, expecially all the "
24811 		"ndb_*_out.log files, Thanks. "
24812 		"Shutting down node due to failed handling of GCP_SAVEREQ");
24813 
24814     }
24815   }
24816 
24817   if (dumpState->args[0] == DumpStateOrd::LqhErrorInsert5042 && (signal->getLength() >= 2))
24818   {
24819     c_error_insert_table_id = dumpState->args[1];
24820     if (signal->getLength() == 2)
24821     {
24822       SET_ERROR_INSERT_VALUE(5042);
24823     }
24824     else
24825     {
24826       SET_ERROR_INSERT_VALUE(dumpState->args[2]);
24827     }
24828   }
24829 
24830   TcConnectionrec *regTcConnectionrec = tcConnectionrec;
24831   Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize;
24832   if(arg == 2306)
24833   {
24834     Uint32 bucketLen[1024];
24835     for(Uint32 i = 0; i<1024; i++)
24836     {
24837       TcConnectionrecPtr tcRec;
24838       tcRec.i = ctransidHash[i];
24839       bucketLen[i] = 0;
24840       while(tcRec.i != RNIL)
24841       {
24842 	ptrCheckGuard(tcRec, ttcConnectrecFileSize, regTcConnectionrec);
24843 	ndbout << "TcConnectionrec " << tcRec.i;
24844 	signal->theData[0] = 2307;
24845 	signal->theData[1] = tcRec.i;
24846 	execDUMP_STATE_ORD(signal);
24847 	tcRec.i = tcRec.p->nextHashRec;
24848         bucketLen[i]++;
24849       }
24850     }
24851     ndbout << "LQH transid hash bucket lengths : " << endl;
24852     for (Uint32 i = 0; i < 1024; i++)
24853     {
24854       if (bucketLen[i] > 0)
24855       {
24856         ndbout << " bucket " << i << " len " << bucketLen[i] << endl;
24857       }
24858     }
24859     ndbout << "Done." << endl;
24860   }
24861 
24862   if(arg == 2307 || arg == 2308)
24863   {
24864     TcConnectionrecPtr tcRec;
24865     tcRec.i = signal->theData[1];
24866     ptrCheckGuard(tcRec, ttcConnectrecFileSize, regTcConnectionrec);
24867 
24868     ndbout << " transactionState = " << tcRec.p->transactionState<<endl;
24869     ndbout << " operation = " << tcRec.p->operation<<endl;
24870     ndbout << " tcNodeFailrec = " << tcRec.p->tcNodeFailrec
24871 	   << " seqNoReplica = " << tcRec.p->seqNoReplica
24872 	   << endl;
24873     ndbout << " replicaType = " << tcRec.p->replicaType
24874 	   << " reclenAiLqhkey = " << tcRec.p->reclenAiLqhkey
24875 	   << " opExec = " << tcRec.p->opExec
24876 	   << endl;
24877     ndbout << " opSimple = " << tcRec.p->opSimple
24878 	   << " nextSeqNoReplica = " << tcRec.p->nextSeqNoReplica
24879 	   << " lockType = " << tcRec.p->lockType
24880 	   << endl;
24881     ndbout << " lastReplicaNo = " << tcRec.p->lastReplicaNo
24882 	   << " indTakeOver = " << tcRec.p->indTakeOver
24883 	   << " dirtyOp = " << tcRec.p->dirtyOp
24884 	   << endl;
24885     ndbout << " activeCreat = " << tcRec.p->activeCreat
24886 	   << " tcBlockref = " << hex << tcRec.p->tcBlockref
24887 	   << " reqBlockref = " << hex << tcRec.p->reqBlockref
24888 	   << " primKeyLen = " << tcRec.p->primKeyLen
24889 	   << " nrcopyflag = " << LqhKeyReq::getNrCopyFlag(tcRec.p->reqinfo)
24890 	   << endl;
24891     ndbout << " nextReplica = " << tcRec.p->nextReplica
24892 	   << " tcBlockref = " << hex << tcRec.p->tcBlockref
24893 	   << " reqBlockref = " << hex << tcRec.p->reqBlockref
24894 	   << " primKeyLen = " << tcRec.p->primKeyLen
24895 	   << endl;
24896     ndbout << " logStopPageNo = " << tcRec.p->logStopPageNo
24897 	   << " logStartPageNo = " << tcRec.p->logStartPageNo
24898 	   << " logStartPageIndex = " << tcRec.p->logStartPageIndex
24899 	   << endl;
24900     ndbout << " errorCode = " << tcRec.p->errorCode
24901 	   << " clientBlockref = " << hex << tcRec.p->clientBlockref
24902 	   << " applRef = " << hex << tcRec.p->applRef
24903 	   << " totSendlenAi = " << tcRec.p->totSendlenAi
24904 	   << endl;
24905     ndbout << " totReclenAi = " << tcRec.p->totReclenAi
24906 	   << " tcScanRec = " << tcRec.p->tcScanRec
24907 	   << " tcScanInfo = " << tcRec.p->tcScanInfo
24908 	   << " tcOprec = " << hex << tcRec.p->tcOprec
24909 	   << endl;
24910     ndbout << " tableref = " << tcRec.p->tableref
24911 	   << " simpleTcConnect = " << tcRec.p->simpleTcConnect
24912 	   << " storedProcId = " << tcRec.p->storedProcId
24913 	   << " schemaVersion = " << tcRec.p->schemaVersion
24914 	   << endl;
24915     ndbout << " reqinfo = " << tcRec.p->reqinfo
24916 	   << " reqRef = " << tcRec.p->reqRef
24917 	   << " readlenAi = " << tcRec.p->readlenAi
24918 	   << endl;
24919     ndbout << " prevLogTcrec = " << tcRec.p->prevLogTcrec
24920 	   << " prevHashRec = " << tcRec.p->prevHashRec
24921 	   << " nodeAfterNext0 = " << tcRec.p->nodeAfterNext[0]
24922 	   << " nodeAfterNext1 = " << tcRec.p->nodeAfterNext[1]
24923 	   << endl;
24924     ndbout << " nextTcConnectrec = " << tcRec.p->nextTcConnectrec
24925 	   << " nextTcLogQueue = " << tcRec.p->nextTcLogQueue
24926 	   << " prevTcLogQueue = " << tcRec.p->prevTcLogQueue
24927 	   << " nextLogTcrec = " << tcRec.p->nextLogTcrec
24928 	   << endl;
24929     ndbout << " nextHashRec = " << tcRec.p->nextHashRec
24930 	   << " logWriteState = " << tcRec.p->logWriteState
24931 	   << " logStartFileNo = " << tcRec.p->logStartFileNo
24932 	   << endl;
24933     ndbout << " gci_hi = " << tcRec.p->gci_hi
24934            << " gci_lo = " << tcRec.p->gci_lo
24935 	   << " fragmentptr = " << tcRec.p->fragmentptr
24936 	   << " fragmentid = " << tcRec.p->fragmentid
24937 	   << endl;
24938     ndbout << " hashValue = " << tcRec.p->hashValue
24939            << " currTupAiLen = " << tcRec.p->currTupAiLen
24940 	   << " currReclenAi = " << tcRec.p->currReclenAi
24941 	   << endl;
24942     ndbout << " tcTimer = " << tcRec.p->tcTimer
24943 	   << " clientConnectrec = " << tcRec.p->clientConnectrec
24944 	   << " applOprec = " << hex << tcRec.p->applOprec
24945 	   << " abortState = " << tcRec.p->abortState
24946 	   << endl;
24947     ndbout << " transid0 = " << hex << tcRec.p->transid[0]
24948 	   << " transid1 = " << hex << tcRec.p->transid[1]
24949 	   << " key[0] = " << getKeyInfoWordOrZero(tcRec.p, 0)
24950 	   << " key[1] = " << getKeyInfoWordOrZero(tcRec.p, 1)
24951 	   << endl;
24952     ndbout << " key[2] = " << getKeyInfoWordOrZero(tcRec.p, 2)
24953 	   << " key[3] = " << getKeyInfoWordOrZero(tcRec.p, 3)
24954 	   << " m_nr_delete.m_cnt = " << tcRec.p->m_nr_delete.m_cnt
24955 	   << endl;
24956     switch (tcRec.p->transactionState) {
24957 
24958     case TcConnectionrec::SCAN_STATE_USED:
24959       if (tcRec.p->tcScanRec < cscanrecFileSize){
24960 	ScanRecordPtr TscanPtr;
24961 	c_scanRecordPool.getPtr(TscanPtr, tcRec.p->tcScanRec);
24962 	ndbout << " scanState = " << TscanPtr.p->scanState << endl;
24963 	//TscanPtr.p->scanLocalref[2];
24964 	ndbout << " copyPtr="<<TscanPtr.p->copyPtr
24965 	       << " scanAccPtr="<<TscanPtr.p->scanAccPtr
24966 	       << " scanAiLength="<<TscanPtr.p->scanAiLength
24967 	       << endl;
24968 	ndbout << " m_curr_batch_size_rows="<<
24969 	  TscanPtr.p->m_curr_batch_size_rows
24970 	       << " m_max_batch_size_rows="<<
24971 	  TscanPtr.p->m_max_batch_size_rows
24972 	       << " scanErrorCounter="<<TscanPtr.p->scanErrorCounter
24973 	       << endl;
24974 	ndbout << " scanSchemaVersion="<<TscanPtr.p->scanSchemaVersion
24975 	       << "  scanStoredProcId="<<TscanPtr.p->scanStoredProcId
24976 	       << "  scanTcrec="<<TscanPtr.p->scanTcrec
24977 	       << endl;
24978 	ndbout << "  scanType="<<TscanPtr.p->scanType
24979 	       << "  scanApiBlockref="<<TscanPtr.p->scanApiBlockref
24980 	       << "  scanNodeId="<<TscanPtr.p->scanNodeId
24981 	       << "  scanCompletedStatus="<<TscanPtr.p->scanCompletedStatus
24982 	       << endl;
24983 	ndbout << "  scanFlag="<<TscanPtr.p->scanFlag
24984 	       << "  scanLockHold="<<TscanPtr.p->scanLockHold
24985 	       << "  scanLockMode="<<TscanPtr.p->scanLockMode
24986 	       << "  scanNumber="<<TscanPtr.p->scanNumber
24987 	       << endl;
24988 	ndbout << "  scanReleaseCounter="<<TscanPtr.p->scanReleaseCounter
24989 	       << "  scanTcWaiting="<<TscanPtr.p->scanTcWaiting
24990 	       << "  scanKeyinfoFlag="<<TscanPtr.p->scanKeyinfoFlag
24991 	       << endl;
24992       } else{
24993 	ndbout << "No connected scan record found" << endl;
24994       }
24995       break;
24996     default:
24997       break;
24998     }
24999     ndbrequire(arg != 2308);
25000   }
25001 
25002 #ifdef NDBD_TRACENR
25003   if (arg == 5712 || arg == 5713)
25004   {
25005     if (arg == 5712)
25006     {
25007       traceopout = &ndbout;
25008     }
25009     else if (arg == 5713)
25010     {
25011       traceopout = tracenrout;
25012     }
25013     SET_ERROR_INSERT_VALUE(arg);
25014   }
25015 #endif
25016 
25017   if (arg == 2350)
25018   {
25019     jam();
25020     Uint32 len = signal->getLength() - 1;
25021     if (len + 3 > 25)
25022     {
25023       jam();
25024       infoEvent("Too long filter");
25025       return;
25026     }
25027     if (validate_filter(signal))
25028     {
25029       jam();
25030       memmove(signal->theData + 3, signal->theData + 1, 4 * len);
25031       signal->theData[0] = 2351;
25032       signal->theData[1] = 0;    // Bucket
25033       signal->theData[2] = RNIL; // Record
25034       sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, len + 3, JBB);
25035 
25036       infoEvent("Starting dump of operations");
25037     }
25038     return;
25039   }
25040 
25041   if (arg == 2351)
25042   {
25043     jam();
25044     Uint32 bucket = signal->theData[1];
25045     Uint32 record = signal->theData[2];
25046     Uint32 len = signal->getLength();
25047     TcConnectionrecPtr tcRec;
25048     if (record != RNIL)
25049     {
25050       jam();
25051       /**
25052        * Check that record is still in use...
25053        */
25054       tcRec.i = record;
25055       ptrCheckGuard(tcRec, ttcConnectrecFileSize, regTcConnectionrec);
25056 
25057       Uint32 hashIndex = (tcRec.p->transid[0] ^ tcRec.p->tcOprec) & 1023;
25058       if (hashIndex != bucket)
25059       {
25060 	jam();
25061 	record = RNIL;
25062       }
25063       else
25064       {
25065 	jam();
25066 	if (tcRec.p->nextHashRec == RNIL &&
25067 	    tcRec.p->prevHashRec == RNIL &&
25068 	    ctransidHash[hashIndex] != record)
25069 	{
25070 	  jam();
25071 	  record = RNIL;
25072 	}
25073       }
25074 
25075       if (record == RNIL)
25076       {
25077 	jam();
25078 	signal->theData[2] = RNIL;
25079 	sendSignal(reference(), GSN_DUMP_STATE_ORD, signal,
25080 		   signal->getLength(), JBB);
25081 	return;
25082       }
25083     }
25084     else if ((record = ctransidHash[bucket]) == RNIL)
25085     {
25086       jam();
25087       bucket++;
25088       if (bucket < 1024)
25089       {
25090 	jam();
25091 	signal->theData[1] = bucket;
25092 	signal->theData[2] = RNIL;
25093 	sendSignal(reference(), GSN_DUMP_STATE_ORD, signal,
25094 		   signal->getLength(), JBB);
25095       }
25096       else
25097       {
25098 	jam();
25099         infoEvent("End of operation dump");
25100         if (ERROR_INSERTED(4002))
25101         {
25102           ndbrequire(false);
25103         }
25104       }
25105 
25106       return;
25107     }
25108     else
25109     {
25110       jam();
25111       tcRec.i = record;
25112       ptrCheckGuard(tcRec, ttcConnectrecFileSize, regTcConnectionrec);
25113     }
25114 
25115     for (Uint32 i = 0; i<32; i++)
25116     {
25117       jam();
25118       bool print = match_and_print(signal, tcRec);
25119 
25120       tcRec.i = tcRec.p->nextHashRec;
25121       if (tcRec.i == RNIL || print)
25122       {
25123 	jam();
25124 	break;
25125       }
25126 
25127       ptrCheckGuard(tcRec, ttcConnectrecFileSize, regTcConnectionrec);
25128     }
25129 
25130     if (tcRec.i == RNIL)
25131     {
25132       jam();
25133       bucket++;
25134       if (bucket < 1024)
25135       {
25136 	jam();
25137 	signal->theData[1] = bucket;
25138 	signal->theData[2] = RNIL;
25139 	sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, len, JBB);
25140       }
25141       else
25142       {
25143 	jam();
25144         infoEvent("End of operation dump");
25145         if (ERROR_INSERTED(4002))
25146         {
25147           ndbrequire(false);
25148         }
25149       }
25150 
25151       return;
25152     }
25153     else
25154     {
25155       jam();
25156       signal->theData[2] = tcRec.i;
25157       sendSignalWithDelay(reference(), GSN_DUMP_STATE_ORD, signal, 200, len);
25158       return;
25159     }
25160   }
25161 
25162   if (arg == 2352 && signal->getLength() == 2)
25163   {
25164     jam();
25165     Uint32 opNo = signal->theData[1];
25166     TcConnectionrecPtr tcRec;
25167     if (opNo < ttcConnectrecFileSize)
25168     {
25169       jam();
25170       tcRec.i = opNo;
25171       ptrCheckGuard(tcRec, ttcConnectrecFileSize, regTcConnectionrec);
25172 
25173       BaseString key;
25174       if (tcRec.p->keyInfoIVal != RNIL)
25175       {
25176         jam();
25177         SectionReader keyInfoReader(tcRec.p->keyInfoIVal,
25178                                     g_sectionSegmentPool);
25179 
25180         Uint32 keyWord;
25181         while (keyInfoReader.getWord(&keyWord))
25182           key.appfmt("0x%x ", keyWord);
25183       }
25184 
25185       char buf[100];
25186       BaseString::snprintf(buf, sizeof(buf),
25187 			   "OP[%u]: transid: 0x%x 0x%x key: %s",
25188 			   tcRec.i,
25189 			   tcRec.p->transid[0], tcRec.p->transid[1], key.c_str());
25190       infoEvent("%s", buf);
25191     }
25192   }
25193 
25194   if (arg == DumpStateOrd::SchemaResourceSnapshot)
25195   {
25196     RSS_AP_SNAPSHOT_SAVE(c_fragment_pool);
25197     return;
25198   }
25199 
25200   if (arg == DumpStateOrd::SchemaResourceCheckLeak)
25201   {
25202     RSS_AP_SNAPSHOT_CHECK(c_fragment_pool);
25203     return;
25204   }
25205 
25206   if (arg == 4002)
25207   {
25208     bool ops = false;
25209     for (Uint32 i = 0; i<1024; i++)
25210     {
25211       if (ctransidHash[i] != RNIL)
25212       {
25213         jam();
25214         ops = true;
25215         break;
25216       }
25217     }
25218 
25219     bool markers = m_commitAckMarkerPool.getNoOfFree() !=
25220       m_commitAckMarkerPool.getSize();
25221     if (unlikely(ops || markers))
25222     {
25223 
25224       if (markers)
25225       {
25226         ndbout_c("LQH: m_commitAckMarkerPool: %d free size: %d",
25227                  m_commitAckMarkerPool.getNoOfFree(),
25228                  m_commitAckMarkerPool.getSize());
25229 
25230         CommitAckMarkerIterator iter;
25231         for(m_commitAckMarkerHash.first(iter); iter.curr.i != RNIL;
25232             m_commitAckMarkerHash.next(iter))
25233         {
25234           ndbout_c("CommitAckMarker: i = %d (H'%.8x, H'%.8x)"
25235                    " ApiRef: 0x%x apiOprec: 0x%x TcRef: %x ref_count: %u",
25236                    iter.curr.i,
25237                    iter.curr.p->transid1,
25238                    iter.curr.p->transid2,
25239                    iter.curr.p->apiRef,
25240                    iter.curr.p->apiOprec,
25241                    iter.curr.p->tcRef,
25242                    iter.curr.p->reference_count);
25243         }
25244       }
25245       SET_ERROR_INSERT_VALUE(4002);
25246       signal->theData[0] = 2350;
25247       EXECUTE_DIRECT(DBLQH, GSN_DUMP_STATE_ORD, signal, 1);
25248     }
25249   }
25250 
25251   if(arg == 2399)
25252   {
25253     jam();
25254 
25255     if (cstartRecReq < SRR_REDO_COMPLETE)
25256     {
25257       jam();
25258       return;
25259     }
25260 
25261     for(Uint32 i = 0; i < clogPartFileSize; i++)
25262     {
25263       logPartPtr.i = i;
25264       ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
25265       LogFileRecordPtr logFile;
25266       logFile.i = logPartPtr.p->currentLogfile;
25267       ptrCheckGuard(logFile, clogFileFileSize, logFileRecord);
25268 
25269       LogPosition head = { logFile.p->fileNo, logFile.p->currentMbyte };
25270       LogPosition tail = { logPartPtr.p->logTailFileNo,
25271                            logPartPtr.p->logTailMbyte};
25272       Uint64 mb = free_log(head, tail, logPartPtr.p->noLogFiles, clogFileSize);
25273       Uint64 total = logPartPtr.p->noLogFiles * Uint64(clogFileSize);
25274       signal->theData[0] = NDB_LE_RedoStatus;
25275       signal->theData[1] = logPartPtr.p->logPartNo;
25276       signal->theData[2] = head.m_file_no;
25277       signal->theData[3] = head.m_mbyte;
25278       signal->theData[4] = tail.m_file_no;
25279       signal->theData[5] = tail.m_mbyte;
25280       signal->theData[6] = Uint32(total >> 32);
25281       signal->theData[7] = Uint32(total);
25282       signal->theData[8] = Uint32(mb >> 32);
25283       signal->theData[9] = Uint32(mb);
25284       signal->theData[10] = logPartPtr.p->noLogFiles;
25285       signal->theData[11] = clogFileSize;
25286       sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 12, JBB);
25287     }
25288   }
25289 
25290   if(arg == 2398)
25291   {
25292     jam();
25293 
25294     if (cstartRecReq < SRR_REDO_COMPLETE)
25295     {
25296       jam();
25297       return;
25298     }
25299 
25300     for(Uint32 i = 0; i<clogPartFileSize; i++)
25301     {
25302       logPartPtr.i = i;
25303       ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
25304       LogFileRecordPtr logFile;
25305       logFile.i = logPartPtr.p->currentLogfile;
25306       ptrCheckGuard(logFile, clogFileFileSize, logFileRecord);
25307 
25308       LogPosition head = { logFile.p->fileNo, logFile.p->currentMbyte };
25309       LogPosition tail = { logPartPtr.p->logTailFileNo,
25310                            logPartPtr.p->logTailMbyte};
25311       Uint64 mb = free_log(head, tail, logPartPtr.p->noLogFiles, clogFileSize);
25312       Uint64 total = logPartPtr.p->noLogFiles * Uint64(clogFileSize);
25313       ndbout_c("REDO part: %u HEAD: file: %u mbyte: %u TAIL: file: %u mbyte: %u total: %llu free: %llu (mb)",
25314                logPartPtr.p->logPartNo,
25315                head.m_file_no, head.m_mbyte,
25316                tail.m_file_no, tail.m_mbyte,
25317                total, mb);
25318     }
25319   }
25320 
25321 #if defined VM_TRACE || defined ERROR_INSERT
25322   if (arg == 2396 && signal->length() == 2)
25323       cmaxLogFilesInPageZero_DUMP = dumpState->args[1];
25324 #endif
25325 
25326   if (arg == 2397)
25327   {
25328     /* Send LCP_STATUS_REQ to BACKUP */
25329     LcpStatusReq* req = (LcpStatusReq*) signal->getDataPtr();
25330     req->senderRef = reference();
25331     req->senderData = 0;
25332 
25333     BlockReference backupRef = calcInstanceBlockRef(BACKUP);
25334     sendSignal(backupRef, GSN_LCP_STATUS_REQ, signal,
25335                LcpStatusReq::SignalLength, JBB);
25336   }
25337 
25338   if (arg == 2395)
25339   {
25340     ndbout_c("LCPFragWatchdog : WarnElapsed : %u(ms) MaxElapsed %u(ms) "
25341              ": period millis : %u",
25342              c_lcpFragWatchdog.WarnElapsedWithNoProgressMillis,
25343              c_lcpFragWatchdog.MaxElapsedWithNoProgressMillis,
25344              LCPFragWatchdog::PollingPeriodMillis);
25345     return;
25346   }
25347 
25348   if(arg == 2309)
25349   {
25350     if (ERROR_INSERTED(5086))
25351     {
25352       g_eventLogger->info("LQH instance %u discards DUMP 2309",
25353                           instance());
25354       return;
25355     }
25356 
25357     CRASH_INSERTION(5075);
25358 
25359     progError(__LINE__, NDBD_EXIT_LCP_SCAN_WATCHDOG_FAIL,
25360               "Please report this as a bug. "
25361               "Provide as much info as possible, expecially all the "
25362               "ndb_*_out.log files, Thanks. "
25363               "Shutting down node due to lack of LCP fragment scan progress");
25364   }
25365 
25366 
25367   if (arg == 4003)
25368   {
25369     ndbrequire(m_commitAckMarkerPool.getNoOfFree() ==
25370                m_commitAckMarkerPool.getSize());
25371   }
25372   if (arg == 5050)
25373   {
25374 #ifdef ERROR_INSERT
25375     SET_ERROR_INSERT_VALUE2(5050, c_master_node_id);
25376 #endif
25377   }
25378 
25379   if (arg == DumpStateOrd::LqhDumpPoolLevels)
25380   {
25381     /* Dump some state info for internal buffers */
25382     if (signal->getLength() == 1)
25383     {
25384       signal->theData[1] = 1;
25385       signal->theData[2] = 0;
25386       signal->theData[3] = 0;
25387       sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 4, JBB);
25388       return;
25389     }
25390     if (signal->getLength() != 4)
25391     {
25392       ndbout_c("DUMP LqhDumpPoolLevels : Bad signal length : %u", signal->getLength());
25393       return;
25394     }
25395 
25396     Uint32 resource = signal->theData[1];
25397     Uint32 position = signal->theData[2];
25398     Uint32 sum = signal->theData[3];
25399     /*const Uint32 MAX_ITER = 200; */
25400 
25401     switch(resource)
25402     {
25403     case 1:
25404     {
25405       /* Must get all in one loop, as we're traversing a dynamic list */
25406       sum = ctcNumFree;
25407       infoEvent("LQH : TcConnection (operation) records in use/total %u/%u (%u bytes each)",
25408                 ctcConnectrecFileSize - sum, ctcConnectrecFileSize, (Uint32) sizeof(TcConnectionrec));
25409       resource++;
25410       position = 0;
25411       sum = 0;
25412       break;
25413     }
25414     case 2:
25415     {
25416       infoEvent("LQH : ScanRecord (Fragment) pool in use/total %u/%u (%u bytes each)",
25417                 c_scanRecordPool.getSize()-
25418                 c_scanRecordPool.getNoOfFree(),
25419                 c_scanRecordPool.getSize(),
25420                 (Uint32) sizeof(ScanRecord));
25421       resource++;
25422       position = 0;
25423       sum = 0;
25424       break;
25425     }
25426     default:
25427       return;
25428     }
25429 
25430     signal->theData[0] = DumpStateOrd::LqhDumpPoolLevels;
25431     signal->theData[1] = resource;
25432     signal->theData[2] = position;
25433     signal->theData[3] = sum;
25434     sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 4, JBB);
25435     return;
25436   }
25437 
25438   if (arg == DumpStateOrd::LqhReportCopyInfo)
25439   {
25440     jam();
25441     Uint64 duration = 0;
25442     Uint64 rate = 0;
25443 
25444     if (c_fragmentCopyStart == 0)
25445     {
25446       infoEvent("LDM(%u): CopyFrag complete no fragments copied",
25447                 instance());
25448       return;
25449     }
25450     duration = NdbTick_CurrentMillisecond() - c_fragmentCopyStart;
25451 
25452     if (duration == 0)
25453       duration = 1;
25454 
25455     rate = (c_totalBytesCopied * 1000) / duration;
25456 
25457     infoEvent("LDM(%u): CopyFrag complete. %u frags,"
25458               " +%llu/-%llu rows, "
25459               "%llu bytes/%llu ms %llu bytes/s.",
25460               instance(),
25461               c_fragmentsCopied,
25462               c_totalCopyRowsIns,
25463               c_totalCopyRowsDel,
25464               c_totalBytesCopied,
25465               duration,
25466               rate);
25467   }
25468 
25469 }//Dblqh::execDUMP_STATE_ORD()
25470 
25471 
execDBINFO_SCANREQ(Signal * signal)25472 void Dblqh::execDBINFO_SCANREQ(Signal *signal)
25473 {
25474   DbinfoScanReq req= *(DbinfoScanReq*)signal->theData;
25475   const Ndbinfo::ScanCursor* cursor =
25476     CAST_CONSTPTR(Ndbinfo::ScanCursor, DbinfoScan::getCursorPtr(&req));
25477   Ndbinfo::Ratelimit rl;
25478 
25479   jamEntry();
25480 
25481   switch(req.tableId){
25482   case Ndbinfo::LOGSPACES_TABLEID:
25483   {
25484     Uint32 logpart = cursor->data[0];
25485     while(logpart < clogPartFileSize)
25486     {
25487       jam();
25488 
25489       logPartPtr.i = logpart;
25490       ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
25491 
25492       LogFileRecordPtr logFile;
25493       logFile.i = logPartPtr.p->currentLogfile;
25494       ptrCheckGuard(logFile, clogFileFileSize, logFileRecord);
25495 
25496       LogPosition head = { logFile.p->fileNo, logFile.p->currentMbyte };
25497       LogPosition tail = { logPartPtr.p->logTailFileNo,
25498                            logPartPtr.p->logTailMbyte};
25499       Uint64 mb = free_log(head, tail, logPartPtr.p->noLogFiles, clogFileSize);
25500       Uint64 total = logPartPtr.p->noLogFiles * Uint64(clogFileSize);
25501       Uint64 high = 0; // TODO
25502 
25503       Ndbinfo::Row row(signal, req);
25504       row.write_uint32(getOwnNodeId());
25505       row.write_uint32(0);              // log type, 0 = REDO
25506       row.write_uint32(0);              // log id, always 0 in LQH
25507       row.write_uint32(logPartPtr.p->logPartNo); // log part
25508 
25509       row.write_uint64(total*1024*1024);          // total allocated
25510       row.write_uint64((total-mb)*1024*1024);     // currently in use
25511       row.write_uint64(high*1024*1024);           // in use high water mark
25512       ndbinfo_send_row(signal, req, row, rl);
25513       logpart++;
25514       if (rl.need_break(req))
25515       {
25516         jam();
25517         ndbinfo_send_scan_break(signal, req, rl, logpart);
25518         return;
25519       }
25520     }
25521     break;
25522   }
25523 
25524   case Ndbinfo::LOGBUFFERS_TABLEID:
25525   {
25526     const size_t entry_size = sizeof(LogPageRecord);
25527     const Uint64 free = cnoOfLogPages;
25528     const Uint64 total = clogPageCount;
25529     const Uint64 high = 0; // TODO
25530 
25531     Ndbinfo::Row row(signal, req);
25532     row.write_uint32(getOwnNodeId());
25533     row.write_uint32(0);              // log type, 0 = REDO
25534     row.write_uint32(0);              // log id, always 0 in LQH
25535     row.write_uint32(instance());     // log part, instance for ndbmtd
25536 
25537     row.write_uint64(total*entry_size);        // total allocated
25538     row.write_uint64((total-free)*entry_size); // currently in use
25539     row.write_uint64(high*entry_size);         // in use high water mark
25540     ndbinfo_send_row(signal, req, row, rl);
25541 
25542     break;
25543   }
25544 
25545   case Ndbinfo::COUNTERS_TABLEID:
25546   {
25547     Ndbinfo::counter_entry counters[] = {
25548       { Ndbinfo::OPERATIONS_COUNTER,              c_Counters.operations },
25549       { Ndbinfo::LQHKEY_OVERLOAD,                 c_keyOverloads },
25550       { Ndbinfo::LQHKEY_OVERLOAD_TC,              c_keyOverloadsTcNode },
25551       { Ndbinfo::LQHKEY_OVERLOAD_READER,          c_keyOverloadsReaderApi },
25552       { Ndbinfo::LQHKEY_OVERLOAD_NODE_PEER,       c_keyOverloadsPeerNode },
25553       { Ndbinfo::LQHKEY_OVERLOAD_SUBSCRIBER,      c_keyOverloadsSubscriber },
25554       { Ndbinfo::LQHSCAN_SLOWDOWN,                c_scanSlowDowns }
25555     };
25556     const size_t num_counters = sizeof(counters) / sizeof(counters[0]);
25557 
25558     Uint32 i = cursor->data[0];
25559     BlockNumber bn = blockToMain(number());
25560     while(i < num_counters)
25561     {
25562       jam();
25563       Ndbinfo::Row row(signal, req);
25564       row.write_uint32(getOwnNodeId());
25565       row.write_uint32(bn);           // block number
25566       row.write_uint32(instance());   // block instance
25567       row.write_uint32(counters[i].id);
25568 
25569       row.write_uint64(counters[i].val);
25570       ndbinfo_send_row(signal, req, row, rl);
25571       i++;
25572       if (rl.need_break(req))
25573       {
25574         jam();
25575         ndbinfo_send_scan_break(signal, req, rl, i);
25576         return;
25577       }
25578     }
25579     break;
25580   }
25581   case Ndbinfo::OPERATIONS_TABLEID:{
25582     Uint32 bucket = cursor->data[0];
25583 
25584     while (true)
25585     {
25586       if (rl.need_break(req))
25587       {
25588         jam();
25589         ndbinfo_send_scan_break(signal, req, rl, bucket);
25590         return;
25591       }
25592 
25593       for (; bucket < NDB_ARRAY_SIZE(ctransidHash); bucket++)
25594       {
25595         if (ctransidHash[bucket] != RNIL)
25596           break;
25597       }
25598 
25599       if (bucket == NDB_ARRAY_SIZE(ctransidHash))
25600       {
25601         break;
25602       }
25603 
25604       TcConnectionrecPtr tcPtr;
25605       tcPtr.i = ctransidHash[bucket];
25606       while (tcPtr.i != RNIL)
25607       {
25608         jam();
25609         ptrCheckGuard(tcPtr, ctcConnectrecFileSize, tcConnectionrec);
25610         Ndbinfo::Row row(signal, req);
25611         ndbinfo_write_op(row, tcPtr);
25612         ndbinfo_send_row(signal, req, row, rl);
25613         tcPtr.i = tcPtr.p->nextHashRec;
25614       }
25615       bucket++;
25616     }
25617     break;
25618   }
25619   case Ndbinfo::FRAG_OPERATIONS_TABLEID:
25620   {
25621     Uint32 tableid = cursor->data[0];
25622 
25623     for (;tableid < ctabrecFileSize; tableid++)
25624     {
25625       TablerecPtr tabPtr;
25626       tabPtr.i = tableid;
25627       ptrAss(tabPtr, tablerec);
25628       if (tabPtr.p->tableStatus != Tablerec::NOT_DEFINED)
25629       {
25630         jam();
25631         // Loop over all fragments for this table.
25632         for (Uint32 f = 0; f<NDB_ARRAY_SIZE(tabPtr.p->fragrec); f++)
25633         {
25634           if (tabPtr.p->fragrec[f] != RNIL)
25635           {
25636             jam();
25637             Fragrecord* const frag =
25638               c_fragment_pool.getPtr(tabPtr.p->fragrec[f]);
25639 
25640             Uint64 commitCount = 0;
25641             if (frag->accFragptr != RNIL)
25642             {
25643               // Fetch 'commit_count'.
25644               Uint32* const sigData = signal->getDataPtrSend();
25645               sigData[0] = frag->accFragptr;
25646               sigData[1] = AttributeHeader::COMMIT_COUNT;
25647               EXECUTE_DIRECT(DBACC, GSN_READ_PSEUDO_REQ, signal, 2);
25648               /*
25649                 Must use memcpy rather than assignment, since sigData may not
25650                 be suitably aligned.
25651               */
25652               memcpy(&commitCount, sigData, sizeof commitCount);
25653             }
25654 
25655             Fragrecord::UsageStat& useStat = frag->m_useStat;
25656 
25657             Ndbinfo::Row row(signal, req);
25658             row.write_uint32(getOwnNodeId());
25659             row.write_uint32(instance());
25660             row.write_uint32(tableid);
25661             row.write_uint32(frag->fragId);
25662             row.write_uint64(useStat.m_readKeyReqCount);
25663             row.write_uint64(useStat.m_insKeyReqCount);
25664             row.write_uint64(useStat.m_updKeyReqCount);
25665             row.write_uint64(useStat.m_writeKeyReqCount);
25666             row.write_uint64(useStat.m_delKeyReqCount);
25667             row.write_uint64(useStat.m_keyRefCount);
25668             row.write_uint64(useStat.m_keyReqAttrWords * sizeof(Uint32));
25669             row.write_uint64(useStat.m_keyReqKeyWords * sizeof(Uint32));
25670             row.write_uint64(useStat.m_keyProgramWords * sizeof(Uint32));
25671             row.write_uint64(useStat.m_keyInstructionCount);
25672             row.write_uint64(useStat.m_keyReqWordsReturned * sizeof(Uint32));
25673             row.write_uint64(useStat.m_scanFragReqCount);
25674             row.write_uint64(useStat.m_scanRowsExamined);
25675             row.write_uint64(useStat.m_scanRowsReturned);
25676             row.write_uint64(useStat.m_scanWordsReturned * sizeof(Uint32));
25677             row.write_uint64(useStat.m_scanProgramWords * sizeof(Uint32));
25678             row.write_uint64(useStat.m_scanBoundWords * sizeof(Uint32));
25679             row.write_uint64(useStat.m_scanInstructionCount);
25680             row.write_uint64(useStat.m_queuedScanCount);
25681 
25682             row.write_uint32(LocalDLCList<ScanRecord>
25683                              (c_scanRecordPool, frag->m_activeScans).count());
25684 
25685             row.write_uint32(LocalDLCFifoList<ScanRecord>
25686                              (c_scanRecordPool, frag->m_queuedScans).count());
25687 
25688             row.write_uint32(LocalDLCFifoList<ScanRecord>
25689                              (c_scanRecordPool, frag->m_queuedTupScans).count());
25690 
25691             row.write_uint32(LocalDLCFifoList<ScanRecord>
25692                              (c_scanRecordPool,
25693                               frag->m_queuedAccScans).count());
25694 
25695             row.write_uint64(commitCount);
25696             ndbinfo_send_row(signal, req, row, rl);
25697           }
25698         }
25699       }
25700 
25701       /*
25702         If a break is needed, break on a table bondary, as we use the table id
25703         as a cursor.
25704       */
25705       if (rl.need_break(req))
25706       {
25707         jam();
25708         ndbinfo_send_scan_break(signal, req, rl, tableid + 1);
25709         return;
25710       }
25711     }
25712 
25713     break;
25714   }
25715   case Ndbinfo::FRAG_MEM_USE_TABLEID:
25716   {
25717     /*
25718       Loop over all tables. cursor->data[0] shows where this batch should start.
25719      */
25720     for (Uint32 tableid = cursor->data[0]; tableid < ctabrecFileSize; tableid++)
25721     {
25722       TablerecPtr tabPtr;
25723       tabPtr.i = tableid;
25724       ptrAss(tabPtr, tablerec);
25725       if (tabPtr.p->tableStatus != Tablerec::NOT_DEFINED)
25726       {
25727         jam();
25728         // Loop over the fragments of this table.
25729         for (Uint32 fragNo = 0; fragNo<NDB_ARRAY_SIZE(tabPtr.p->fragrec);
25730              fragNo++)
25731         {
25732           FragrecordPtr myFragPtr;
25733           if ((myFragPtr.i = tabPtr.p->fragrec[fragNo]) != RNIL)
25734           {
25735             jam();
25736             c_fragment_pool.getPtr(myFragPtr);
25737 
25738             /* Get fragment's stats from TUP */
25739             const Dbtup::FragStats fs
25740               = c_tup->get_frag_stats(myFragPtr.p->tupFragptr);
25741 
25742             Ndbinfo::Row row(signal, req);
25743             row.write_uint32(getOwnNodeId());
25744             row.write_uint32(instance());
25745             row.write_uint32(tableid);
25746             row.write_uint32(myFragPtr.p->fragId);
25747 
25748             FragrecordPtr rowsLookupFragPtr;
25749             rowsLookupFragPtr.i = myFragPtr.i;
25750 
25751             Uint64 hashMapBytes = 0;
25752             Uint32 accL2PMapBytes = 0;
25753 
25754             if (myFragPtr.p->accFragptr == RNIL)
25755             {
25756               jam();
25757               ndbassert(DictTabInfo::isOrderedIndex(tabPtr.p->tableType));
25758               /* Lookup row count on base table fragment */
25759               rowsLookupFragPtr.i = myFragPtr.p->tableFragptr;
25760             }
25761             else
25762             {
25763               jam();
25764               accL2PMapBytes =
25765                 c_acc->getL2PMapAllocBytes(myFragPtr.p->accFragptr);
25766               hashMapBytes = c_acc->getLinHashByteSize(myFragPtr.p->accFragptr);
25767             }
25768             c_fragment_pool.getPtr(rowsLookupFragPtr);
25769 
25770             ndbrequire(rowsLookupFragPtr.p->accFragptr != RNIL);
25771 
25772             signal->theData[0] = rowsLookupFragPtr.p->accFragptr;
25773             signal->theData[1] = AttributeHeader::ROW_COUNT;
25774 
25775             EXECUTE_DIRECT(DBACC, GSN_READ_PSEUDO_REQ, signal, 2);
25776             Uint64 rows = 0;
25777             /*
25778               signal->theData may not be 64-bit aligned. Therefore, we use
25779               memcpy rather than assignment.
25780             */
25781             memcpy(&rows, signal->theData, sizeof rows);
25782 
25783             const Uint64 fixedSlotsAvailable =
25784               fs.fixedMemoryAllocPages * fs.fixedSlotsPerPage;
25785             ndbassert(fs.fixedElemCount <= fixedSlotsAvailable);
25786 
25787             const Uint64 fixedFreeSlots
25788               = fixedSlotsAvailable - fs.fixedElemCount;
25789 
25790             const Uint64 fixedFreeBytes
25791               = fixedFreeSlots * fs.fixedRecordBytes;
25792 
25793             row.write_uint64(rows);
25794             row.write_uint64(fs.fixedMemoryAllocPages * fs.pageSizeBytes);
25795             row.write_uint64(fixedFreeBytes);
25796             row.write_uint64(fs.fixedElemCount);
25797             row.write_uint32(fs.fixedRecordBytes);
25798             row.write_uint64(fs.varMemoryAllocPages * fs.pageSizeBytes);
25799             row.write_uint64(fs.varMemoryFreeBytes);
25800             row.write_uint64(fs.varElemCount);
25801             row.write_uint64(fs.logToPhysMapAllocBytes);
25802             row.write_uint64(accL2PMapBytes);
25803             row.write_uint64(hashMapBytes);
25804 
25805             ndbinfo_send_row(signal, req, row, rl);
25806           }
25807         }
25808       }
25809 
25810       /*
25811         If necessary, make a break before starting on the next table. Since
25812         we use table ids to tell where to start the next batch, we cannot
25813         make a break before all fragments of the current table have been sent.
25814        */
25815       if (rl.need_break(req))
25816       {
25817         jam();
25818         ndbinfo_send_scan_break(signal, req, rl, tableid + 1);
25819         return;
25820       }
25821     }
25822 
25823     break;
25824   }
25825   case Ndbinfo::POOLS_TABLEID:
25826   {
25827     Ndbinfo::pool_entry pools[] =
25828     {
25829       { "Commit ACK Marker",
25830         m_commitAckMarkerPool.getUsed(),
25831         m_commitAckMarkerPool.getSize(),
25832         m_commitAckMarkerPool.getEntrySize(),
25833         m_commitAckMarkerPool.getUsedHi(),
25834         { CFG_DB_NO_LOCAL_OPS, CFG_DB_NO_OPS,0,0 }},
25835       { NULL, 0,0,0,0,{0,0,0,0} }
25836     };
25837 
25838     const size_t num_config_params =
25839       sizeof(pools[0].config_params) / sizeof(pools[0].config_params[0]);
25840     Uint32 pool = cursor->data[0];
25841     BlockNumber bn = blockToMain(number());
25842     while(pools[pool].poolname)
25843     {
25844       jam();
25845       Ndbinfo::Row row(signal, req);
25846       row.write_uint32(getOwnNodeId());
25847       row.write_uint32(bn);           // block number
25848       row.write_uint32(instance());   // block instance
25849       row.write_string(pools[pool].poolname);
25850 
25851       row.write_uint64(pools[pool].used);
25852       row.write_uint64(pools[pool].total);
25853       row.write_uint64(pools[pool].used_hi);
25854       row.write_uint64(pools[pool].entry_size);
25855       for (size_t i = 0; i < num_config_params; i++)
25856         row.write_uint32(pools[pool].config_params[i]);
25857       ndbinfo_send_row(signal, req, row, rl);
25858       pool++;
25859       if (rl.need_break(req))
25860       {
25861         jam();
25862         ndbinfo_send_scan_break(signal, req, rl, pool);
25863         return;
25864       }
25865     }
25866     break;
25867   }
25868 
25869   default:
25870     break;
25871   }
25872 
25873   ndbinfo_send_scan_conf(signal, req, rl);
25874 }
25875 
25876 void
ndbinfo_write_op(Ndbinfo::Row & row,TcConnectionrecPtr tcPtr)25877 Dblqh::ndbinfo_write_op(Ndbinfo::Row & row, TcConnectionrecPtr tcPtr)
25878 {
25879   row.write_uint32(getOwnNodeId());
25880   row.write_uint32(instance());          // block instance
25881   row.write_uint32(tcPtr.i);             // objid
25882   row.write_uint32(tcPtr.p->tcBlockref); // tcref
25883   row.write_uint32(tcPtr.p->applRef);    // apiref
25884 
25885   row.write_uint32(tcPtr.p->transid[0]);
25886   row.write_uint32(tcPtr.p->transid[1]);
25887   row.write_uint32(tcPtr.p->tableref);
25888   row.write_uint32(tcPtr.p->fragmentid);
25889 
25890   if (tcPtr.p->tcScanRec != RNIL)
25891   {
25892     ScanRecordPtr sp;
25893     sp.i = tcPtr.p->tcScanRec;
25894     c_scanRecordPool.getPtr(sp);
25895 
25896     Uint32 op = NDB_INFO_OP_SCAN_UNKNOWN;
25897     if (sp.p->scanLockMode)
25898       op = NDB_INFO_OP_SCAN_EX;
25899     else if (sp.p->scanLockHold)
25900       op = NDB_INFO_OP_SCAN_SH;
25901     else
25902       op = NDB_INFO_OP_SCAN;
25903 
25904     row.write_uint32(op);
25905     row.write_uint32(sp.p->scanState);
25906     row.write_uint32(0);
25907   }
25908   else
25909   {
25910     Uint32 op = NDB_INFO_OP_UNKNOWN;
25911     switch(tcPtr.p->operation){
25912     case ZREAD:
25913       if (tcPtr.p->lockType)
25914 	op = NDB_INFO_OP_READ_EX;
25915       else if (!tcPtr.p->dirtyOp)
25916 	op = NDB_INFO_OP_READ_SH;
25917       else
25918         op = NDB_INFO_OP_READ;
25919       break;
25920     case ZINSERT:
25921       op = NDB_INFO_OP_INSERT;
25922       break;
25923     case ZUPDATE:
25924       op = NDB_INFO_OP_UPDATE;
25925       break;
25926     case ZDELETE:
25927       op = NDB_INFO_OP_DELETE;
25928       break;
25929     case ZWRITE:
25930       op = NDB_INFO_OP_WRITE;
25931       break;
25932     case ZUNLOCK:
25933       op = NDB_INFO_OP_UNLOCK;
25934       break;
25935     case ZREFRESH:
25936       op = NDB_INFO_OP_REFRESH;
25937       break;
25938     }
25939     row.write_uint32(op);
25940     row.write_uint32(tcPtr.p->transactionState);
25941     row.write_uint32(0);
25942   }
25943 }
25944 
25945 
25946 void
startLcpFragWatchdog(Signal * signal)25947 Dblqh::startLcpFragWatchdog(Signal* signal)
25948 {
25949   jam();
25950   /* Must not already be running */
25951   /* Thread could still be active from a previous run */
25952   ndbrequire(c_lcpFragWatchdog.scan_running == false);
25953   c_lcpFragWatchdog.scan_running = true;
25954   c_lcpFragWatchdog.elapsedNoProgressMillis = 0;
25955   c_lcpFragWatchdog.lastChecked = NdbTick_getCurrentTicks();
25956 
25957   /* If thread is not already active, start it */
25958   if (! c_lcpFragWatchdog.thread_active)
25959   {
25960     jam();
25961     invokeLcpFragWatchdogThread(signal);
25962   }
25963 
25964   ndbrequire(c_lcpFragWatchdog.thread_active == true);
25965 }
25966 
25967 void
invokeLcpFragWatchdogThread(Signal * signal)25968 Dblqh::invokeLcpFragWatchdogThread(Signal* signal)
25969 {
25970   jam();
25971   ndbrequire(c_lcpFragWatchdog.scan_running);
25972 
25973   c_lcpFragWatchdog.thread_active = true;
25974 
25975   signal->getDataPtrSend()[0] = ZLCP_FRAG_WATCHDOG;
25976   sendSignalWithDelay(cownref, GSN_CONTINUEB, signal,
25977                       LCPFragWatchdog::PollingPeriodMillis, 1);
25978 
25979   LcpStatusReq* req = (LcpStatusReq*)signal->getDataPtr();
25980   req->senderRef = cownref;
25981   req->senderData = 1;
25982   BlockReference backupRef = calcInstanceBlockRef(BACKUP);
25983   sendSignal(backupRef, GSN_LCP_STATUS_REQ, signal,
25984              LcpStatusReq::SignalLength, JBB);
25985 }
25986 
25987 void
execLCP_STATUS_CONF(Signal * signal)25988 Dblqh::execLCP_STATUS_CONF(Signal* signal)
25989 {
25990   jamEntry();
25991   LcpStatusConf* conf = (LcpStatusConf*) signal->getDataPtr();
25992 
25993   if (conf->senderData == 0)
25994   {
25995     /* DUMP STATE variant */
25996     ndbout_c("Received LCP_STATUS_CONF from %x", conf->senderRef);
25997     ndbout_c("  Status = %u, Table = %u, Frag = %u",
25998              conf->lcpState,
25999              conf->tableId,
26000              conf->fragId);
26001     ndbout_c("  Completion State %llu",
26002              (((Uint64)conf->completionStateHi) << 32) + conf->completionStateLo);
26003     ndbout_c("  Lcp done rows %llu, done bytes %llu",
26004              (((Uint64)conf->lcpDoneRowsHi) << 32) + conf->lcpDoneRowsLo,
26005              (((Uint64)conf->lcpDoneBytesHi) << 32) + conf->lcpDoneBytesLo);
26006     ndbout_c(" Lcp scanned %u pages", conf->lcpScannedPages);
26007   }
26008 
26009   /* We can ignore the LCP status as if it's complete then we should
26010    * promptly stop watching
26011    */
26012   c_lcpFragWatchdog.handleLcpStatusRep((LcpStatusConf::LcpState)conf->lcpState,
26013                                        conf->tableId,
26014                                        conf->fragId,
26015                                        (((Uint64)conf->completionStateHi) << 32) +
26016                                        conf->completionStateLo,
26017                                        conf->lcpScannedPages);
26018 }
26019 
26020 void
execLCP_STATUS_REF(Signal * signal)26021 Dblqh::execLCP_STATUS_REF(Signal* signal)
26022 {
26023   jamEntry();
26024   LcpStatusRef* ref = (LcpStatusRef*) signal->getDataPtr();
26025 
26026   ndbout_c("Received LCP_STATUS_REF from %x, senderData = %u with error code %u",
26027            ref->senderRef, ref->senderData, ref->error);
26028 
26029   ndbrequire(false);
26030 }
26031 
26032 void
reset()26033 Dblqh::LCPFragWatchdog::reset()
26034 {
26035   jamBlock(block);
26036   scan_running = false;
26037   lcpState = LcpStatusConf::LCP_IDLE;
26038   tableId = ~Uint32(0);
26039   fragId = ~Uint32(0);
26040   completionStatus = ~Uint64(0);
26041   lcpScannedPages = 0;
26042   elapsedNoProgressMillis = 0;
26043   NdbTick_Invalidate(&lastChecked);
26044 }
26045 
26046 void
handleLcpStatusRep(LcpStatusConf::LcpState repLcpState,Uint32 repTableId,Uint32 repFragId,Uint64 repCompletionStatus,Uint32 repLcpScannedPages)26047 Dblqh::LCPFragWatchdog::handleLcpStatusRep(LcpStatusConf::LcpState repLcpState,
26048                                            Uint32 repTableId,
26049                                            Uint32 repFragId,
26050                                            Uint64 repCompletionStatus,
26051                                            Uint32 repLcpScannedPages)
26052 {
26053   jamBlock(block);
26054   if (scan_running)
26055   {
26056     jamBlock(block);
26057     if ((repCompletionStatus != completionStatus) ||
26058         (repFragId != fragId) ||
26059         (repTableId != tableId) ||
26060         (repLcpState != lcpState) ||
26061         (repLcpScannedPages != lcpScannedPages))
26062     {
26063       jamBlock(block);
26064       /* Something moved since last time, reset
26065        * progress monitor and data.
26066        */
26067       elapsedNoProgressMillis = 0;
26068       lastChecked = NdbTick_getCurrentTicks();
26069       lcpState = repLcpState;
26070       tableId = repTableId;
26071       fragId = repFragId;
26072       completionStatus = repCompletionStatus;
26073       lcpScannedPages = repLcpScannedPages;
26074     }
26075   }
26076 }
26077 
26078 
26079 /**
26080  * checkLcpFragWatchdog
26081  *
26082  * This method implements the LCP Frag watchdog 'thread', periodically
26083  * checking for progress in the current LCP fragment scan
26084  */
26085 void
checkLcpFragWatchdog(Signal * signal)26086 Dblqh::checkLcpFragWatchdog(Signal* signal)
26087 {
26088   jam();
26089   ndbrequire(c_lcpFragWatchdog.thread_active == true);
26090 
26091   if (!c_lcpFragWatchdog.scan_running)
26092   {
26093     jam();
26094     /* We've been asked to stop */
26095     c_lcpFragWatchdog.thread_active = false;
26096     return;
26097   }
26098 
26099   // Calculate real time elapsed since last check
26100   const NDB_TICKS now = NdbTick_getCurrentTicks();
26101   const NDB_TICKS last = c_lcpFragWatchdog.lastChecked;
26102   c_lcpFragWatchdog.lastChecked = now;
26103 
26104   /**
26105    * Avoid false LCP failures if timers misbehaves,
26106    * (timer is non-monotonic, or OS/VM bugs which there are some of)
26107    * or we have scheduler problems due to being CPU starved:
26108    *
26109    * - If we overslept 'PollingPeriodMillis', (CPU startved?) or
26110    *   timer leapt forward for other reasons (Adjusted, or OS-bug)
26111    *   we never calculate an elapsed periode of more than
26112    *   the requested sleep 'PollingPeriodMillis'
26113    * - Else we add the real measured elapsed time to total.
26114    *   (Timers may fire prior to requested 'PollingPeriodMillis')
26115    *
26116    * Note: If timer for some reason ticked backwards such that
26117    *       'now < last', NdbTick_Elapsed() will return '0' such
26118    *       that this is 'absorbed'
26119    */
26120   Uint32 elapsed = (Uint32)NdbTick_Elapsed(last,now).milliSec();
26121   if (elapsed > LCPFragWatchdog::PollingPeriodMillis)
26122     elapsed = LCPFragWatchdog::PollingPeriodMillis;
26123 
26124   c_lcpFragWatchdog.elapsedNoProgressMillis += elapsed;
26125 
26126   /* Check how long we've been waiting for progress on this scan */
26127   if ((c_lcpFragWatchdog.WarnElapsedWithNoProgressMillis > 0) &&
26128       ((c_lcpFragWatchdog.elapsedNoProgressMillis >=
26129         c_lcpFragWatchdog.WarnElapsedWithNoProgressMillis)))
26130   {
26131     jam();
26132     const char* completionStatusString =
26133       (c_lcpFragWatchdog.lcpState == LcpStatusConf::LCP_SCANNING?
26134        "rows completed":
26135        "bytes remaining.");
26136 
26137     warningEvent("LCP Frag watchdog : No progress on table %u, frag %u for %u s."
26138                  "  %llu %s",
26139                  c_lcpFragWatchdog.tableId,
26140                  c_lcpFragWatchdog.fragId,
26141                  c_lcpFragWatchdog.elapsedNoProgressMillis / 1000,
26142                  c_lcpFragWatchdog.completionStatus,
26143                  completionStatusString);
26144     ndbout_c("LCP Frag watchdog : No progress on table %u, frag %u for %u s."
26145              "  %llu %s",
26146              c_lcpFragWatchdog.tableId,
26147              c_lcpFragWatchdog.fragId,
26148              c_lcpFragWatchdog.elapsedNoProgressMillis / 1000,
26149              c_lcpFragWatchdog.completionStatus,
26150              completionStatusString);
26151 
26152     if (c_lcpFragWatchdog.elapsedNoProgressMillis >=
26153         c_lcpFragWatchdog.MaxElapsedWithNoProgressMillis)
26154     {
26155       jam();
26156       /* Too long with no progress... */
26157 
26158       warningEvent("LCP Frag watchdog : Checkpoint of table %u fragment %u "
26159                    "too slow (no progress for > %u s).",
26160                    c_lcpFragWatchdog.tableId,
26161                    c_lcpFragWatchdog.fragId,
26162                    c_lcpFragWatchdog.elapsedNoProgressMillis / 1000);
26163       ndbout_c("LCP Frag watchdog : Checkpoint of table %u fragment %u "
26164                "too slow (no progress for > %u s).",
26165                c_lcpFragWatchdog.tableId,
26166                c_lcpFragWatchdog.fragId,
26167                c_lcpFragWatchdog.elapsedNoProgressMillis / 1000);
26168 
26169       /* Dump some LCP state for debugging... */
26170       {
26171         DumpStateOrd* ds = (DumpStateOrd*) signal->getDataPtrSend();
26172 
26173         /* DIH : */
26174         ds->args[0] = DumpStateOrd::DihDumpLCPState;
26175         sendSignal(DBDIH_REF, GSN_DUMP_STATE_ORD, signal, 1, JBA);
26176 
26177         ds->args[0] = 7012;
26178         sendSignal(DBDIH_REF, GSN_DUMP_STATE_ORD, signal, 1, JBA);
26179 
26180         /* BACKUP : */
26181         ds->args[0] = 23;
26182         sendSignal(BACKUP_REF, GSN_DUMP_STATE_ORD, signal, 1, JBA);
26183 
26184         ds->args[0] = 24;
26185         ds->args[1] = 2424;
26186         sendSignal(BACKUP_REF, GSN_DUMP_STATE_ORD, signal, 2, JBA);
26187 
26188         /* LQH : */
26189         ds->args[0] = DumpStateOrd::LqhDumpLcpState;
26190         sendSignal(cownref, GSN_DUMP_STATE_ORD, signal, 1, JBA);
26191 
26192         const Uint32 ShutdownDelayMillis = 5 * 1000;
26193         /* Delay self-execution to give time for dump output */
26194         ds->args[0] = 2309;
26195         sendSignalWithDelay(cownref,
26196                             GSN_DUMP_STATE_ORD,
26197                             signal,
26198                             ShutdownDelayMillis,
26199                             1);
26200 
26201         /**
26202          * Ask other nodes to isolate me in delay + 500 millis if I have
26203          * not failed by then
26204          */
26205         {
26206           IsolateOrd* ord = (IsolateOrd*) signal->theData;
26207           ord->senderRef = reference();
26208           ord->isolateStep = IsolateOrd::IS_REQ;
26209           ord->delayMillis = ShutdownDelayMillis + 500;
26210 
26211           NdbNodeBitmask victims;
26212           victims.set(cownNodeid);
26213           victims.copyto(NdbNodeBitmask::Size, ord->nodesToIsolate);
26214 
26215           /* QMGR handles this */
26216           sendSignal(QMGR_REF,
26217                      GSN_ISOLATE_ORD,
26218                      signal,
26219                      IsolateOrd::SignalLength,
26220                      JBA);
26221         }
26222       }
26223 
26224       return;
26225     }
26226   }
26227 
26228   invokeLcpFragWatchdogThread(signal);
26229 }
26230 
26231 void
stopLcpFragWatchdog()26232 Dblqh::stopLcpFragWatchdog()
26233 {
26234   jam();
26235   /* Mark watchdog as no longer running,
26236    * If the 'thread' is active then it will
26237    * stop at the next wakeup
26238    */
26239   ndbrequire(c_lcpFragWatchdog.scan_running);
26240   c_lcpFragWatchdog.reset();
26241 };
26242 
26243 /* **************************************************************** */
26244 /* ---------------------------------------------------------------- */
26245 /* ---------------------- TRIGGER HANDLING ------------------------ */
26246 /* ---------------------------------------------------------------- */
26247 /*                                                                  */
26248 /*      All trigger signals from TRIX are forwarded top TUP         */
26249 /* ---------------------------------------------------------------- */
26250 /* **************************************************************** */
26251 
26252 // Trigger signals
26253 void
execCREATE_TRIG_IMPL_REQ(Signal * signal)26254 Dblqh::execCREATE_TRIG_IMPL_REQ(Signal* signal)
26255 {
26256   jamEntry();
26257 
26258   if (!assembleFragments(signal))
26259   {
26260     jam();
26261     return;
26262   }
26263 
26264   CreateTrigImplReq* req = (CreateTrigImplReq*)signal->getDataPtrSend();
26265   SectionHandle handle(this, signal);
26266   req->senderRef = reference();
26267   BlockReference tupRef = calcInstanceBlockRef(DBTUP);
26268   sendSignal(tupRef, GSN_CREATE_TRIG_IMPL_REQ, signal,
26269              signal->getLength(), JBB, &handle);
26270 }
26271 
26272 void
execCREATE_TRIG_IMPL_CONF(Signal * signal)26273 Dblqh::execCREATE_TRIG_IMPL_CONF(Signal* signal)
26274 {
26275   jamEntry();
26276 
26277   BlockReference dictRef = !isNdbMtLqh() ? DBDICT_REF : DBLQH_REF;
26278   sendSignal(dictRef, GSN_CREATE_TRIG_IMPL_CONF, signal,
26279              CreateTrigImplConf::SignalLength, JBB);
26280 }
26281 
26282 void
execCREATE_TRIG_IMPL_REF(Signal * signal)26283 Dblqh::execCREATE_TRIG_IMPL_REF(Signal* signal)
26284 {
26285   jamEntry();
26286 
26287   BlockReference dictRef = !isNdbMtLqh() ? DBDICT_REF : DBLQH_REF;
26288   sendSignal(dictRef, GSN_CREATE_TRIG_IMPL_REF, signal,
26289              CreateTrigImplRef::SignalLength, JBB);
26290 }
26291 
26292 void
execDROP_TRIG_IMPL_REQ(Signal * signal)26293 Dblqh::execDROP_TRIG_IMPL_REQ(Signal* signal)
26294 {
26295   jamEntry();
26296 
26297   DropTrigImplReq* req = (DropTrigImplReq*)signal->getDataPtrSend();
26298   req->senderRef = reference();
26299   BlockReference tupRef = calcInstanceBlockRef(DBTUP);
26300   sendSignal(tupRef, GSN_DROP_TRIG_IMPL_REQ, signal,
26301              DropTrigImplReq::SignalLength, JBB);
26302 }
26303 
26304 void
execDROP_TRIG_IMPL_CONF(Signal * signal)26305 Dblqh::execDROP_TRIG_IMPL_CONF(Signal* signal)
26306 {
26307   jamEntry();
26308 
26309   BlockReference dictRef = !isNdbMtLqh() ? DBDICT_REF : DBLQH_REF;
26310   sendSignal(dictRef, GSN_DROP_TRIG_IMPL_CONF, signal,
26311              DropTrigImplConf::SignalLength, JBB);
26312 }
26313 
26314 void
execDROP_TRIG_IMPL_REF(Signal * signal)26315 Dblqh::execDROP_TRIG_IMPL_REF(Signal* signal)
26316 {
26317   jamEntry();
26318 
26319   BlockReference dictRef = !isNdbMtLqh() ? DBDICT_REF : DBLQH_REF;
26320   sendSignal(dictRef, GSN_DROP_TRIG_IMPL_REF, signal,
26321              DropTrigImplRef::SignalLength, JBB);
26322 }
26323 
calcPageCheckSum(LogPageRecordPtr logP)26324 Uint32 Dblqh::calcPageCheckSum(LogPageRecordPtr logP){
26325     Uint32 checkSum = 37;
26326 #ifdef VM_TRACE
26327     checkSum = computeXorChecksum(
26328                  logP.p->logPageWord + (ZPOS_CHECKSUM+1),
26329                  ZPAGE_SIZE - (ZPOS_CHECKSUM+1),
26330                  checkSum);
26331 #endif
26332     return checkSum;
26333   }
26334 
26335 #ifdef NDB_DEBUG_FULL
26336 #ifdef ERROR_INSERT
26337 void
sendSignal(Uint32 ref,Uint32 gsn,Signal * signal,Uint32 len,Uint32 prio)26338 TraceLCP::sendSignal(Uint32 ref, Uint32 gsn, Signal* signal,
26339 		     Uint32 len, Uint32 prio)
26340 {
26341   Sig s;
26342   s.type = Sig::Sig_send;
26343   s.header = signal->header;
26344   s.header.theVerId_signalNumber = gsn;
26345   s.header.theReceiversBlockNumber = ref;
26346   s.header.theLength = len;
26347   memcpy(s.theData, signal->theData, 4 * len);
26348   m_signals.push_back(s);
26349   assert(signal->getNoOfSections() == 0);
26350 }
26351 
26352 void
save(Signal * signal)26353 TraceLCP::save(Signal* signal){
26354   Sig s;
26355   s.type = Sig::Sig_save;
26356   s.header = signal->header;
26357   memcpy(s.theData, signal->theData, 4 * signal->getLength());
26358   m_signals.push_back(s);
26359   assert(signal->getNoOfSections() == 0);
26360 }
26361 
26362 void
restore(SimulatedBlock & lqh,Signal * sig)26363 TraceLCP::restore(SimulatedBlock& lqh, Signal* sig){
26364   Uint32 cnt = m_signals.size();
26365   for(Uint32 i = 0; i<cnt; i++){
26366     sig->header = m_signals[i].header;
26367     memcpy(sig->theData, m_signals[i].theData, 4 * sig->getLength());
26368     switch(m_signals[i].type){
26369     case Sig::Sig_send:
26370       lqh.sendSignal(sig->header.theReceiversBlockNumber,
26371 		     sig->header.theVerId_signalNumber,
26372 		     sig,
26373 		     sig->header.theLength,
26374 		     JBB);
26375       break;
26376     case Sig::Sig_save:
26377       lqh.executeFunction(sig->header.theVerId_signalNumber, sig);
26378       break;
26379     }
26380   }
26381   m_signals.clear();
26382 }
26383 #endif
26384 #endif
26385 
writeDbgInfoPageHeader(LogPageRecordPtr logP,Uint32 place,Uint32 pageNo,Uint32 wordWritten)26386 void Dblqh::writeDbgInfoPageHeader(LogPageRecordPtr logP, Uint32 place,
26387                                    Uint32 pageNo, Uint32 wordWritten)
26388 {
26389   logP.p->logPageWord[ZPOS_LOG_TIMER]= logPartPtr.p->logTimer;
26390   logP.p->logPageWord[ZPOS_PREV_PAGE_NO]= logP.p->logPageWord[ZPOS_PAGE_NO];
26391   logP.p->logPageWord[ZPOS_PAGE_I]= logP.i;
26392   logP.p->logPageWord[ZPOS_PLACE_WRITTEN_FROM]= place;
26393   logP.p->logPageWord[ZPOS_PAGE_NO]= pageNo;
26394   logP.p->logPageWord[ZPOS_PAGE_FILE_NO]= logFilePtr.p->fileNo;
26395   logP.p->logPageWord[ZPOS_WORD_WRITTEN]= wordWritten;
26396   logP.p->logPageWord[ZPOS_IN_WRITING]= 1;
26397 }
26398 
initReportStatus(Signal * signal)26399 void Dblqh::initReportStatus(Signal* signal){
26400   m_last_report_time = NdbTick_getCurrentTicks();
26401 }
26402 
checkReportStatus(Signal * signal)26403 void Dblqh::checkReportStatus(Signal* signal){
26404   if (m_startup_report_frequency == 0)
26405     return;
26406 
26407   const NDB_TICKS now = NdbTick_getCurrentTicks();
26408   const Uint64 elapsed = NdbTick_Elapsed(m_last_report_time, now).seconds();
26409   if (elapsed > m_startup_report_frequency)
26410   {
26411     reportStatus(signal);
26412     m_last_report_time = now;
26413   }
26414 }
26415 
reportStatus(Signal * signal)26416 void Dblqh::reportStatus(Signal* signal){
26417   const int signal_length = 6;
26418 
26419   signal->theData[0] = NDB_LE_LogFileInitStatus;
26420   signal->theData[1] = reference();
26421   for (int i = 2; i < signal_length; i++)
26422     signal->theData[i] = 0;
26423   if (getNodeState().startLevel < NodeState::SL_STARTED){
26424     signal->theData[2] = totalLogFiles;
26425     signal->theData[3] = logFileInitDone;
26426     signal->theData[4] = totallogMBytes;
26427     signal->theData[5] = logMBytesInitDone;
26428   }
26429   sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, signal_length, JBB);
26430 }
26431 
logfileInitCompleteReport(Signal * signal)26432 void Dblqh::logfileInitCompleteReport(Signal* signal){
26433   const int signal_length = 6;
26434 
26435   signal->theData[0] = NDB_LE_LogFileInitCompStatus;
26436   signal->theData[1] = reference();
26437   signal->theData[2] = totalLogFiles;
26438   signal->theData[3] = logFileInitDone;
26439   signal->theData[4] = totallogMBytes;
26440   signal->theData[5] = logMBytesInitDone;
26441   sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, signal_length, JBB);
26442 }
26443 
26444 #ifdef NDBD_TRACENR
26445 void
TRACE_OP_DUMP(const Dblqh::TcConnectionrec * regTcPtr,const char * pos)26446 Dblqh::TRACE_OP_DUMP(const Dblqh::TcConnectionrec* regTcPtr, const char * pos)
26447 {
26448   (* traceopout)
26449     << "[ " << hex << regTcPtr->transid[0]
26450     << " " << hex << regTcPtr->transid[1] << " ] " << dec
26451     << pos
26452     << " " << (Operation_t)regTcPtr->operation
26453     << " " << regTcPtr->tableref
26454     << "(" << regTcPtr->fragmentid << ")"
26455     << "(" << (regTcPtr->seqNoReplica == 0 ? "P" : "B") << ")" ;
26456 
26457   {
26458     (* traceopout) << "key=[" << hex;
26459     if (regTcPtr->keyInfoIVal != RNIL)
26460     {
26461       SectionReader keyInfoReader(regTcPtr->keyInfoIVal,
26462                                   g_sectionSegmentPool);
26463 
26464       Uint32 keyWord;
26465       while (keyInfoReader.getWord(&keyWord))
26466         (* traceopout) << hex << keyWord << " ";
26467     }
26468     (* traceopout) << "] ";
26469   }
26470 
26471   if (regTcPtr->m_use_rowid)
26472     (* traceopout) << " " << regTcPtr->m_row_id;
26473   (* traceopout) << endl;
26474 }
26475 #endif
26476 
26477 Uint32
get_node_status(Uint32 nodeId) const26478 Dblqh::get_node_status(Uint32 nodeId) const
26479 {
26480   HostRecordPtr Thostptr;
26481   Thostptr.i = nodeId;
26482   ptrCheckGuard(Thostptr, chostFileSize, hostRecord);
26483   return Thostptr.p->nodestatus;
26484 }
26485 
26486 #ifndef NO_REDO_PAGE_CACHE
26487 /**
26488  * Don't cache pages if less then 64 pages are free
26489  */
26490 #define MIN_REDO_PAGES_FREE 64
26491 
26492 void
do_evict(RedoPageCache & cache,Ptr<RedoCacheLogPageRecord> pagePtr)26493 Dblqh::do_evict(RedoPageCache& cache, Ptr<RedoCacheLogPageRecord> pagePtr)
26494 {
26495   LogPageRecordPtr save = logPagePtr;
26496   cache.m_lru.remove(pagePtr);
26497   cache.m_hash.remove(pagePtr);
26498   if (0)
26499   ndbout_c("evict part: %u file: %u page: %u cnoOfLogPages: %u",
26500            pagePtr.p->m_part_no,
26501            pagePtr.p->m_file_no,
26502            pagePtr.p->m_page_no,
26503            cnoOfLogPages);
26504 
26505   logPagePtr.i = pagePtr.i;
26506   ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
26507 
26508   Ptr<LogPageRecord> prevPagePtr, nextPagePtr;
26509   prevPagePtr.i = logPagePtr.p->logPageWord[ZPREV_PAGE];
26510   nextPagePtr.i = logPagePtr.p->logPageWord[ZNEXT_PAGE];
26511   if (prevPagePtr.i != RNIL)
26512   {
26513     jam();
26514     /**
26515      * Remove ZNEXT pointer from prevPagePtr
26516      *   so we don't try to "serve" multi-page request
26517      *   if next-page has been evicted
26518      */
26519     ptrCheckGuard(prevPagePtr, clogPageFileSize, logPageRecord);
26520     ndbrequire(prevPagePtr.p->logPageWord[ZNEXT_PAGE] == logPagePtr.i);
26521     prevPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL;
26522   }
26523 
26524   if (nextPagePtr.i != RNIL)
26525   {
26526     jam();
26527     /**
26528      * Remove ZPREV pointer from nextPagePtr
26529      *   so don't try to do above if prev has been evicted
26530      */
26531     ptrCheckGuard(nextPagePtr, clogPageFileSize, logPageRecord);
26532     ndbrequire(nextPagePtr.p->logPageWord[ZPREV_PAGE] == logPagePtr.i);
26533     nextPagePtr.p->logPageWord[ZPREV_PAGE] = RNIL;
26534   }
26535 
26536   releaseLogpage(0);
26537   logPagePtr = save;
26538 }
26539 
26540 void
evict(RedoPageCache & cache,Uint32 cnt)26541 Dblqh::evict(RedoPageCache& cache, Uint32 cnt)
26542 {
26543   while (cnoOfLogPages < (cnt + MIN_REDO_PAGES_FREE) && !cache.m_lru.isEmpty())
26544   {
26545     jam();
26546     Ptr<RedoCacheLogPageRecord> pagePtr;
26547     cache.m_lru.last(pagePtr);
26548     do_evict(cache, pagePtr);
26549   }
26550 }
26551 
26552 void
addCachePages(RedoPageCache & cache,Uint32 partNo,Uint32 startPageNo,LogFileOperationRecord * lfoPtrP)26553 Dblqh::addCachePages(RedoPageCache& cache,
26554                      Uint32 partNo,
26555                      Uint32 startPageNo,
26556                      LogFileOperationRecord* lfoPtrP)
26557 {
26558   Uint32 cnt = lfoPtrP->noPagesRw;
26559   Ptr<LogFileRecord> filePtr;
26560   filePtr.i = lfoPtrP->logFileRec;
26561   ptrCheckGuard(filePtr, clogFileFileSize, logFileRecord);
26562 
26563   evict(cache, 0);
26564 
26565   if (cnoOfLogPages < cnt + MIN_REDO_PAGES_FREE)
26566   {
26567     /**
26568      * Don't cache if low on redo-buffer
26569      */
26570     return;
26571   }
26572 
26573   for (Uint32 i = 0; i<cnt ; i++)
26574   {
26575     Ptr<RedoCacheLogPageRecord> pagePtr;
26576     pagePtr.i = lfoPtrP->logPageArray[i];
26577     cache.m_pool.getPtr(pagePtr);
26578     pagePtr.p->m_part_no = partNo;
26579     pagePtr.p->m_page_no = startPageNo + i;
26580     pagePtr.p->m_file_no = filePtr.p->fileNo;
26581 
26582     bool found = false;
26583     {
26584       RedoCacheLogPageRecord key;
26585       key.m_part_no = partNo;
26586       key.m_page_no = startPageNo + i;
26587       key.m_file_no = filePtr.p->fileNo;
26588       Ptr<RedoCacheLogPageRecord> tmp;
26589       if (cache.m_hash.find(tmp, key))
26590       {
26591         jam();
26592         found = true;
26593         do_evict(cache, tmp);
26594       }
26595     }
26596 
26597     cache.m_hash.add(pagePtr);
26598     cache.m_lru.addFirst(pagePtr);
26599     if (0)
26600     ndbout_c("adding(%u) part: %u file: %u page: %u cnoOfLogPages: %u cnt: %u",
26601              found,
26602              pagePtr.p->m_part_no,
26603              pagePtr.p->m_file_no,
26604              pagePtr.p->m_page_no,
26605              cnoOfLogPages,
26606              cnt);
26607   }
26608 
26609   /**
26610    * Make sure pages are not released when prepare-record is executed
26611    * @see releaseLfoPages
26612    */
26613   lfoPtrP->firstLfoPage = RNIL;
26614 }
26615 
26616 void
release(RedoPageCache & cache)26617 Dblqh::release(RedoPageCache& cache)
26618 {
26619   while (!cache.m_lru.isEmpty())
26620   {
26621     jam();
26622     Ptr<RedoCacheLogPageRecord> pagePtr;
26623     cache.m_lru.last(pagePtr);
26624     cache.m_lru.remove(pagePtr);
26625 
26626     logPagePtr.i = pagePtr.i;
26627     ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord);
26628     releaseLogpage(0);
26629   }
26630   cache.m_hash.removeAll();
26631 
26632 #if defined VM_TRACE || defined ERROR_INSERT || 1
26633   ndbout_c("RedoPageCache: avoided %u (%u/%u) page-reads",
26634            cache.m_hits, cache.m_multi_page, cache.m_multi_miss);
26635 #endif
26636   cache.m_hits = 0;
26637   cache.m_multi_page = 0;
26638   cache.m_multi_miss = 0;
26639 }
26640 #endif
26641 
26642 #ifndef NO_REDO_OPEN_FILE_CACHE
26643 
26644 #define MAX_CACHED_OPEN_FILES 4
26645 
26646 void
openFileRw_cache(Signal * signal,LogFileRecordPtr filePtr)26647 Dblqh::openFileRw_cache(Signal* signal,
26648                         LogFileRecordPtr filePtr)
26649 {
26650   jam();
26651 
26652   LogFileRecord::LogFileStatus state = filePtr.p->logFileStatus;
26653   if (state != LogFileRecord::CLOSED)
26654   {
26655     jam();
26656 
26657     m_redo_open_file_cache.m_hits++;
26658 
26659     if (m_redo_open_file_cache.m_lru.hasPrev(filePtr))
26660     {
26661       jam();
26662       m_redo_open_file_cache.m_lru.remove(filePtr);
26663       m_redo_open_file_cache.m_lru.addFirst(filePtr);
26664     }
26665 
26666     filePtr.p->logFileStatus = LogFileRecord::OPEN_EXEC_LOG_CACHED;
26667 
26668     signal->theData[0] = filePtr.i;
26669     signal->theData[1] = filePtr.p->fileRef;
26670     sendSignal(reference(), GSN_FSOPENCONF, signal, 2, JBB);
26671     return;
26672   }
26673 
26674   filePtr.p->logFileStatus = LogFileRecord::OPEN_EXEC_LOG;
26675   openFileRw(signal, filePtr, false);
26676 }
26677 
26678 void
closeFile_cache(Signal * signal,LogFileRecordPtr filePtr,Uint32 line)26679 Dblqh::closeFile_cache(Signal* signal,
26680                        LogFileRecordPtr filePtr,
26681                        Uint32 line)
26682 {
26683   jam();
26684 
26685   filePtr.p->logFileStatus = LogFileRecord::CLOSING_EXEC_LOG_CACHED;
26686   if (m_redo_open_file_cache.m_lru.count() >= MAX_CACHED_OPEN_FILES)
26687   {
26688     jam();
26689     Ptr<LogFileRecord> evictPtr;
26690     Uint32 logPartRec = filePtr.p->logPartRec;
26691     /**
26692      * Only evict file with same log-part, other redo-execution will continue
26693      *   for the log-part once file is closed
26694      *
26695      * Note: 1) loop is guaranteed to terminate as filePtr must be in list
26696      *       2) loop is ok as MAX_CACHED_OPEN_FILES is "small"
26697      *          (if it was big, the m_lru should be split per log-part)
26698      */
26699     m_redo_open_file_cache.m_lru.last(evictPtr);
26700     while (evictPtr.p->logPartRec != logPartRec)
26701     {
26702       jam();
26703       ndbrequire(m_redo_open_file_cache.m_lru.prev(evictPtr));
26704     }
26705     m_redo_open_file_cache.m_lru.remove(evictPtr);
26706     evictPtr.p->logFileStatus = LogFileRecord::CLOSING_EXEC_LOG;
26707     closeFile(signal, evictPtr, line);
26708   }
26709   else
26710   {
26711     jam();
26712     signal->theData[0] = ZEXEC_SR;
26713     signal->theData[1] = filePtr.p->logPartRec;
26714     sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
26715   }
26716 }
26717 
26718 void
release(Signal * signal,RedoOpenFileCache & cache)26719 Dblqh::release(Signal* signal, RedoOpenFileCache & cache)
26720 {
26721   Ptr<LogFileRecord> closePtr;
26722 
26723   while (m_redo_open_file_cache.m_lru.first(closePtr))
26724   {
26725     jam();
26726     m_redo_open_file_cache.m_lru.remove(closePtr);
26727     if (closePtr.p->logFileStatus == LogFileRecord::CLOSING_EXEC_LOG_CACHED)
26728     {
26729       jam();
26730       closePtr.p->logFileStatus = LogFileRecord::CLOSING_EXEC_LOG_CACHED;
26731       m_redo_open_file_cache.m_close_cnt ++;
26732       signal->theData[0] = closePtr.p->fileRef;
26733       signal->theData[1] = reference();
26734       signal->theData[2] = closePtr.i;
26735       signal->theData[3] = ZCLOSE_NO_DELETE;
26736       signal->theData[4] = __LINE__;
26737       sendSignal(NDBFS_REF, GSN_FSCLOSEREQ, signal, 5, JBA);
26738       return;
26739     }
26740     else
26741     {
26742       ndbout_c("Found file with state: %u",
26743                closePtr.p->logFileStatus);
26744     }
26745   }
26746 
26747   ndbout_c("RedoOpenFileCache: Avoided %u file-open/close closed: %u",
26748            m_redo_open_file_cache.m_hits,
26749            m_redo_open_file_cache.m_close_cnt);
26750   m_redo_open_file_cache.m_hits = 0;
26751   m_redo_open_file_cache.m_close_cnt = 0;
26752   execLogComp_extra_files_closed(signal);
26753 }
26754 
26755 #endif
26756 
26757 bool
check_ndb_versions() const26758 Dblqh::check_ndb_versions() const
26759 {
26760   Uint32 version = getNodeInfo(getOwnNodeId()).m_version;
26761   for (Uint32 i = 0; i < cnoOfNodes; i++)
26762   {
26763     Uint32 node = cnodeData[i];
26764     if (cnodeStatus[i] == ZNODE_UP)
26765     {
26766       if(getNodeInfo(node).m_version != version)
26767       {
26768         return false;
26769       }
26770     }
26771   }
26772   return true;
26773 }
26774 
26775 void
suspendFile(Signal * signal,Uint32 filePtrI,Uint32 millis)26776 Dblqh::suspendFile(Signal* signal, Uint32 filePtrI, Uint32 millis)
26777 {
26778   Ptr<LogFileRecord> tmp;
26779   tmp.i = filePtrI;
26780   ptrCheckGuard(tmp, clogFileFileSize, logFileRecord);
26781   suspendFile(signal, tmp, millis);
26782 }
26783 
26784 void
suspendFile(Signal * signal,Ptr<LogFileRecord> logFilePtr,Uint32 millis)26785 Dblqh::suspendFile(Signal* signal, Ptr<LogFileRecord> logFilePtr, Uint32 millis)
26786 {
26787   SaveSignal<FsSuspendOrd::SignalLength> tmp(signal);
26788   signal->theData[0] = logFilePtr.p->fileRef;
26789   signal->theData[1] = millis;
26790   sendSignal(NDBFS_REF, GSN_FSSUSPENDORD, signal, 2, JBA);
26791 }
26792 
26793 void
send_runredo_event(Signal * signal,LogPartRecord * lp,Uint32 gci)26794 Dblqh::send_runredo_event(Signal* signal, LogPartRecord * lp, Uint32 gci)
26795 {
26796   signal->theData[0] = NDB_LE_RunRedo;
26797   signal->theData[1] = lp->logPartNo;
26798   signal->theData[2] = csrPhasesCompleted;
26799   signal->theData[3] = lp->logStartGci;
26800   signal->theData[4] = gci;
26801   signal->theData[5] = lp->logLastGci;
26802 
26803 
26804   LogFileRecordPtr filePtr;
26805   filePtr.i = lp->startLogfile;
26806   ptrCheckGuard(filePtr, clogFileFileSize, logFileRecord);
26807   signal->theData[6] = filePtr.p->fileNo;
26808   signal->theData[7] = lp->startMbyte;
26809 
26810   filePtr.i = lp->currentLogfile;
26811   ptrCheckGuard(filePtr, clogFileFileSize, logFileRecord);
26812   signal->theData[8] = filePtr.p->fileNo;
26813   signal->theData[9] = filePtr.p->currentMbyte;
26814 
26815   filePtr.i = lp->stopLogfile;
26816   ptrCheckGuard(filePtr, clogFileFileSize, logFileRecord);
26817   signal->theData[10] = filePtr.p->fileNo;
26818   signal->theData[11] = lp->stopMbyte;
26819   sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 12, JBB);
26820 }
26821 
26822 void
init(Uint32 partNo)26823 Dblqh::IOTracker::init(Uint32 partNo)
26824 {
26825   bzero(this, sizeof(* this));
26826   m_log_part_no = partNo;
26827 }
26828 
26829 int
tick(Uint32 now,Uint32 maxlag,Uint32 maxlag_cnt)26830 Dblqh::IOTracker::tick(Uint32 now, Uint32 maxlag, Uint32 maxlag_cnt)
26831 {
26832   Uint32 t = m_current_time;
26833 
26834   if ((t / SAMPLE_TIME) == (now / SAMPLE_TIME))
26835     return 0;
26836 
26837   m_redo_written_bytes += m_sample_completed_bytes;
26838 
26839   m_current_time = now;
26840   if (m_sample_completed_bytes >= m_sample_sent_bytes)
26841   {
26842     /**
26843      * If we completed all io we sent during current sample...
26844      *   we can't have any problem...and
26845      *   we can't measure io throughput, so don't add measurement
26846      *
26847      */
26848     m_sample_sent_bytes = 0;
26849     m_sample_completed_bytes = 0;
26850   }
26851   else
26852   {
26853     // io maxed out...
26854     Uint32 elapsed = now - t;
26855     m_save_written_bytes[m_save_pos] += m_sample_completed_bytes;
26856     m_save_elapsed_millis[m_save_pos] += elapsed;
26857 
26858     m_curr_written_bytes += m_sample_completed_bytes;
26859     m_curr_elapsed_millis += elapsed;
26860 
26861     Uint32 bps = (1000 * m_sample_completed_bytes) / elapsed;
26862     Uint32 lag = bps ? m_sum_outstanding_bytes / bps : 30;
26863     if (false && lag >= 30)
26864     {
26865       g_eventLogger->info("part: %u tick(%u) m_sample_completed_bytes: %ukb "
26866                           "m_sample_sent_bytes: %ukb elapsed: %u kbps: %u lag:"
26867                           " %u",
26868                           m_log_part_no,
26869                           now,
26870                           Uint32(m_sample_completed_bytes / 1024),
26871                           Uint32(m_sample_sent_bytes/1024),
26872                           elapsed, bps/1000, lag);
26873     }
26874 
26875     m_sample_sent_bytes -= m_sample_completed_bytes;
26876     m_sample_completed_bytes = 0;
26877   }
26878 
26879   int retVal = 0;
26880   Uint32 save_lag_cnt = m_lag_cnt;
26881   if ((now / SLIDING_WINDOW_LEN) != (t / SLIDING_WINDOW_LEN))
26882   {
26883     Uint32 lag = m_curr_written_bytes ?
26884       ((Uint64(m_sum_outstanding_bytes) / 1000) *
26885         Uint64(m_curr_elapsed_millis)) / m_curr_written_bytes :
26886       0;
26887 
26888     m_lag_in_seconds = lag;
26889 
26890     if (lag > maxlag)
26891     {
26892       /**
26893        * We did have lag last second...
26894        *   increase m_lag_cnt and check if it has reached maxlag_cnt
26895        */
26896       Uint32 tmp = m_lag_cnt;
26897       m_lag_cnt += (lag / maxlag);
26898       if (tmp < maxlag_cnt && m_lag_cnt >= maxlag_cnt)
26899       {
26900         retVal = -1; // start aborting transactions
26901       }
26902     }
26903     else
26904     {
26905       /**
26906        * We did not have lag...reset m_lag_cnt
26907        */
26908       if (m_lag_cnt >= maxlag_cnt)
26909       {
26910         // stop aborting transactions
26911         retVal = 1;
26912       }
26913       m_lag_cnt = 0;
26914     }
26915 
26916 #if 1
26917     if (m_lag_cnt == 0 && lag == 0)
26918     {
26919     }
26920     else if (lag > 0 && m_lag_cnt == 0)
26921     {
26922       g_eventLogger->info("part: %u : time to complete: %u",
26923                           m_log_part_no, lag);
26924     }
26925     else if (m_lag_cnt < maxlag_cnt && m_lag_cnt == save_lag_cnt)
26926     {
26927       g_eventLogger->info("part: %u : time to complete: %u lag_cnt:"
26928                           " %u => %u => retVal: %d",
26929                           m_log_part_no,
26930                           lag,
26931                           save_lag_cnt,
26932                           m_lag_cnt,
26933                           retVal);
26934     }
26935     else
26936     {
26937       g_eventLogger->info("part: %u : sum_outstanding: %ukb avg_written:"
26938                           " %ukb avg_elapsed: %ums time to complete:"
26939                           " %u lag_cnt: %u => %u retVal: %d",
26940                           m_log_part_no,
26941                           Uint32(m_sum_outstanding_bytes / 1024),
26942                           Uint32(m_curr_written_bytes/1024),
26943                           m_curr_elapsed_millis,
26944                           lag,
26945                           save_lag_cnt,
26946                           m_lag_cnt,
26947                           retVal);
26948     }
26949 #endif
26950 
26951     /**
26952      * And finally rotate sliding window
26953      */
26954     Uint32 last = (m_save_pos + 1) % SLIDING_WINDOW_HISTORY_LEN;
26955     assert(m_curr_written_bytes >= m_save_written_bytes[last]);
26956     assert(m_curr_elapsed_millis >= m_save_elapsed_millis[last]);
26957     m_curr_written_bytes -= m_save_written_bytes[last];
26958     m_curr_elapsed_millis -= m_save_elapsed_millis[last];
26959     m_save_written_bytes[last] = 0;
26960     m_save_elapsed_millis[last] = 0;
26961     m_save_pos = last;
26962   }
26963   return retVal;
26964 }
26965 
26966 void
send_io(Uint32 bytes)26967 Dblqh::IOTracker::send_io(Uint32 bytes)
26968 {
26969   m_sum_outstanding_bytes += bytes;
26970   m_sample_sent_bytes += bytes;
26971 }
26972 
26973 void
complete_io(Uint32 bytes)26974 Dblqh::IOTracker::complete_io(Uint32 bytes)
26975 {
26976   assert(m_sum_outstanding_bytes >= bytes);
26977 
26978   m_sum_outstanding_bytes -= bytes;
26979   m_sample_completed_bytes += bytes;
26980 }
26981 
26982 void
mark_end_of_lcp_restore(Signal * signal)26983 Dblqh::mark_end_of_lcp_restore(Signal* signal)
26984 {
26985   jam();
26986 
26987   /* Get Restore to summarise the work and rates */
26988   /* Done directly to keep expected ordering between log messages +
26989    * reduce cognitive burden on readers
26990    */
26991   signal->theData[0] = DumpStateOrd::RestoreRates;
26992   EXECUTE_DIRECT(RESTORE, GSN_DUMP_STATE_ORD, signal, 1);
26993   jamEntry();
26994 
26995   /* Todo : Summarise non-trans copy stats if relevant */
26996 
26997   /* Summarise our work */
26998   g_eventLogger->info("LDM(%u): Completed fuzzy restore %u fragments (%u from LCP,"
26999                       " %u by non-trans copy)",
27000                       instance(),
27001                       c_fragmentsStarted,
27002                       c_fragmentsStarted - c_fragmentsStartedWithCopy,
27003                       c_fragmentsStartedWithCopy);
27004   g_eventLogger->info("LDM(%u): Starting DD Undo log application",
27005                       instance());
27006 
27007   sendLOCAL_RECOVERY_COMPLETE_REP(signal,
27008                  LocalRecoveryCompleteRep::RESTORE_FRAG_COMPLETED);
27009 }
27010 
27011 void
log_fragment_copied(Signal * signal)27012 Dblqh::log_fragment_copied(Signal* signal)
27013 {
27014   jam();
27015 
27016   Uint64 fragRows = 0;
27017   if (fragptr.p->accFragptr != RNIL)
27018   {
27019     ndbassert(DictTabInfo::isTable(fragptr.p->tableType) ||
27020               DictTabInfo::isHashIndex(fragptr.p->tableType));
27021     /* Determine number of rows in this fragment... */
27022 
27023     signal->theData[0] = fragptr.p->accFragptr;
27024     signal->theData[1] = AttributeHeader::ROW_COUNT;
27025     EXECUTE_DIRECT(DBACC, GSN_READ_PSEUDO_REQ, signal, 2);
27026     jamEntry();
27027 
27028     memcpy(&fragRows, &signal->theData[0], sizeof(Uint64));
27029   }
27030 
27031   Uint64 percentChanged = (fragRows ?
27032         ((c_fragCopyRowsIns + c_fragCopyRowsDel) * 100) / fragRows
27033                            : 0);
27034 
27035   /* Have already copied a fragment...report on it now */
27036   g_eventLogger->info("LDM(%u): Completed copy of fragment T%uF%u. "
27037                       "Changed +%llu/-%llu rows, %llu bytes. "
27038                       "%llu pct churn to %llu rows.",
27039                       instance(),
27040                       c_fragCopyTable,
27041                       c_fragCopyFrag,
27042                       c_fragCopyRowsIns,
27043                       c_fragCopyRowsDel,
27044                       c_fragBytesCopied,
27045                       percentChanged,
27046                       fragRows);
27047 
27048   c_totalCopyRowsIns+= c_fragCopyRowsIns;
27049   c_totalCopyRowsDel+= c_fragCopyRowsDel;
27050   c_totalBytesCopied+= c_fragBytesCopied;
27051   c_fragCopyRowsIns = 0;
27052   c_fragCopyRowsDel = 0;
27053   c_fragBytesCopied = 0;
27054 }
27055 
27056 /**
27057  * We assist the Backup block in reporting disk write speeds by sending the
27058  * number of bytes written and completed since last time we were asked.
27059  */
27060 Uint64
report_redo_written_bytes()27061 Dblqh::report_redo_written_bytes()
27062 {
27063   Uint64 redo_written_bytes = 0;
27064   for (logPartPtr.i = 0; logPartPtr.i < clogPartFileSize; logPartPtr.i++)
27065   {
27066     ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
27067     redo_written_bytes +=
27068       logPartPtr.p->m_io_tracker.get_and_reset_redo_written_bytes();
27069   }
27070   return redo_written_bytes;
27071 }
27072 
27073 /**
27074  * We define REDO log IO lagging as when at least 2 seconds of log data has been
27075  * sent to the file system and not yet been completed.
27076  */
27077 bool
is_ldm_instance_io_lagging()27078 Dblqh::is_ldm_instance_io_lagging()
27079 {
27080   for (logPartPtr.i = 0; logPartPtr.i < clogPartFileSize; logPartPtr.i++)
27081   {
27082     ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord);
27083     if (logPartPtr.p->m_io_tracker.get_lag_in_seconds() >= 2)
27084     {
27085       jam();
27086       return true;
27087     }
27088     jam();
27089   }
27090   return false;
27091 }
27092