MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DbtupDiskAlloc.cpp
1 /*
2  Copyright (c) 2005, 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_DISK_ALLOC_CPP
20 #include "Dbtup.hpp"
21 
22 static
23 NdbOut&
24 operator<<(NdbOut& out, const Ptr<Dbtup::Page> & ptr)
25 {
26  out << "[ Page: ptr.i: " << ptr.i
27  << " [ m_file_no: " << ptr.p->m_file_no
28  << " m_page_no: " << ptr.p->m_page_no << "]"
29  << " list_index: " << ptr.p->list_index
30  << " free_space: " << ptr.p->free_space
31  << " uncommitted_used_space: " << ptr.p->uncommitted_used_space
32  << " ]";
33  return out;
34 }
35 
36 static
37 NdbOut&
38 operator<<(NdbOut& out, const Ptr<Dbtup::Page_request> & ptr)
39 {
40  out << "[ Page_request: ptr.i: " << ptr.i
41  << " " << ptr.p->m_key
42  << " m_original_estimated_free_space: " << ptr.p->m_original_estimated_free_space
43  << " m_list_index: " << ptr.p->m_list_index
44  << " m_frag_ptr_i: " << ptr.p->m_frag_ptr_i
45  << " m_extent_info_ptr: " << ptr.p->m_extent_info_ptr
46  << " m_ref_count: " << ptr.p->m_ref_count
47  << " m_uncommitted_used_space: " << ptr.p->m_uncommitted_used_space
48  << " ]";
49 
50  return out;
51 }
52 
53 static
54 NdbOut&
55 operator<<(NdbOut& out, const Ptr<Dbtup::Extent_info> & ptr)
56 {
57  out << "[ Extent_info: ptr.i " << ptr.i
58  << " " << ptr.p->m_key
59  << " m_first_page_no: " << ptr.p->m_first_page_no
60  << " m_free_space: " << ptr.p->m_free_space
61  << " m_free_matrix_pos: " << ptr.p->m_free_matrix_pos
62  << " m_free_page_count: [";
63 
64  for(Uint32 i = 0; i<Dbtup::EXTENT_SEARCH_MATRIX_COLS; i++)
65  out << " " << ptr.p->m_free_page_count[i];
66  out << " ] ]";
67 
68  return out;
69 }
70 
71 #if NOT_YET_FREE_EXTENT
72 static
73 inline
74 bool
75 check_free(const Dbtup::Extent_info* extP)
76 {
77  Uint32 res = 0;
78  for (Uint32 i = 1; i<MAX_FREE_LIST; i++)
79  res += extP->m_free_page_count[i];
80  return res;
81 }
82 #error "Code for deallocting extents when they get empty"
83 #error "This code is not yet complete"
84 #endif
85 
86 #if NOT_YET_UNDO_ALLOC_EXTENT
87 #error "This is needed for deallocting extents when they get empty"
88 #error "This code is not complete yet"
89 #endif
90 
91 void
92 Dbtup::dump_disk_alloc(Dbtup::Disk_alloc_info & alloc)
93 {
94  const Uint32 limit = 512;
95  ndbout_c("dirty pages");
96  for(Uint32 i = 0; i<MAX_FREE_LIST; i++)
97  {
98  printf(" %d : ", i);
99  PagePtr ptr;
100  ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool;
101  LocalDLList<Page> list(*pool, alloc.m_dirty_pages[i]);
102  Uint32 c = 0;
103  for (list.first(ptr); c < limit && !ptr.isNull(); c++, list.next(ptr))
104  {
105  ndbout << ptr << " ";
106  }
107  if (c == limit)
108  {
109  ndbout << "MAXLIMIT ";
110  }
111  ndbout_c(" ");
112  }
113  ndbout_c("page requests");
114  for(Uint32 i = 0; i<MAX_FREE_LIST; i++)
115  {
116  printf(" %d : ", i);
117  Ptr<Page_request> ptr;
118  Local_page_request_list list(c_page_request_pool,
119  alloc.m_page_requests[i]);
120  Uint32 c = 0;
121  for (list.first(ptr); c < limit && !ptr.isNull(); c++, list.next(ptr))
122  {
123  ndbout << ptr << " ";
124  }
125  if (c == limit)
126  {
127  ndbout << "MAXLIMIT ";
128  }
129  ndbout_c(" ");
130  }
131 
132  ndbout_c("Extent matrix");
133  for(Uint32 i = 0; i<alloc.SZ; i++)
134  {
135  printf(" %d : ", i);
136  Ptr<Extent_info> ptr;
137  Local_extent_info_list list(c_extent_pool, alloc.m_free_extents[i]);
138  Uint32 c = 0;
139  for (list.first(ptr); c < limit && !ptr.isNull(); c++, list.next(ptr))
140  {
141  ndbout << ptr << " ";
142  }
143  if (c == limit)
144  {
145  ndbout << "MAXLIMIT ";
146  }
147  ndbout_c(" ");
148  }
149 
150  if (alloc.m_curr_extent_info_ptr_i != RNIL)
151  {
152  Ptr<Extent_info> ptr;
153  c_extent_pool.getPtr(ptr, alloc.m_curr_extent_info_ptr_i);
154  ndbout << "current extent: " << ptr << endl;
155  }
156 }
157 
158 #if defined VM_TRACE || 1
159 #define ddassert(x) do { if(unlikely(!(x))) { dump_disk_alloc(alloc); ndbrequire(false); } } while(0)
160 #else
161 #define ddassert(x)
162 #endif
163 
164 Dbtup::Disk_alloc_info::Disk_alloc_info(const Tablerec* tabPtrP,
165  Uint32 extent_size)
166 {
167  m_extent_size = extent_size;
168  m_curr_extent_info_ptr_i = RNIL;
169  if (tabPtrP->m_no_of_disk_attributes == 0)
170  return;
171 
172  Uint32 min_size= 4*tabPtrP->m_offsets[DD].m_fix_header_size;
173 
174  if (tabPtrP->m_attributes[DD].m_no_of_varsize == 0)
175  {
176  Uint32 recs_per_page= (4*Tup_fixsize_page::DATA_WORDS)/min_size;
177  m_page_free_bits_map[0] = recs_per_page; // 100% free
178  m_page_free_bits_map[1] = 1;
179  m_page_free_bits_map[2] = 0;
180  m_page_free_bits_map[3] = 0;
181 
182  Uint32 max= recs_per_page * extent_size;
183  for(Uint32 i = 0; i<EXTENT_SEARCH_MATRIX_ROWS; i++)
184  {
185  m_total_extent_free_space_thresholds[i] =
186  (EXTENT_SEARCH_MATRIX_ROWS - i - 1)*max/EXTENT_SEARCH_MATRIX_ROWS;
187  }
188  }
189  else
190  {
191  abort();
192  }
193 }
194 
195 Uint32
197 {
203  Uint32 col = calc_page_free_bits(sz);
204  Uint32 mask= EXTENT_SEARCH_MATRIX_COLS - 1;
205  for(Uint32 i= 0; i<EXTENT_SEARCH_MATRIX_SIZE; i++)
206  {
207  // Check that it can cater for request
208  if (!m_free_extents[i].isEmpty())
209  {
210  return i;
211  }
212 
213  if ((i & mask) >= col)
214  {
215  i = (i & ~mask) + mask;
216  }
217  }
218 
219  return RNIL;
220 }
221 
222 Uint32
224 {
225  Uint32 free= extP->m_free_space;
226  Uint32 mask= EXTENT_SEARCH_MATRIX_COLS - 1;
227 
228  Uint32 col= 0, row=0;
229 
235  {
236  const Uint32 *arr= m_total_extent_free_space_thresholds;
237  for(; free < * arr++; row++)
238  assert(row < EXTENT_SEARCH_MATRIX_ROWS);
239  }
240 
244  {
245  const Uint16 *arr= extP->m_free_page_count;
246  for(; col < EXTENT_SEARCH_MATRIX_COLS && * arr++ == 0; col++);
247  }
248 
258  Uint32 pos= (row * (mask + 1)) + (col & mask);
259 
260  assert(pos < EXTENT_SEARCH_MATRIX_SIZE);
261  return pos;
262 }
263 
264 void
265 Dbtup::update_extent_pos(Disk_alloc_info& alloc,
266  Ptr<Extent_info> extentPtr,
267  Int32 delta)
268 {
269  if (delta < 0)
270  {
271  jam();
272  Uint32 sub = Uint32(- delta);
273  ddassert(extentPtr.p->m_free_space >= sub);
274  extentPtr.p->m_free_space -= sub;
275  }
276  else
277  {
278  jam();
279  extentPtr.p->m_free_space += delta;
280  ndbassert(Uint32(delta) <= alloc.calc_page_free_space(0));
281  }
282 
283 #ifdef VM_TRACE
284  Uint32 cnt = 0;
285  Uint32 sum = 0;
286  for(Uint32 i = 0; i<MAX_FREE_LIST; i++)
287  {
288  cnt += extentPtr.p->m_free_page_count[i];
289  sum += extentPtr.p->m_free_page_count[i] * alloc.calc_page_free_space(i);
290  }
291  if (extentPtr.p->m_free_page_count[0] == cnt)
292  {
293  ddassert(extentPtr.p->m_free_space == cnt*alloc.m_page_free_bits_map[0]);
294  }
295  else
296  {
297  ddassert(extentPtr.p->m_free_space < cnt*alloc.m_page_free_bits_map[0]);
298  }
299  ddassert(extentPtr.p->m_free_space >= sum);
300  ddassert(extentPtr.p->m_free_space <= cnt*alloc.m_page_free_bits_map[0]);
301 #endif
302 
303  Uint32 old = extentPtr.p->m_free_matrix_pos;
304  if (old != RNIL)
305  {
306  Uint32 pos = alloc.calc_extent_pos(extentPtr.p);
307  if (old != pos)
308  {
309  jam();
310  Local_extent_info_list old_list(c_extent_pool, alloc.m_free_extents[old]);
311  Local_extent_info_list new_list(c_extent_pool, alloc.m_free_extents[pos]);
312  old_list.remove(extentPtr);
313  new_list.add(extentPtr);
314  extentPtr.p->m_free_matrix_pos= pos;
315  }
316  }
317  else
318  {
319  ddassert(alloc.m_curr_extent_info_ptr_i == extentPtr.i);
320  }
321 }
322 
323 void
324 Dbtup::restart_setup_page(Disk_alloc_info& alloc, PagePtr pagePtr,
325  Int32 estimate)
326 {
327  jam();
331  pagePtr.p->uncommitted_used_space = 0;
332  pagePtr.p->m_restart_seq = globalData.m_restart_seq;
333 
334  Extent_info key;
335  key.m_key.m_file_no = pagePtr.p->m_file_no;
336  key.m_key.m_page_idx = pagePtr.p->m_extent_no;
337  Ptr<Extent_info> extentPtr;
338  ndbrequire(c_extent_hash.find(extentPtr, key));
339  pagePtr.p->m_extent_info_ptr = extentPtr.i;
340 
341  Uint32 real_free = pagePtr.p->free_space;
342  const bool prealloc = estimate >= 0;
343  Uint32 estimated;
344  if (prealloc)
345  {
346  jam();
350  estimated = (Uint32)estimate;
351  }
352  else
353  {
354  jam();
358  estimated =alloc.calc_page_free_space(alloc.calc_page_free_bits(real_free));
359  }
360 
361 #ifdef VM_TRACE
362  {
363  Local_key page;
364  page.m_file_no = pagePtr.p->m_file_no;
365  page.m_page_no = pagePtr.p->m_page_no;
366 
367  D("Tablespace_client - restart_setup_page");
368  Tablespace_client tsman(0, this, c_tsman,
369  0, 0, 0);
370  unsigned uncommitted, committed;
371  uncommitted = committed = ~(unsigned)0;
372  (void) tsman.get_page_free_bits(&page, &uncommitted, &committed);
373  jamEntry();
374 
375  ddassert(alloc.calc_page_free_bits(real_free) == committed);
376  if (prealloc)
377  {
382  ddassert(uncommitted == MAX_FREE_LIST - 1);
383  }
384  else
385  {
386  ddassert(committed == uncommitted);
387  }
388  }
389 #endif
390 
391  ddassert(real_free >= estimated);
392 
393  if (real_free != estimated)
394  {
395  jam();
396  Uint32 delta = (real_free-estimated);
397  update_extent_pos(alloc, extentPtr, delta);
398  }
399 }
400 
410 #define DBG_DISK 0
411 
412 int
413 Dbtup::disk_page_prealloc(Signal* signal,
414  Ptr<Fragrecord> fragPtr,
415  Local_key* key, Uint32 sz)
416 {
417  int err;
418  Uint32 i, ptrI;
419  Ptr<Page_request> req;
420  Fragrecord* fragPtrP = fragPtr.p;
421  Disk_alloc_info& alloc= fragPtrP->m_disk_alloc_info;
422  Uint32 idx= alloc.calc_page_free_bits(sz);
423  D("Tablespace_client - disk_page_prealloc");
424  Tablespace_client tsman(signal, this, c_tsman,
425  fragPtrP->fragTableId,
426  fragPtrP->fragmentId,
427  fragPtrP->m_tablespace_id);
428 
429  if (DBG_DISK)
430  ndbout << "disk_page_prealloc";
431 
435  for(i= 0; i <= idx; i++)
436  {
437  if (!alloc.m_dirty_pages[i].isEmpty())
438  {
439  ptrI= alloc.m_dirty_pages[i].firstItem;
440  Ptr<GlobalPage> gpage;
441  m_global_page_pool.getPtr(gpage, ptrI);
442 
443  PagePtr tmp;
444  tmp.i = gpage.i;
445  tmp.p = reinterpret_cast<Page*>(gpage.p);
446  disk_page_prealloc_dirty_page(alloc, tmp, i, sz);
447  key->m_page_no= tmp.p->m_page_no;
448  key->m_file_no= tmp.p->m_file_no;
449  if (DBG_DISK)
450  ndbout << " found dirty page " << *key << endl;
451  jam();
452  return 0; // Page in memory
453  }
454  }
455 
461  for(i= 0; i <= idx; i++)
462  {
463  if (!alloc.m_page_requests[i].isEmpty())
464  {
465  ptrI= alloc.m_page_requests[i].firstItem;
466  Ptr<Page_request> req;
467  c_page_request_pool.getPtr(req, ptrI);
468 
469  disk_page_prealloc_transit_page(alloc, req, i, sz);
470  * key = req.p->m_key;
471  if (DBG_DISK)
472  ndbout << " found transit page " << *key << endl;
473  jam();
474  return 0;
475  }
476  }
477 
481  if (!c_page_request_pool.seize(req))
482  {
483  jam();
484  err= 1;
485  //XXX set error code
486  ndbout_c("no free request");
487  return -err;
488  }
489 
490  req.p->m_ref_count= 1;
491  req.p->m_frag_ptr_i= fragPtr.i;
492  req.p->m_uncommitted_used_space= sz;
493 
494  int pageBits; // received
495  Ptr<Extent_info> ext;
496  const Uint32 bits= alloc.calc_page_free_bits(sz); // required
497  bool found= false;
498 
502  if ((ext.i= alloc.m_curr_extent_info_ptr_i) != RNIL)
503  {
504  jam();
505  c_extent_pool.getPtr(ext);
506  if ((pageBits= tsman.alloc_page_from_extent(&ext.p->m_key, bits)) >= 0)
507  {
508  jamEntry();
509  found= true;
510  }
511  else
512  {
513  jamEntry();
519  alloc.m_curr_extent_info_ptr_i = RNIL;
520  Uint32 pos= alloc.calc_extent_pos(ext.p);
521  ext.p->m_free_matrix_pos = pos;
522  Local_extent_info_list list(c_extent_pool, alloc.m_free_extents[pos]);
523  list.add(ext);
524  }
525  }
526 
527  if (!found)
528  {
529  Uint32 pos;
530  if ((pos= alloc.find_extent(sz)) != RNIL)
531  {
532  jam();
533  Local_extent_info_list list(c_extent_pool, alloc.m_free_extents[pos]);
534  list.first(ext);
535  list.remove(ext);
536  }
537  else
538  {
539  jam();
543 #if NOT_YET_UNDO_ALLOC_EXTENT
544  Uint32 logfile_group_id = fragPtr.p->m_logfile_group_id;
545 
546  err = c_lgman->alloc_log_space(logfile_group_id,
547  sizeof(Disk_undo::AllocExtent)>>2);
548  jamEntry();
549  if(unlikely(err))
550  {
551  return -err;
552  }
553 #endif
554 
555  if (!c_extent_pool.seize(ext))
556  {
557  jam();
558  //XXX
559  err= 2;
560 #if NOT_YET_UNDO_ALLOC_EXTENT
561  c_lgman->free_log_space(logfile_group_id,
562  sizeof(Disk_undo::AllocExtent)>>2);
563 #endif
564  c_page_request_pool.release(req);
565  ndbout_c("no free extent info");
566  return -err;
567  }
568 
569  if ((err= tsman.alloc_extent(&ext.p->m_key)) < 0)
570  {
571  jamEntry();
572 #if NOT_YET_UNDO_ALLOC_EXTENT
573  c_lgman->free_log_space(logfile_group_id,
574  sizeof(Disk_undo::AllocExtent)>>2);
575 #endif
576  c_extent_pool.release(ext);
577  c_page_request_pool.release(req);
578  return err;
579  }
580 
581  int pages= err;
582 #if NOT_YET_UNDO_ALLOC_EXTENT
583  {
587  {
588  Callback cb;
589  cb.m_callbackData= ext.i;
590  cb.m_callbackFunction =
591  safe_cast(&Dbtup::disk_page_alloc_extent_log_buffer_callback);
592  Uint32 sz= sizeof(Disk_undo::AllocExtent)>>2;
593 
594  Logfile_client lgman(this, c_lgman, logfile_group_id);
595  int res= lgman.get_log_buffer(signal, sz, &cb);
596  jamEntry();
597  switch(res){
598  case 0:
599  break;
600  case -1:
601  ndbrequire("NOT YET IMPLEMENTED" == 0);
602  break;
603  default:
604  execute(signal, cb, res);
605  }
606  }
607  }
608 #endif
609 
610 #ifdef VM_TRACE
611  ndbout << "allocated " << pages << " pages: " << ext.p->m_key
612  << " table: " << fragPtr.p->fragTableId
613  << " fragment: " << fragPtr.p->fragmentId << endl;
614 #endif
615  ext.p->m_first_page_no = ext.p->m_key.m_page_no;
616  memset(ext.p->m_free_page_count, 0, sizeof(ext.p->m_free_page_count));
617  ext.p->m_free_space= alloc.m_page_free_bits_map[0] * pages;
618  ext.p->m_free_page_count[0]= pages; // All pages are "free"-est
619  ext.p->m_empty_page_no = 0;
620  c_extent_hash.add(ext);
621 
622  Local_fragment_extent_list list1(c_extent_pool, alloc.m_extent_list);
623  list1.add(ext);
624  }
625 
626  alloc.m_curr_extent_info_ptr_i= ext.i;
627  ext.p->m_free_matrix_pos= RNIL;
628  pageBits= tsman.alloc_page_from_extent(&ext.p->m_key, bits);
629  jamEntry();
630  ddassert(pageBits >= 0);
631  }
632 
636  *key= req.p->m_key= ext.p->m_key;
637 
638  if (DBG_DISK)
639  ndbout << " allocated page " << *key << endl;
640 
646  Uint32 size= alloc.calc_page_free_space((Uint32)pageBits);
647 
648  ddassert(size >= sz);
649  req.p->m_original_estimated_free_space = size;
650 
651  Uint32 new_size = size - sz; // Subtract alloc rec
652  Uint32 newPageBits= alloc.calc_page_free_bits(new_size);
653  if (newPageBits != (Uint32)pageBits)
654  {
655  jam();
656  ddassert(ext.p->m_free_page_count[pageBits] > 0);
657  ext.p->m_free_page_count[pageBits]--;
658  ext.p->m_free_page_count[newPageBits]++;
659  }
660  update_extent_pos(alloc, ext, -Int32(sz));
661 
662  // And put page request in correct free list
663  idx= alloc.calc_page_free_bits(new_size);
664  {
665  Local_page_request_list list(c_page_request_pool,
666  alloc.m_page_requests[idx]);
667 
668  list.add(req);
669  }
670  req.p->m_list_index= idx;
671  req.p->m_extent_info_ptr= ext.i;
672 
674  preq.m_page = *key;
675  preq.m_callback.m_callbackData= req.i;
676  preq.m_callback.m_callbackFunction =
677  safe_cast(&Dbtup::disk_page_prealloc_callback);
678 
679  int flags= Page_cache_client::ALLOC_REQ;
680  if (pageBits == 0)
681  {
682  jam();
683 
684  if (ext.p->m_first_page_no + ext.p->m_empty_page_no == key->m_page_no)
685  {
686  jam();
687  flags |= Page_cache_client::EMPTY_PAGE;
688  //ndbout << "EMPTY_PAGE " << ext.p->m_empty_page_no << " " << *key << endl;
689  ext.p->m_empty_page_no++;
690  }
691 
692  preq.m_callback.m_callbackFunction =
693  safe_cast(&Dbtup::disk_page_prealloc_initial_callback);
694  }
695 
696  Page_cache_client pgman(this, c_pgman);
697  int res= pgman.get_page(signal, preq, flags);
698  m_pgman_ptr = pgman.m_ptr;
699  jamEntry();
700  switch(res)
701  {
702  case 0:
703  jam();
704  break;
705  case -1:
706  ndbassert(false);
707  break;
708  default:
709  jam();
710  execute(signal, preq.m_callback, res); // run callback
711  }
712 
713  return res;
714 }
715 
716 void
717 Dbtup::disk_page_prealloc_dirty_page(Disk_alloc_info & alloc,
718  PagePtr pagePtr,
719  Uint32 old_idx, Uint32 sz)
720 {
721  jam();
722  ddassert(pagePtr.p->list_index == old_idx);
723 
724  Uint32 free= pagePtr.p->free_space;
725  Uint32 used= pagePtr.p->uncommitted_used_space + sz;
726  Uint32 ext= pagePtr.p->m_extent_info_ptr;
727 
728  ddassert(free >= used);
729  Ptr<Extent_info> extentPtr;
730  c_extent_pool.getPtr(extentPtr, ext);
731 
732  Uint32 new_idx= alloc.calc_page_free_bits(free - used);
733 
734  if (old_idx != new_idx)
735  {
736  jam();
737  disk_page_move_dirty_page(alloc, extentPtr, pagePtr, old_idx, new_idx);
738  }
739 
740  pagePtr.p->uncommitted_used_space = used;
741  update_extent_pos(alloc, extentPtr, -Int32(sz));
742 }
743 
744 
745 void
746 Dbtup::disk_page_prealloc_transit_page(Disk_alloc_info& alloc,
747  Ptr<Page_request> req,
748  Uint32 old_idx, Uint32 sz)
749 {
750  jam();
751  ddassert(req.p->m_list_index == old_idx);
752 
753  Uint32 free= req.p->m_original_estimated_free_space;
754  Uint32 used= req.p->m_uncommitted_used_space + sz;
755  Uint32 ext= req.p->m_extent_info_ptr;
756 
757  Ptr<Extent_info> extentPtr;
758  c_extent_pool.getPtr(extentPtr, ext);
759 
760  ddassert(free >= used);
761  Uint32 new_idx= alloc.calc_page_free_bits(free - used);
762 
763  if (old_idx != new_idx)
764  {
765  jam();
766  disk_page_move_page_request(alloc, extentPtr, req, old_idx, new_idx);
767  }
768 
769  req.p->m_uncommitted_used_space = used;
770  update_extent_pos(alloc, extentPtr, -Int32(sz));
771 }
772 
773 void
774 Dbtup::disk_page_prealloc_callback(Signal* signal,
775  Uint32 page_request, Uint32 page_id)
776 {
777  jamEntry();
778  //ndbout_c("disk_alloc_page_callback id: %d", page_id);
779 
780  Ptr<Page_request> req;
781  c_page_request_pool.getPtr(req, page_request);
782 
783  Ptr<GlobalPage> gpage;
784  m_global_page_pool.getPtr(gpage, page_id);
785 
786  Ptr<Fragrecord> fragPtr;
787  fragPtr.i= req.p->m_frag_ptr_i;
788  ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
789 
790  PagePtr pagePtr;
791  pagePtr.i = gpage.i;
792  pagePtr.p = reinterpret_cast<Page*>(gpage.p);
793 
794  Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info;
795  if (unlikely(pagePtr.p->m_restart_seq != globalData.m_restart_seq))
796  {
797  jam();
798  D(V(pagePtr.p->m_restart_seq) << V(globalData.m_restart_seq));
799  restart_setup_page(alloc, pagePtr, req.p->m_original_estimated_free_space);
800  }
801 
802  Ptr<Extent_info> extentPtr;
803  c_extent_pool.getPtr(extentPtr, req.p->m_extent_info_ptr);
804 
805  pagePtr.p->uncommitted_used_space += req.p->m_uncommitted_used_space;
806  ddassert(pagePtr.p->free_space >= pagePtr.p->uncommitted_used_space);
807 
808  Uint32 free = pagePtr.p->free_space - pagePtr.p->uncommitted_used_space;
809  Uint32 idx = req.p->m_list_index;
810  Uint32 real_idx = alloc.calc_page_free_bits(free);
811 
812  if (idx != real_idx)
813  {
814  jam();
815  ddassert(extentPtr.p->m_free_page_count[idx]);
816  extentPtr.p->m_free_page_count[idx]--;
817  extentPtr.p->m_free_page_count[real_idx]++;
818  update_extent_pos(alloc, extentPtr, 0);
819  }
820 
821  {
825  pagePtr.p->list_index = real_idx;
826  ArrayPool<Page> *cheat_pool= (ArrayPool<Page>*)&m_global_page_pool;
827  LocalDLList<Page> list(* cheat_pool, alloc.m_dirty_pages[real_idx]);
828  list.add(pagePtr);
829  }
830 
831  {
835  Local_page_request_list list(c_page_request_pool,
836  alloc.m_page_requests[idx]);
837  list.release(req);
838  }
839 }
840 
841 void
842 Dbtup::disk_page_move_dirty_page(Disk_alloc_info& alloc,
843  Ptr<Extent_info> extentPtr,
844  Ptr<Page> pagePtr,
845  Uint32 old_idx,
846  Uint32 new_idx)
847 {
848  ddassert(extentPtr.p->m_free_page_count[old_idx]);
849  extentPtr.p->m_free_page_count[old_idx]--;
850  extentPtr.p->m_free_page_count[new_idx]++;
851 
852  ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool;
853  LocalDLList<Page> new_list(*pool, alloc.m_dirty_pages[new_idx]);
854  LocalDLList<Page> old_list(*pool, alloc.m_dirty_pages[old_idx]);
855  old_list.remove(pagePtr);
856  new_list.add(pagePtr);
857  pagePtr.p->list_index = new_idx;
858 }
859 
860 void
861 Dbtup::disk_page_move_page_request(Disk_alloc_info& alloc,
862  Ptr<Extent_info> extentPtr,
863  Ptr<Page_request> req,
864  Uint32 old_idx, Uint32 new_idx)
865 {
866  Page_request_list::Head *lists = alloc.m_page_requests;
867  Local_page_request_list old_list(c_page_request_pool, lists[old_idx]);
868  Local_page_request_list new_list(c_page_request_pool, lists[new_idx]);
869  old_list.remove(req);
870  new_list.add(req);
871 
872  ddassert(extentPtr.p->m_free_page_count[old_idx]);
873  extentPtr.p->m_free_page_count[old_idx]--;
874  extentPtr.p->m_free_page_count[new_idx]++;
875  req.p->m_list_index= new_idx;
876 }
877 
878 void
879 Dbtup::disk_page_prealloc_initial_callback(Signal*signal,
880  Uint32 page_request,
881  Uint32 page_id)
882 {
883  jamEntry();
884  //ndbout_c("disk_alloc_page_callback_initial id: %d", page_id);
892  Ptr<Page_request> req;
893  c_page_request_pool.getPtr(req, page_request);
894 
895  Ptr<GlobalPage> gpage;
896  m_global_page_pool.getPtr(gpage, page_id);
897  PagePtr pagePtr;
898  pagePtr.i = gpage.i;
899  pagePtr.p = reinterpret_cast<Page*>(gpage.p);
900 
901  Ptr<Fragrecord> fragPtr;
902  fragPtr.i= req.p->m_frag_ptr_i;
903  ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
904 
905  Ptr<Tablerec> tabPtr;
906  tabPtr.i = fragPtr.p->fragTableId;
907  ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
908 
909  Ptr<Extent_info> extentPtr;
910  c_extent_pool.getPtr(extentPtr, req.p->m_extent_info_ptr);
911 
912  if (tabPtr.p->m_attributes[DD].m_no_of_varsize == 0)
913  {
914  convertThPage((Fix_page*)pagePtr.p, tabPtr.p, DD);
915  }
916  else
917  {
918  abort();
919  }
920 
921  pagePtr.p->m_page_no= req.p->m_key.m_page_no;
922  pagePtr.p->m_file_no= req.p->m_key.m_file_no;
923  pagePtr.p->m_table_id= fragPtr.p->fragTableId;
924  pagePtr.p->m_fragment_id = fragPtr.p->fragmentId;
925  pagePtr.p->m_extent_no = extentPtr.p->m_key.m_page_idx; // logical extent no
926  pagePtr.p->m_extent_info_ptr= req.p->m_extent_info_ptr;
927  pagePtr.p->m_restart_seq = globalData.m_restart_seq;
928  pagePtr.p->nextList = pagePtr.p->prevList = RNIL;
929  pagePtr.p->list_index = req.p->m_list_index;
930  pagePtr.p->uncommitted_used_space = req.p->m_uncommitted_used_space;
931 
932  Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info;
933  Uint32 idx = req.p->m_list_index;
934 
935  {
936  Uint32 free = pagePtr.p->free_space - pagePtr.p->uncommitted_used_space;
937  ddassert(idx == alloc.calc_page_free_bits(free));
938  ddassert(pagePtr.p->free_space == req.p->m_original_estimated_free_space);
939  }
940 
941  {
945  ArrayPool<Page> *cheat_pool= (ArrayPool<Page>*)&m_global_page_pool;
946  LocalDLList<Page> list(* cheat_pool, alloc.m_dirty_pages[idx]);
947  list.add(pagePtr);
948  }
949 
950  {
954  Local_page_request_list list(c_page_request_pool,
955  alloc.m_page_requests[idx]);
956  list.release(req);
957  }
958 }
959 
960 void
961 Dbtup::disk_page_set_dirty(PagePtr pagePtr)
962 {
963  jam();
964  Uint32 idx = pagePtr.p->list_index;
965  if ((pagePtr.p->m_restart_seq == globalData.m_restart_seq) &&
966  ((idx & 0x8000) == 0))
967  {
968  jam();
972  return ;
973  }
974 
975  Local_key key;
976  key.m_page_no = pagePtr.p->m_page_no;
977  key.m_file_no = pagePtr.p->m_file_no;
978 
979  pagePtr.p->nextList = pagePtr.p->prevList = RNIL;
980 
981  if (DBG_DISK)
982  ndbout << " disk_page_set_dirty " << key << endl;
983 
984  Ptr<Tablerec> tabPtr;
985  tabPtr.i= pagePtr.p->m_table_id;
986  ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
987 
988  Ptr<Fragrecord> fragPtr;
989  getFragmentrec(fragPtr, pagePtr.p->m_fragment_id, tabPtr.p);
990 
991  Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info;
992 
993  Uint32 free = pagePtr.p->free_space;
994  Uint32 used = pagePtr.p->uncommitted_used_space;
995  if (unlikely(pagePtr.p->m_restart_seq != globalData.m_restart_seq))
996  {
997  jam();
998  D(V(pagePtr.p->m_restart_seq) << V(globalData.m_restart_seq));
999  restart_setup_page(alloc, pagePtr, -1);
1000  ndbassert(free == pagePtr.p->free_space);
1001  idx = alloc.calc_page_free_bits(free);
1002  used = 0;
1003  }
1004  else
1005  {
1006  jam();
1007  idx &= ~0x8000;
1008  ddassert(idx == alloc.calc_page_free_bits(free - used));
1009  }
1010 
1011  ddassert(free >= used);
1012 
1013  D("Tablespace_client - disk_page_set_dirty");
1014  Tablespace_client tsman(0, this, c_tsman,
1015  fragPtr.p->fragTableId,
1016  fragPtr.p->fragmentId,
1017  fragPtr.p->m_tablespace_id);
1018 
1019  pagePtr.p->list_index = idx;
1020  ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool;
1021  LocalDLList<Page> list(*pool, alloc.m_dirty_pages[idx]);
1022  list.add(pagePtr);
1023 
1024  // Make sure no one will allocate it...
1025  tsman.unmap_page(&key, MAX_FREE_LIST - 1);
1026  jamEntry();
1027 }
1028 
1029 void
1031  Uint32 page_id, Uint32 dirty_count)
1032 {
1033  jamEntry();
1034  Ptr<GlobalPage> gpage;
1035  m_global_page_pool.getPtr(gpage, page_id);
1036  PagePtr pagePtr;
1037  pagePtr.i = gpage.i;
1038  pagePtr.p = reinterpret_cast<Page*>(gpage.p);
1039 
1040  Uint32 type = pagePtr.p->m_page_header.m_page_type;
1041  if (unlikely((type != File_formats::PT_Tup_fixsize_page &&
1042  type != File_formats::PT_Tup_varsize_page) ||
1043  f_undo_done == false))
1044  {
1045  jam();
1046  D("disk_page_unmap_callback" << V(type) << V(f_undo_done));
1047  return ;
1048  }
1049 
1050  Uint32 idx = pagePtr.p->list_index;
1051 
1052  Ptr<Tablerec> tabPtr;
1053  tabPtr.i= pagePtr.p->m_table_id;
1054  ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
1055 
1056  Ptr<Fragrecord> fragPtr;
1057  getFragmentrec(fragPtr, pagePtr.p->m_fragment_id, tabPtr.p);
1058 
1059  Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info;
1060 
1061  if (when == 0)
1062  {
1066  jam();
1067 
1068  if (DBG_DISK)
1069  {
1070  Local_key key;
1071  key.m_page_no = pagePtr.p->m_page_no;
1072  key.m_file_no = pagePtr.p->m_file_no;
1073  ndbout << "disk_page_unmap_callback(before) " << key
1074  << " cnt: " << dirty_count << " " << (idx & ~0x8000) << endl;
1075  }
1076 
1077  ndbassert((idx & 0x8000) == 0);
1078 
1079  ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool;
1080  LocalDLList<Page> list(*pool, alloc.m_dirty_pages[idx]);
1081  LocalDLList<Page> list2(*pool, alloc.m_unmap_pages);
1082  list.remove(pagePtr);
1083  list2.add(pagePtr);
1084 
1085  if (dirty_count == 0)
1086  {
1087  jam();
1088  pagePtr.p->list_index = idx | 0x8000;
1089 
1090  Local_key key;
1091  key.m_page_no = pagePtr.p->m_page_no;
1092  key.m_file_no = pagePtr.p->m_file_no;
1093 
1094  Uint32 free = pagePtr.p->free_space;
1095  Uint32 used = pagePtr.p->uncommitted_used_space;
1096  ddassert(free >= used);
1097  ddassert(alloc.calc_page_free_bits(free - used) == idx);
1098 
1099  D("Tablespace_client - disk_page_unmap_callback");
1100  Tablespace_client tsman(0, this, c_tsman,
1101  fragPtr.p->fragTableId,
1102  fragPtr.p->fragmentId,
1103  fragPtr.p->m_tablespace_id);
1104 
1105  tsman.unmap_page(&key, idx);
1106  jamEntry();
1107  }
1108  }
1109  else if (when == 1)
1110  {
1114  jam();
1115 
1116  Local_key key;
1117  key.m_page_no = pagePtr.p->m_page_no;
1118  key.m_file_no = pagePtr.p->m_file_no;
1119  Uint32 real_free = pagePtr.p->free_space;
1120 
1121  if (DBG_DISK)
1122  {
1123  ndbout << "disk_page_unmap_callback(after) " << key
1124  << " cnt: " << dirty_count << " " << (idx & ~0x8000) << endl;
1125  }
1126 
1127  ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool;
1128  LocalDLList<Page> list(*pool, alloc.m_unmap_pages);
1129  list.remove(pagePtr);
1130 
1131  D("Tablespace_client - disk_page_unmap_callback");
1132  Tablespace_client tsman(0, this, c_tsman,
1133  fragPtr.p->fragTableId,
1134  fragPtr.p->fragmentId,
1135  fragPtr.p->m_tablespace_id);
1136 
1137  if (DBG_DISK && alloc.calc_page_free_bits(real_free) != (idx & ~0x8000))
1138  {
1139  ndbout << key
1140  << " calc: " << alloc.calc_page_free_bits(real_free)
1141  << " idx: " << (idx & ~0x8000)
1142  << endl;
1143  }
1144  tsman.update_page_free_bits(&key, alloc.calc_page_free_bits(real_free));
1145  jamEntry();
1146  }
1147 }
1148 
1149 void
1150 Dbtup::disk_page_alloc(Signal* signal,
1151  Tablerec* tabPtrP, Fragrecord* fragPtrP,
1152  Local_key* key, PagePtr pagePtr, Uint32 gci)
1153 {
1154  jam();
1155  Uint32 logfile_group_id= fragPtrP->m_logfile_group_id;
1156  Disk_alloc_info& alloc= fragPtrP->m_disk_alloc_info;
1157 
1158  Uint64 lsn;
1159  if (tabPtrP->m_attributes[DD].m_no_of_varsize == 0)
1160  {
1161  ddassert(pagePtr.p->uncommitted_used_space > 0);
1162  pagePtr.p->uncommitted_used_space--;
1163  key->m_page_idx= ((Fix_page*)pagePtr.p)->alloc_record();
1164  lsn= disk_page_undo_alloc(pagePtr.p, key, 1, gci, logfile_group_id);
1165  }
1166  else
1167  {
1168  Uint32 sz= key->m_page_idx;
1169  ddassert(pagePtr.p->uncommitted_used_space >= sz);
1170  pagePtr.p->uncommitted_used_space -= sz;
1171  key->m_page_idx= ((Var_page*)pagePtr.p)->
1172  alloc_record(sz, (Var_page*)ctemp_page, 0);
1173 
1174  lsn= disk_page_undo_alloc(pagePtr.p, key, sz, gci, logfile_group_id);
1175  }
1176 }
1177 
1178 void
1179 Dbtup::disk_page_free(Signal *signal,
1180  Tablerec *tabPtrP, Fragrecord * fragPtrP,
1181  Local_key* key, PagePtr pagePtr, Uint32 gci)
1182 {
1183  jam();
1184  if (DBG_DISK)
1185  ndbout << " disk_page_free " << *key << endl;
1186 
1187  Uint32 page_idx= key->m_page_idx;
1188  Uint32 logfile_group_id= fragPtrP->m_logfile_group_id;
1189  Disk_alloc_info& alloc= fragPtrP->m_disk_alloc_info;
1190  Uint32 old_free= pagePtr.p->free_space;
1191 
1192  Uint32 sz;
1193  Uint64 lsn;
1194  if (tabPtrP->m_attributes[DD].m_no_of_varsize == 0)
1195  {
1196  sz = 1;
1197  const Uint32 *src= ((Fix_page*)pagePtr.p)->get_ptr(page_idx, 0);
1198  ndbassert(* (src + 1) != Tup_fixsize_page::FREE_RECORD);
1199  lsn= disk_page_undo_free(pagePtr.p, key,
1200  src, tabPtrP->m_offsets[DD].m_fix_header_size,
1201  gci, logfile_group_id);
1202 
1203  ((Fix_page*)pagePtr.p)->free_record(page_idx);
1204  }
1205  else
1206  {
1207  const Uint32 *src= ((Var_page*)pagePtr.p)->get_ptr(page_idx);
1208  sz= ((Var_page*)pagePtr.p)->get_entry_len(page_idx);
1209  lsn= disk_page_undo_free(pagePtr.p, key,
1210  src, sz,
1211  gci, logfile_group_id);
1212 
1213  ((Var_page*)pagePtr.p)->free_record(page_idx, 0);
1214  }
1215 
1216  Uint32 new_free = pagePtr.p->free_space;
1217 
1218  Uint32 ext = pagePtr.p->m_extent_info_ptr;
1219  Uint32 used = pagePtr.p->uncommitted_used_space;
1220  Uint32 old_idx = pagePtr.p->list_index;
1221  ddassert(old_free >= used);
1222  ddassert(new_free >= used);
1223  ddassert(new_free >= old_free);
1224  ddassert((old_idx & 0x8000) == 0);
1225 
1226  Uint32 new_idx = alloc.calc_page_free_bits(new_free - used);
1227  ddassert(alloc.calc_page_free_bits(old_free - used) == old_idx);
1228 
1229  Ptr<Extent_info> extentPtr;
1230  c_extent_pool.getPtr(extentPtr, ext);
1231 
1232  if (old_idx != new_idx)
1233  {
1234  jam();
1235  disk_page_move_dirty_page(alloc, extentPtr, pagePtr, old_idx, new_idx);
1236  }
1237 
1238  update_extent_pos(alloc, extentPtr, sz);
1239 #if NOT_YET_FREE_EXTENT
1240  if (check_free(extentPtr.p) == 0)
1241  {
1242  ndbout_c("free: extent is free");
1243  }
1244 #endif
1245 }
1246 
1247 void
1248 Dbtup::disk_page_abort_prealloc(Signal *signal, Fragrecord* fragPtrP,
1249  Local_key* key, Uint32 sz)
1250 {
1251  jam();
1252 
1254  req.m_callback.m_callbackData= sz;
1255  req.m_callback.m_callbackFunction =
1256  safe_cast(&Dbtup::disk_page_abort_prealloc_callback);
1257 
1258  int flags= Page_cache_client::DIRTY_REQ;
1259  memcpy(&req.m_page, key, sizeof(Local_key));
1260 
1261  Page_cache_client pgman(this, c_pgman);
1262  int res= pgman.get_page(signal, req, flags);
1263  m_pgman_ptr = pgman.m_ptr;
1264  jamEntry();
1265  switch(res)
1266  {
1267  case 0:
1268  jam();
1269  break;
1270  case -1:
1271  ndbrequire(false);
1272  break;
1273  default:
1274  jam();
1275  Ptr<GlobalPage> gpage;
1276  m_global_page_pool.getPtr(gpage, (Uint32)res);
1277  PagePtr pagePtr;
1278  pagePtr.i = gpage.i;
1279  pagePtr.p = reinterpret_cast<Page*>(gpage.p);
1280 
1281  disk_page_abort_prealloc_callback_1(signal, fragPtrP, pagePtr, sz);
1282  }
1283 }
1284 
1285 void
1286 Dbtup::disk_page_abort_prealloc_callback(Signal* signal,
1287  Uint32 sz, Uint32 page_id)
1288 {
1289  //ndbout_c("disk_alloc_page_callback id: %d", page_id);
1290  jamEntry();
1291  Ptr<GlobalPage> gpage;
1292  m_global_page_pool.getPtr(gpage, page_id);
1293 
1294  PagePtr pagePtr;
1295  pagePtr.i = gpage.i;
1296  pagePtr.p = reinterpret_cast<Page*>(gpage.p);
1297 
1298  Ptr<Tablerec> tabPtr;
1299  tabPtr.i= pagePtr.p->m_table_id;
1300  ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
1301 
1302  Ptr<Fragrecord> fragPtr;
1303  getFragmentrec(fragPtr, pagePtr.p->m_fragment_id, tabPtr.p);
1304 
1305  disk_page_abort_prealloc_callback_1(signal, fragPtr.p, pagePtr, sz);
1306 }
1307 
1308 void
1309 Dbtup::disk_page_abort_prealloc_callback_1(Signal* signal,
1310  Fragrecord* fragPtrP,
1311  PagePtr pagePtr,
1312  Uint32 sz)
1313 {
1314  jam();
1315  disk_page_set_dirty(pagePtr);
1316 
1317  Disk_alloc_info& alloc= fragPtrP->m_disk_alloc_info;
1318 
1319  Ptr<Extent_info> extentPtr;
1320  c_extent_pool.getPtr(extentPtr, pagePtr.p->m_extent_info_ptr);
1321 
1322  Uint32 idx = pagePtr.p->list_index & 0x7FFF;
1323  Uint32 used = pagePtr.p->uncommitted_used_space;
1324  Uint32 free = pagePtr.p->free_space;
1325 
1326  ddassert(free >= used);
1327  ddassert(used >= sz);
1328  ddassert(alloc.calc_page_free_bits(free - used) == idx);
1329 
1330  pagePtr.p->uncommitted_used_space = used - sz;
1331 
1332  Uint32 new_idx = alloc.calc_page_free_bits(free - used + sz);
1333 
1334  if (idx != new_idx)
1335  {
1336  jam();
1337  disk_page_move_dirty_page(alloc, extentPtr, pagePtr, idx, new_idx);
1338  }
1339 
1340  update_extent_pos(alloc, extentPtr, sz);
1341 #if NOT_YET_FREE_EXTENT
1342  if (check_free(extentPtr.p) == 0)
1343  {
1344  ndbout_c("abort: extent is free");
1345  }
1346 #endif
1347 }
1348 
1349 #if NOT_YET_UNDO_ALLOC_EXTENT
1350 void
1351 Dbtup::disk_page_alloc_extent_log_buffer_callback(Signal* signal,
1352  Uint32 extentPtrI,
1353  Uint32 unused)
1354 {
1355  Ptr<Extent_info> extentPtr;
1356  c_extent_pool.getPtr(extentPtr, extentPtrI);
1357 
1358  Local_key key = extentPtr.p->m_key;
1359  Tablespace_client2 tsman(signal, c_tsman, &key);
1360 
1361  Ptr<Tablerec> tabPtr;
1362  tabPtr.i= tsman.m_table_id;
1363  ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
1364 
1365  Ptr<Fragrecord> fragPtr;
1366  getFragmentrec(fragPtr, tsman.m_fragment_id, tabPtr.p);
1367 
1368  Logfile_client lgman(this, c_lgman, fragPtr.p->m_logfile_group_id);
1369 
1370  Disk_undo::AllocExtent alloc;
1371  alloc.m_table = tabPtr.i;
1372  alloc.m_fragment = tsman.m_fragment_id;
1373  alloc.m_page_no = key.m_page_no;
1374  alloc.m_file_no = key.m_file_no;
1375  alloc.m_type_length = (Disk_undo::UNDO_ALLOC_EXTENT<<16)|(sizeof(alloc)>> 2);
1376 
1377  Logfile_client::Change c[1] = {{ &alloc, sizeof(alloc) >> 2 } };
1378 
1379  Uint64 lsn= lgman.add_entry(c, 1);
1380 
1381  tsman.update_lsn(&key, lsn);
1382  jamEntry();
1383 }
1384 #endif
1385 
1386 Uint64
1387 Dbtup::disk_page_undo_alloc(Page* page, const Local_key* key,
1388  Uint32 sz, Uint32 gci, Uint32 logfile_group_id)
1389 {
1390  jam();
1391  D("Logfile_client - disk_page_undo_alloc");
1392  Logfile_client lgman(this, c_lgman, logfile_group_id);
1393 
1394  Disk_undo::Alloc alloc;
1395  alloc.m_type_length= (Disk_undo::UNDO_ALLOC << 16) | (sizeof(alloc) >> 2);
1396  alloc.m_page_no = key->m_page_no;
1397  alloc.m_file_no_page_idx= key->m_file_no << 16 | key->m_page_idx;
1398 
1399  Logfile_client::Change c[1] = {{ &alloc, sizeof(alloc) >> 2 } };
1400 
1401  Uint64 lsn= lgman.add_entry(c, 1);
1402  jamEntry();
1403  Page_cache_client pgman(this, c_pgman);
1404  pgman.update_lsn(* key, lsn);
1405  jamEntry();
1406 
1407  return lsn;
1408 }
1409 
1410 Uint64
1411 Dbtup::disk_page_undo_update(Page* page, const Local_key* key,
1412  const Uint32* src, Uint32 sz,
1413  Uint32 gci, Uint32 logfile_group_id)
1414 {
1415  jam();
1416  D("Logfile_client - disk_page_undo_update");
1417  Logfile_client lgman(this, c_lgman, logfile_group_id);
1418 
1419  Disk_undo::Update update;
1420  update.m_page_no = key->m_page_no;
1421  update.m_file_no_page_idx= key->m_file_no << 16 | key->m_page_idx;
1422  update.m_gci= gci;
1423 
1424  update.m_type_length=
1425  (Disk_undo::UNDO_UPDATE << 16) | (sz + (sizeof(update) >> 2) - 1);
1426 
1427  Logfile_client::Change c[3] = {
1428  { &update, 3 },
1429  { src, sz },
1430  { &update.m_type_length, 1 }
1431  };
1432 
1433  ndbassert(4*(3 + sz + 1) == (sizeof(update) + 4*sz - 4));
1434 
1435  Uint64 lsn= lgman.add_entry(c, 3);
1436  jamEntry();
1437  Page_cache_client pgman(this, c_pgman);
1438  pgman.update_lsn(* key, lsn);
1439  jamEntry();
1440 
1441  return lsn;
1442 }
1443 
1444 Uint64
1445 Dbtup::disk_page_undo_free(Page* page, const Local_key* key,
1446  const Uint32* src, Uint32 sz,
1447  Uint32 gci, Uint32 logfile_group_id)
1448 {
1449  jam();
1450  D("Logfile_client - disk_page_undo_free");
1451  Logfile_client lgman(this, c_lgman, logfile_group_id);
1452 
1453  Disk_undo::Free free;
1454  free.m_page_no = key->m_page_no;
1455  free.m_file_no_page_idx= key->m_file_no << 16 | key->m_page_idx;
1456  free.m_gci= gci;
1457 
1458  free.m_type_length=
1459  (Disk_undo::UNDO_FREE << 16) | (sz + (sizeof(free) >> 2) - 1);
1460 
1461  Logfile_client::Change c[3] = {
1462  { &free, 3 },
1463  { src, sz },
1464  { &free.m_type_length, 1 }
1465  };
1466 
1467  ndbassert(4*(3 + sz + 1) == (sizeof(free) + 4*sz - 4));
1468 
1469  Uint64 lsn= lgman.add_entry(c, 3);
1470  jamEntry();
1471  Page_cache_client pgman(this, c_pgman);
1472  pgman.update_lsn(* key, lsn);
1473  jamEntry();
1474 
1475  return lsn;
1476 }
1477 
1478 #include <signaldata/LgmanContinueB.hpp>
1479 
1480 #define DBG_UNDO 0
1481 
1482 void
1483 Dbtup::disk_restart_undo(Signal* signal, Uint64 lsn,
1484  Uint32 type, const Uint32 * ptr, Uint32 len)
1485 {
1486  f_undo_done = false;
1487  f_undo.m_lsn= lsn;
1488  f_undo.m_ptr= ptr;
1489  f_undo.m_len= len;
1490  f_undo.m_type = type;
1491 
1493  switch(f_undo.m_type){
1494  case File_formats::Undofile::UNDO_LCP_FIRST:
1495  case File_formats::Undofile::UNDO_LCP:
1496  {
1497  jam();
1498  ndbrequire(len == 3);
1499  Uint32 lcp = ptr[0];
1500  Uint32 tableId = ptr[1] >> 16;
1501  Uint32 fragId = ptr[1] & 0xFFFF;
1502  disk_restart_undo_lcp(tableId, fragId, Fragrecord::UC_LCP, lcp);
1503  if (!isNdbMtLqh())
1504  disk_restart_undo_next(signal);
1505 
1506  if (DBG_UNDO)
1507  {
1508  ndbout_c("UNDO LCP %u (%u, %u)", lcp, tableId, fragId);
1509  }
1510  return;
1511  }
1512  case File_formats::Undofile::UNDO_TUP_ALLOC:
1513  {
1514  jam();
1516  preq.m_page.m_page_no = rec->m_page_no;
1517  preq.m_page.m_file_no = rec->m_file_no_page_idx >> 16;
1518  preq.m_page.m_page_idx = rec->m_file_no_page_idx & 0xFFFF;
1519  break;
1520  }
1521  case File_formats::Undofile::UNDO_TUP_UPDATE:
1522  {
1523  jam();
1525  preq.m_page.m_page_no = rec->m_page_no;
1526  preq.m_page.m_file_no = rec->m_file_no_page_idx >> 16;
1527  preq.m_page.m_page_idx = rec->m_file_no_page_idx & 0xFFFF;
1528  break;
1529  }
1530  case File_formats::Undofile::UNDO_TUP_FREE:
1531  {
1532  jam();
1534  preq.m_page.m_page_no = rec->m_page_no;
1535  preq.m_page.m_file_no = rec->m_file_no_page_idx >> 16;
1536  preq.m_page.m_page_idx = rec->m_file_no_page_idx & 0xFFFF;
1537  break;
1538  }
1539  case File_formats::Undofile::UNDO_TUP_CREATE:
1543  {
1544  jam();
1546  Ptr<Tablerec> tabPtr;
1547  tabPtr.i= rec->m_table;
1548  ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
1549  for(Uint32 i = 0; i<MAX_FRAG_PER_NODE; i++)
1550  if (tabPtr.p->fragrec[i] != RNIL)
1551  disk_restart_undo_lcp(tabPtr.i, tabPtr.p->fragid[i],
1552  Fragrecord::UC_CREATE, 0);
1553  if (!isNdbMtLqh())
1554  disk_restart_undo_next(signal);
1555 
1556  if (DBG_UNDO)
1557  {
1558  ndbout_c("UNDO CREATE (%u)", tabPtr.i);
1559  }
1560  return;
1561  }
1562  case File_formats::Undofile::UNDO_TUP_DROP:
1563  {
1564  jam();
1566  Ptr<Tablerec> tabPtr;
1567  tabPtr.i= rec->m_table;
1568  ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
1569  for(Uint32 i = 0; i<MAX_FRAG_PER_NODE; i++)
1570  if (tabPtr.p->fragrec[i] != RNIL)
1571  disk_restart_undo_lcp(tabPtr.i, tabPtr.p->fragid[i],
1572  Fragrecord::UC_CREATE, 0);
1573  if (!isNdbMtLqh())
1574  disk_restart_undo_next(signal);
1575 
1576  if (DBG_UNDO)
1577  {
1578  ndbout_c("UNDO DROP (%u)", tabPtr.i);
1579  }
1580  return;
1581  }
1582  case File_formats::Undofile::UNDO_TUP_ALLOC_EXTENT:
1583  jam();
1584  case File_formats::Undofile::UNDO_TUP_FREE_EXTENT:
1585  jam();
1586  disk_restart_undo_next(signal);
1587  return;
1588 
1589  case File_formats::Undofile::UNDO_END:
1590  jam();
1591  f_undo_done = true;
1592  return;
1593  default:
1594  ndbrequire(false);
1595  }
1596 
1597  f_undo.m_key = preq.m_page;
1598  preq.m_callback.m_callbackFunction =
1599  safe_cast(&Dbtup::disk_restart_undo_callback);
1600 
1601  int flags = 0;
1602  Page_cache_client pgman(this, c_pgman);
1603  int res= pgman.get_page(signal, preq, flags);
1604  m_pgman_ptr = pgman.m_ptr;
1605  jamEntry();
1606  switch(res)
1607  {
1608  case 0:
1609  break; // Wait for callback
1610  case -1:
1611  ndbrequire(false);
1612  break;
1613  default:
1614  execute(signal, preq.m_callback, res); // run callback
1615  }
1616 }
1617 
1618 void
1619 Dbtup::disk_restart_undo_next(Signal* signal)
1620 {
1621  signal->theData[0] = LgmanContinueB::EXECUTE_UNDO_RECORD;
1622  sendSignal(LGMAN_REF, GSN_CONTINUEB, signal, 1, JBB);
1623 }
1624 
1625 void
1626 Dbtup::disk_restart_lcp_id(Uint32 tableId, Uint32 fragId, Uint32 lcpId)
1627 {
1628  jamEntry();
1629 
1630  if (lcpId == RNIL)
1631  {
1632  disk_restart_undo_lcp(tableId, fragId, Fragrecord::UC_CREATE, 0);
1633  if (DBG_UNDO)
1634  {
1635  ndbout_c("mark_no_lcp (%u, %u)", tableId, fragId);
1636  }
1637  }
1638  else
1639  {
1640  disk_restart_undo_lcp(tableId, fragId, Fragrecord::UC_SET_LCP, lcpId);
1641  if (DBG_UNDO)
1642  {
1643  ndbout_c("mark_no_lcp (%u, %u)", tableId, fragId);
1644  }
1645 
1646  }
1647 }
1648 
1649 void
1650 Dbtup::disk_restart_undo_lcp(Uint32 tableId, Uint32 fragId, Uint32 flag,
1651  Uint32 lcpId)
1652 {
1653  Ptr<Tablerec> tabPtr;
1654  tabPtr.i= tableId;
1655  ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
1656 
1657  if (tabPtr.p->tableStatus == DEFINED && tabPtr.p->m_no_of_disk_attributes)
1658  {
1659  jam();
1660  FragrecordPtr fragPtr;
1661  getFragmentrec(fragPtr, fragId, tabPtr.p);
1662  if (!fragPtr.isNull())
1663  {
1664  jam();
1665  switch(flag){
1666  case Fragrecord::UC_CREATE:
1667  jam();
1668  fragPtr.p->m_undo_complete |= flag;
1669  return;
1670  case Fragrecord::UC_LCP:
1671  jam();
1672  if (fragPtr.p->m_undo_complete == 0 &&
1673  fragPtr.p->m_restore_lcp_id == lcpId)
1674  {
1675  jam();
1676  fragPtr.p->m_undo_complete |= flag;
1677  if (DBG_UNDO)
1678  ndbout_c("table: %u fragment: %u lcp: %u -> done",
1679  tableId, fragId, lcpId);
1680  }
1681  return;
1682  case Fragrecord::UC_SET_LCP:
1683  {
1684  jam();
1685  if (DBG_UNDO)
1686  ndbout_c("table: %u fragment: %u restore to lcp: %u",
1687  tableId, fragId, lcpId);
1688  ndbrequire(fragPtr.p->m_undo_complete == 0);
1689  ndbrequire(fragPtr.p->m_restore_lcp_id == RNIL);
1690  fragPtr.p->m_restore_lcp_id = lcpId;
1691  return;
1692  }
1693  }
1694  jamLine(flag);
1695  ndbrequire(false);
1696  }
1697  }
1698 }
1699 
1700 void
1701 Dbtup::disk_restart_undo_callback(Signal* signal,
1702  Uint32 id,
1703  Uint32 page_id)
1704 {
1705  jamEntry();
1706  Ptr<GlobalPage> gpage;
1707  m_global_page_pool.getPtr(gpage, page_id);
1708  PagePtr pagePtr;
1709  pagePtr.i = gpage.i;
1710  pagePtr.p = reinterpret_cast<Page*>(gpage.p);
1711 
1712  Apply_undo* undo = &f_undo;
1713 
1714  bool update = false;
1715  if (! (pagePtr.p->list_index & 0x8000) ||
1716  pagePtr.p->nextList != RNIL ||
1717  pagePtr.p->prevList != RNIL)
1718  {
1719  jam();
1720  update = true;
1721  pagePtr.p->list_index |= 0x8000;
1722  pagePtr.p->nextList = pagePtr.p->prevList = RNIL;
1723  }
1724 
1725  Uint32 tableId= pagePtr.p->m_table_id;
1726  Uint32 fragId = pagePtr.p->m_fragment_id;
1727 
1728  if (tableId >= cnoOfTablerec)
1729  {
1730  jam();
1731  if (DBG_UNDO)
1732  ndbout_c("UNDO table> %u", tableId);
1733  disk_restart_undo_next(signal);
1734  return;
1735  }
1736  undo->m_table_ptr.i = tableId;
1737  ptrCheckGuard(undo->m_table_ptr, cnoOfTablerec, tablerec);
1738 
1739  if (! (undo->m_table_ptr.p->tableStatus == DEFINED &&
1740  undo->m_table_ptr.p->m_no_of_disk_attributes))
1741  {
1742  jam();
1743  if (DBG_UNDO)
1744  ndbout_c("UNDO !defined (%u) ", tableId);
1745  disk_restart_undo_next(signal);
1746  return;
1747  }
1748 
1749  getFragmentrec(undo->m_fragment_ptr, fragId, undo->m_table_ptr.p);
1750  if(undo->m_fragment_ptr.isNull())
1751  {
1752  jam();
1753  if (DBG_UNDO)
1754  ndbout_c("UNDO fragment null %u/%u", tableId, fragId);
1755  disk_restart_undo_next(signal);
1756  return;
1757  }
1758 
1759  if (undo->m_fragment_ptr.p->m_undo_complete)
1760  {
1761  jam();
1762  if (DBG_UNDO)
1763  ndbout_c("UNDO undo complete %u/%u", tableId, fragId);
1764  disk_restart_undo_next(signal);
1765  return;
1766  }
1767 
1768  Local_key key = undo->m_key;
1769 // key.m_page_no = pagePtr.p->m_page_no;
1770 // key.m_file_no = pagePtr.p->m_file_no;
1771 
1772  Uint64 lsn = 0;
1773  lsn += pagePtr.p->m_page_header.m_page_lsn_hi; lsn <<= 32;
1774  lsn += pagePtr.p->m_page_header.m_page_lsn_lo;
1775 
1776  undo->m_page_ptr = pagePtr;
1777 
1778  if (undo->m_lsn <= lsn)
1779  {
1780  jam();
1781  if (DBG_UNDO)
1782  {
1783  ndbout << "apply: " << undo->m_lsn << "(" << lsn << " )"
1784  << key << " type: " << undo->m_type << endl;
1785  }
1786 
1787  update = true;
1788  if (DBG_UNDO)
1789  ndbout_c("applying %lld", undo->m_lsn);
1793  switch(undo->m_type){
1794  case File_formats::Undofile::UNDO_TUP_ALLOC:
1795  jam();
1796  disk_restart_undo_alloc(undo);
1797  break;
1798  case File_formats::Undofile::UNDO_TUP_UPDATE:
1799  jam();
1800  disk_restart_undo_update(undo);
1801  break;
1802  case File_formats::Undofile::UNDO_TUP_FREE:
1803  jam();
1804  disk_restart_undo_free(undo);
1805  break;
1806  default:
1807  ndbrequire(false);
1808  }
1809 
1810  if (DBG_UNDO)
1811  ndbout << "disk_restart_undo: " << undo->m_type << " "
1812  << undo->m_key << endl;
1813 
1814  lsn = undo->m_lsn - 1; // make sure undo isn't run again...
1815 
1816  Page_cache_client pgman(this, c_pgman);
1817  pgman.update_lsn(undo->m_key, lsn);
1818  jamEntry();
1819 
1820  disk_restart_undo_page_bits(signal, undo);
1821  }
1822  else if (DBG_UNDO)
1823  {
1824  jam();
1825  ndbout << "ignore: " << undo->m_lsn << "(" << lsn << " )"
1826  << key << " type: " << undo->m_type
1827  << " tab: " << tableId << endl;
1828  }
1829 
1830  disk_restart_undo_next(signal);
1831 }
1832 
1833 void
1834 Dbtup::disk_restart_undo_alloc(Apply_undo* undo)
1835 {
1836  ndbassert(undo->m_page_ptr.p->m_file_no == undo->m_key.m_file_no);
1837  ndbassert(undo->m_page_ptr.p->m_page_no == undo->m_key.m_page_no);
1838  if (undo->m_table_ptr.p->m_attributes[DD].m_no_of_varsize == 0)
1839  {
1840  ((Fix_page*)undo->m_page_ptr.p)->free_record(undo->m_key.m_page_idx);
1841  }
1842  else
1843  ((Var_page*)undo->m_page_ptr.p)->free_record(undo->m_key.m_page_idx, 0);
1844 }
1845 
1846 void
1847 Dbtup::disk_restart_undo_update(Apply_undo* undo)
1848 {
1849  Uint32* ptr;
1850  Uint32 len= undo->m_len - 4;
1851  if (undo->m_table_ptr.p->m_attributes[DD].m_no_of_varsize == 0)
1852  {
1853  ptr= ((Fix_page*)undo->m_page_ptr.p)->get_ptr(undo->m_key.m_page_idx, len);
1854  ndbrequire(len == undo->m_table_ptr.p->m_offsets[DD].m_fix_header_size);
1855  }
1856  else
1857  {
1858  ptr= ((Var_page*)undo->m_page_ptr.p)->get_ptr(undo->m_key.m_page_idx);
1859  abort();
1860  }
1861 
1862  const Disk_undo::Update *update = (const Disk_undo::Update*)undo->m_ptr;
1863  const Uint32* src= update->m_data;
1864  memcpy(ptr, src, 4 * len);
1865 }
1866 
1867 void
1868 Dbtup::disk_restart_undo_free(Apply_undo* undo)
1869 {
1870  Uint32* ptr, idx = undo->m_key.m_page_idx;
1871  Uint32 len= undo->m_len - 4;
1872  if (undo->m_table_ptr.p->m_attributes[DD].m_no_of_varsize == 0)
1873  {
1874  ndbrequire(len == undo->m_table_ptr.p->m_offsets[DD].m_fix_header_size);
1875  idx= ((Fix_page*)undo->m_page_ptr.p)->alloc_record(idx);
1876  ptr= ((Fix_page*)undo->m_page_ptr.p)->get_ptr(idx, len);
1877  }
1878  else
1879  {
1880  abort();
1881  }
1882 
1883  ndbrequire(idx == undo->m_key.m_page_idx);
1884  const Disk_undo::Free *free = (const Disk_undo::Free*)undo->m_ptr;
1885  const Uint32* src= free->m_data;
1886  memcpy(ptr, src, 4 * len);
1887 }
1888 
1889 void
1890 Dbtup::disk_restart_undo_page_bits(Signal* signal, Apply_undo* undo)
1891 {
1892  Fragrecord* fragPtrP = undo->m_fragment_ptr.p;
1893  Disk_alloc_info& alloc= fragPtrP->m_disk_alloc_info;
1894 
1899  Page* pageP = undo->m_page_ptr.p;
1900  Uint32 free = pageP->free_space;
1901  Uint32 new_bits = alloc.calc_page_free_bits(free);
1902  pageP->list_index = 0x8000 | new_bits;
1903 
1904  D("Tablespace_client - disk_restart_undo_page_bits");
1905  Tablespace_client tsman(signal, this, c_tsman,
1906  fragPtrP->fragTableId,
1907  fragPtrP->fragmentId,
1908  fragPtrP->m_tablespace_id);
1909 
1910  tsman.restart_undo_page_free_bits(&undo->m_key, new_bits);
1911  jamEntry();
1912 }
1913 
1914 int
1915 Dbtup::disk_restart_alloc_extent(Uint32 tableId, Uint32 fragId,
1916  const Local_key* key, Uint32 pages)
1917 {
1918  TablerecPtr tabPtr;
1919  FragrecordPtr fragPtr;
1920  tabPtr.i = tableId;
1921  ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
1922  if (tabPtr.p->tableStatus == DEFINED && tabPtr.p->m_no_of_disk_attributes)
1923  {
1924  getFragmentrec(fragPtr, fragId, tabPtr.p);
1925 
1926  if (!fragPtr.isNull())
1927  {
1928  jam();
1929 
1930  if (fragPtr.p->m_undo_complete & Fragrecord::UC_CREATE)
1931  {
1932  jam();
1933  return -1;
1934  }
1935 
1936  Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info;
1937 
1938  Ptr<Extent_info> ext;
1939  ndbrequire(c_extent_pool.seize(ext));
1940 #ifdef VM_TRACE
1941  ndbout << "allocated " << pages << " pages: " << *key
1942  << " table: " << tabPtr.i << " fragment: " << fragId << endl;
1943 #endif
1944  ext.p->m_key = *key;
1945  ext.p->m_first_page_no = ext.p->m_key.m_page_no;
1946  ext.p->m_free_space= 0;
1947  ext.p->m_empty_page_no = (1 << 16); // We don't know, so assume none
1948  memset(ext.p->m_free_page_count, 0, sizeof(ext.p->m_free_page_count));
1949 
1950  if (alloc.m_curr_extent_info_ptr_i != RNIL)
1951  {
1952  jam();
1953  Ptr<Extent_info> old;
1954  c_extent_pool.getPtr(old, alloc.m_curr_extent_info_ptr_i);
1955  ndbassert(old.p->m_free_matrix_pos == RNIL);
1956  Uint32 pos= alloc.calc_extent_pos(old.p);
1957  Local_extent_info_list new_list(c_extent_pool, alloc.m_free_extents[pos]);
1958  new_list.add(old);
1959  old.p->m_free_matrix_pos= pos;
1960  }
1961 
1962  alloc.m_curr_extent_info_ptr_i = ext.i;
1963  ext.p->m_free_matrix_pos = RNIL;
1964  c_extent_hash.add(ext);
1965 
1966  Local_fragment_extent_list list1(c_extent_pool, alloc.m_extent_list);
1967  list1.add(ext);
1968  return 0;
1969  }
1970  }
1971 
1972  return -1;
1973 }
1974 
1975 void
1976 Dbtup::disk_restart_page_bits(Uint32 tableId, Uint32 fragId,
1977  const Local_key* key, Uint32 bits)
1978 {
1979  jam();
1980  TablerecPtr tabPtr;
1981  FragrecordPtr fragPtr;
1982  tabPtr.i = tableId;
1983  ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
1984  if (tabPtr.p->tableStatus == DEFINED && tabPtr.p->m_no_of_disk_attributes)
1985  {
1986  jam();
1987  getFragmentrec(fragPtr, fragId, tabPtr.p);
1988  Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info;
1989 
1990  Ptr<Extent_info> ext;
1991  c_extent_pool.getPtr(ext, alloc.m_curr_extent_info_ptr_i);
1992 
1993  Uint32 size= alloc.calc_page_free_space(bits);
1994 
1995  ext.p->m_free_page_count[bits]++;
1996  update_extent_pos(alloc, ext, size); // actually only to update free_space
1997  ndbassert(ext.p->m_free_matrix_pos == RNIL);
1998  }
1999 }
2000 
2001 void
2002 Dbtup::disk_page_get_allocated(const Tablerec* tabPtrP,
2003  const Fragrecord * fragPtrP,
2004  Uint64 res[2])
2005 {
2006  res[0] = res[1] = 0;
2007  if (tabPtrP->m_no_of_disk_attributes)
2008  {
2009  jam();
2010  const Disk_alloc_info& alloc= fragPtrP->m_disk_alloc_info;
2011  Uint64 cnt = 0;
2012  Uint64 free = 0;
2013 
2014  {
2015  Disk_alloc_info& tmp = const_cast<Disk_alloc_info&>(alloc);
2016  Local_fragment_extent_list list(c_extent_pool, tmp.m_extent_list);
2017  Ptr<Extent_info> extentPtr;
2018  for (list.first(extentPtr); !extentPtr.isNull(); list.next(extentPtr))
2019  {
2020  cnt++;
2021  free += extentPtr.p->m_free_space;
2022  }
2023  }
2024  res[0] = cnt * alloc.m_extent_size * File_formats::NDB_PAGE_SIZE;
2025  res[1] = free * 4 * tabPtrP->m_offsets[DD].m_fix_header_size;
2026  }
2027 }