MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DbtupIndex.cpp
1 /*
2  Copyright (c) 2003, 2010, 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 as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 #define DBTUP_C
19 #define DBTUP_INDEX_CPP
20 #include <dblqh/Dblqh.hpp>
21 #include "Dbtup.hpp"
22 #include <RefConvert.hpp>
23 #include <ndb_limits.h>
24 #include <pc.hpp>
25 #include <AttributeDescriptor.hpp>
26 #include "AttributeOffset.hpp"
27 #include <AttributeHeader.hpp>
28 #include <signaldata/TuxMaint.hpp>
29 #include <signaldata/AlterIndxImpl.hpp>
30 
31 // methods used by ordered index
32 
33 void
34 Dbtup::tuxGetTupAddr(Uint32 fragPtrI,
35  Uint32 pageId,
36  Uint32 pageIndex,
37  Uint32& lkey1,
38  Uint32& lkey2)
39 {
40  jamEntry();
41  PagePtr pagePtr;
42  c_page_pool.getPtr(pagePtr, pageId);
43  lkey1 = pagePtr.p->frag_page_id;
44  lkey2 = pageIndex;
45 }
46 
47 int
48 Dbtup::tuxAllocNode(EmulatedJamBuffer * jamBuf,
49  Uint32 fragPtrI,
50  Uint32& pageId,
51  Uint32& pageOffset,
52  Uint32*& node)
53 {
54  thrjamEntry(jamBuf);
55  FragrecordPtr fragPtr;
56  fragPtr.i= fragPtrI;
57  ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
58  TablerecPtr tablePtr;
59  tablePtr.i= fragPtr.p->fragTableId;
60  ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);
61 
62  Local_key key;
63  Uint32* ptr, frag_page_id, err;
64  if ((ptr= alloc_fix_rec(&err,fragPtr.p,tablePtr.p, &key, &frag_page_id)) == 0)
65  {
66  thrjam(jamBuf);
67  return err;
68  }
69  pageId= key.m_page_no;
70  pageOffset= key.m_page_idx;
71  Uint32 attrDescIndex= tablePtr.p->tabDescriptor + (0 << ZAD_LOG_SIZE);
72  Uint32 attrDataOffset= AttributeOffset::getOffset(
73  tableDescriptor[attrDescIndex + 1].tabDescr);
74  node= ptr + attrDataOffset;
75  return 0;
76 }
77 
78 void
79 Dbtup::tuxFreeNode(Uint32 fragPtrI,
80  Uint32 pageId,
81  Uint32 pageOffset,
82  Uint32* node)
83 {
84  jamEntry();
85  FragrecordPtr fragPtr;
86  fragPtr.i= fragPtrI;
87  ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
88  TablerecPtr tablePtr;
89  tablePtr.i= fragPtr.p->fragTableId;
90  ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);
91 
92  Local_key key;
93  key.m_page_no = pageId;
94  key.m_page_idx = pageOffset;
95  PagePtr pagePtr;
96  Tuple_header* ptr = (Tuple_header*)get_ptr(&pagePtr, &key, tablePtr.p);
97 
98  Uint32 attrDescIndex= tablePtr.p->tabDescriptor + (0 << ZAD_LOG_SIZE);
99  Uint32 attrDataOffset= AttributeOffset::getOffset(tableDescriptor[attrDescIndex + 1].tabDescr);
100  ndbrequire(node == (Uint32*)ptr + attrDataOffset);
101 
102  free_fix_rec(fragPtr.p, tablePtr.p, &key, (Fix_page*)pagePtr.p);
103 }
104 
105 void
106 Dbtup::tuxGetNode(Uint32 fragPtrI,
107  Uint32 pageId,
108  Uint32 pageOffset,
109  Uint32*& node)
110 {
111  FragrecordPtr fragPtr;
112  fragPtr.i= fragPtrI;
113  ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
114  TablerecPtr tablePtr;
115  tablePtr.i= fragPtr.p->fragTableId;
116  ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);
117  PagePtr pagePtr;
118  c_page_pool.getPtr(pagePtr, pageId);
119  Uint32 attrDescIndex= tablePtr.p->tabDescriptor + (0 << ZAD_LOG_SIZE);
120  Uint32 attrDataOffset= AttributeOffset::getOffset(
121  tableDescriptor[attrDescIndex + 1].tabDescr);
122  node= ((Fix_page*)pagePtr.p)->
123  get_ptr(pageOffset, tablePtr.p->m_offsets[MM].m_fix_header_size) +
124  attrDataOffset;
125 }
126 int
127 Dbtup::tuxReadAttrs(EmulatedJamBuffer * jamBuf,
128  Uint32 fragPtrI,
129  Uint32 pageId,
130  Uint32 pageIndex,
131  Uint32 tupVersion,
132  const Uint32* attrIds,
133  Uint32 numAttrs,
134  Uint32* dataOut,
135  bool xfrmFlag)
136 {
137  thrjamEntry(jamBuf);
138  // use own variables instead of globals
139  FragrecordPtr fragPtr;
140  fragPtr.i= fragPtrI;
141  ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
142  TablerecPtr tablePtr;
143  tablePtr.i= fragPtr.p->fragTableId;
144  ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);
145 
146  // search for tuple version if not original
147 
148  Operationrec tmpOp;
149  KeyReqStruct req_struct(jamBuf);
150  req_struct.tablePtrP = tablePtr.p;
151  req_struct.fragPtrP = fragPtr.p;
152 
153  tmpOp.m_tuple_location.m_page_no= pageId;
154  tmpOp.m_tuple_location.m_page_idx= pageIndex;
155  tmpOp.op_struct.op_type = ZREAD; // valgrind
156  setup_fixed_part(&req_struct, &tmpOp, tablePtr.p);
157  Tuple_header *tuple_ptr= req_struct.m_tuple_ptr;
158  if (tuple_ptr->get_tuple_version() != tupVersion)
159  {
160  jam();
161  OperationrecPtr opPtr;
162  opPtr.i= tuple_ptr->m_operation_ptr_i;
163  Uint32 loopGuard= 0;
164  while (opPtr.i != RNIL) {
165  c_operation_pool.getPtr(opPtr);
166  if (opPtr.p->tupVersion == tupVersion) {
167  jam();
168  if (!opPtr.p->m_copy_tuple_location.isNull()) {
169  req_struct.m_tuple_ptr=
170  get_copy_tuple(&opPtr.p->m_copy_tuple_location);
171  }
172  break;
173  }
174  jam();
175  opPtr.i= opPtr.p->prevActiveOp;
176  ndbrequire(++loopGuard < (1 << ZTUP_VERSION_BITS));
177  }
178  }
179  // read key attributes from found tuple version
180  // save globals
181  prepare_read(&req_struct, tablePtr.p, false);
182 
183  // do it
184  int ret = readAttributes(&req_struct,
185  attrIds,
186  numAttrs,
187  dataOut,
188  ZNIL,
189  xfrmFlag);
190 
191  // done
192  return ret;
193 }
194 int
195 Dbtup::tuxReadPk(Uint32 fragPtrI, Uint32 pageId, Uint32 pageIndex, Uint32* dataOut, bool xfrmFlag)
196 {
197  jamEntry();
198  // use own variables instead of globals
199  FragrecordPtr fragPtr;
200  fragPtr.i= fragPtrI;
201  ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
202  TablerecPtr tablePtr;
203  tablePtr.i= fragPtr.p->fragTableId;
204  ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);
205 
206  Operationrec tmpOp;
207  tmpOp.m_tuple_location.m_page_no= pageId;
208  tmpOp.m_tuple_location.m_page_idx= pageIndex;
209 
210  KeyReqStruct req_struct(this);
211  req_struct.tablePtrP = tablePtr.p;
212  req_struct.fragPtrP = fragPtr.p;
213 
214  PagePtr page_ptr;
215  Uint32* ptr= get_ptr(&page_ptr, &tmpOp.m_tuple_location, tablePtr.p);
216  req_struct.m_page_ptr = page_ptr;
217  req_struct.m_tuple_ptr = (Tuple_header*)ptr;
218 
219  int ret = 0;
220  if (! (req_struct.m_tuple_ptr->m_header_bits & Tuple_header::FREE))
221  {
222  req_struct.check_offset[MM]= tablePtr.p->get_check_offset(MM);
223  req_struct.check_offset[DD]= tablePtr.p->get_check_offset(DD);
224 
225  Uint32 num_attr= tablePtr.p->m_no_of_attributes;
226  Uint32 descr_start= tablePtr.p->tabDescriptor;
227  TableDescriptor *tab_descr= &tableDescriptor[descr_start];
228  ndbrequire(descr_start + (num_attr << ZAD_LOG_SIZE) <= cnoOfTabDescrRec);
229  req_struct.attr_descr= tab_descr;
230 
231  if(req_struct.m_tuple_ptr->m_header_bits & Tuple_header::ALLOC)
232  {
233  Uint32 opPtrI= req_struct.m_tuple_ptr->m_operation_ptr_i;
234  Operationrec* opPtrP= c_operation_pool.getPtr(opPtrI);
235  ndbassert(!opPtrP->m_copy_tuple_location.isNull());
236  req_struct.m_tuple_ptr=
237  get_copy_tuple(&opPtrP->m_copy_tuple_location);
238  }
239  prepare_read(&req_struct, tablePtr.p, false);
240 
241  const Uint32* attrIds= &tableDescriptor[tablePtr.p->readKeyArray].tabDescr;
242  const Uint32 numAttrs= tablePtr.p->noOfKeyAttr;
243  // read pk attributes from original tuple
244 
245  // do it
246  ret = readAttributes(&req_struct,
247  attrIds,
248  numAttrs,
249  dataOut,
250  ZNIL,
251  xfrmFlag);
252  // done
253  if (ret >= 0) {
254  // remove headers
255  Uint32 n= 0;
256  Uint32 i= 0;
257  while (n < numAttrs) {
258  const AttributeHeader ah(dataOut[i]);
259  Uint32 size= ah.getDataSize();
260  ndbrequire(size != 0);
261  for (Uint32 j= 0; j < size; j++) {
262  dataOut[i + j - n]= dataOut[i + j + 1];
263  }
264  n+= 1;
265  i+= 1 + size;
266  }
267  ndbrequire((int)i == ret);
268  ret -= numAttrs;
269  } else {
270  return ret;
271  }
272  }
273  if (tablePtr.p->m_bits & Tablerec::TR_RowGCI)
274  {
275  dataOut[ret] = *req_struct.m_tuple_ptr->get_mm_gci(tablePtr.p);
276  }
277  else
278  {
279  dataOut[ret] = 0;
280  }
281  return ret;
282 }
283 
284 int
285 Dbtup::accReadPk(Uint32 tableId, Uint32 fragId, Uint32 fragPageId, Uint32 pageIndex, Uint32* dataOut, bool xfrmFlag)
286 {
287  jamEntry();
288  // get table
289  TablerecPtr tablePtr;
290  tablePtr.i = tableId;
291  ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);
292  // get fragment
293  FragrecordPtr fragPtr;
294  getFragmentrec(fragPtr, fragId, tablePtr.p);
295  // get real page id and tuple offset
296 
297  Uint32 pageId = getRealpid(fragPtr.p, fragPageId);
298  // use TUX routine - optimize later
299  int ret = tuxReadPk(fragPtr.i, pageId, pageIndex, dataOut, xfrmFlag);
300  return ret;
301 }
302 
303 /*
304  * TUX index contains all tuple versions. A scan in TUX has scanned
305  * one of them and asks if it can be returned as scan result. This
306  * depends on trans id, dirty read flag, and savepoint within trans.
307  *
308  * Previously this faked a ZREAD operation and used getPage().
309  * In TUP getPage() is run after ACC locking, but TUX comes here
310  * before ACC access. Instead of modifying getPage() it is more
311  * clear to do the full check here.
312  */
313 bool
314 Dbtup::tuxQueryTh(Uint32 fragPtrI,
315  Uint32 pageId,
316  Uint32 pageIndex,
317  Uint32 tupVersion,
318  Uint32 transId1,
319  Uint32 transId2,
320  bool dirty,
321  Uint32 savepointId)
322 {
323  jamEntry();
324  FragrecordPtr fragPtr;
325  fragPtr.i= fragPtrI;
326  ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
327  TablerecPtr tablePtr;
328  tablePtr.i= fragPtr.p->fragTableId;
329  ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);
330  PagePtr pagePtr;
331  pagePtr.i = pageId;
332  c_page_pool.getPtr(pagePtr);
333 
334  KeyReqStruct req_struct(this);
335 
336  {
337  Operationrec tmpOp;
338  tmpOp.m_tuple_location.m_page_no = pageId;
339  tmpOp.m_tuple_location.m_page_idx = pageIndex;
340  tmpOp.op_struct.op_type = ZREAD; // valgrind
341  setup_fixed_part(&req_struct, &tmpOp, tablePtr.p);
342  }
343 
344  Tuple_header* tuple_ptr = req_struct.m_tuple_ptr;
345 
346  OperationrecPtr currOpPtr;
347  currOpPtr.i = tuple_ptr->m_operation_ptr_i;
348  if (currOpPtr.i == RNIL) {
349  jam();
350  // tuple has no operation, any scan can see it
351  return true;
352  }
353  c_operation_pool.getPtr(currOpPtr);
354 
355  const bool sameTrans =
356  c_lqh->is_same_trans(currOpPtr.p->userpointer, transId1, transId2);
357 
358  bool res = false;
359  OperationrecPtr loopOpPtr = currOpPtr;
360 
361  if (!sameTrans) {
362  jam();
363  if (!dirty) {
364  jam();
365  if (currOpPtr.p->nextActiveOp == RNIL) {
366  jam();
367  // last op - TUX makes ACC lock request in same timeslice
368  res = true;
369  }
370  }
371  else {
372  // loop to first op (returns false)
373  find_savepoint(loopOpPtr, 0);
374  const Uint32 op_type = loopOpPtr.p->op_struct.op_type;
375 
376  if (op_type != ZINSERT) {
377  jam();
378  // read committed version
379  const Uint32 origVersion = tuple_ptr->get_tuple_version();
380  if (origVersion == tupVersion) {
381  jam();
382  res = true;
383  }
384  }
385  }
386  }
387  else {
388  jam();
389  // for own trans, ignore dirty flag
390 
391  if (find_savepoint(loopOpPtr, savepointId)) {
392  jam();
393  const Uint32 op_type = loopOpPtr.p->op_struct.op_type;
394 
395  if (op_type != ZDELETE) {
396  jam();
397  // check if this op has produced the scanned version
398  Uint32 loopVersion = loopOpPtr.p->tupVersion;
399  if (loopVersion == tupVersion) {
400  jam();
401  res = true;
402  }
403  }
404  }
405  }
406 
407  return res;
408 }
409 
410 // ordered index build
411 
412 //#define TIME_MEASUREMENT
413 #ifdef TIME_MEASUREMENT
414  static Uint32 time_events;
415  NDB_TICKS tot_time_passed;
416  Uint32 number_events;
417 #endif
418 void
419 Dbtup::execBUILD_INDX_IMPL_REQ(Signal* signal)
420 {
421  jamEntry();
422 #ifdef TIME_MEASUREMENT
423  time_events= 0;
424  tot_time_passed= 0;
425  number_events= 1;
426 #endif
427  const BuildIndxImplReq* const req =
428  (const BuildIndxImplReq*)signal->getDataPtr();
429  // get new operation
430  BuildIndexPtr buildPtr;
431  if (ERROR_INSERTED(4031) || ! c_buildIndexList.seize(buildPtr)) {
432  jam();
433  BuildIndexRec buildRec;
434  buildRec.m_request = *req;
435  buildRec.m_errorCode = BuildIndxImplRef::Busy;
436  if (ERROR_INSERTED(4031))
437  {
438  CLEAR_ERROR_INSERT_VALUE;
439  }
440  buildIndexReply(signal, &buildRec);
441  return;
442  }
443  buildPtr.p->m_request = *req;
444  const BuildIndxImplReq* buildReq = &buildPtr.p->m_request;
445  // check
446  buildPtr.p->m_errorCode= BuildIndxImplRef::NoError;
447  buildPtr.p->m_outstanding = 0;
448  do {
449  if (buildReq->tableId >= cnoOfTablerec) {
450  jam();
451  buildPtr.p->m_errorCode= BuildIndxImplRef::InvalidPrimaryTable;
452  break;
453  }
454  TablerecPtr tablePtr;
455  tablePtr.i= buildReq->tableId;
456  ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);
457  if (tablePtr.p->tableStatus != DEFINED) {
458  jam();
459  buildPtr.p->m_errorCode= BuildIndxImplRef::InvalidPrimaryTable;
460  break;
461  }
462  // memory page format
463  buildPtr.p->m_build_vs =
464  (tablePtr.p->m_attributes[MM].m_no_of_varsize +
465  tablePtr.p->m_attributes[MM].m_no_of_dynamic) > 0;
466  if (DictTabInfo::isOrderedIndex(buildReq->indexType)) {
467  jam();
468  const DLList<TupTriggerData>& triggerList =
469  tablePtr.p->tuxCustomTriggers;
470 
471  TriggerPtr triggerPtr;
472  triggerList.first(triggerPtr);
473  while (triggerPtr.i != RNIL) {
474  if (triggerPtr.p->indexId == buildReq->indexId) {
475  jam();
476  break;
477  }
478  triggerList.next(triggerPtr);
479  }
480  if (triggerPtr.i == RNIL) {
481  jam();
482  // trigger was not created
483  ndbassert(false);
484  buildPtr.p->m_errorCode = BuildIndxImplRef::InternalError;
485  break;
486  }
487  buildPtr.p->m_indexId = buildReq->indexId;
488  buildPtr.p->m_buildRef = DBTUX;
489  AlterIndxImplReq* req = (AlterIndxImplReq*)signal->getDataPtrSend();
490  req->indexId = buildReq->indexId;
491  req->senderRef = 0;
492  req->requestType = AlterIndxImplReq::AlterIndexBuilding;
493  EXECUTE_DIRECT(DBTUX, GSN_ALTER_INDX_IMPL_REQ, signal,
494  AlterIndxImplReq::SignalLength);
495  } else if(buildReq->indexId == RNIL) {
496  jam();
497  // REBUILD of acc
498  buildPtr.p->m_indexId = RNIL;
499  buildPtr.p->m_buildRef = DBACC;
500  } else {
501  jam();
502  buildPtr.p->m_errorCode = BuildIndxImplRef::InvalidIndexType;
503  break;
504  }
505 
506  // set to first tuple position
507  const Uint32 firstTupleNo = 0;
508  buildPtr.p->m_fragNo= 0;
509  buildPtr.p->m_pageId= 0;
510  buildPtr.p->m_tupleNo= firstTupleNo;
511  // start build
512 
513  bool offline = !!(buildReq->requestType&BuildIndxImplReq::RF_BUILD_OFFLINE);
514  if (offline && m_max_parallel_index_build > 1)
515  {
516  jam();
517  buildIndexOffline(signal, buildPtr.i);
518  }
519  else
520  {
521  jam();
522  buildIndex(signal, buildPtr.i);
523  }
524  return;
525  } while (0);
526  // check failed
527  buildIndexReply(signal, buildPtr.p);
528  c_buildIndexList.release(buildPtr);
529 }
530 
531 void
532 Dbtup::buildIndex(Signal* signal, Uint32 buildPtrI)
533 {
534  // get build record
535  BuildIndexPtr buildPtr;
536  buildPtr.i= buildPtrI;
537  c_buildIndexList.getPtr(buildPtr);
538  const BuildIndxImplReq* buildReq= &buildPtr.p->m_request;
539  // get table
540  TablerecPtr tablePtr;
541  tablePtr.i= buildReq->tableId;
542  ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);
543 
544  const Uint32 firstTupleNo = 0;
545  const Uint32 tupheadsize = tablePtr.p->m_offsets[MM].m_fix_header_size;
546 
547 #ifdef TIME_MEASUREMENT
548  MicroSecondTimer start;
549  MicroSecondTimer stop;
550  NDB_TICKS time_passed;
551 #endif
552  do {
553  // get fragment
554  FragrecordPtr fragPtr;
555  if (buildPtr.p->m_fragNo == MAX_FRAG_PER_NODE) {
556  jam();
557  // build ready
558  buildIndexReply(signal, buildPtr.p);
559  c_buildIndexList.release(buildPtr);
560  return;
561  }
562  ndbrequire(buildPtr.p->m_fragNo < MAX_FRAG_PER_NODE);
563  fragPtr.i= tablePtr.p->fragrec[buildPtr.p->m_fragNo];
564  if (fragPtr.i == RNIL) {
565  jam();
566  buildPtr.p->m_fragNo++;
567  buildPtr.p->m_pageId= 0;
568  buildPtr.p->m_tupleNo= firstTupleNo;
569  break;
570  }
571  ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
572  // get page
573  PagePtr pagePtr;
574  if (buildPtr.p->m_pageId >= fragPtr.p->m_max_page_no) {
575  jam();
576  buildPtr.p->m_fragNo++;
577  buildPtr.p->m_pageId= 0;
578  buildPtr.p->m_tupleNo= firstTupleNo;
579  break;
580  }
581  Uint32 realPageId= getRealpidCheck(fragPtr.p, buildPtr.p->m_pageId);
582  // skip empty page
583  if (realPageId == RNIL)
584  {
585  jam();
586  goto next_tuple;
587  }
588 
589  c_page_pool.getPtr(pagePtr, realPageId);
590 
591 next_tuple:
592  // get tuple
593  Uint32 pageIndex = ~0;
594  const Tuple_header* tuple_ptr = 0;
595  pageIndex = buildPtr.p->m_tupleNo * tupheadsize;
596  if (pageIndex + tupheadsize > Fix_page::DATA_WORDS) {
597  jam();
598  buildPtr.p->m_pageId++;
599  buildPtr.p->m_tupleNo= firstTupleNo;
600  break;
601  }
602 
603  if (realPageId == RNIL)
604  {
605  jam();
606  buildPtr.p->m_tupleNo++;
607  break;
608  }
609 
610  tuple_ptr = (Tuple_header*)&pagePtr.p->m_data[pageIndex];
611  // skip over free tuple
612  if (tuple_ptr->m_header_bits & Tuple_header::FREE) {
613  jam();
614  buildPtr.p->m_tupleNo++;
615  break;
616  }
617  Uint32 tupVersion= tuple_ptr->get_tuple_version();
618  OperationrecPtr pageOperPtr;
619  pageOperPtr.i= tuple_ptr->m_operation_ptr_i;
620 #ifdef TIME_MEASUREMENT
621  NdbTick_getMicroTimer(&start);
622 #endif
623  // add to index
624  TuxMaintReq* const req = (TuxMaintReq*)signal->getDataPtrSend();
625  req->errorCode = RNIL;
626  req->tableId = tablePtr.i;
627  req->indexId = buildPtr.p->m_indexId;
628  req->fragId = tablePtr.p->fragid[buildPtr.p->m_fragNo];
629  req->pageId = realPageId;
630  req->tupVersion = tupVersion;
631  req->opInfo = TuxMaintReq::OpAdd;
632  req->tupFragPtrI = fragPtr.i;
633  req->fragPageId = buildPtr.p->m_pageId;
634  req->pageIndex = pageIndex;
635 
636  if (pageOperPtr.i == RNIL)
637  {
638  EXECUTE_DIRECT(buildPtr.p->m_buildRef, GSN_TUX_MAINT_REQ,
639  signal, TuxMaintReq::SignalLength+2);
640  }
641  else
642  {
643  /*
644  If there is an ongoing operation on the tuple then it is either a
645  copy tuple or an original tuple with an ongoing transaction. In
646  both cases realPageId and pageOffset refer to the original tuple.
647  The tuple address stored in TUX will always be the original tuple
648  but with the tuple version of the tuple we found.
649 
650  This is necessary to avoid having to update TUX at abort of
651  update. If an update aborts then the copy tuple is copied to
652  the original tuple. The build will however have found that
653  tuple as a copy tuple. The original tuple is stable and is thus
654  preferrable to store in TUX.
655  */
656  jam();
657 
667  /*
668  * Start from first operation. This is only to make things more
669  * clear. It is not required by ordered index implementation.
670  */
671  c_operation_pool.getPtr(pageOperPtr);
672  while (pageOperPtr.p->prevActiveOp != RNIL)
673  {
674  jam();
675  pageOperPtr.i = pageOperPtr.p->prevActiveOp;
676  c_operation_pool.getPtr(pageOperPtr);
677  }
678  /*
679  * Do not use req->errorCode as global control.
680  */
681  bool ok = true;
682  /*
683  * If first operation is an update, add previous version.
684  * This version does not appear as the version of any operation.
685  * At commit this version is removed by executeTuxCommitTriggers.
686  * At abort it is preserved by executeTuxAbortTriggers.
687  */
688  if (pageOperPtr.p->op_struct.op_type == ZUPDATE)
689  {
690  jam();
691  req->errorCode = RNIL;
692  req->tupVersion = decr_tup_version(pageOperPtr.p->tupVersion);
693  EXECUTE_DIRECT(buildPtr.p->m_buildRef, GSN_TUX_MAINT_REQ,
694  signal, TuxMaintReq::SignalLength+2);
695  ok = (req->errorCode == 0);
696  }
697  /*
698  * Add versions from all operations.
699  *
700  * Each operation has a tuple version. For insert and update it
701  * is the newly created version. For delete it is the version
702  * deleted. The existence of operation tuple version implies that
703  * a corresponding tuple version exists for TUX to read.
704  *
705  * We could be in the middle of a commit. The process here makes
706  * no assumptions about operation commit order. (It should be
707  * first to last but this is not the place to assert it).
708  *
709  * Duplicate versions are possible e.g. a delete in the middle
710  * may have same version as the previous operation. TUX ignores
711  * duplicate version errors during index build.
712  */
713  while (pageOperPtr.i != RNIL && ok)
714  {
715  jam();
716  c_operation_pool.getPtr(pageOperPtr);
717  req->errorCode = RNIL;
718  req->tupVersion = pageOperPtr.p->tupVersion;
719  EXECUTE_DIRECT(buildPtr.p->m_buildRef, GSN_TUX_MAINT_REQ,
720  signal, TuxMaintReq::SignalLength+2);
721  pageOperPtr.i = pageOperPtr.p->nextActiveOp;
722  ok = (req->errorCode == 0);
723  }
724  }
725 
726  jamEntry();
727  if (req->errorCode != 0) {
728  switch (req->errorCode) {
729  case TuxMaintReq::NoMemError:
730  jam();
731  buildPtr.p->m_errorCode= BuildIndxImplRef::AllocationFailure;
732  break;
733  default:
734  ndbrequire(false);
735  break;
736  }
737  buildIndexReply(signal, buildPtr.p);
738  c_buildIndexList.release(buildPtr);
739  return;
740  }
741 #ifdef TIME_MEASUREMENT
742  NdbTick_getMicroTimer(&stop);
743  time_passed= NdbTick_getMicrosPassed(start, stop);
744  if (time_passed < 1000) {
745  time_events++;
746  tot_time_passed += time_passed;
747  if (time_events == number_events) {
748  NDB_TICKS mean_time_passed= tot_time_passed /
749  (NDB_TICKS)number_events;
750  ndbout << "Number of events= " << number_events;
751  ndbout << " Mean time passed= " << mean_time_passed << endl;
752  number_events <<= 1;
753  tot_time_passed= (NDB_TICKS)0;
754  time_events= 0;
755  }
756  }
757 #endif
758  // next tuple
759  buildPtr.p->m_tupleNo++;
760  break;
761  } while (0);
762  signal->theData[0]= ZBUILD_INDEX;
763  signal->theData[1]= buildPtr.i;
764  sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
765 }
766 
767 Uint32 Dbtux_mt_buildIndexFragment_wrapper_C(void*);
768 
769 void
770 Dbtup::buildIndexOffline(Signal* signal, Uint32 buildPtrI)
771 {
772  jam();
776  BuildIndexPtr buildPtr;
777  buildPtr.i= buildPtrI;
778  c_buildIndexList.getPtr(buildPtr);
779  const BuildIndxImplReq* buildReq =
780  (const BuildIndxImplReq*)&buildPtr.p->m_request;
781 
782  AlterTabReq* req = (AlterTabReq*)signal->getDataPtrSend();
783  bzero(req, sizeof(req));
784  req->senderRef = reference();
785  req->senderData = buildPtrI;
786  req->tableId = buildReq->tableId;
787  req->requestType = AlterTabReq::AlterTableReadOnly;
788  sendSignal(calcInstanceBlockRef(DBLQH), GSN_ALTER_TAB_REQ, signal,
789  AlterTabReq::SignalLength, JBB);
790 }
791 
792 void
793 Dbtup::execALTER_TAB_CONF(Signal* signal)
794 {
795  jamEntry();
796  AlterTabConf* conf = (AlterTabConf*)signal->getDataPtr();
797 
798  BuildIndexPtr buildPtr;
799  buildPtr.i = conf->senderData;
800  c_buildIndexList.getPtr(buildPtr);
801 
802 
803  if (buildPtr.p->m_fragNo == 0)
804  {
805  jam();
806  buildIndexOffline_table_readonly(signal, conf->senderData);
807  return;
808  }
809  else
810  {
811  jam();
812  ndbrequire(buildPtr.p->m_fragNo >= MAX_FRAG_PER_NODE);
813  buildIndexReply(signal, buildPtr.p);
814  c_buildIndexList.release(buildPtr);
815  return;
816  }
817 }
818 
819 void
820 Dbtup::buildIndexOffline_table_readonly(Signal* signal, Uint32 buildPtrI)
821 {
822  // get build record
823  BuildIndexPtr buildPtr;
824  buildPtr.i= buildPtrI;
825  c_buildIndexList.getPtr(buildPtr);
826  const BuildIndxImplReq* buildReq =
827  (const BuildIndxImplReq*)&buildPtr.p->m_request;
828  // get table
829  TablerecPtr tablePtr;
830  tablePtr.i= buildReq->tableId;
831  ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);
832 
833  for (;buildPtr.p->m_fragNo < MAX_FRAG_PER_NODE;
834  buildPtr.p->m_fragNo++)
835  {
836  jam();
837  FragrecordPtr fragPtr;
838  fragPtr.i = tablePtr.p->fragrec[buildPtr.p->m_fragNo];
839  if (fragPtr.i == RNIL)
840  {
841  jam();
842  continue;
843  }
844  ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
845  mt_BuildIndxReq req;
846  bzero(&req, sizeof(req));
847  req.senderRef = reference();
848  req.senderData = buildPtr.i;
849  req.tableId = buildReq->tableId;
850  req.indexId = buildPtr.p->m_indexId;
851  req.fragId = tablePtr.p->fragid[buildPtr.p->m_fragNo];
852 
853  SimulatedBlock * tux = globalData.getBlock(DBTUX);
854  if (instance() != 0)
855  {
856  tux = tux->getInstance(instance());
857  ndbrequire(tux != 0);
858  }
859  req.tux_ptr = tux;
860  req.tup_ptr = this;
861  req.func_ptr = Dbtux_mt_buildIndexFragment_wrapper_C;
862  req.buffer_size = 16*32768; // thread-local-buffer
863 
864  Uint32 * req_ptr = signal->getDataPtrSend();
865  memcpy(req_ptr, &req, sizeof(req));
866 
867  sendSignal(NDBFS_REF, GSN_BUILD_INDX_IMPL_REQ, signal,
868  (sizeof(req) + 15) / 4, JBB);
869 
870  buildPtr.p->m_outstanding++;
871  if (buildPtr.p->m_outstanding >= m_max_parallel_index_build)
872  {
873  jam();
874  return;
875  }
876  }
877 
878  if (buildPtr.p->m_outstanding == 0)
879  {
880  jam();
881  AlterTabReq* req = (AlterTabReq*)signal->getDataPtrSend();
882  bzero(req, sizeof(req));
883  req->senderRef = reference();
884  req->senderData = buildPtrI;
885  req->tableId = buildReq->tableId;
886  req->requestType = AlterTabReq::AlterTableReadWrite;
887  sendSignal(calcInstanceBlockRef(DBLQH), GSN_ALTER_TAB_REQ, signal,
888  AlterTabReq::SignalLength, JBB);
889  return;
890  }
891  else
892  {
893  jam();
894  // wait for replies
895  return;
896  }
897 }
898 
899 int
900 Dbtup::mt_scan_init(Uint32 tableId, Uint32 fragId,
901  Local_key* pos, Uint32 * fragPtrI)
902 {
903  TablerecPtr tablePtr;
904  tablePtr.i = tableId;
905  ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);
906 
907  FragrecordPtr fragPtr;
908  fragPtr.i = RNIL;
909  for (Uint32 i = 0; i<MAX_FRAG_PER_NODE; i++)
910  {
911  if (tablePtr.p->fragid[i] == fragId)
912  {
913  fragPtr.i = tablePtr.p->fragrec[i];
914  break;
915  }
916  }
917 
918  if (fragPtr.i == RNIL)
919  return -1;
920 
921  ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
922 
923  Uint32 fragPageId = 0;
924  while (fragPageId < fragPtr.p->m_max_page_no)
925  {
926  Uint32 realPageId= getRealpidCheck(fragPtr.p, fragPageId);
927  if (realPageId != RNIL)
928  {
929  * fragPtrI = fragPtr.i;
930  pos->m_page_no = realPageId;
931  pos->m_page_idx = 0;
932  pos->m_file_no = 0;
933  return 0;
934  }
935  fragPageId++;
936  }
937 
938  return 1;
939 }
940 
941 int
942 Dbtup::mt_scan_next(Uint32 tableId, Uint32 fragPtrI,
943  Local_key* pos, bool moveNext)
944 {
945  TablerecPtr tablePtr;
946  tablePtr.i = tableId;
947  ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);
948 
949  FragrecordPtr fragPtr;
950  fragPtr.i = fragPtrI;
951  ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
952 
953  Uint32 tupheadsize = tablePtr.p->m_offsets[MM].m_fix_header_size;
954  if (moveNext)
955  {
956  pos->m_page_idx += tupheadsize;
957  }
958 
959  PagePtr pagePtr;
960  c_page_pool.getPtr(pagePtr, pos->m_page_no);
961 
962  while (1)
963  {
964  Tuple_header* tuple_ptr;
965  while (pos->m_page_idx + tupheadsize <= Fix_page::DATA_WORDS)
966  {
967  tuple_ptr = (Tuple_header*)(pagePtr.p->m_data + pos->m_page_idx);
968  // skip over free tuple
969  if (tuple_ptr->m_header_bits & Tuple_header::FREE)
970  {
971  pos->m_page_idx += tupheadsize;
972  continue;
973  }
974  pos->m_file_no = tuple_ptr->get_tuple_version();
975  return 0; // Found
976  }
977 
978  // End of page...move to next
979  Uint32 fragPageId = pagePtr.p->frag_page_id + 1;
980  while (fragPageId < fragPtr.p->m_max_page_no)
981  {
982  Uint32 realPageId = getRealpidCheck(fragPtr.p, fragPageId);
983  if (realPageId != RNIL)
984  {
985  pos->m_page_no = realPageId;
986  break;
987  }
988  fragPageId++;
989  }
990 
991  if (fragPageId == fragPtr.p->m_max_page_no)
992  break;
993 
994  pos->m_page_idx = 0;
995  c_page_pool.getPtr(pagePtr, pos->m_page_no);
996  }
997 
998  return 1;
999 }
1000 
1001 void
1002 Dbtup::execBUILD_INDX_IMPL_REF(Signal* signal)
1003 {
1004  jamEntry();
1005  BuildIndxImplRef* ref = (BuildIndxImplRef*)signal->getDataPtrSend();
1006  Uint32 ptr = ref->senderData;
1007  Uint32 err = ref->errorCode;
1008 
1009  BuildIndexPtr buildPtr;
1010  c_buildIndexList.getPtr(buildPtr, ptr);
1011  ndbrequire(buildPtr.p->m_outstanding);
1012  buildPtr.p->m_outstanding--;
1013 
1014  buildPtr.p->m_errorCode = (BuildIndxImplRef::ErrorCode)err;
1015  buildPtr.p->m_fragNo = MAX_FRAG_PER_NODE; // No point in starting any more
1016  buildIndexOffline_table_readonly(signal, ptr);
1017 }
1018 
1019 void
1020 Dbtup::execBUILD_INDX_IMPL_CONF(Signal* signal)
1021 {
1022  jamEntry();
1023  BuildIndxImplConf* conf = (BuildIndxImplConf*)signal->getDataPtrSend();
1024  Uint32 ptr = conf->senderData;
1025 
1026  BuildIndexPtr buildPtr;
1027  c_buildIndexList.getPtr(buildPtr, ptr);
1028  ndbrequire(buildPtr.p->m_outstanding);
1029  buildPtr.p->m_outstanding--;
1030  buildPtr.p->m_fragNo++;
1031 
1032  buildIndexOffline_table_readonly(signal, ptr);
1033 }
1034 
1035 void
1036 Dbtup::buildIndexReply(Signal* signal, const BuildIndexRec* buildPtrP)
1037 {
1038  const BuildIndxImplReq* buildReq = &buildPtrP->m_request;
1039 
1040  AlterIndxImplReq* req = (AlterIndxImplReq*)signal->getDataPtrSend();
1041  req->indexId = buildReq->indexId;
1042  req->senderRef = 0; //
1043  if (buildPtrP->m_errorCode == BuildIndxImplRef::NoError)
1044  {
1045  jam();
1046  req->requestType = AlterIndxImplReq::AlterIndexOnline;
1047  }
1048  else
1049  {
1050  jam();
1051  req->requestType = AlterIndxImplReq::AlterIndexOffline;
1052  }
1053  EXECUTE_DIRECT(DBTUX, GSN_ALTER_INDX_IMPL_REQ, signal,
1054  AlterIndxImplReq::SignalLength);
1055 
1056  if (buildPtrP->m_errorCode == BuildIndxImplRef::NoError) {
1057  jam();
1058  BuildIndxImplConf* conf =
1059  (BuildIndxImplConf*)signal->getDataPtrSend();
1060  conf->senderRef = reference();
1061  conf->senderData = buildReq->senderData;
1062 
1063  sendSignal(buildReq->senderRef, GSN_BUILD_INDX_IMPL_CONF,
1064  signal, BuildIndxImplConf::SignalLength, JBB);
1065  } else {
1066  jam();
1067  BuildIndxImplRef* ref =
1068  (BuildIndxImplRef*)signal->getDataPtrSend();
1069  ref->senderRef = reference();
1070  ref->senderData = buildReq->senderData;
1071  ref->errorCode = buildPtrP->m_errorCode;
1072 
1073  sendSignal(buildReq->senderRef, GSN_BUILD_INDX_IMPL_REF,
1074  signal, BuildIndxImplRef::SignalLength, JBB);
1075  }
1076 }