MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
tsman.cpp
1 /*
2  Copyright (c) 2005, 2011, 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 #include "tsman.hpp"
19 #include "pgman.hpp"
20 #include "diskpage.hpp"
21 #include <signaldata/FsRef.hpp>
22 #include <signaldata/FsConf.hpp>
23 #include <signaldata/FsOpenReq.hpp>
24 #include <signaldata/FsCloseReq.hpp>
25 #include <signaldata/CreateFilegroupImpl.hpp>
26 #include <signaldata/DropFilegroupImpl.hpp>
27 #include <signaldata/FsReadWriteReq.hpp>
28 #include <signaldata/Extent.hpp>
29 #include <signaldata/DumpStateOrd.hpp>
30 #include <signaldata/TsmanContinueB.hpp>
31 #include <signaldata/GetTabInfo.hpp>
32 #include <signaldata/NodeFailRep.hpp>
33 #include <dbtup/Dbtup.hpp>
34 
35 #define JONAS 0
36 
37 #define COMMITTED_MASK ((1 << 0) | (1 << 1))
38 #define UNCOMMITTED_MASK ((1 << 2) | (1 << 3))
39 #define UNCOMMITTED_SHIFT 2
40 
41 #define DBG_UNDO 0
42 
43 Tsman::Tsman(Block_context& ctx) :
44  SimulatedBlock(TSMAN, ctx),
45  m_file_hash(m_file_pool),
46  m_tablespace_list(m_tablespace_pool),
47  m_tablespace_hash(m_tablespace_pool),
48  m_pgman(0),
49  m_lgman(0),
50  m_tup(0),
51  m_client_mutex("tsman-client", 2, true)
52 {
53  BLOCK_CONSTRUCTOR(Tsman);
54 
55  Uint32 SZ = File_formats::Datafile::EXTENT_HEADER_BITMASK_BITS_PER_PAGE;
56  ndbrequire((COMMITTED_MASK & UNCOMMITTED_MASK) == 0);
57  ndbrequire((COMMITTED_MASK | UNCOMMITTED_MASK) == ((1 << SZ) - 1));
58 
59  // Add received signals
60  addRecSignal(GSN_STTOR, &Tsman::execSTTOR);
61  addRecSignal(GSN_READ_CONFIG_REQ, &Tsman::execREAD_CONFIG_REQ);
62  addRecSignal(GSN_DUMP_STATE_ORD, &Tsman::execDUMP_STATE_ORD);
63  addRecSignal(GSN_CONTINUEB, &Tsman::execCONTINUEB);
64  addRecSignal(GSN_NODE_FAILREP, &Tsman::execNODE_FAILREP);
65 
66  addRecSignal(GSN_CREATE_FILE_IMPL_REQ, &Tsman::execCREATE_FILE_IMPL_REQ);
67  addRecSignal(GSN_CREATE_FILEGROUP_IMPL_REQ, &Tsman::execCREATE_FILEGROUP_IMPL_REQ);
68 
69  addRecSignal(GSN_DROP_FILE_IMPL_REQ, &Tsman::execDROP_FILE_IMPL_REQ);
70  addRecSignal(GSN_DROP_FILEGROUP_IMPL_REQ, &Tsman::execDROP_FILEGROUP_IMPL_REQ);
71 
72  addRecSignal(GSN_FSWRITEREQ, &Tsman::execFSWRITEREQ);
73 
74  addRecSignal(GSN_FSOPENREF, &Tsman::execFSOPENREF, true);
75  addRecSignal(GSN_FSOPENCONF, &Tsman::execFSOPENCONF);
76 
77  //addRecSignal(GSN_FSCLOSEREF, &Tsman::execFSCLOSEREF);
78  addRecSignal(GSN_FSCLOSECONF, &Tsman::execFSCLOSECONF);
79  addRecSignal(GSN_FSREADCONF, &Tsman::execFSREADCONF);
80 
81  addRecSignal(GSN_ALLOC_EXTENT_REQ, &Tsman::execALLOC_EXTENT_REQ);
82  addRecSignal(GSN_FREE_EXTENT_REQ, &Tsman::execFREE_EXTENT_REQ);
83 
84  addRecSignal(GSN_START_RECREQ, &Tsman::execSTART_RECREQ);
85 
86  addRecSignal(GSN_LCP_FRAG_ORD, &Tsman::execLCP_FRAG_ORD);
87  addRecSignal(GSN_END_LCP_REQ, &Tsman::execEND_LCP_REQ);
88 
89  addRecSignal(GSN_GET_TABINFOREQ, &Tsman::execGET_TABINFOREQ);
90 
91  m_tablespace_hash.setSize(10);
92  m_file_hash.setSize(10);
93  m_lcp_ongoing = false;
94 
95  if (isNdbMtLqh()) {
96  jam();
97  int ret = m_client_mutex.create();
98  ndbrequire(ret == 0);
99  }
100 }
101 
102 Tsman::~Tsman()
103 {
104  if (isNdbMtLqh()) {
105  (void)m_client_mutex.destroy();
106  }
107 }
108 
109 void
110 Tsman::client_lock(BlockNumber block, int line)
111 {
112  if (isNdbMtLqh()) {
113 #ifdef VM_TRACE
114  Uint32 bno = blockToMain(block);
115  Uint32 ino = blockToInstance(block);
116 #endif
117  D("try lock " << bno << "/" << ino << V(line));
118  int ret = m_client_mutex.lock();
119  ndbrequire(ret == 0);
120  D("got lock " << bno << "/" << ino << V(line));
121  }
122 }
123 
124 void
125 Tsman::client_unlock(BlockNumber block, int line)
126 {
127  if (isNdbMtLqh()) {
128 #ifdef VM_TRACE
129  Uint32 bno = blockToMain(block);
130  Uint32 ino = blockToInstance(block);
131 #endif
132  D("unlock " << bno << "/" << ino << V(line));
133  int ret = m_client_mutex.unlock();
134  ndbrequire(ret == 0);
135  }
136 }
137 
138 BLOCK_FUNCTIONS(Tsman)
139 
140 void
141 Tsman::execREAD_CONFIG_REQ(Signal* signal)
142 {
143  jamEntry();
144 
145  const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr();
146 
147  Uint32 ref = req->senderRef;
148  Uint32 senderData = req->senderData;
149 
150  const ndb_mgm_configuration_iterator * p =
151  m_ctx.m_config.getOwnConfigIterator();
152  ndbrequire(p != 0);
153 
154  Pool_context pc;
155  pc.m_block = this;
156 
157  m_file_pool.init(RT_TSMAN_FILE, pc);
158  m_tablespace_pool.init(RT_TSMAN_FILEGROUP, pc);
159 
160  ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend();
161  conf->senderRef = reference();
162  conf->senderData = senderData;
163  sendSignal(ref, GSN_READ_CONFIG_CONF, signal,
164  ReadConfigConf::SignalLength, JBB);
165 }
166 
167 void
168 Tsman::execSTTOR(Signal* signal)
169 {
170  jamEntry();
171  Uint32 startPhase = signal->theData[1];
172  switch (startPhase) {
173  case 1:
174  m_pgman = globalData.getBlock(PGMAN);
175  m_lgman = (Lgman*)globalData.getBlock(LGMAN);
176  m_tup = globalData.getBlock(DBTUP);
177  ndbrequire(m_pgman != 0 && m_lgman != 0 && m_tup != 0);
178  break;
179  }
180  sendSTTORRY(signal);
181 }
182 
183 void
184 Tsman::sendSTTORRY(Signal* signal){
185  signal->theData[0] = 0;
186  signal->theData[3] = 1;
187  signal->theData[4] = 3;
188  signal->theData[5] = 255; // No more start phases from missra
189  sendSignal(NDBCNTR_REF, GSN_STTORRY, signal, 6, JBB);
190 }
191 
192 void
193 Tsman::execCONTINUEB(Signal* signal){
194  jamEntry();
195  Uint32 type = signal->theData[0];
196  Uint32 ptrI = signal->theData[1];
197  client_lock(number(), __LINE__);
198  switch(type){
199  case TsmanContinueB::SCAN_TABLESPACE_EXTENT_HEADERS:
200  scan_tablespace(signal, ptrI);
201  break;
202  case TsmanContinueB::SCAN_DATAFILE_EXTENT_HEADERS:
203  scan_datafile(signal, ptrI, signal->theData[2]);
204  break;
205  case TsmanContinueB::END_LCP:
206  end_lcp(signal, ptrI, signal->theData[2], signal->theData[3]);
207  break;
208  case TsmanContinueB::RELEASE_EXTENT_PAGES:
209  {
210  Ptr<Datafile> ptr;
211  m_file_pool.getPtr(ptr, ptrI);
212  release_extent_pages(signal, ptr);
213  break;
214  }
215  case TsmanContinueB::LOAD_EXTENT_PAGES:
216  {
217  Ptr<Datafile> ptr;
218  m_file_pool.getPtr(ptr, ptrI);
219  load_extent_pages(signal, ptr);
220  break;
221  }
222  default:
223  ndbrequire(false);
224  break;
225  }
226  client_unlock(number(), __LINE__);
227 }
228 
229 void
230 Tsman::execNODE_FAILREP(Signal* signal)
231 {
232  jamEntry();
233  const NodeFailRep * rep = (NodeFailRep*)signal->getDataPtr();
234  NdbNodeBitmask failed;
235  failed.assign(NdbNodeBitmask::Size, rep->theNodes);
236 
237  /* Block level cleanup */
238  for(unsigned i = 1; i < MAX_NDB_NODES; i++) {
239  jam();
240  if(failed.get(i)) {
241  jam();
242  Uint32 elementsCleaned = simBlockNodeFailure(signal, i); // No callback
243  ndbassert(elementsCleaned == 0); // No distributed fragmented signals
244  (void) elementsCleaned; // Remove compiler warning
245  }//if
246  }//for
247 }
248 
249 #ifdef VM_TRACE
250 struct TsmanChunk
251 {
252  Uint32 page_count;
253  Local_key start_page;
254  Vector<Uint32> bitmask;
255 };
256 template class Vector<TsmanChunk>;
257 #endif
258 
259 void
261  jamEntry();
262 
267  if(signal->theData[0] == DumpStateOrd::DumpTsman + 0)
268  {
269  Uint32 id = signal->theData[1];
270 
271  AllocExtentReq* req = (AllocExtentReq*)signal->theData;
272  req->request.tablespace_id = id;
273  req->request.table_id = 0;
274  req->request.fragment_id = 0;
275  execALLOC_EXTENT_REQ(signal);
276 
277  if(req->reply.errorCode == 0){
278  ndbout_c("Success");
279  ndbout_c("page: %d %d count: %d",
280  req->reply.page_id.m_file_no,
281  req->reply.page_id.m_page_no,
282  req->reply.page_count);
283  } else {
284  ndbout_c("Error: %d", req->reply.errorCode);
285  }
286  }
287 
288  if(signal->theData[0] == DumpStateOrd::DumpTsman + 1)
289  {
290  Uint32 id = signal->theData[1];
291  Uint32 file= signal->theData[2];
292  Uint32 page= signal->theData[3];
293  Uint32 bits= signal->theData[4];
294 
295  AllocPageReq* req = (AllocPageReq*)signal->theData;
296  req->request.tablespace_id = id;
297  req->request.table_id = 0;
298  req->request.fragment_id = 0;
299  req->key.m_page_no= page;
300  req->key.m_file_no= file;
301  req->bits= bits;
302  execALLOC_PAGE_REQ(signal);
303 
304  if(req->reply.errorCode == 0){
305  ndbout_c("Success");
306  ndbout_c("page: %d %d bits: %d",
307  req->key.m_file_no,
308  req->key.m_page_no,
309  req->bits);
310  } else {
311  ndbout_c("Error: %d", req->reply.errorCode);
312  }
313  }
314 
315 #ifdef VM_TRACE
316  if(signal->theData[0] == DumpStateOrd::DumpTsman + 2)
317  {
318  Uint32 id = signal->theData[1];
319  Vector<TsmanChunk> chunks;
320  for(size_t i = 0; i<1000; i++)
321  {
327  Uint32 sz = chunks.size();
328  switch((rand() * sz) % 2){
329  case 0:
330  {
331  ndbout_c("case 0");
332  AllocExtentReq* req = (AllocExtentReq*)signal->theData;
333  req->request.tablespace_id = id;
334  req->request.table_id = 0;
335  req->request.fragment_id = 0;
336  execALLOC_EXTENT_REQ(signal);
337  if(req->reply.errorCode == 0){
338  TsmanChunk c;
339  c.start_page = req->reply.page_id;
340  c.page_count = req->reply.page_count;
341  Uint32 words = File_formats::Datafile::extent_header_words(c.page_count);
342  ndbout_c("execALLOC_EXTENT_REQ - OK - [ %d %d ] count: %d(%d)",
343  c.start_page.m_file_no,
344  c.start_page.m_page_no,
345  c.page_count,
346  words);
347  Uint32 zero = 0;
348  chunks.push_back(c);
349  chunks.back().bitmask.fill(words, zero);
350 
351  ndbout_c("execALLOC_EXTENT_REQ - OK - [ %d %d ] count: %d",
352  chunks.back().start_page.m_file_no,
353  chunks.back().start_page.m_page_no,
354  chunks.back().page_count);
355  } else {
356  ndbout_c("Error: %d", req->reply.errorCode);
357  }
358  break;
359  }
360  case 1:
361  {
362  Uint32 chunk = rand() % sz;
363  Uint32 count = chunks[chunk].page_count;
364  Uint32 page = rand() % count;
365  ndbout_c("case 1 - %d %d %d", chunk, count, page);
366 
369  (chunks[chunk].bitmask.getBase());
370  Uint32 curr_bits = header->get_free_bits(page);
371  Uint32 new_bits = curr_bits ^ rand();
372  Local_key key = chunks[chunk].start_page;
373  key.m_page_no += page;
374  ndbrequire(update_page_free_bits(signal, &key, new_bits) == 0);
375  }
376  }
377  }
378  }
379 #endif
380 
381  if(signal->theData[0] == DumpStateOrd::DumpTsman + 3)
382  {
383  GetTabInfoReq* req = (GetTabInfoReq*)signal->theData;
384  req->requestType= GetTabInfoReq::RequestById;
385  req->tableId= signal->theData[1];
386 
387  execGET_TABINFOREQ(signal);
388 
389  }
390 
391 }
392 
393 void
394 Tsman::execCREATE_FILEGROUP_IMPL_REQ(Signal* signal){
395  jamEntry();
396  CreateFilegroupImplReq* req= (CreateFilegroupImplReq*)signal->getDataPtr();
397 
398  Uint32 senderRef = req->senderRef;
399  Uint32 senderData = req->senderData;
400 
401  Ptr<Tablespace> ptr;
402  CreateFilegroupImplRef::ErrorCode err = CreateFilegroupImplRef::NoError;
403  do {
404  if (m_tablespace_hash.find(ptr, req->filegroup_id))
405  {
406  jam();
407  err = CreateFilegroupImplRef::FilegroupAlreadyExists;
408  break;
409  }
410 
411  if (!m_tablespace_pool.seize(ptr))
412  {
413  jam();
414  err = CreateFilegroupImplRef::OutOfFilegroupRecords;
415  break;
416  }
417 
418  new (ptr.p) Tablespace(this, req);
419  m_tablespace_hash.add(ptr);
420  m_tablespace_list.add(ptr);
421 
422  ptr.p->m_state = Tablespace::TS_ONLINE;
423 
425  (CreateFilegroupImplConf*)signal->getDataPtr();
426  conf->senderData = senderData;
427  conf->senderRef = reference();
428  sendSignal(senderRef, GSN_CREATE_FILEGROUP_IMPL_CONF, signal,
429  CreateFilegroupImplConf::SignalLength, JBB);
430  return;
431  } while(0);
432 
433  CreateFilegroupImplRef* ref= (CreateFilegroupImplRef*)signal->getDataPtr();
434  ref->senderData = senderData;
435  ref->senderRef = reference();
436  ref->errorCode = err;
437  sendSignal(senderRef, GSN_CREATE_FILEGROUP_IMPL_REF, signal,
438  CreateFilegroupImplRef::SignalLength, JBB);
439 }
440 
441 NdbOut&
442 operator<<(NdbOut& out, const File_formats::Datafile::Extent_header & obj)
443 {
444  out << "table: " << obj.m_table
445  << " fragment: " << obj.m_fragment_id << " ";
446  for(Uint32 i = 0; i<32; i++)
447  {
448  char t[2];
449  BaseString::snprintf(t, sizeof(t), "%x", obj.get_free_bits(i));
450  out << t;
451  }
452  return out;
453 }
454 
455 void
456 Tsman::execDROP_FILEGROUP_IMPL_REQ(Signal* signal){
457  jamEntry();
458 
459  Uint32 errorCode = 0;
460  DropFilegroupImplReq req = *(DropFilegroupImplReq*)signal->getDataPtr();
461  Ptr<Tablespace> ptr;
462  do
463  {
464  if (!m_tablespace_hash.find(ptr, req.filegroup_id))
465  {
466  errorCode = DropFilegroupImplRef::NoSuchFilegroup;
467  break;
468  }
469 
470  if (ptr.p->m_version != req.filegroup_version)
471  {
472  errorCode = DropFilegroupImplRef::InvalidFilegroupVersion;
473  break;
474  }
475 
476  if (! (ptr.p->m_meta_files.isEmpty() && ptr.p->m_free_files.isEmpty() &&
477  ptr.p->m_full_files.isEmpty()))
478  {
479  errorCode = DropFilegroupImplRef::FilegroupInUse;
480  break;
481  }
482 
483  switch(req.requestInfo){
484  case DropFilegroupImplReq::Prepare:
485  ptr.p->m_state = Tablespace::TS_DROPPING;
486  break;
487  case DropFilegroupImplReq::Commit:
488  if (ptr.p->m_ref_count)
489  {
490  jam();
491  sendSignalWithDelay(reference(), GSN_DROP_FILEGROUP_REQ, signal,
492  100, signal->getLength());
493  return;
494  }
495  m_tablespace_list.remove(ptr);
496  m_tablespace_hash.release(ptr);
497  break;
498  case DropFilegroupImplReq::Abort:
499  ptr.p->m_state = Tablespace::TS_ONLINE;
500  break;
501  default:
502  ndbrequire(false);
503  }
504  } while(0);
505 
506  if (errorCode)
507  {
508  DropFilegroupImplRef* ref =
509  (DropFilegroupImplRef*)signal->getDataPtrSend();
510  ref->senderRef = reference();
511  ref->senderData = req.senderData;
512  ref->errorCode = errorCode;
513  sendSignal(req.senderRef, GSN_DROP_FILEGROUP_IMPL_REF, signal,
514  DropFilegroupImplRef::SignalLength, JBB);
515  }
516  else
517  {
518  DropFilegroupImplConf* conf =
519  (DropFilegroupImplConf*)signal->getDataPtrSend();
520  conf->senderRef = reference();
521  conf->senderData = req.senderData;
522  sendSignal(req.senderRef, GSN_DROP_FILEGROUP_IMPL_CONF, signal,
523  DropFilegroupImplConf::SignalLength, JBB);
524  }
525 }
526 
527 bool
528 Tsman::find_file_by_id(Ptr<Datafile>& ptr,
529  Datafile_list::Head& head,
530  Uint32 id)
531 {
532  Local_datafile_list list(m_file_pool, head);
533  for(list.first(ptr); !ptr.isNull(); list.next(ptr))
534  if(ptr.p->m_file_id == id)
535  return true;
536  return false;
537 }
538 
539 void
540 Tsman::execCREATE_FILE_IMPL_REQ(Signal* signal){
541  jamEntry();
542  client_lock(number(), __LINE__);
543  CreateFileImplReq* req= (CreateFileImplReq*)signal->getDataPtr();
544 
545  Uint32 senderRef = req->senderRef;
546  Uint32 senderData = req->senderData;
547 
548  Ptr<Tablespace> ptr;
549  CreateFileImplRef::ErrorCode err = CreateFileImplRef::NoError;
550  SectionHandle handle(this, signal);
551  do {
552  if (!m_tablespace_hash.find(ptr, req->filegroup_id))
553  {
554  jam();
555  err = CreateFileImplRef::InvalidFilegroup;
556  break;
557  }
558 
559  if (ptr.p->m_version != req->filegroup_version)
560  {
561  jam();
562  err = CreateFileImplRef::InvalidFilegroupVersion;
563  break;
564  }
565 
566  if (ptr.p->m_state != Tablespace::TS_ONLINE)
567  {
568  jam();
569  err = CreateFileImplRef::FilegroupNotOnline;
570  break;
571  }
572 
573  Ptr<Datafile> file_ptr;
574  switch(req->requestInfo){
575  case CreateFileImplReq::Commit:
576  {
577  ndbrequire(find_file_by_id(file_ptr, ptr.p->m_meta_files, req->file_id));
578  file_ptr.p->m_create.m_senderRef = req->senderRef;
579  file_ptr.p->m_create.m_senderData = req->senderData;
580  file_ptr.p->m_create.m_requestInfo = req->requestInfo;
581 
582  Page_cache_client pgman(this, m_pgman);
583  pgman.map_file_no(signal, file_ptr.p->m_file_no, file_ptr.p->m_fd);
584  file_ptr.p->m_create.m_loading_extent_page = 1;
585  load_extent_pages(signal, file_ptr);
586  client_unlock(number(), __LINE__);
587  return;
588  }
589  case CreateFileImplReq::Abort:
590  {
591  Uint32 senderRef = req->senderRef;
592  Uint32 senderData = req->senderData;
593  if(find_file_by_id(file_ptr, ptr.p->m_meta_files, req->file_id))
594  {
595  file_ptr.p->m_create.m_senderRef = senderRef;
596  file_ptr.p->m_create.m_senderData = senderData;
597  file_ptr.p->m_create.m_requestInfo = req->requestInfo;
598  create_file_abort(signal, file_ptr);
599  client_unlock(number(), __LINE__);
600  return;
601  }
602  else
603  {
604  CreateFileImplConf* conf= (CreateFileImplConf*)signal->getDataPtr();
605  conf->senderData = senderData;
606  conf->senderRef = reference();
607  sendSignal(senderRef, GSN_CREATE_FILE_IMPL_CONF, signal,
608  CreateFileImplConf::SignalLength, JBB);
609  client_unlock(number(), __LINE__);
610  return;
611  }
612  }
613  default:
614  // Prepare
615  break;
616  }
617 
618  if (!handle.m_cnt == 1)
619  {
620  ndbrequire(false);
621  }
622 
623  if (!m_file_pool.seize(file_ptr))
624  {
625  jam();
626  err = CreateFileImplRef::OutOfFileRecords;
627  break;
628  }
629 
630  if(ERROR_INSERTED(16000) ||
631  (sizeof(void*) == 4 && req->file_size_hi & 0xFFFFFFFF))
632  {
633  jam();
634  releaseSections(handle);
635 
636  CreateFileImplRef* ref= (CreateFileImplRef*)signal->getDataPtr();
637  ref->senderData = senderData;
638  ref->senderRef = reference();
639  ref->errorCode = CreateFileImplRef::FileSizeTooLarge;
640  sendSignal(senderRef, GSN_CREATE_FILE_IMPL_REF, signal,
641  CreateFileImplRef::SignalLength, JBB);
642  client_unlock(number(), __LINE__);
643  return;
644  }
645 
646  new (file_ptr.p) Datafile(req);
647  Local_datafile_list tmp(m_file_pool, ptr.p->m_meta_files);
648  tmp.add(file_ptr);
649 
650  file_ptr.p->m_state = Datafile::FS_CREATING;
651  file_ptr.p->m_tablespace_ptr_i = ptr.i;
652  file_ptr.p->m_extent_size = ptr.p->m_extent_size;
653 
654  err = (CreateFileImplRef::ErrorCode)open_file(signal, ptr, file_ptr, req,
655  &handle);
656  if(err)
657  break;
658  client_unlock(number(), __LINE__);
659  return;
660  } while(0);
661 
662  releaseSections(handle);
663  CreateFileImplRef* ref= (CreateFileImplRef*)signal->getDataPtr();
664  ref->senderData = senderData;
665  ref->senderRef = reference();
666  ref->errorCode = err;
667  sendSignal(senderRef, GSN_CREATE_FILE_IMPL_REF, signal,
668  CreateFileImplRef::SignalLength, JBB);
669  client_unlock(number(), __LINE__);
670 }
671 
672 static inline Uint64 DIV(Uint64 a, Uint64 b){ return (a + b - 1) / b;}
673 
674 void
675 Tsman::release_extent_pages(Signal* signal, Ptr<Datafile> ptr)
676 {
677  Uint32 page = ptr.p->m_create.m_extent_pages;
678  if (page > 0)
679  {
681  preq.m_page.m_file_no = ptr.p->m_file_no;
682  preq.m_page.m_page_no = page;
683 
684  preq.m_callback.m_callbackData = ptr.i;
685  preq.m_callback.m_callbackFunction =
686  safe_cast(&Tsman::release_extent_pages_callback);
687 
688  int page_id;
689  int flags = Page_cache_client::UNLOCK_PAGE;
690  Page_cache_client pgman(this, m_pgman);
691  if((page_id = pgman.get_page(signal, preq, flags)) > 0)
692  {
693  execute(signal, preq.m_callback, page_id);
694  }
695  return;
696  }
697 
698  create_file_abort(signal, ptr);
699 }
700 
701 void
702 Tsman::release_extent_pages_callback(Signal* signal,
703  Uint32 ptrI,
704  Uint32 page_id)
705 {
706  Ptr<Datafile> ptr;
707  m_file_pool.getPtr(ptr, ptrI);
708  Local_key key;
709  key.m_file_no = ptr.p->m_file_no;
710  key.m_page_no = ptr.p->m_create.m_extent_pages;
711  Page_cache_client pgman(this, m_pgman);
712  ndbrequire(pgman.drop_page(key, page_id));
713  ptr.p->m_create.m_extent_pages--;
714 
715  signal->theData[0] = TsmanContinueB::RELEASE_EXTENT_PAGES;
716  signal->theData[1] = ptr.i;
717 
718  sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
719 }
720 
721 void
722 Tsman::create_file_abort(Signal* signal, Ptr<Datafile> ptr)
723 {
724  if (ptr.p->m_fd == RNIL)
725  {
726  ((FsConf*)signal->getDataPtr())->userPointer = ptr.i;
727  execFSCLOSECONF(signal);
728  return;
729  }
730 
731  FsCloseReq *req= (FsCloseReq*)signal->getDataPtrSend();
732  req->filePointer = ptr.p->m_fd;
733  req->userReference = reference();
734  req->userPointer = ptr.i;
735  req->fileFlag = 0;
736  FsCloseReq::setRemoveFileFlag(req->fileFlag, true);
737 
738  sendSignal(NDBFS_REF, GSN_FSCLOSEREQ, signal,
739  FsCloseReq::SignalLength, JBB);
740 }
741 
742 void
743 Tsman::execFSCLOSECONF(Signal* signal)
744 {
745  Ptr<Datafile> ptr;
746  Ptr<Tablespace> lg_ptr;
747  Uint32 ptrI = ((FsConf*)signal->getDataPtr())->userPointer;
748  m_file_pool.getPtr(ptr, ptrI);
749 
750  Uint32 senderRef = ptr.p->m_create.m_senderRef;
751  Uint32 senderData = ptr.p->m_create.m_senderData;
752 
753  if (ptr.p->m_state == Datafile::FS_CREATING)
754  {
755  if (ptr.p->m_file_no != RNIL)
756  {
757  jam();
758  Page_cache_client pgman(this, m_pgman);
759  pgman.free_data_file(signal, ptr.p->m_file_no);
760  }
761 
762  CreateFileImplConf* conf= (CreateFileImplConf*)signal->getDataPtr();
763  conf->senderData = senderData;
764  conf->senderRef = reference();
765  sendSignal(senderRef, GSN_CREATE_FILE_IMPL_CONF, signal,
766  CreateFileImplConf::SignalLength, JBB);
767  }
768  else if(ptr.p->m_state == Datafile::FS_DROPPING)
769  {
770  m_file_hash.remove(ptr);
771  Page_cache_client pgman(this, m_pgman);
772  pgman.free_data_file(signal, ptr.p->m_file_no, ptr.p->m_fd);
773  DropFileImplConf* conf= (DropFileImplConf*)signal->getDataPtr();
774  conf->senderData = senderData;
775  conf->senderRef = reference();
776  sendSignal(senderRef, GSN_DROP_FILE_IMPL_CONF, signal,
777  DropFileImplConf::SignalLength, JBB);
778 
779  }
780  else
781  {
782  ndbrequire(false);
783  }
784 
785  {
786  m_tablespace_pool.getPtr(lg_ptr, ptr.p->m_tablespace_ptr_i);
787  Local_datafile_list list(m_file_pool, lg_ptr.p->m_meta_files);
788  list.release(ptr);
789  }
790 }
791 
792 int
793 Tsman::open_file(Signal* signal,
794  Ptr<Tablespace> ts_ptr,
795  Ptr<Datafile> ptr,
796  CreateFileImplReq* org,
797  SectionHandle* handle)
798 {
799  Uint32 requestInfo = org->requestInfo;
800  Uint32 hi = org->file_size_hi;
801  Uint32 lo = org->file_size_lo;
802 
803  if(requestInfo == CreateFileImplReq::Create ||
804  requestInfo == CreateFileImplReq::CreateForce){
805  jam();
806  Page_cache_client pgman(this, m_pgman);
807  Uint32 file_no = pgman.create_data_file(signal);
808  if(file_no == RNIL)
809  {
810  return CreateFileImplRef::OutOfFileRecords;
811  }
812  ptr.p->m_file_no = file_no;
813  }
814 
815  FsOpenReq* req = (FsOpenReq*)signal->getDataPtrSend();
816  req->userReference = reference();
817  req->userPointer = ptr.i;
818 
819  memset(req->fileNumber, 0, sizeof(req->fileNumber));
820  FsOpenReq::setVersion(req->fileNumber, 4); // Version 4 = specified filename
821  FsOpenReq::v4_setBasePath(req->fileNumber, FsOpenReq::BP_DD_DF);
822 
823  req->fileFlags = 0;
824  req->fileFlags |= FsOpenReq::OM_READWRITE;
825  req->fileFlags |= FsOpenReq::OM_DIRECT;
826  req->fileFlags |= FsOpenReq::OM_THREAD_POOL;
827  switch(requestInfo){
828  case CreateFileImplReq::Create:
829  req->fileFlags |= FsOpenReq::OM_CREATE_IF_NONE;
830  req->fileFlags |= FsOpenReq::OM_INIT;
831  break;
832  case CreateFileImplReq::CreateForce:
833  req->fileFlags |= FsOpenReq::OM_CREATE;
834  req->fileFlags |= FsOpenReq::OM_INIT;
835  break;
836  case CreateFileImplReq::Open:
837  req->fileFlags |= FsOpenReq::OM_CHECK_SIZE;
838  break;
839  default:
840  ndbrequire(false);
841  }
842 
843  req->page_size = File_formats::NDB_PAGE_SIZE;
844  req->file_size_hi = hi;
845  req->file_size_lo = lo;
846 
847  Uint64 pages = (Uint64(hi) << 32 | lo) / File_formats::NDB_PAGE_SIZE;
848  Uint32 extent_size = ts_ptr.p->m_extent_size; // Extent size in #pages
849  Uint64 extents = (pages + extent_size - 1) / extent_size;
850  extents = extents ? extents : 1;
851  Uint64 data_pages = extents * extent_size;
852 
853  Uint32 eh_words = File_formats::Datafile::extent_header_words(extent_size);
854  ndbrequire(eh_words < File_formats::Datafile::EXTENT_PAGE_WORDS);
855  Uint32 extents_per_page = File_formats::Datafile::EXTENT_PAGE_WORDS/eh_words;
856  Uint64 extent_pages = (extents + extents_per_page - 1) / extents_per_page;
857 
858  // TODO check overflow in cast
859  ptr.p->m_create.m_extent_pages = Uint32(extent_pages);
860  ptr.p->m_create.m_data_pages = Uint32(data_pages);
861 
865  pages = 1 + extent_pages + data_pages;
866  Uint64 bytes = pages * File_formats::NDB_PAGE_SIZE;
867  hi = (Uint32)(bytes >> 32);
868  lo = (Uint32)(bytes & 0xFFFFFFFF);
869  req->file_size_hi = hi;
870  req->file_size_lo = lo;
871 #if defined VM_TRACE || defined ERROR_INSERT
872  ndbout << "DD tsman: file id:" << ptr.p->m_file_id << " datafile pages/bytes:" << data_pages << "/" << data_pages*File_formats::NDB_PAGE_SIZE << " extent pages:" << extent_pages << endl;
873 #endif
874 
875  sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, FsOpenReq::SignalLength, JBB,
876  handle);
877 
878  return 0;
879 }
880 
881 void
883 {
887  //jamEntry();
888  Ptr<Datafile> ptr;
889  Ptr<GlobalPage> page_ptr;
890  FsReadWriteReq* req= (FsReadWriteReq*)signal->getDataPtr();
891 
892  m_file_pool.getPtr(ptr, req->userPointer);
893  m_shared_page_pool.getPtr(page_ptr, req->data.pageData[0]);
894  memset(page_ptr.p, 0, File_formats::NDB_PAGE_SIZE);
895 
896  Uint32 page_no = req->varIndex;
897  Uint32 size = ptr.p->m_extent_size;
898  Uint32 extent_pages = ptr.p->m_create.m_extent_pages;
899  Uint32 datapages = ptr.p->m_create.m_data_pages;
900 
901  Uint32 header_words = File_formats::Datafile::extent_header_words(size);
902  Uint32 per_page = File_formats::Datafile::EXTENT_PAGE_WORDS / header_words;
903  Uint32 extents = datapages/size;
904 
905  if (page_no == 0)
906  {
907  //jam();
908  Ptr<Tablespace> lg_ptr;
909  m_tablespace_hash.getPtr(lg_ptr, ptr.p->m_tablespace_ptr_i);
910 
913  page->m_page_header.init(File_formats::FT_Datafile,
914  getOwnNodeId(),
915  ndbGetOwnVersion(),
916  (Uint32)time(0));
917  page->m_file_no = ptr.p->m_file_no;
918  page->m_file_id = ptr.p->m_file_id;
919  page->m_tablespace_id = lg_ptr.p->m_tablespace_id;
920  page->m_tablespace_version = lg_ptr.p->m_version;
921  page->m_data_pages = extents * size;
922  page->m_extent_pages = extent_pages;
923  page->m_extent_size = size;
924  page->m_extent_count = extents;
925  page->m_extent_headers_per_page = per_page;
926  page->m_extent_header_words = header_words;
927  page->m_extent_header_bits_per_page =
928  File_formats::Datafile::EXTENT_HEADER_BITMASK_BITS_PER_PAGE;
929  }
930  else if ((page_no-1) < extent_pages)
931  {
932  //jam();
933 
934  Uint32 curr_extent = page_no*per_page;
935 
938  page->m_page_header.m_page_lsn_hi = 0;
939  page->m_page_header.m_page_lsn_lo = 0;
940  page->m_page_header.m_page_type = File_formats::PT_Unallocated;
941 
942  for(Uint32 i = 0; i<per_page; i++)
943  {
944  File_formats::Datafile::Extent_header * head = page->get_header(i, size);
945  memset(head, 0, 4*header_words);
946  head->m_table = RNIL;
947  head->m_next_free_extent = ++curr_extent;
948  }
949  if (page_no == extent_pages)
950  {
951  Uint32 last = extents - ((extent_pages - 1) * per_page);
952  page->get_header(last - 1, size)->m_next_free_extent = RNIL;
953  }
954  }
955  else
956  {
957  //jam();
960  page->m_page_header.m_page_lsn_hi = 0;
961  page->m_page_header.m_page_lsn_lo = 0;
962  }
963 }
964 
965 void
966 Tsman::create_file_ref(Signal* signal,
967  Ptr<Tablespace> lg_ptr,
968  Ptr<Datafile> ptr,
969  Uint32 error, Uint32 fsError, Uint32 osError)
970 {
971  CreateFileImplRef* ref= (CreateFileImplRef*)signal->getDataPtr();
972  ref->senderData = ptr.p->m_create.m_senderData;
973  ref->senderRef = reference();
974  ref->errorCode = (CreateFileImplRef::ErrorCode)error;
975  ref->fsErrCode = fsError;
976  ref->osErrCode = osError;
977  sendSignal(ptr.p->m_create.m_senderRef, GSN_CREATE_FILE_IMPL_REF, signal,
978  CreateFileImplRef::SignalLength, JBB);
979 
980  Local_datafile_list meta(m_file_pool, lg_ptr.p->m_meta_files);
981  meta.release(ptr);
982 }
983 
984 void
985 Tsman::execFSOPENREF(Signal* signal)
986 {
987  jamEntry();
988 
989  Ptr<Datafile> ptr;
990  Ptr<Tablespace> lg_ptr;
991  FsRef* ref = (FsRef*)signal->getDataPtr();
992 
993  Uint32 errCode = ref->errorCode;
994  Uint32 osErrCode = ref->osErrorCode;
995 
996  m_file_pool.getPtr(ptr, ref->userPointer);
997  m_tablespace_hash.getPtr(lg_ptr, ptr.p->m_tablespace_ptr_i);
998 
999  create_file_ref(signal, lg_ptr, ptr,
1000  CreateFileImplRef::FileError, errCode, osErrCode);
1001 }
1002 
1003 void
1005 {
1006  jamEntry();
1007  Ptr<Datafile> ptr;
1008  Ptr<Tablespace> lg_ptr;
1009  FsConf* conf = (FsConf*)signal->getDataPtr();
1010 
1011  m_file_pool.getPtr(ptr, conf->userPointer);
1012  m_tablespace_hash.getPtr(lg_ptr, ptr.p->m_tablespace_ptr_i);
1013 
1014  Uint32 fd = ptr.p->m_fd = conf->filePointer;
1015 
1016  switch(ptr.p->m_create.m_requestInfo){
1017  case CreateFileImplReq::Create:
1018  case CreateFileImplReq::CreateForce:
1019  {
1020  jam();
1021 
1022  CreateFileImplConf* conf= (CreateFileImplConf*)signal->getDataPtr();
1023  conf->senderData = ptr.p->m_create.m_senderData;
1024  conf->senderRef = reference();
1025  sendSignal(ptr.p->m_create.m_senderRef, GSN_CREATE_FILE_IMPL_CONF, signal,
1026  CreateFileImplConf::SignalLength, JBB);
1027  return;
1028  }
1029  case CreateFileImplReq::Open:
1030  {
1031  jam();
1036  Ptr<GlobalPage> page_ptr;
1037  if(m_global_page_pool.seize(page_ptr) == false)
1038  {
1039  jam();
1040  create_file_ref(signal, lg_ptr, ptr,
1041  CreateFileImplRef::OutOfMemory, 0, 0);
1042  return;
1043  }
1044 
1045  ptr.p->m_create.m_page_ptr_i = page_ptr.i;
1046 
1047  FsReadWriteReq* req= (FsReadWriteReq*)signal->getDataPtrSend();
1048  req->filePointer = fd;
1049  req->userReference = reference();
1050  req->userPointer = ptr.i;
1051  req->varIndex = 0;
1052  req->numberOfPages = 1;
1053  req->operationFlag = 0;
1054  FsReadWriteReq::setFormatFlag(req->operationFlag,
1055  FsReadWriteReq::fsFormatGlobalPage);
1056  req->data.pageData[0] = page_ptr.i;
1057  sendSignal(NDBFS_REF, GSN_FSREADREQ, signal,
1058  FsReadWriteReq::FixedLength + 1, JBB);
1059  return;
1060  }
1061  }
1062 }
1063 
1064 void
1066  jamEntry();
1067  Ptr<Datafile> ptr;
1068  Ptr<Tablespace> lg_ptr;
1069  FsConf* conf = (FsConf*)signal->getDataPtr();
1070 
1075  m_file_pool.getPtr(ptr, conf->userPointer);
1076  m_tablespace_hash.getPtr(lg_ptr, ptr.p->m_tablespace_ptr_i);
1077 
1078  Ptr<GlobalPage> page_ptr;
1079  m_global_page_pool.getPtr(page_ptr, ptr.p->m_create.m_page_ptr_i);
1080 
1082  (File_formats::Datafile::Zero_page*)page_ptr.p;
1083 
1084  CreateFileImplRef::ErrorCode err = CreateFileImplRef::NoError;
1085  Uint32 fsError = 0;
1086  Uint32 osError = 0;
1087 
1088  do {
1089  err = CreateFileImplRef::InvalidFileMetadata;
1090  fsError = page->m_page_header.validate(File_formats::FT_Datafile,
1091  getOwnNodeId(),
1092  ndbGetOwnVersion(),
1093  (Uint32)time(0));
1094  if(fsError)
1095  break;
1096 
1097  osError = 1;
1098  if(page->m_file_id != ptr.p->m_file_id)
1099  break;
1100 
1101  osError = 2;
1102  if(page->m_tablespace_id != lg_ptr.p->m_tablespace_id)
1103  break;
1104 
1105  osError = 3;
1106  if(page->m_tablespace_version != lg_ptr.p->m_version)
1107  break;
1108 
1109  osError = 4;
1110  if(page->m_data_pages != ptr.p->m_create.m_data_pages)
1111  break;
1112 
1113  osError = 5;
1114  if(page->m_extent_pages != ptr.p->m_create.m_extent_pages)
1115  break;
1116 
1117  osError = 6;
1118  if(page->m_extent_size != ptr.p->m_extent_size)
1119  break;
1120 
1121  osError = 7;
1122  if(page->m_extent_header_bits_per_page !=
1123  File_formats::Datafile::EXTENT_HEADER_BITMASK_BITS_PER_PAGE)
1124  break;
1125 
1126  osError = 8;
1127  Uint32 eh_words =
1128  File_formats::Datafile::extent_header_words(ptr.p->m_extent_size);
1129  if(page->m_extent_header_words != eh_words)
1130  break;
1131 
1132  osError = 9;
1133  Uint32 per_page = File_formats::Datafile::EXTENT_PAGE_WORDS/eh_words;
1134  if(page->m_extent_headers_per_page != per_page)
1135  break;
1136 
1137  osError = 10;
1138  Uint32 extents = page->m_data_pages / ptr.p->m_extent_size;
1139  if(page->m_extent_count != extents)
1140  break;
1141 
1142  osError = 11;
1143  ptr.p->m_file_no = page->m_file_no;
1144  Page_cache_client pgman(this, m_pgman);
1145  if(pgman.alloc_data_file(signal, ptr.p->m_file_no) == RNIL)
1146  {
1147  jam();
1148  break;
1149  }
1150 
1154  m_global_page_pool.release(page_ptr);
1155 
1156  CreateFileImplConf* conf= (CreateFileImplConf*)signal->getDataPtr();
1157  conf->senderData = ptr.p->m_create.m_senderData;
1158  conf->senderRef = reference();
1159  sendSignal(ptr.p->m_create.m_senderRef, GSN_CREATE_FILE_IMPL_CONF, signal,
1160  CreateFileImplConf::SignalLength, JBB);
1161  return;
1162  } while(0);
1163 
1164  m_global_page_pool.release(page_ptr);
1165  create_file_ref(signal, lg_ptr, ptr, err, fsError, osError);
1166 }
1167 
1168 void
1169 Tsman::execFSREADREF(Signal* signal)
1170 {
1171  jamEntry();
1172  Ptr<Datafile> ptr;
1173  Ptr<Tablespace> lg_ptr;
1174  FsRef* ref = (FsRef*)signal->getDataPtr();
1175 
1176  m_file_pool.getPtr(ptr, ref->userPointer);
1177  m_tablespace_hash.find(lg_ptr, ptr.p->m_tablespace_ptr_i);
1178 
1179  m_global_page_pool.release(ptr.p->m_create.m_page_ptr_i);
1180  create_file_ref(signal, lg_ptr, ptr, CreateFileImplRef::FileReadError,
1181  ref->errorCode, ref->osErrorCode);
1182 }
1183 
1184 void
1185 Tsman::load_extent_pages(Signal* signal, Ptr<Datafile> ptr)
1186 {
1191  preq.m_page.m_file_no = ptr.p->m_file_no;
1192  preq.m_page.m_page_no = ptr.p->m_create.m_loading_extent_page;
1193 
1194  preq.m_callback.m_callbackData = ptr.i;
1195  preq.m_callback.m_callbackFunction =
1196  safe_cast(&Tsman::load_extent_page_callback);
1197 
1198  int page_id;
1199  int flags = Page_cache_client::LOCK_PAGE;
1200  Page_cache_client pgman(this, m_pgman);
1201  if((page_id = pgman.get_page(signal, preq, flags)) > 0)
1202  {
1203  load_extent_page_callback(signal, ptr.i, (Uint32)page_id);
1204  }
1205 
1206  if(page_id < 0)
1207  {
1208  ndbrequire(false);
1209  }
1210 }
1211 
1212 void
1213 Tsman::load_extent_page_callback(Signal* signal,
1214  Uint32 callback,
1215  Uint32 real_page_ptr_i)
1216 {
1217  jamEntry();
1218  Ptr<Datafile> ptr;
1219  m_file_pool.getPtr(ptr, callback);
1220 
1221  if(++ptr.p->m_create.m_loading_extent_page <= ptr.p->m_create.m_extent_pages)
1222  {
1223  signal->theData[0] = TsmanContinueB::LOAD_EXTENT_PAGES;
1224  signal->theData[1] = ptr.i;
1225  sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
1226  return;
1227  }
1228 
1229  Uint32 senderRef = ptr.p->m_create.m_senderRef;
1230  Uint32 senderData = ptr.p->m_create.m_senderData;
1231  Uint32 extent_pages = ptr.p->m_create.m_extent_pages;
1232  Uint32 data_pages = ptr.p->m_create.m_data_pages;
1233  ndbassert(ptr.p->m_create.m_requestInfo == CreateFileImplReq::Commit);
1234 
1235  Uint32 eh= File_formats::Datafile::extent_header_words(ptr.p->m_extent_size);
1236  Uint32 per_page = File_formats::Datafile::EXTENT_PAGE_WORDS/eh;
1237 
1238  ptr.p->m_state = Datafile::FS_ONLINE;
1239  ptr.p->m_online.m_offset_data_pages = 1 + extent_pages;
1240  ptr.p->m_online.m_first_free_extent = per_page;
1241  ptr.p->m_online.m_lcp_free_extent_head = RNIL;
1242  ptr.p->m_online.m_lcp_free_extent_tail = RNIL;
1243  ptr.p->m_online.m_data_pages = data_pages;
1244  ptr.p->m_online.m_used_extent_cnt = 0;
1245  ptr.p->m_online.m_extent_headers_per_extent_page = per_page;
1246 
1247  Ptr<Tablespace> ts_ptr;
1248  m_tablespace_pool.getPtr(ts_ptr, ptr.p->m_tablespace_ptr_i);
1249  if (getNodeState().startLevel >= NodeState::SL_STARTED ||
1250  (getNodeState().startLevel == NodeState::SL_STARTING &&
1251  getNodeState().starting.restartType == NodeState::ST_INITIAL_START) ||
1252  (getNodeState().getNodeRestartInProgress() &&
1253  getNodeState().starting.restartType == NodeState::ST_INITIAL_NODE_RESTART))
1254  {
1255  Local_datafile_list free(m_file_pool, ts_ptr.p->m_free_files);
1256  Local_datafile_list meta(m_file_pool, ts_ptr.p->m_meta_files);
1257  meta.remove(ptr);
1258  free.add(ptr);
1259  }
1260  m_file_hash.add(ptr);
1261 
1262  CreateFileImplConf* conf= (CreateFileImplConf*)signal->getDataPtr();
1263  conf->senderData = senderData;
1264  conf->senderRef = reference();
1265  sendSignal(senderRef, GSN_CREATE_FILE_IMPL_CONF, signal,
1266  CreateFileImplConf::SignalLength, JBB);
1267 }
1268 
1269 void
1270 Tsman::execSTART_RECREQ(Signal* signal)
1271 {
1272  Ptr<Tablespace> lg_ptr;
1273  m_tablespace_list.first(lg_ptr);
1274 
1275  signal->theData[0] = TsmanContinueB::SCAN_TABLESPACE_EXTENT_HEADERS;
1276  signal->theData[1] = lg_ptr.i;
1277  sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
1278 }
1279 
1280 void
1281 Tsman::scan_tablespace(Signal* signal, Uint32 ptrI)
1282 {
1283  Ptr<Tablespace> lg_ptr;
1284  if(ptrI == RNIL)
1285  {
1286  signal->theData[0] = reference();
1287  sendSignal(DBLQH_REF, GSN_START_RECCONF, signal, 1, JBB);
1288  return;
1289  }
1290 
1291  m_tablespace_pool.getPtr(lg_ptr, ptrI);
1292 
1293  Ptr<Datafile> file_ptr;
1294  {
1295  Local_datafile_list meta(m_file_pool, lg_ptr.p->m_meta_files);
1296  meta.first(file_ptr);
1297  }
1298 
1299  scan_datafile(signal, lg_ptr.i, file_ptr.i);
1300 }
1301 
1302 void
1303 Tsman::scan_datafile(Signal* signal, Uint32 ptrI, Uint32 filePtrI)
1304 {
1305  Ptr<Datafile> file_ptr;
1306  Ptr<Tablespace> lg_ptr;
1307  m_tablespace_pool.getPtr(lg_ptr, ptrI);
1308  if(filePtrI == RNIL)
1309  {
1310  m_tablespace_list.next(lg_ptr);
1311  signal->theData[0] = TsmanContinueB::SCAN_TABLESPACE_EXTENT_HEADERS;
1312  signal->theData[1] = lg_ptr.i;
1313  sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
1314  }
1315  else
1316  {
1317  m_file_pool.getPtr(file_ptr, filePtrI);
1318  scan_extent_headers(signal, file_ptr);
1319  }
1320 }
1321 
1322 void
1323 Tsman::scan_extent_headers(Signal* signal, Ptr<Datafile> ptr)
1324 {
1325  Ptr<Tablespace> lg_ptr;
1326  m_tablespace_pool.getPtr(lg_ptr, ptr.p->m_tablespace_ptr_i);
1327 
1328  Uint32 firstFree= RNIL;
1329  Uint32 size = ptr.p->m_extent_size;
1330  Uint32 per_page = ptr.p->m_online.m_extent_headers_per_extent_page;
1331  Uint32 pages= ptr.p->m_online.m_offset_data_pages - 1;
1332  Uint32 datapages= ptr.p->m_online.m_data_pages;
1333  for(Uint32 i = 0; i < pages; i++)
1334  {
1335  Uint32 page_no = pages - i;
1337  preq.m_page.m_page_no = page_no;
1338  preq.m_page.m_file_no = ptr.p->m_file_no;
1339 
1340  int flags = Page_cache_client::DIRTY_REQ;
1341  Page_cache_client pgman(this, m_pgman);
1342  int real_page_id = pgman.get_page(signal, preq, flags);
1343  ndbrequire(real_page_id > 0);
1344  D("scan_extent_headers" << V(pages) << V(page_no) << V(real_page_id));
1345 
1347  (File_formats::Datafile::Extent_page*)pgman.m_ptr.p;
1348 
1349  Uint32 extents= per_page;
1350  if(page_no == pages)
1351  {
1356  Uint32 total_extents = datapages / size;
1357  extents= total_extents - (pages - 1)*per_page;
1358  }
1359  for(Uint32 j = 0; j<extents; j++)
1360  {
1361  Uint32 extent_no = extents - j - 1;
1363  page->get_header(extent_no, size);
1364  if (header->m_table == RNIL)
1365  {
1366  D("extent free" << V(j));
1367  header->m_next_free_extent = firstFree;
1368  firstFree = page_no * per_page + extent_no;
1369  }
1370  else
1371  {
1372  Uint32 tableId= header->m_table;
1373  Uint32 fragmentId= header->m_fragment_id;
1374  Dbtup_client tup(this, m_tup);
1375  Local_key key;
1376  key.m_file_no = ptr.p->m_file_no;
1377  key.m_page_no =
1378  pages + 1 + size * (page_no * per_page + extent_no - per_page);
1379  key.m_page_idx = page_no * per_page + extent_no;
1380  if(!tup.disk_restart_alloc_extent(tableId, fragmentId, &key, size))
1381  {
1382  ptr.p->m_online.m_used_extent_cnt++;
1383  for(Uint32 i = 0; i<size; i++, key.m_page_no++)
1384  {
1385  Uint32 bits= header->get_free_bits(i) & COMMITTED_MASK;
1386  header->update_free_bits(i, bits | (bits << UNCOMMITTED_SHIFT));
1387  tup.disk_restart_page_bits(tableId, fragmentId, &key, bits);
1388  }
1389  D("extent used" << V(j) << V(tableId) << V(fragmentId) << V(key));
1390  }
1391  else
1392  {
1393  header->m_table = RNIL;
1394  header->m_next_free_extent = firstFree;
1395  firstFree = page_no * per_page + extent_no;
1396  D("extent free" << V(j) << V(tableId) << V(fragmentId) << V(key));
1397  }
1398  }
1399  }
1400  }
1401  ptr.p->m_online.m_first_free_extent= firstFree;
1402 
1403  Local_datafile_list meta(m_file_pool, lg_ptr.p->m_meta_files);
1404  Ptr<Datafile> next = ptr;
1405  meta.next(next);
1406  if(firstFree != RNIL)
1407  {
1408  Local_datafile_list free(m_file_pool, lg_ptr.p->m_free_files);
1409  meta.remove(ptr);
1410  free.add(ptr);
1411  }
1412  else
1413  {
1414  Local_datafile_list full(m_file_pool, lg_ptr.p->m_full_files);
1415  meta.remove(ptr);
1416  full.add(ptr);
1417  }
1418 
1419  signal->theData[0] = TsmanContinueB::SCAN_DATAFILE_EXTENT_HEADERS;
1420  signal->theData[1] = lg_ptr.i;
1421  signal->theData[2] = next.i;
1422  sendSignal(reference(), GSN_CONTINUEB, signal, 3, JBB);
1423 }
1424 
1425 void
1426 Tsman::execDROP_FILE_IMPL_REQ(Signal* signal)
1427 {
1428  jamEntry();
1429  client_lock(number(), __LINE__);
1430  DropFileImplReq req = *(DropFileImplReq*)signal->getDataPtr();
1431  Ptr<Datafile> file_ptr;
1432  Ptr<Tablespace> fg_ptr;
1433 
1434  Uint32 errorCode = 0;
1435  do
1436  {
1437  if (!m_tablespace_hash.find(fg_ptr, req.filegroup_id))
1438  {
1439  errorCode = DropFileImplRef::InvalidFilegroup;
1440  break;
1441  }
1442 
1443  if (fg_ptr.p->m_version != req.filegroup_version)
1444  {
1445  errorCode = DropFileImplRef::InvalidFilegroupVersion;
1446  break;
1447  }
1448 
1449  switch(req.requestInfo){
1450  case DropFileImplReq::Prepare:{
1451  if (find_file_by_id(file_ptr, fg_ptr.p->m_full_files, req.file_id))
1452  {
1453  jam();
1454  Local_datafile_list full(m_file_pool, fg_ptr.p->m_full_files);
1455  full.remove(file_ptr);
1456  }
1457  else if(find_file_by_id(file_ptr, fg_ptr.p->m_free_files, req.file_id))
1458  {
1459  jam();
1460  Local_datafile_list free(m_file_pool, fg_ptr.p->m_free_files);
1461  free.remove(file_ptr);
1462  }
1463  else if(find_file_by_id(file_ptr, fg_ptr.p->m_meta_files, req.file_id))
1464  {
1465  jam();
1466  Local_datafile_list meta(m_file_pool, fg_ptr.p->m_meta_files);
1467  meta.remove(file_ptr);
1468  }
1469  else
1470  {
1471  errorCode = DropFileImplRef::NoSuchFile;
1472  break;
1473  }
1474 
1475  Local_datafile_list meta(m_file_pool, fg_ptr.p->m_meta_files);
1476  meta.add(file_ptr);
1477 
1478  if (file_ptr.p->m_online.m_used_extent_cnt ||
1479  file_ptr.p->m_state != Datafile::FS_ONLINE)
1480  {
1481  errorCode = DropFileImplRef::FileInUse;
1482  break;
1483  }
1484 
1485  file_ptr.p->m_state = Datafile::FS_DROPPING;
1486  break;
1487  }
1488  case DropFileImplReq::Commit:
1489  ndbrequire(find_file_by_id(file_ptr, fg_ptr.p->m_meta_files, req.file_id));
1490  if (file_ptr.p->m_ref_count)
1491  {
1492  jam();
1493  sendSignalWithDelay(reference(), GSN_DROP_FILE_REQ, signal,
1494  100, signal->getLength());
1495  return;
1496  }
1497 
1498  file_ptr.p->m_create.m_extent_pages =
1499  file_ptr.p->m_online.m_offset_data_pages - 1;
1500  file_ptr.p->m_create.m_senderRef = req.senderRef;
1501  file_ptr.p->m_create.m_senderData = req.senderData;
1502  release_extent_pages(signal, file_ptr);
1503  client_unlock(number(), __LINE__);
1504  return;
1505  case DropFileImplReq::Abort:{
1506  ndbrequire(find_file_by_id(file_ptr, fg_ptr.p->m_meta_files, req.file_id));
1507  file_ptr.p->m_state = Datafile::FS_ONLINE;
1508  Local_datafile_list meta(m_file_pool, fg_ptr.p->m_meta_files);
1509  meta.remove(file_ptr);
1510  if (file_ptr.p->m_online.m_first_free_extent != RNIL)
1511  {
1512  Local_datafile_list free(m_file_pool, fg_ptr.p->m_free_files);
1513  free.add(file_ptr);
1514  }
1515  else
1516  {
1517  Local_datafile_list full(m_file_pool, fg_ptr.p->m_full_files);
1518  full.add(file_ptr);
1519  }
1520  break;
1521  }
1522  }
1523  } while(0);
1524 
1525  if (errorCode)
1526  {
1527  DropFileImplRef* ref = (DropFileImplRef*)signal->getDataPtrSend();
1528  ref->senderRef = reference();
1529  ref->senderData = req.senderData;
1530  ref->errorCode = errorCode;
1531  sendSignal(req.senderRef, GSN_DROP_FILE_IMPL_REF, signal,
1532  DropFileImplRef::SignalLength, JBB);
1533  }
1534  else
1535  {
1536  DropFileImplConf* conf = (DropFileImplConf*)signal->getDataPtrSend();
1537  conf->senderRef = reference();
1538  conf->senderData = req.senderData;
1539  sendSignal(req.senderRef, GSN_DROP_FILE_IMPL_CONF, signal,
1540  DropFileImplConf::SignalLength, JBB);
1541  }
1542  client_unlock(number(), __LINE__);
1543 }
1544 
1545 Tsman::Tablespace::Tablespace(Tsman* ts, const CreateFilegroupImplReq* req)
1546 {
1547  m_tsman = ts;
1548  m_logfile_group_id = req->tablespace.logfile_group_id;
1549  m_tablespace_id = req->filegroup_id;
1550  m_version = req->filegroup_version;
1551  m_ref_count = 0;
1552 
1553  m_extent_size = (Uint32)DIV(req->tablespace.extent_size, File_formats::NDB_PAGE_SIZE);
1554 #if defined VM_TRACE || defined ERROR_INSERT
1555  ndbout << "DD tsman: ts id:" << m_tablespace_id << " extent pages/bytes:" << m_extent_size << "/" << m_extent_size*File_formats::NDB_PAGE_SIZE << endl;
1556 #endif
1557 }
1558 
1559 Tsman::Datafile::Datafile(const struct CreateFileImplReq* req)
1560 {
1561  m_file_id = req->file_id;
1562 
1563  m_file_no = RNIL;
1564  m_fd = RNIL;
1565  m_online.m_first_free_extent = RNIL;
1566  m_ref_count = 0;
1567 
1568  m_create.m_senderRef = req->senderRef; // During META
1569  m_create.m_senderData = req->senderData; // During META
1570  m_create.m_requestInfo = req->requestInfo;
1571 }
1572 
1573 void
1575 {
1576  jamEntry();
1577  Ptr<Tablespace> ts_ptr;
1578  Ptr<Datafile> file_ptr;
1579  AllocExtentReq req = *(AllocExtentReq*)signal->getDataPtr();
1580  AllocExtentReq::ErrorCode err;
1581 
1582  ndbrequire(m_tablespace_hash.find(ts_ptr, req.request.tablespace_id));
1583  Local_datafile_list tmp(m_file_pool, ts_ptr.p->m_free_files);
1584 
1585  if (tmp.first(file_ptr))
1586  {
1587  Uint32 size = file_ptr.p->m_extent_size;
1588  Uint32 extent = file_ptr.p->m_online.m_first_free_extent;
1589  Uint32 data_off = file_ptr.p->m_online.m_offset_data_pages;
1590  Uint32 eh_words = File_formats::Datafile::extent_header_words(size);
1591  Uint32 per_page = File_formats::Datafile::EXTENT_PAGE_WORDS/eh_words;
1592  Uint32 page_no = extent / per_page;
1593  Uint32 extent_no = extent % per_page;
1594 
1596  preq.m_page.m_page_no = page_no;
1597  preq.m_page.m_file_no = file_ptr.p->m_file_no;
1598 
1602  int flags = Page_cache_client::DIRTY_REQ;
1603  int real_page_id;
1604  Page_cache_client pgman(this, m_pgman);
1605  if ((real_page_id = pgman.get_page(signal, preq, flags)) > 0)
1606  {
1607  GlobalPage* ptr_p = pgman.m_ptr.p;
1608 
1612  page->get_header(extent_no, size);
1613 
1614  ndbrequire(header->m_table == RNIL);
1615  Uint32 next_free = header->m_next_free_extent;
1616 
1620  memset(header, 0, 4*eh_words);
1621  header->m_table = req.request.table_id;
1622  header->m_fragment_id = req.request.fragment_id;
1623 
1627  file_ptr.p->m_online.m_used_extent_cnt++;
1628  file_ptr.p->m_online.m_first_free_extent = next_free;
1629  if (next_free == RNIL)
1630  {
1631  jam();
1632  Local_datafile_list full(m_file_pool, ts_ptr.p->m_full_files);
1633  tmp.remove(file_ptr);
1634  full.add(file_ptr);
1635  }
1636 
1640  ndbassert(extent >= per_page);
1641  preq.m_page.m_page_no = data_off + size * (extent - /* zero */ per_page);
1642  preq.m_page.m_page_idx = extent; // extent_no
1643 
1644  AllocExtentReq* rep = (AllocExtentReq*)signal->getDataPtr();
1645  rep->reply.errorCode = 0;
1646  rep->reply.page_id = preq.m_page;
1647  rep->reply.page_count = size;
1648  return;
1649  }
1650  else
1651  {
1652  jam();
1653  err = AllocExtentReq::UnmappedExtentPageIsNotImplemented;
1654  }
1655  }
1656  else
1657  {
1658  jam();
1659  err = AllocExtentReq::NoExtentAvailable;
1660  Local_datafile_list full_tmp(m_file_pool, ts_ptr.p->m_full_files);
1661  if (tmp.isEmpty() && full_tmp.isEmpty())
1662  {
1663  jam();
1664  err = AllocExtentReq::NoDatafile;
1665  }
1666  }
1667 
1671  AllocExtentReq* rep = (AllocExtentReq*)signal->getDataPtr();
1672  rep->reply.errorCode = err;
1673  return;
1674 }
1675 
1676 void
1678 {
1679  jamEntry();
1680  Ptr<Datafile> file_ptr;
1681  FreeExtentReq req = *(FreeExtentReq*)signal->getDataPtr();
1682  FreeExtentReq::ErrorCode err = (FreeExtentReq::ErrorCode)0;
1683 
1684  Datafile file_key;
1685  file_key.m_file_no = req.request.key.m_file_no;
1686  ndbrequire(m_file_hash.find(file_ptr, file_key));
1687 
1688  struct req val = lookup_extent(req.request.key.m_page_no, file_ptr.p);
1689  Uint32 extent =
1690  (req.request.key.m_page_no - val.m_extent_pages) / val.m_extent_size +
1691  file_ptr.p->m_online.m_extent_headers_per_extent_page;
1692 
1694  preq.m_page.m_page_no = val.m_extent_page_no;
1695  preq.m_page.m_file_no = req.request.key.m_file_no;
1696 
1697  ndbout << "Free extent: " << req.request.key << endl;
1698 
1702  int flags = Page_cache_client::DIRTY_REQ;
1703  int real_page_id;
1704  Page_cache_client pgman(this, m_pgman);
1705  if ((real_page_id = pgman.get_page(signal, preq, flags)) > 0)
1706  {
1707  GlobalPage* ptr_p = pgman.m_ptr.p;
1708 
1712  page->get_header(val.m_extent_no, val.m_extent_size);
1713 
1714  ndbrequire(header->m_table == req.request.table_id);
1715  header->m_table = RNIL;
1716 
1717  file_ptr.p->m_online.m_used_extent_cnt--;
1718  if (m_lcp_ongoing)
1719  {
1720  jam();
1721  header->m_next_free_extent= file_ptr.p->m_online.m_lcp_free_extent_head;
1722  if(file_ptr.p->m_online.m_lcp_free_extent_head == RNIL)
1723  file_ptr.p->m_online.m_lcp_free_extent_tail= extent;
1724  file_ptr.p->m_online.m_lcp_free_extent_head= extent;
1725  }
1726  else
1727  {
1728  jam();
1729  header->m_next_free_extent = file_ptr.p->m_online.m_first_free_extent;
1730  if (file_ptr.p->m_online.m_first_free_extent == RNIL)
1731  {
1735  Ptr<Tablespace> ptr;
1736  m_tablespace_pool.getPtr(ptr, file_ptr.p->m_tablespace_ptr_i);
1737  Local_datafile_list free(m_file_pool, ptr.p->m_free_files);
1738  Local_datafile_list full(m_file_pool, ptr.p->m_full_files);
1739  full.remove(file_ptr);
1740  free.add(file_ptr);
1741  }
1742  file_ptr.p->m_online.m_first_free_extent = extent;
1743  }
1744  }
1745  else
1746  {
1747  jam();
1748  err = FreeExtentReq::UnmappedExtentPageIsNotImplemented;
1749  }
1750 
1754  FreeExtentReq* rep = (FreeExtentReq*)signal->getDataPtr();
1755  rep->reply.errorCode = err;
1756  return;
1757 }
1758 
1759 int
1760 Tsman::update_page_free_bits(Signal* signal,
1761  Local_key *key,
1762  unsigned committed_bits)
1763 {
1764  jamEntry();
1765 
1772  Ptr<Datafile> file_ptr;
1773  Datafile file_key;
1774  file_key.m_file_no = key->m_file_no;
1775  ndbrequire(m_file_hash.find(file_ptr, file_key));
1776 
1777  struct req val = lookup_extent(key->m_page_no, file_ptr.p);
1778 
1780  preq.m_page.m_page_no = val.m_extent_page_no;
1781  preq.m_page.m_file_no = key->m_file_no;
1782 
1786  int flags = Page_cache_client::COMMIT_REQ;
1787  int real_page_id;
1788  Page_cache_client pgman(this, m_pgman);
1789  if ((real_page_id = pgman.get_page(signal, preq, flags)) > 0)
1790  {
1791  GlobalPage* ptr_p = pgman.m_ptr.p;
1792 
1796  page->get_header(val.m_extent_no, val.m_extent_size);
1797 
1798  if (header->m_table == RNIL)
1799  {
1800  ndbout << "update page free bits page: " << *key
1801  << " " << *header << endl;
1802  }
1803 
1804  if (0)
1805  {
1806  ndbout << "update page free bits page(" << committed_bits << ") "
1807  << *key << " " << *header << endl;
1808  }
1809 
1810  ndbrequire(header->m_table != RNIL);
1811 
1812  Uint32 page_no_in_extent = calc_page_no_in_extent(key->m_page_no, &val);
1813 
1817  ndbassert((committed_bits & ~(COMMITTED_MASK)) == 0);
1818  Uint32 src = header->get_free_bits(page_no_in_extent) & UNCOMMITTED_MASK;
1819  header->update_free_bits(page_no_in_extent, src | committed_bits);
1820 
1821  pgman.update_lsn(preq.m_page, 0);
1822 
1823  return 0;
1824  }
1825 
1826  return AllocExtentReq::UnmappedExtentPageIsNotImplemented;
1827 }
1828 
1829 int
1830 Tsman::get_page_free_bits(Signal* signal, Local_key *key,
1831  unsigned* uncommitted,
1832  unsigned* committed)
1833 {
1834  jamEntry();
1835 
1836  Ptr<Datafile> file_ptr;
1837  Datafile file_key;
1838  file_key.m_file_no = key->m_file_no;
1839  ndbrequire(m_file_hash.find(file_ptr, file_key));
1840 
1841  struct req val = lookup_extent(key->m_page_no, file_ptr.p);
1842 
1844  preq.m_page.m_page_no = val.m_extent_page_no;
1845  preq.m_page.m_file_no = key->m_file_no;
1846 
1850  int flags = 0;
1851  int real_page_id;
1852  Page_cache_client pgman(this, m_pgman);
1853  if ((real_page_id = pgman.get_page(signal, preq, flags)) > 0)
1854  {
1855  GlobalPage* ptr_p = pgman.m_ptr.p;
1856 
1860  page->get_header(val.m_extent_no, val.m_extent_size);
1861 
1862  ndbrequire(header->m_table != RNIL);
1863 
1864  Uint32 page_no_in_extent = calc_page_no_in_extent(key->m_page_no, &val);
1865  Uint32 bits = header->get_free_bits(page_no_in_extent);
1866  *uncommitted = (bits & UNCOMMITTED_MASK) >> UNCOMMITTED_SHIFT;
1867  *committed = (bits & COMMITTED_MASK);
1868  return 0;
1869  }
1870 
1871  return AllocExtentReq::UnmappedExtentPageIsNotImplemented;
1872 }
1873 
1874 int
1875 Tsman::unmap_page(Signal* signal, Local_key *key, Uint32 uncommitted_bits)
1876 {
1877  jamEntry();
1878 
1885  Ptr<Datafile> file_ptr;
1886  Datafile file_key;
1887  file_key.m_file_no = key->m_file_no;
1888  ndbrequire(m_file_hash.find(file_ptr, file_key));
1889 
1890  struct req val = lookup_extent(key->m_page_no, file_ptr.p);
1891 
1893  preq.m_page.m_page_no = val.m_extent_page_no;
1894  preq.m_page.m_file_no = key->m_file_no;
1895 
1899  int flags = 0;
1900  int real_page_id;
1901  Page_cache_client pgman(this, m_pgman);
1902  if ((real_page_id = pgman.get_page(signal, preq, flags)) > 0)
1903  {
1904  GlobalPage* ptr_p = pgman.m_ptr.p;
1905 
1909  page->get_header(val.m_extent_no, val.m_extent_size);
1910 
1911  if (header->m_table == RNIL)
1912  {
1913  ndbout << "trying to unmap page: " << *key
1914  << " " << *header << endl;
1915  }
1916  ndbrequire(header->m_table != RNIL);
1917 
1918  Uint32 page_no_in_extent = calc_page_no_in_extent(key->m_page_no, &val);
1919 
1923  ndbassert(((uncommitted_bits << UNCOMMITTED_SHIFT) & ~UNCOMMITTED_MASK) == 0);
1924  Uint32 src = header->get_free_bits(page_no_in_extent) & COMMITTED_MASK;
1925  header->update_free_bits(page_no_in_extent,
1926  src | (uncommitted_bits << UNCOMMITTED_SHIFT));
1927  }
1928 
1929  return AllocExtentReq::UnmappedExtentPageIsNotImplemented;
1930 }
1931 
1932 int
1933 Tsman::restart_undo_page_free_bits(Signal* signal,
1934  Uint32 tableId,
1935  Uint32 fragId,
1936  Local_key *key,
1937  unsigned bits)
1938 {
1939  jamEntry();
1940 
1947  Ptr<Datafile> file_ptr;
1948  Datafile file_key;
1949  file_key.m_file_no = key->m_file_no;
1950  ndbrequire(m_file_hash.find(file_ptr, file_key));
1951 
1952  struct req val = lookup_extent(key->m_page_no, file_ptr.p);
1953 
1955  preq.m_page.m_page_no = val.m_extent_page_no;
1956  preq.m_page.m_file_no = key->m_file_no;
1957 
1961  int flags = Page_cache_client::DIRTY_REQ;
1962  int real_page_id;
1963  Page_cache_client pgman(this, m_pgman);
1964  if ((real_page_id = pgman.get_page(signal, preq, flags)) > 0)
1965  {
1966  GlobalPage* ptr_p = pgman.m_ptr.p;
1967 
1971  page->get_header(val.m_extent_no, val.m_extent_size);
1972 
1973  if (header->m_table == RNIL)
1974  {
1975  if (DBG_UNDO)
1976  ndbout_c("tsman: apply undo - skip table == RNIL");
1977  return 0;
1978  }
1979 
1980  Uint32 page_no_in_extent = calc_page_no_in_extent(key->m_page_no, &val);
1981  Uint32 src = header->get_free_bits(page_no_in_extent);
1982 
1983  if (! (header->m_table == tableId && header->m_fragment_id == fragId))
1984  {
1985  ndbout_c("%u %u != %u %u",
1986  header->m_table, header->m_fragment_id,
1987  tableId, fragId);
1988  }
1989 
1990  ndbrequire(header->m_table == tableId);
1991  ndbrequire(header->m_fragment_id == fragId);
1992 
1996  if (DBG_UNDO)
1997  {
1998  ndbout << "tsman: apply "
1999  << *key << " " << (src & COMMITTED_MASK)
2000  << " -> " << bits << endl;
2001  }
2002 
2003  ndbassert((bits & ~(COMMITTED_MASK)) == 0);
2004  header->update_free_bits(page_no_in_extent,
2005  bits | (bits << UNCOMMITTED_SHIFT));
2006 
2007  return 0;
2008  }
2009 
2010  return AllocExtentReq::UnmappedExtentPageIsNotImplemented;
2011 }
2012 
2013 void
2015 {
2016  jamEntry();
2017 
2018  AllocPageReq *rep= (AllocPageReq*)signal->getDataPtr();
2019  AllocPageReq req = *rep;
2020  AllocPageReq::ErrorCode
2021  err= AllocPageReq::UnmappedExtentPageIsNotImplemented;
2022 
2029  Ptr<Datafile> file_ptr;
2030  Datafile file_key;
2031  file_key.m_file_no = req.key.m_file_no;
2032  ndbrequire(m_file_hash.find(file_ptr, file_key));
2033 
2034  struct req val = lookup_extent(req.key.m_page_no, file_ptr.p);
2035  Uint32 page_no_in_extent = calc_page_no_in_extent(req.key.m_page_no, &val);
2036 
2038  preq.m_page.m_page_no = val.m_extent_page_no;
2039  preq.m_page.m_file_no = req.key.m_file_no;
2040 
2041  Uint32 SZ= File_formats::Datafile::EXTENT_HEADER_BITMASK_BITS_PER_PAGE;
2042 
2046  int flags = Page_cache_client::DIRTY_REQ;
2047  int real_page_id;
2048  Uint32 page_no;
2049  Uint32 src_bits;
2051  Page_cache_client pgman(this, m_pgman);
2052  if ((real_page_id = pgman.get_page(signal, preq, flags)) > 0)
2053  {
2054  GlobalPage* ptr_p = pgman.m_ptr.p;
2055 
2058  header= page->get_header(val.m_extent_no, val.m_extent_size);
2059 
2060  ndbrequire(header->m_table == req.request.table_id);
2061 
2062  Uint32 word = header->get_free_word_offset(page_no_in_extent);
2063  Uint32 shift = SZ * (page_no_in_extent & 7);
2064 
2072  Uint32 reqbits = req.bits << UNCOMMITTED_SHIFT;
2073 
2077  Uint32 *src= header->m_page_bitmask + word;
2078  for(page_no= page_no_in_extent; page_no<val.m_extent_size; page_no++)
2079  {
2080  src_bits= (* src >> shift) & ((1 << SZ) - 1);
2081  if((src_bits & UNCOMMITTED_MASK) <= reqbits)
2082  {
2083  goto found;
2084  }
2085  shift += SZ;
2086  src = src + (shift >> 5);
2087  shift &= 31;
2088  }
2089 
2090  shift= 0;
2091  src= header->m_page_bitmask;
2092  for(page_no= 0; page_no<page_no_in_extent; page_no++)
2093  {
2094  src_bits= (* src >> shift) & ((1 << SZ) - 1);
2095  if((src_bits & UNCOMMITTED_MASK) <= reqbits)
2096  {
2097  goto found;
2098  }
2099  shift += SZ;
2100  src = src + (shift >> 5);
2101  shift &= 31;
2102  }
2103 
2104 #if 0
2105  printf("req.bits: %d bits: ", req.bits);
2106  for(Uint32 i = 0; i<size; i++)
2107  {
2108  printf("%x", header->get_free_bits(i));
2109  }
2110  ndbout_c("");
2111 #endif
2112  err= AllocPageReq::NoPageFree;
2113  }
2114 
2115  rep->reply.errorCode = err;
2116  return;
2117 
2118 found:
2119  header->update_free_bits(page_no, src_bits | UNCOMMITTED_MASK);
2120  rep->bits= (src_bits & UNCOMMITTED_MASK) >> UNCOMMITTED_SHIFT;
2121  rep->key.m_page_no = req.key.m_page_no + page_no - page_no_in_extent;
2122  rep->reply.errorCode= 0;
2123  return;
2124 }
2125 
2126 void
2127 Tsman::execLCP_FRAG_ORD(Signal* signal)
2128 {
2129  jamEntry();
2130  ndbrequire(!m_lcp_ongoing);
2131  m_lcp_ongoing = true;
2132 }
2133 
2134 void
2136 {
2137  jamEntry();
2138  ndbrequire(m_lcp_ongoing);
2139  m_lcp_ongoing = false;
2140 
2144  Ptr<Tablespace> ptr;
2145  if (m_tablespace_list.first(ptr))
2146  {
2147  jam();
2148  ptr.p->m_ref_count ++;
2149  signal->theData[0] = TsmanContinueB::END_LCP;
2150  signal->theData[1] = ptr.i;
2151  signal->theData[2] = 0; // free
2152  signal->theData[3] = RNIL; // first
2153  sendSignal(reference(), GSN_CONTINUEB, signal, 4, JBB);
2154  }
2155 }
2156 
2157 void
2158 Tsman::end_lcp(Signal* signal, Uint32 ptrI, Uint32 list, Uint32 filePtrI)
2159 {
2160  Ptr<Tablespace> ptr;
2161  m_tablespace_list.getPtr(ptr, ptrI);
2162  ndbrequire(ptr.p->m_ref_count);
2163  ptr.p->m_ref_count--;
2164 
2166  file.i = filePtrI;
2167  Uint32 nextFile = RNIL;
2168 
2169  switch(list){
2170  case 0:
2171  {
2172  Local_datafile_list tmp(m_file_pool, ptr.p->m_free_files);
2173  if(file.i == RNIL)
2174  {
2175  if(!tmp.first(file))
2176  {
2177  list= 1;
2178  goto next;
2179  }
2180  }
2181  else
2182  {
2183  tmp.getPtr(file);
2184  ndbrequire(file.p->m_ref_count);
2185  file.p->m_ref_count--;
2186  }
2187  break;
2188  }
2189  case 1:
2190  {
2191  Local_datafile_list tmp(m_file_pool, ptr.p->m_full_files);
2192  if(file.i == RNIL)
2193  {
2194  if(!tmp.first(file))
2195  {
2196  list= 0;
2197  if(m_tablespace_list.next(ptr))
2198  goto next;
2199  return;
2200  }
2201  }
2202  else
2203  {
2204  tmp.getPtr(file);
2205  ndbrequire(file.p->m_ref_count);
2206  file.p->m_ref_count--;
2207  }
2208  break;
2209  }
2210  default:
2211  ndbrequire(false);
2212  }
2213 
2214  nextFile = file.p->nextList;
2215 
2219  if(file.p->m_online.m_lcp_free_extent_head != RNIL)
2220  {
2221  ndbout_c("moving extents (%d %d) to real free list %d",
2222  file.p->m_online.m_lcp_free_extent_head,
2223  file.p->m_online.m_lcp_free_extent_tail,
2224  file.p->m_online.m_first_free_extent);
2225 
2226  if(file.p->m_online.m_first_free_extent == RNIL)
2227  {
2228  ndbrequire(list == 1);
2229  file.p->m_online.m_first_free_extent =
2230  file.p->m_online.m_lcp_free_extent_head;
2231  file.p->m_online.m_lcp_free_extent_head = RNIL;
2232  file.p->m_online.m_lcp_free_extent_tail = RNIL;
2233 
2234  Local_datafile_list free(m_file_pool, ptr.p->m_free_files);
2235  Local_datafile_list full(m_file_pool, ptr.p->m_full_files);
2236  full.remove(file);
2237  free.add(file);
2238  }
2239  else
2240  {
2241  Uint32 extent = file.p->m_online.m_lcp_free_extent_tail;
2242  Uint32 size = ptr.p->m_extent_size;
2243  Uint32 eh_words = File_formats::Datafile::extent_header_words(size);
2244  Uint32 per_page = File_formats::Datafile::EXTENT_PAGE_WORDS/eh_words;
2245 
2246  Uint32 page_no = extent / per_page;
2247  Uint32 extent_no = extent % per_page;
2248 
2250  preq.m_page.m_page_no = page_no;
2251  preq.m_page.m_file_no = file.p->m_file_no;
2252 
2253  int flags = Page_cache_client::DIRTY_REQ;
2254  int real_page_id;
2255  Page_cache_client pgman(this, m_pgman);
2256  ndbrequire((real_page_id = pgman.get_page(signal, preq, flags)) > 0);
2257 
2258  GlobalPage* ptr_p = pgman.m_ptr.p;
2259 
2263  page->get_header(extent_no, size);
2264 
2265  header->m_next_free_extent = file.p->m_online.m_first_free_extent;
2266  file.p->m_online.m_first_free_extent =
2267  file.p->m_online.m_lcp_free_extent_head;
2268 
2269  file.p->m_online.m_lcp_free_extent_head = RNIL;
2270  file.p->m_online.m_lcp_free_extent_tail = RNIL;
2271  }
2272  }
2273 
2274 
2278  file.i = nextFile;
2279  if(file.i == RNIL)
2280  {
2281  if(list == 0)
2282  list = 1;
2283  else
2284  {
2285  list = 0;
2286  m_tablespace_list.next(ptr);
2287  }
2288  }
2289  else
2290  {
2291  jam();
2292  ndbrequire(ptr.i != RNIL);
2293  m_file_pool.getPtr(file);
2294  file.p->m_ref_count++;
2295  }
2296 
2297 next:
2298  if(ptr.i != RNIL)
2299  {
2300  ptr.p->m_ref_count++;
2301 
2302  signal->theData[0] = TsmanContinueB::END_LCP;
2303  signal->theData[1] = ptr.i;
2304  signal->theData[2] = list;
2305  signal->theData[3] = file.i;
2306  sendSignal(reference(), GSN_CONTINUEB, signal, 4, JBB);
2307  }
2308 }
2309 
2310 int
2312 {
2313  Ptr<Tsman::Tablespace> ts_ptr;
2314  if(m_tsman->m_tablespace_hash.find(ts_ptr, m_tablespace_id))
2315  {
2316  Uint32 logfile_group_id = ts_ptr.p->m_logfile_group_id;
2317  // ctor is used here only for logging
2318  D("Logfile_client - get_tablespace_info");
2319  Logfile_client lgman(m_tsman, m_tsman->m_lgman, logfile_group_id, false);
2320  rep->tablespace.extent_size = ts_ptr.p->m_extent_size;
2321  rep->tablespace.logfile_group_id = lgman.m_logfile_group_id;
2322  return 0;
2323  }
2324  return -1;
2325 }
2326 
2327 void Tsman::execGET_TABINFOREQ(Signal* signal)
2328 {
2329  jamEntry();
2330 
2331  if(!assembleFragments(signal))
2332  {
2333  return;
2334  }
2335 
2336  GetTabInfoReq * const req = (GetTabInfoReq *)&signal->theData[0];
2337 
2338  Uint32 tableId= req->tableId;
2339  const Uint32 reqType = req->requestType & (~GetTabInfoReq::LongSignalConf);
2340  BlockReference retRef= req->senderRef;
2341  Uint32 senderData= req->senderData;
2342 
2343  if(reqType == GetTabInfoReq::RequestByName)
2344  {
2345  jam();
2346  SectionHandle handle(this, signal);
2347  releaseSections(handle);
2348 
2349  sendGET_TABINFOREF(signal, req, GetTabInfoRef::NoFetchByName);
2350  return;
2351  }
2352 
2353  Datafile_hash::Iterator iter;
2354  if (!m_file_hash.first(iter))
2355  {
2356  ndbrequire(false);
2357  return; // Silence compiler warning
2358  }
2359 
2360  while(iter.curr.p->m_file_id != tableId && m_file_hash.next(iter))
2361  ;
2362 
2363  if(iter.curr.p->m_file_id != tableId)
2364  {
2365  sendGET_TABINFOREF(signal, req, GetTabInfoRef::InvalidTableId);
2366  return;
2367  }
2368 
2369  const Ptr<Datafile> &file_ptr= iter.curr;
2370 
2371  jam();
2372 
2373  Uint32 total_free_extents = file_ptr.p->m_online.m_data_pages;
2374  total_free_extents /= file_ptr.p->m_extent_size;
2375  total_free_extents -= file_ptr.p->m_online.m_used_extent_cnt;
2376 
2377  GetTabInfoConf *conf = (GetTabInfoConf *)&signal->theData[0];
2378 
2379  conf->senderData= senderData;
2380  conf->tableId= tableId;
2381  conf->freeExtents= total_free_extents;
2382  conf->tableType= DictTabInfo::Datafile;
2383  conf->senderRef= reference();
2384  sendSignal(retRef, GSN_GET_TABINFO_CONF, signal,
2385  GetTabInfoConf::SignalLength, JBB);
2386 }
2387 
2389  GetTabInfoReq * req,
2390  GetTabInfoRef::ErrorCode errorCode)
2391 {
2392  jamEntry();
2393  GetTabInfoRef * const ref = (GetTabInfoRef *)&signal->theData[0];
2397  BlockReference retRef = req->senderRef;
2398  ref->errorCode = errorCode;
2399 
2400  sendSignal(retRef, GSN_GET_TABINFOREF, signal, signal->length(), JBB);
2401 }