1 /*
2 Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #include "Restore.hpp"
26 #include <NdbTCP.h>
27 #include <OutputStream.hpp>
28 #include <Bitmask.hpp>
29
30 #include <AttributeHeader.hpp>
31 #include <trigger_definitions.h>
32 #include <SimpleProperties.hpp>
33 #include <signaldata/DictTabInfo.hpp>
34 #include <ndb_limits.h>
35 #include <NdbAutoPtr.hpp>
36 #include "../src/kernel/blocks/backup/BackupFormat.hpp"
37 #include "../src/ndbapi/NdbDictionaryImpl.hpp"
38
39 #include "restore_tables.h"
40 #include <NdbThread.h>
41 #include "../src/kernel/vm/Emulator.hpp"
42
43 extern thread_local EmulatedJamBuffer* NDB_THREAD_TLS_JAM;
44
45 extern NdbRecordPrintFormat g_ndbrecord_print_format;
46 extern bool ga_skip_unknown_objects;
47 extern bool ga_skip_broken_objects;
48 extern bool opt_include_stored_grants;
49
50 #define LOG_MSGLEN 1024
51
52 Uint16 Twiddle16(Uint16 in); // Byte shift 16-bit data
53 Uint32 Twiddle32(Uint32 in); // Byte shift 32-bit data
54 Uint64 Twiddle64(Uint64 in); // Byte shift 64-bit data
55
56
57 /*
58 TwiddleUtil
59
60 Utility class used when swapping byteorder
61 of one attribute in a table
62
63 */
64
65 class TwiddleUtil {
66 Uint32 m_twiddle_size;
67 Uint32 m_twiddle_array_size;
68 public:
69 TwiddleUtil(); // Not implemented
70 TwiddleUtil(const TwiddleUtil&); // Not implemented
71
TwiddleUtil(const AttributeDesc * const attr_desc)72 TwiddleUtil(const AttributeDesc * const attr_desc) {
73 const NdbDictionary::Column::Type attribute_type =
74 attr_desc->m_column->getType();
75
76 switch(attribute_type){
77 case NdbDictionary::Column::Datetime:
78 // Datetime is stored as 8x8, should be twiddled as 64 bit
79 assert(attr_desc->size == 8);
80 assert(attr_desc->arraySize == 8);
81 m_twiddle_size = 64;
82 m_twiddle_array_size = 1;
83 break;
84
85 case NdbDictionary::Column::Timestamp:
86 // Timestamp is stored as 4x8, should be twiddled as 32 bit
87 assert(attr_desc->size == 8);
88 assert(attr_desc->arraySize == 4);
89 m_twiddle_size = 32;
90 m_twiddle_array_size = 1;
91 break;
92
93 case NdbDictionary::Column::Blob:
94 case NdbDictionary::Column::Text:
95 if (attr_desc->m_column->getArrayType() ==
96 NdbDictionary::Column::ArrayTypeFixed)
97 {
98 // Length of fixed size blob which is stored in first 64 bit's
99 // has to be twiddled, the remaining byte stream left as is
100 assert(attr_desc->size == 8);
101 assert(attr_desc->arraySize > 8);
102 m_twiddle_size = 64;
103 m_twiddle_array_size = 1;
104 break;
105 }
106 // Fall through - for blob/text with ArrayTypeVar
107 default:
108 // Default twiddling parameters
109 m_twiddle_size = attr_desc->size;
110 m_twiddle_array_size = attr_desc->arraySize;
111 break;
112 }
113
114 assert(m_twiddle_array_size);
115 assert(m_twiddle_size);
116 }
117
is_aligned(void * data_ptr) const118 bool is_aligned (void* data_ptr) const {
119 switch (m_twiddle_size){
120 case 8:
121 // Always aligned
122 return true;
123 break;
124 case 16:
125 return ((((size_t)data_ptr) & 1) == 0);
126 break;
127 case 32:
128 return ((((size_t)data_ptr) & 3) == 0);
129 break;
130 case 64:
131 return ((((size_t)data_ptr) & 7) == 0);
132 break;
133 default:
134 abort();
135 break;
136 }
137 return false; // Never reached
138 }
139
twiddle_aligned(void * const data_ptr) const140 void twiddle_aligned(void* const data_ptr) const {
141 // Make sure the data pointer is properly aligned
142 assert(is_aligned(data_ptr));
143
144 switch(m_twiddle_size){
145 case 8:
146 // Nothing to swap
147 break;
148 case 16:
149 {
150 Uint16* ptr = (Uint16*)data_ptr;
151 for (Uint32 i = 0; i < m_twiddle_array_size; i++){
152 *ptr = Twiddle16(*ptr);
153 ptr++;
154 }
155 break;
156 }
157 case 32:
158 {
159 Uint32* ptr = (Uint32*)data_ptr;
160 for (Uint32 i = 0; i < m_twiddle_array_size; i++){
161 *ptr = Twiddle32(*ptr);
162 ptr++;
163 }
164 break;
165 }
166 case 64:
167 {
168 Uint64* ptr = (Uint64*)data_ptr;
169 for (Uint32 i = 0; i < m_twiddle_array_size; i++){
170 *ptr = Twiddle64(*ptr);
171 ptr++;
172 }
173 break;
174 }
175 default:
176 abort();
177 } // switch
178 }
179 };
180
181
182 /*
183 BackupFile::twiddle_attribute
184
185 Swap the byte order of one attribute whose data may or may not
186 be properly aligned for the current datatype
187
188 */
189
190 void
twiddle_atribute(const AttributeDesc * const attr_desc,AttributeData * attr_data)191 BackupFile::twiddle_atribute(const AttributeDesc * const attr_desc,
192 AttributeData* attr_data)
193 {
194 TwiddleUtil map(attr_desc);
195
196 // Check if data is aligned properly
197 void* data_ptr = (char*)attr_data->void_value;
198 Uint32 data_sz = attr_desc->getSizeInBytes();
199 bool aligned= map.is_aligned(data_ptr);
200 if (!aligned)
201 {
202 // The pointer is not properly aligned, copy the data
203 // to aligned memory before twiddling
204 m_twiddle_buffer.assign(data_ptr, data_sz);
205 data_ptr = m_twiddle_buffer.get_data();
206 }
207
208 // Swap the byteorder of the aligned data
209 map.twiddle_aligned(data_ptr);
210
211 if (!aligned)
212 {
213 // Copy data back from aligned memory
214 memcpy(attr_data->void_value,
215 m_twiddle_buffer.get_data(),
216 data_sz);
217 }
218 }
219
220
221 /*
222 BackupFile::Twiddle
223
224 Swap the byteorder for one attribute if it was stored
225 in different byteorder than current host
226
227 */
228
229 bool
Twiddle(const AttributeDesc * const attr_desc,AttributeData * attr_data)230 BackupFile::Twiddle(const AttributeDesc * const attr_desc,
231 AttributeData* attr_data)
232 {
233 // Check parameters are not NULL
234 assert(attr_desc);
235 assert(attr_data);
236
237 // Make sure there is data to fiddle with
238 assert(!attr_data->null);
239 assert(attr_data->void_value);
240
241 if(unlikely(!m_hostByteOrder))
242 {
243 // The data file is not in host byte order, the
244 // attribute need byte order swapped
245 twiddle_atribute(attr_desc, attr_data);
246 }
247 #ifdef VM_TRACE
248 else
249 {
250 // Increase test converage in debug mode by doing
251 // a double byte order swap to prove that both ways work
252 twiddle_atribute(attr_desc, attr_data);
253 twiddle_atribute(attr_desc, attr_data);
254 }
255 #endif
256
257 return true;
258 }
259
260
261 FilteredNdbOut err(* new FileOutputStream(stderr), 0, 0);
262 FilteredNdbOut info(* new FileOutputStream(stdout), 1, 1);
263 FilteredNdbOut debug(* new FileOutputStream(stdout), 2, 0);
264 RestoreLogger restoreLogger;
265
266 // To decide in what byte order data is
267 const Uint32 magicByteOrder = 0x12345678;
268 const Uint32 swappedMagicByteOrder = 0x78563412;
269
RestoreMetaData(const char * path,Uint32 nodeId,Uint32 bNo,Uint32 partId,Uint32 partCount)270 RestoreMetaData::RestoreMetaData(const char* path, Uint32 nodeId,
271 Uint32 bNo, Uint32 partId, Uint32 partCount)
272 {
273 debug << "RestoreMetaData constructor" << endl;
274 m_part_id = partId;
275 m_part_count = partCount;
276 setCtlFile(nodeId, bNo, path);
277 }
278
~RestoreMetaData()279 RestoreMetaData::~RestoreMetaData(){
280 for(Uint32 i= 0; i < allTables.size(); i++)
281 {
282 TableS *table = allTables[i];
283 for(Uint32 j= 0; j < table->m_fragmentInfo.size(); j++)
284 delete table->m_fragmentInfo[j];
285 delete table;
286 }
287
288 for (Uint32 i = 0; i < m_objects.size(); i++)
289 {
290 switch (m_objects[i].m_objType)
291 {
292 case DictTabInfo::Tablespace:
293 {
294 NdbDictionary::Tablespace * dst =
295 (NdbDictionary::Tablespace *)m_objects[i].m_objPtr;
296 delete dst;
297 break;
298 }
299 case DictTabInfo::LogfileGroup:
300 {
301 NdbDictionary::LogfileGroup * dst =
302 (NdbDictionary::LogfileGroup *)m_objects[i].m_objPtr;
303 delete dst;
304 break;
305 }
306 case DictTabInfo::Datafile:
307 {
308 NdbDictionary::Datafile * dst =
309 (NdbDictionary::Datafile *)m_objects[i].m_objPtr;
310 delete dst;
311 break;
312 }
313 case DictTabInfo::Undofile:
314 {
315 NdbDictionary::Undofile * dst =
316 (NdbDictionary::Undofile *)m_objects[i].m_objPtr;
317 delete dst;
318 break;
319 }
320 case DictTabInfo::HashMap:
321 {
322 NdbDictionary::HashMap * dst =
323 (NdbDictionary::HashMap *)m_objects[i].m_objPtr;
324 delete dst;
325 break;
326 }
327 case DictTabInfo::ForeignKey:
328 {
329 NdbDictionary::ForeignKey * dst =
330 (NdbDictionary::ForeignKey *)m_objects[i].m_objPtr;
331 delete dst;
332 break;
333 }
334 default:
335 err << "Unsupported table type!! " << endl;
336 assert(false);
337 break;
338 }
339 }
340 m_objects.clear();
341 }
342
343 TableS *
getTable(Uint32 tableId) const344 RestoreMetaData::getTable(Uint32 tableId) const {
345 for(Uint32 i= 0; i < allTables.size(); i++)
346 if(allTables[i]->getTableId() == tableId)
347 return allTables[i];
348 return NULL;
349 }
350
351 Uint32
getStartGCP() const352 RestoreMetaData::getStartGCP() const {
353 return m_startGCP;
354 }
355
356 Uint32
getStopGCP() const357 RestoreMetaData::getStopGCP() const {
358 return m_stopGCP;
359 }
360
361 int
loadContent()362 RestoreMetaData::loadContent()
363 {
364 Uint32 noOfTables = readMetaTableList();
365 if(noOfTables == 0) {
366 return 1;
367 }
368 for(Uint32 i = 0; i<noOfTables; i++){
369 if(!readMetaTableDesc()){
370 return 0;
371 }
372 }
373 if (!markSysTables())
374 return 0;
375 if (!fixBlobs())
376 return 0;
377 if(!readGCPEntry())
378 return 0;
379
380 if(!readFragmentInfo())
381 return 0;
382 return 1;
383 }
384
385 Uint32
readMetaTableList()386 RestoreMetaData::readMetaTableList() {
387
388 Uint32 sectionInfo[2];
389
390 if (buffer_read(§ionInfo, sizeof(sectionInfo), 1) != 1){
391 restoreLogger.log_error("readMetaTableList read header error");
392 return 0;
393 }
394 sectionInfo[0] = ntohl(sectionInfo[0]);
395 sectionInfo[1] = ntohl(sectionInfo[1]);
396
397 const Uint32 tabCount = sectionInfo[1] - 2;
398
399 void *tmp;
400 Uint32 tabsRead = 0;
401 while (tabsRead < tabCount){
402 int count = buffer_get_ptr(&tmp, 4, tabCount - tabsRead);
403 if(count == 0)
404 break;
405 tabsRead += count;
406 }
407 if (tabsRead != tabCount){
408 restoreLogger.log_error("readMetaTableList read tabCount error, "
409 "expected count = %u, actual count = %u", tabCount, tabsRead);
410 return 0;
411 }
412 #ifdef ERROR_INSERT
413 if(m_error_insert == NDB_RESTORE_ERROR_INSERT_SMALL_BUFFER)
414 {
415 // clear error insert
416 m_error_insert = 0;
417 m_buffer_sz = BUFFER_SIZE;
418 }
419 #endif
420 return tabCount;
421 }
422
423 bool
readMetaTableDesc()424 RestoreMetaData::readMetaTableDesc() {
425
426 Uint32 sectionInfo[3];
427
428 // Read section header
429 Uint32 sz = sizeof(sectionInfo) >> 2;
430 if (m_fileHeader.NdbVersion < NDBD_ROWID_VERSION ||
431 ndbd_drop6(m_fileHeader.NdbVersion))
432 {
433 sz = 2;
434 sectionInfo[2] = htonl(DictTabInfo::UserTable);
435 }
436 if (buffer_read(§ionInfo, 4*sz, 1) != 1){
437 restoreLogger.log_error("readMetaTableDesc read header error");
438 return false;
439 } // if
440 sectionInfo[0] = ntohl(sectionInfo[0]);
441 sectionInfo[1] = ntohl(sectionInfo[1]);
442 sectionInfo[2] = ntohl(sectionInfo[2]);
443
444 assert(sectionInfo[0] == BackupFormat::TABLE_DESCRIPTION);
445
446 // Read dictTabInfo buffer
447 const Uint32 len = (sectionInfo[1] - sz);
448 void *ptr;
449 if (buffer_get_ptr(&ptr, 4, len) != len){
450 restoreLogger.log_error("readMetaTableDesc read error");
451 return false;
452 } // if
453
454 int errcode = 0;
455 DictObject obj = { sectionInfo[2], 0 };
456 switch(obj.m_objType){
457 case DictTabInfo::SystemTable:
458 case DictTabInfo::UserTable:
459 case DictTabInfo::UniqueHashIndex:
460 case DictTabInfo::OrderedIndex:
461 return parseTableDescriptor((Uint32*)ptr, len);
462 break;
463 case DictTabInfo::Tablespace:
464 {
465 NdbDictionary::Tablespace * dst = new NdbDictionary::Tablespace;
466 errcode =
467 NdbDictInterface::parseFilegroupInfo(NdbTablespaceImpl::getImpl(* dst),
468 (Uint32*)ptr, len);
469 if (errcode)
470 delete dst;
471 obj.m_objPtr = dst;
472 restoreLogger.log_debug("%p %u %s", obj.m_objPtr, dst->getObjectId(), dst->getName());
473 break;
474 }
475 case DictTabInfo::LogfileGroup:
476 {
477 NdbDictionary::LogfileGroup * dst = new NdbDictionary::LogfileGroup;
478 errcode =
479 NdbDictInterface::parseFilegroupInfo(NdbLogfileGroupImpl::getImpl(* dst),
480 (Uint32*)ptr, len);
481 if (errcode)
482 delete dst;
483 obj.m_objPtr = dst;
484 restoreLogger.log_debug("%p %u %s", obj.m_objPtr, dst->getObjectId(), dst->getName());
485 break;
486 }
487 case DictTabInfo::Datafile:
488 {
489 NdbDictionary::Datafile * dst = new NdbDictionary::Datafile;
490 errcode =
491 NdbDictInterface::parseFileInfo(NdbDatafileImpl::getImpl(* dst),
492 (Uint32*)ptr, len);
493 if (errcode)
494 delete dst;
495 obj.m_objPtr = dst;
496 restoreLogger.log_debug("%p %u %s", obj.m_objPtr, dst->getObjectId(), dst->getPath());
497 break;
498 }
499 case DictTabInfo::Undofile:
500 {
501 NdbDictionary::Undofile * dst = new NdbDictionary::Undofile;
502 errcode =
503 NdbDictInterface::parseFileInfo(NdbUndofileImpl::getImpl(* dst),
504 (Uint32*)ptr, len);
505 if (errcode)
506 delete dst;
507 obj.m_objPtr = dst;
508 restoreLogger.log_debug("%p %u %s", obj.m_objPtr, dst->getObjectId(), dst->getPath());
509 break;
510 }
511 case DictTabInfo::HashMap:
512 {
513 NdbDictionary::HashMap * dst = new NdbDictionary::HashMap;
514 errcode =
515 NdbDictInterface::parseHashMapInfo(NdbHashMapImpl::getImpl(* dst),
516 (Uint32*)ptr, len);
517 if (errcode)
518 delete dst;
519 obj.m_objPtr = dst;
520
521 if (!m_hostByteOrder)
522 {
523 /**
524 * Bloddy byte-array, need to twiddle
525 */
526 Vector<Uint32> values;
527 Uint32 len = dst->getMapLen();
528 Uint32 zero = 0;
529 values.fill(len - 1, zero);
530 dst->getMapValues(values.getBase(), values.size());
531 for (Uint32 i = 0; i<len; i++)
532 {
533 values[i] = Twiddle16(values[i]);
534 }
535 dst->setMap(values.getBase(), values.size());
536 }
537
538 m_objects.push(obj, 0); // Put first
539 return true;
540 break;
541 }
542 case DictTabInfo::ForeignKey:
543 {
544 NdbDictionary::ForeignKey * dst = new NdbDictionary::ForeignKey;
545 errcode =
546 NdbDictInterface::parseForeignKeyInfo(NdbForeignKeyImpl::getImpl(* dst),
547 (const Uint32*)ptr, len);
548 if (errcode)
549 delete dst;
550 obj.m_objPtr = dst;
551 restoreLogger.log_debug("%p %u %s", obj.m_objPtr, dst->getObjectId(), dst->getName());
552 break;
553 }
554 default:
555 if (ga_skip_unknown_objects)
556 {
557 restoreLogger.log_info("Skipping schema object with unknown table type %u",
558 sectionInfo[2]);
559 return true;
560 }
561 else
562 {
563 restoreLogger.log_error("Unsupported table type!! %u", sectionInfo[2]);
564 return false;
565 }
566 }
567 if (errcode)
568 {
569 restoreLogger.log_error("Unable to parse dict info...%u %u",
570 sectionInfo[2], errcode);
571 return false;
572 }
573
574 /**
575 * DD objects need to be sorted...
576 */
577 for(Uint32 i = 0; i<m_objects.size(); i++)
578 {
579 switch(sectionInfo[2]){
580 case DictTabInfo::Tablespace:
581 if (DictTabInfo::isFile(m_objects[i].m_objType))
582 {
583 m_objects.push(obj, i);
584 goto end;
585 }
586 break;
587 case DictTabInfo::LogfileGroup:
588 {
589 if (DictTabInfo::isFile(m_objects[i].m_objType) ||
590 m_objects[i].m_objType == DictTabInfo::Tablespace)
591 {
592 m_objects.push(obj, i);
593 goto end;
594 }
595 break;
596 }
597 default:
598 m_objects.push_back(obj);
599 goto end;
600 }
601 }
602 m_objects.push_back(obj);
603
604 end:
605 return true;
606 }
607
608 #define OLD_NDB_REP_DB "cluster"
609 #define OLD_NDB_APPLY_TABLE "apply_status"
610 #define OLD_NDB_SCHEMA_TABLE "schema"
611
612 bool
markSysTables()613 RestoreMetaData::markSysTables()
614 {
615 Uint32 i;
616 for (i = 0; i < getNoOfTables(); i++) {
617 TableS* table = allTables[i];
618 table->m_local_id = i;
619 const char* tableName = table->getTableName();
620 if ( // XXX should use type
621 strcmp(tableName, "SYSTAB_0") == 0 ||
622 strcmp(tableName, "NDB$EVENTS_0") == 0 ||
623 strcmp(tableName, "sys/def/SYSTAB_0") == 0 ||
624 strcmp(tableName, "sys/def/NDB$EVENTS_0") == 0 ||
625 // index stats tables and indexes
626 strncmp(tableName, NDB_INDEX_STAT_PREFIX,
627 sizeof(NDB_INDEX_STAT_PREFIX)-1) == 0 ||
628 strstr(tableName, "/" NDB_INDEX_STAT_PREFIX) != 0 ||
629 /*
630 The following is for old MySQL versions,
631 before we changed the database name of the tables from
632 "cluster_replication" -> "cluster" -> "mysql"
633 */
634 strcmp(tableName, "cluster_replication/def/" OLD_NDB_APPLY_TABLE) == 0 ||
635 strcmp(tableName, OLD_NDB_REP_DB "/def/" OLD_NDB_APPLY_TABLE) == 0 ||
636 strcmp(tableName, OLD_NDB_REP_DB "/def/" OLD_NDB_SCHEMA_TABLE) == 0 ||
637 strcmp(tableName, NDB_REP_DB "/def/" NDB_APPLY_TABLE) == 0 ||
638 strcmp(tableName, NDB_REP_DB "/def/" NDB_SCHEMA_TABLE)== 0 ||
639 strcmp(tableName, "mysql/def/ndb_schema_result") == 0 ||
640 (strcmp(tableName, "mysql/def/ndb_sql_metadata") == 0
641 && !opt_include_stored_grants)
642 )
643 {
644 table->m_isSysTable = true;
645 if (strcmp(tableName, "SYSTAB_0") == 0 ||
646 strcmp(tableName, "sys/def/SYSTAB_0") == 0)
647 table->m_isSYSTAB_0 = true;
648 }
649 }
650 for (i = 0; i < getNoOfTables(); i++) {
651 TableS* auxTable = allTables[i];
652 const char* auxTableName = auxTable->getTableName();
653 // Use pattern matching to find blob tables or ordered indexes and
654 // associate them with their main tables
655 static constexpr const char * indxPattern = "sys/def/%d/";
656 static constexpr const char * blobPattern = "%[^/]/%[^/]/NDB$BLOB_%d_%d";
657 int id1, id2 = ~(Uint32)0;
658 char buf[256];
659
660 if((sscanf(auxTableName, indxPattern, &id1) == 1) ||
661 (sscanf(auxTableName, blobPattern, buf, buf, &id1, &id2) == 4)) {
662 TableS *mainTable = getTable(id1);
663 if(mainTable) {
664 auxTable->m_isSysTable = mainTable->m_isSysTable;
665 auxTable->m_main_table = mainTable;
666 auxTable->m_main_column_id = id2;
667 } else {
668 restoreLogger.log_error("Restore: Bad primary table id in %s", auxTableName);
669 return false;
670 }
671 }
672 }
673 return true;
674 }
675
676 bool
fixBlobs()677 RestoreMetaData::fixBlobs()
678 {
679 Uint32 i;
680 for (i = 0; i < getNoOfTables(); i++) {
681 TableS* table = allTables[i];
682 assert(table->m_dictTable != NULL);
683 NdbTableImpl& t = NdbTableImpl::getImpl(*table->m_dictTable);
684 const Uint32 noOfBlobs = t.m_noOfBlobs;
685 if (noOfBlobs == 0)
686 continue;
687 Uint32 n = 0;
688 Uint32 j;
689 for (j = 0; n < noOfBlobs; j++) {
690 NdbColumnImpl* c = t.getColumn(j);
691 assert(c != NULL);
692 if (!c->getBlobType())
693 continue;
694 // tinyblobs are counted in noOfBlobs...
695 n++;
696 if (c->getPartSize() == 0)
697 continue;
698 Uint32 k;
699 TableS* blobTable = NULL;
700 for (k = 0; k < getNoOfTables(); k++) {
701 TableS* tmp = allTables[k];
702 if (tmp->m_main_table == table &&
703 tmp->m_main_column_id == j) {
704 blobTable = tmp;
705 break;
706 }
707 }
708 if (blobTable == NULL)
709 {
710 table->m_broken = true;
711 /* Corrupt backup, has main table, but no blob table */
712 restoreLogger.log_error("Table %s has blob column %u (%s)"
713 " with missing parts table in backup.",
714 table->m_dictTable->getName(), j, c->m_name.c_str());
715 if (ga_skip_broken_objects)
716 {
717 continue;
718 }
719 else
720 {
721 return false;
722 }
723 }
724 assert(blobTable->m_dictTable != NULL);
725 assert(blobTable->m_blobTables.size() == 0);
726 NdbTableImpl& bt = NdbTableImpl::getImpl(*blobTable->m_dictTable);
727 const char* colName = c->m_blobVersion == 1 ? "DATA" : "NDB$DATA";
728 const NdbColumnImpl* bc = bt.getColumn(colName);
729 assert(bc != NULL);
730 assert(c->m_storageType == NDB_STORAGETYPE_MEMORY);
731 c->m_storageType = bc->m_storageType;
732
733 table->m_blobTables.push_back(blobTable);
734 }
735 }
736 return true;
737 }
738
739 bool
readGCPEntry()740 RestoreMetaData::readGCPEntry() {
741
742 BackupFormat::CtlFile::GCPEntry dst;
743
744 if(buffer_read(&dst, 1, sizeof(dst)) != sizeof(dst)){
745 restoreLogger.log_error("readGCPEntry read error");
746 return false;
747 }
748
749 dst.SectionType = ntohl(dst.SectionType);
750 dst.SectionLength = ntohl(dst.SectionLength);
751
752 if(dst.SectionType != BackupFormat::GCP_ENTRY){
753 restoreLogger.log_error("readGCPEntry invalid format");
754 return false;
755 }
756
757 dst.StartGCP = ntohl(dst.StartGCP);
758 dst.StopGCP = ntohl(dst.StopGCP);
759
760 m_startGCP = dst.StartGCP;
761 /**
762 * Stop GCP is recorded as StopGCP -1 by Backup.cpp
763 * We correct this here
764 * Backup format not changed
765 */
766 m_stopGCP = dst.StopGCP + 1;
767 return true;
768 }
769
770 bool
readFragmentInfo()771 RestoreMetaData::readFragmentInfo()
772 {
773 BackupFormat::CtlFile::FragmentInfo fragInfo;
774 TableS * table = 0;
775 Uint32 tableId = RNIL;
776
777 while (buffer_read(&fragInfo, 4, 2) == 2)
778 {
779 fragInfo.SectionType = ntohl(fragInfo.SectionType);
780 fragInfo.SectionLength = ntohl(fragInfo.SectionLength);
781
782 if (fragInfo.SectionType != BackupFormat::FRAGMENT_INFO)
783 {
784 restoreLogger.log_error("readFragmentInfo invalid section type: %u",
785 fragInfo.SectionType);
786 return false;
787 }
788
789 if (buffer_read(&fragInfo.TableId, (fragInfo.SectionLength-2)*4, 1) != 1)
790 {
791 restoreLogger.log_error("readFragmentInfo invalid section length: %u",
792 fragInfo.SectionLength);
793 return false;
794 }
795
796 fragInfo.TableId = ntohl(fragInfo.TableId);
797 if (fragInfo.TableId != tableId)
798 {
799 tableId = fragInfo.TableId;
800 table = getTable(tableId);
801 }
802
803 FragmentInfo * tmp = new FragmentInfo;
804 tmp->fragmentNo = ntohl(fragInfo.FragmentNo);
805 tmp->noOfRecords = ntohl(fragInfo.NoOfRecordsLow) +
806 (((Uint64)ntohl(fragInfo.NoOfRecordsHigh)) << 32);
807 tmp->filePosLow = ntohl(fragInfo.FilePosLow);
808 tmp->filePosHigh = ntohl(fragInfo.FilePosHigh);
809 tmp->sliceSkip = false; /* Init, set later */
810
811 table->m_fragmentInfo.push_back(tmp);
812 table->m_noOfRecords += tmp->noOfRecords;
813 }
814 return true;
815 }
816
TableS(Uint32 version,NdbTableImpl * tableImpl)817 TableS::TableS(Uint32 version, NdbTableImpl* tableImpl)
818 : m_dictTable(tableImpl)
819 {
820 m_noOfNullable = m_nullBitmaskSize = 0;
821 m_auto_val_attrib = 0;
822 m_max_auto_val= 0;
823 m_noOfRecords= 0;
824 backupVersion = version;
825 m_isSysTable = false;
826 m_isSYSTAB_0 = false;
827 m_broken = false;
828 m_main_table = NULL;
829 m_main_column_id = ~(Uint32)0;
830 m_has_blobs = false;
831
832 for (int i = 0; i < tableImpl->getNoOfColumns(); i++)
833 createAttr(tableImpl->getColumn(i));
834
835 m_staging = false;
836 m_stagingTable = NULL;
837 m_stagingFlags = 0;
838
839 m_pk_extended = false;
840 m_pk_index = NULL;
841 }
842
~TableS()843 TableS::~TableS()
844 {
845 for (Uint32 i= 0; i < allAttributesDesc.size(); i++)
846 {
847 if (allAttributesDesc[i]->parameter)
848 free(allAttributesDesc[i]->parameter);
849 delete allAttributesDesc[i];
850 }
851 delete m_stagingTable;
852 delete m_dictTable;
853 }
854
855
856 // Parse dictTabInfo buffer and pushback to to vector storage
857 bool
parseTableDescriptor(const Uint32 * data,Uint32 len)858 RestoreMetaData::parseTableDescriptor(const Uint32 * data, Uint32 len)
859 {
860 NdbTableImpl* tableImpl = 0;
861 int ret = NdbDictInterface::parseTableInfo
862 (&tableImpl, data, len, false,
863 ndbd_drop6(m_fileHeader.NdbVersion) ? MAKE_VERSION(5,1,2) :
864 m_fileHeader.NdbVersion);
865
866 if (ret != 0) {
867 ndberror_struct err_struct;
868 err_struct.code = ret;
869 ndberror_update(&err_struct);
870
871 restoreLogger.log_error("parseTableInfo failed with error %u \"%s\"",
872 err_struct.code, err_struct.message);
873
874 restoreLogger.log_error("Check version of backup and schema contained in backup.");
875 return false;
876 }
877 if(tableImpl == 0)
878 return false;
879
880 restoreLogger.log_debug("parseTableInfo %s done", tableImpl->getName());
881 TableS * table = new TableS(m_fileHeader.NdbVersion, tableImpl);
882 if(table == NULL) {
883 return false;
884 }
885
886 restoreLogger.log_debug("Parsed table id %u\nParsed table #attr %u\n"
887 "Parsed table schema version not used",
888 table->getTableId(),
889 table->getNoOfAttributes());
890
891 restoreLogger.log_debug("Pushing table %s\n with %u attributes",
892 table->getTableName(), table->getNoOfAttributes());
893
894 allTables.push_back(table);
895
896 return true;
897 }
898
899 // Constructor
RestoreDataIterator(const RestoreMetaData & md,void (* _free_data_callback)(void *),void * ctx)900 RestoreDataIterator::RestoreDataIterator(const RestoreMetaData & md, void (* _free_data_callback)(void*), void *ctx)
901 : BackupFile(_free_data_callback, ctx), m_metaData(md),
902 m_current_table_has_transforms(false)
903 {
904 restoreLogger.log_debug("RestoreDataIterator constructor");
905 setDataFile(md, 0);
906
907 alloc_extra_storage(8192);
908 m_row_max_extra_wordlen = 0;
909 }
910
911
912 bool
validateRestoreDataIterator()913 RestoreDataIterator::validateRestoreDataIterator()
914 {
915 if (!m_extra_storage_ptr)
916 {
917 restoreLogger.log_error("m_extra_storage_ptr is NULL");
918 return false;
919 }
920 return true;
921 }
922
923
~RestoreDataIterator()924 RestoreDataIterator::~RestoreDataIterator()
925 {
926 free_extra_storage();
927 }
928
929 void
calc_row_extra_storage_words(const TableS * tableSpec)930 RestoreDataIterator::calc_row_extra_storage_words(const TableS* tableSpec)
931 {
932 const NdbDictionary::Table* tab = tableSpec->m_dictTable;
933 Uint32 bitmap_words = 0;
934 Uint32 transform_words = 0;
935 for (Uint32 i = 0; i<(Uint32)tab->getNoOfColumns(); i++)
936 {
937 /* Space for bitmap-copy out from PACKED format */
938 if (tab->getColumn(i)->getType() == NdbDictionary::Column::Bit)
939 {
940 bitmap_words += (tab->getColumn(i)->getLength() + 31) >> 5;
941 }
942 /* Space for output from this column transform */
943 const AttributeDesc* attr_desc = tableSpec->getAttributeDesc(i);
944 if (attr_desc->transform != NULL)
945 {
946 transform_words += attr_desc->getSizeInWords();
947 }
948 }
949
950 m_current_table_has_transforms = (transform_words > 0);
951
952 m_row_max_extra_wordlen = bitmap_words + transform_words;
953 }
954
955 void
reset_extra_storage()956 RestoreDataIterator::reset_extra_storage()
957 {
958 m_extra_storage_curr_ptr = m_extra_storage_ptr;
959 }
960
961 void
alloc_extra_storage(Uint32 words)962 RestoreDataIterator::alloc_extra_storage(Uint32 words)
963 {
964 m_extra_storage_wordlen = words;
965 m_extra_storage_ptr = (Uint32*)malloc(4 * words);
966 m_extra_storage_curr_ptr = m_extra_storage_ptr;
967 }
968
969 void
free_extra_storage()970 RestoreDataIterator::free_extra_storage()
971 {
972 if (m_extra_storage_ptr)
973 free(m_extra_storage_ptr);
974 m_extra_storage_ptr = 0;
975 m_extra_storage_curr_ptr = 0;
976 }
977
978 Uint32
get_free_extra_storage() const979 RestoreDataIterator::get_free_extra_storage() const
980 {
981
982 return Uint32((m_extra_storage_ptr + m_extra_storage_wordlen) -
983 m_extra_storage_curr_ptr);
984 }
985
986 void
check_extra_storage()987 RestoreDataIterator::check_extra_storage()
988 {
989 assert(m_row_max_extra_wordlen <= m_extra_storage_wordlen);
990 if (m_row_max_extra_wordlen >= get_free_extra_storage())
991 {
992 /**
993 * No more space available to buffer rows, flush
994 * what is outstanding, then reset buffers and
995 * continue.
996 */
997 flush_and_reset_buffers();
998 assert(get_free_extra_storage() > m_row_max_extra_wordlen);
999 assert(m_extra_storage_ptr == m_extra_storage_curr_ptr);
1000
1001 /**
1002 * We do not want to break up batching due to a lack of
1003 * extra buffer storage, but that is what has happened
1004 * here.
1005 * So to avoid this in future we will take this chance
1006 * to double the extra storage size, so that batching
1007 * boundaries are eventually controlled by the file
1008 * buffering only.
1009 */
1010 const Uint32 newWords = m_extra_storage_wordlen * 2;
1011 free_extra_storage();
1012 alloc_extra_storage(newWords);
1013 }
1014 }
1015
1016
1017 Uint32*
get_extra_storage(Uint32 len)1018 RestoreDataIterator::get_extra_storage(Uint32 len)
1019 {
1020 Uint32 * currptr = m_extra_storage_curr_ptr;
1021 Uint32 * nextptr = currptr + len;
1022 Uint32 * endptr = m_extra_storage_ptr + m_extra_storage_wordlen;
1023
1024 if (nextptr <= endptr)
1025 {
1026 m_extra_storage_curr_ptr = nextptr;
1027 return currptr;
1028 }
1029
1030 abort();
1031 return 0;
1032 }
1033
operator =(const TupleS & tuple)1034 TupleS & TupleS::operator=(const TupleS& tuple)
1035 {
1036 prepareRecord(*tuple.m_currentTable);
1037
1038 if (allAttrData)
1039 memcpy(allAttrData, tuple.allAttrData, getNoOfAttributes()*sizeof(AttributeData));
1040
1041 return *this;
1042 }
getNoOfAttributes() const1043 int TupleS::getNoOfAttributes() const {
1044 if (m_currentTable == 0)
1045 return 0;
1046 return m_currentTable->getNoOfAttributes();
1047 }
1048
getTable() const1049 TableS * TupleS::getTable() const {
1050 return m_currentTable;
1051 }
1052
getDesc(int i) const1053 AttributeDesc * TupleS::getDesc(int i) const {
1054 return m_currentTable->allAttributesDesc[i];
1055 }
1056
getData(int i) const1057 AttributeData * TupleS::getData(int i) const{
1058 return &(allAttrData[i]);
1059 }
1060
1061 bool
prepareRecord(TableS & tab)1062 TupleS::prepareRecord(TableS & tab){
1063 if (allAttrData) {
1064 if (getNoOfAttributes() == tab.getNoOfAttributes())
1065 {
1066 m_currentTable = &tab;
1067 return true;
1068 }
1069 delete [] allAttrData;
1070 m_currentTable= 0;
1071 }
1072
1073 allAttrData = new AttributeData[tab.getNoOfAttributes()];
1074 if (allAttrData == 0)
1075 return false;
1076
1077 m_currentTable = &tab;
1078
1079 return true;
1080 }
1081
1082 static
1083 inline
1084 Uint8*
pad(Uint8 * src,Uint32 align,Uint32 bitPos)1085 pad(Uint8* src, Uint32 align, Uint32 bitPos)
1086 {
1087 UintPtr ptr = UintPtr(src);
1088 switch(align){
1089 case DictTabInfo::aBit:
1090 case DictTabInfo::a32Bit:
1091 case DictTabInfo::a64Bit:
1092 case DictTabInfo::a128Bit:
1093 return (Uint8*)(((ptr + 3) & ~(UintPtr)3) + 4 * ((bitPos + 31) >> 5));
1094 charpad:
1095 case DictTabInfo::an8Bit:
1096 case DictTabInfo::a16Bit:
1097 return src + 4 * ((bitPos + 31) >> 5);
1098 default:
1099 #ifdef VM_TRACE
1100 abort();
1101 #endif
1102 goto charpad;
1103 }
1104 }
1105
1106 bool
applyColumnTransform(const NdbDictionary::Column * col,const AttributeDesc * attr_desc,AttributeData * attr_data,void * dst_buf)1107 applyColumnTransform(const NdbDictionary::Column* col,
1108 const AttributeDesc* attr_desc,
1109 AttributeData* attr_data,
1110 void* dst_buf)
1111 {
1112 assert(attr_desc->transform != NULL);
1113
1114 void* src_ptr = (attr_data->null? NULL : attr_data->void_value);
1115 void* dst_ptr = dst_buf;
1116
1117 if (!attr_desc->transform->apply(col,
1118 src_ptr,
1119 &dst_ptr))
1120 {
1121 return false;
1122 }
1123
1124 if (dst_ptr == NULL)
1125 {
1126 assert(col->getNullable());
1127 attr_data->null = true;
1128 attr_data->size = 0;
1129 attr_data->void_value = NULL;
1130 }
1131 else
1132 {
1133 const uchar* dst_char = (const uchar*) dst_ptr;
1134 attr_data->null = false;
1135 attr_data->void_value = dst_ptr;
1136 switch(col->getArrayType())
1137 {
1138 case NDB_ARRAYTYPE_SHORT_VAR:
1139 attr_data->size = 1 + size_t(dst_char[0]);
1140 break;
1141 case NDB_ARRAYTYPE_MEDIUM_VAR:
1142 attr_data->size = 2 + size_t(dst_char[0])
1143 + (256 * size_t(dst_char[1]));
1144 break;
1145 default:
1146 /* No change */
1147 break;
1148 }
1149 }
1150
1151 /* Check size is within 'word length' of column type */
1152 assert(attr_data->size <=
1153 4 * ((((Uint32)col->getSizeInBytes()) +3)/4));
1154
1155 return true;
1156 }
1157
1158
1159 const TupleS *
getNextTuple(int & res,const bool skipFragment)1160 RestoreDataIterator::getNextTuple(int & res, const bool skipFragment)
1161 {
1162 /* Check that we have space to return another tuple */
1163 check_extra_storage();
1164
1165 while (true)
1166 {
1167 Uint32 dataLength = 0;
1168 // Read record length
1169 if (buffer_read(&dataLength, sizeof(dataLength), 1) != 1){
1170 restoreLogger.log_error("getNextTuple:Error reading length of data part");
1171 res = -1;
1172 return NULL;
1173 } // if
1174
1175 // Convert length from network byte order
1176 dataLength = ntohl(dataLength);
1177 const Uint32 dataLenBytes = 4 * dataLength;
1178
1179 if (dataLength == 0) {
1180 // Zero length for last tuple
1181 // End of this data fragment
1182 restoreLogger.log_debug("End of fragment");
1183 res = 0;
1184 return NULL;
1185 } // if
1186
1187 // Read tuple data
1188 void *_buf_ptr;
1189 if (buffer_get_ptr(&_buf_ptr, 1, dataLenBytes) != dataLenBytes) {
1190 restoreLogger.log_error("getNextTuple:Read error: ");
1191 res = -1;
1192 return NULL;
1193 }
1194
1195 m_count++;
1196
1197 if (skipFragment)
1198 {
1199 /**
1200 * Skip unpacking work, we just want to read all the tuples up
1201 * to the end of this fragment
1202 */
1203 continue;
1204 }
1205
1206 Uint32 *buf_ptr = (Uint32*)_buf_ptr;
1207 if (m_currentTable->backupVersion >= NDBD_RAW_LCP)
1208 {
1209 res = readTupleData_packed(buf_ptr, dataLength);
1210 }
1211 else
1212 {
1213 res = readTupleData_old(buf_ptr, dataLength);
1214 }
1215
1216 if (res)
1217 {
1218 return NULL;
1219 }
1220
1221 /* Apply column transforms if the table has any defined */
1222 if (m_current_table_has_transforms)
1223 {
1224 for (int i=0; i < m_currentTable->getNoOfAttributes(); i++)
1225 {
1226 const AttributeDesc* attr_desc = m_currentTable->getAttributeDesc(i);
1227 if (attr_desc->transform == NULL)
1228 {
1229 continue;
1230 }
1231 const NdbDictionary::Column* col = m_currentTable->m_dictTable->getColumn(i);
1232 void* dst_buf = get_extra_storage(attr_desc->getSizeInWords());
1233 assert(dst_buf != NULL);
1234
1235 if (!applyColumnTransform(col,
1236 attr_desc,
1237 m_tuple.getData(i),
1238 dst_buf))
1239 {
1240 res = -1;
1241 return NULL;
1242 }
1243 }
1244 }
1245
1246 res = 0;
1247 return &m_tuple;
1248 }
1249 } // RestoreDataIterator::getNextTuple
1250
1251 TableS *
getCurrentTable()1252 RestoreDataIterator::getCurrentTable()
1253 {
1254 return m_currentTable;
1255 }
1256
1257 int
readTupleData_packed(Uint32 * buf_ptr,Uint32 dataLength)1258 RestoreDataIterator::readTupleData_packed(Uint32 *buf_ptr,
1259 Uint32 dataLength)
1260 {
1261 Uint32 * ptr = buf_ptr;
1262 /**
1263 * Unpack READ_PACKED header
1264 */
1265 Uint32 rp = * ptr;
1266 if(unlikely(!m_hostByteOrder))
1267 rp = Twiddle32(rp);
1268
1269 AttributeHeader ah(rp);
1270 assert(ah.getAttributeId() == AttributeHeader::READ_PACKED);
1271 Uint32 bmlen = ah.getByteSize();
1272 assert((bmlen & 3) == 0);
1273 Uint32 bmlen32 = bmlen / 4;
1274
1275 /**
1276 * Twiddle READ_BACKED header
1277 */
1278 if (!m_hostByteOrder)
1279 {
1280 for (Uint32 i = 0; i < 1 + bmlen32; i++)
1281 {
1282 ptr[i] = Twiddle32(ptr[i]);
1283 }
1284 }
1285
1286 const NdbDictionary::Table* tab = m_currentTable->m_dictTable;
1287
1288 // All columns should be present...
1289 assert(((tab->getNoOfColumns() + 31) >> 5) <= (int)bmlen32);
1290
1291 /**
1292 * Iterate through attributes...
1293 */
1294 const Uint32 * bmptr = ptr + 1;
1295 Uint8* src = (Uint8*)(bmptr + bmlen32);
1296 Uint32 bmpos = 0;
1297 Uint32 bitPos = 0;
1298 for (Uint32 i = 0; i < (Uint32)tab->getNoOfColumns(); i++, bmpos++)
1299 {
1300 // All columns should be present
1301 assert(BitmaskImpl::get(bmlen32, bmptr, bmpos));
1302 const NdbColumnImpl & col = NdbColumnImpl::getImpl(* tab->getColumn(i));
1303 AttributeData * attr_data = m_tuple.getData(i);
1304 const AttributeDesc * attr_desc = m_tuple.getDesc(i);
1305 if (col.getNullable())
1306 {
1307 bmpos++;
1308 if (BitmaskImpl::get(bmlen32, bmptr, bmpos))
1309 {
1310 attr_data->null = true;
1311 attr_data->void_value = NULL;
1312 continue;
1313 }
1314 }
1315
1316 attr_data->null = false;
1317
1318 /**
1319 * Handle padding
1320 */
1321 Uint32 align = col.m_orgAttrSize;
1322 Uint32 attrSize = col.m_attrSize;
1323 Uint32 array = col.m_arraySize;
1324 Uint32 len = col.m_length;
1325 Uint32 sz = attrSize * array;
1326 Uint32 arrayType = col.m_arrayType;
1327
1328 switch(align){
1329 case DictTabInfo::aBit:{ // Bit
1330 src = pad(src, 0, 0);
1331 Uint32* src32 = (Uint32*)src;
1332
1333 Uint32 len32 = (len + 31) >> 5;
1334 Uint32* tmp = get_extra_storage(len32);
1335 attr_data->null = false;
1336 attr_data->void_value = tmp;
1337 attr_data->size = 4*len32;
1338
1339 if (m_hostByteOrder)
1340 {
1341 BitmaskImpl::getField(1 + len32, src32, bitPos, len, tmp);
1342 }
1343 else
1344 {
1345 Uint32 ii;
1346 for (ii = 0; ii< (1 + len32); ii++)
1347 src32[ii] = Twiddle32(src32[ii]);
1348 BitmaskImpl::getField(1 + len32, (Uint32*)src, bitPos, len, tmp);
1349 for (ii = 0; ii< (1 + len32); ii++)
1350 src32[ii] = Twiddle32(src32[ii]);
1351 }
1352
1353 src += 4 * ((bitPos + len) >> 5);
1354 bitPos = (bitPos + len) & 31;
1355 goto next;
1356 }
1357 default:
1358 src = pad(src, align, bitPos);
1359 }
1360 switch(arrayType){
1361 case NDB_ARRAYTYPE_FIXED:
1362 break;
1363 case NDB_ARRAYTYPE_SHORT_VAR:
1364 sz = 1 + src[0];
1365 break;
1366 case NDB_ARRAYTYPE_MEDIUM_VAR:
1367 sz = 2 + src[0] + 256 * src[1];
1368 break;
1369 default:
1370 abort();
1371 }
1372
1373 attr_data->void_value = src;
1374 attr_data->size = sz;
1375
1376 if(!Twiddle(attr_desc, attr_data))
1377 {
1378 return -1;
1379 }
1380
1381 /**
1382 * Next
1383 */
1384 bitPos = 0;
1385 src += sz;
1386 next:
1387 (void)1;
1388 }
1389 return 0;
1390 }
1391
1392 int
readTupleData_old(Uint32 * buf_ptr,Uint32 dataLength)1393 RestoreDataIterator::readTupleData_old(Uint32 *buf_ptr,
1394 Uint32 dataLength)
1395 {
1396 Uint32 * ptr = buf_ptr;
1397 ptr += m_currentTable->m_nullBitmaskSize;
1398 Uint32 i;
1399 for(i= 0; i < m_currentTable->m_fixedKeys.size(); i++){
1400 assert(ptr < buf_ptr + dataLength);
1401
1402 const Uint32 attrId = m_currentTable->m_fixedKeys[i]->attrId;
1403
1404 AttributeData * attr_data = m_tuple.getData(attrId);
1405 const AttributeDesc * attr_desc = m_tuple.getDesc(attrId);
1406
1407 const Uint32 sz = attr_desc->getSizeInWords();
1408
1409 attr_data->null = false;
1410 attr_data->void_value = ptr;
1411 attr_data->size = 4*sz;
1412
1413 if(!Twiddle(attr_desc, attr_data))
1414 {
1415 return -1;
1416 }
1417 ptr += sz;
1418 }
1419
1420 for(i = 0; i < m_currentTable->m_fixedAttribs.size(); i++){
1421 assert(ptr < buf_ptr + dataLength);
1422
1423 const Uint32 attrId = m_currentTable->m_fixedAttribs[i]->attrId;
1424
1425 AttributeData * attr_data = m_tuple.getData(attrId);
1426 const AttributeDesc * attr_desc = m_tuple.getDesc(attrId);
1427
1428 const Uint32 sz = attr_desc->getSizeInWords();
1429
1430 attr_data->null = false;
1431 attr_data->void_value = ptr;
1432 attr_data->size = 4*sz;
1433
1434 if(!Twiddle(attr_desc, attr_data))
1435 {
1436 return -1;
1437 }
1438
1439 ptr += sz;
1440 }
1441
1442 // init to NULL
1443 for(i = 0; i < m_currentTable->m_variableAttribs.size(); i++){
1444 const Uint32 attrId = m_currentTable->m_variableAttribs[i]->attrId;
1445
1446 AttributeData * attr_data = m_tuple.getData(attrId);
1447
1448 attr_data->null = true;
1449 attr_data->void_value = NULL;
1450 }
1451
1452 int res;
1453 if (!ndbd_drop6(m_currentTable->backupVersion))
1454 {
1455 if ((res = readVarData(buf_ptr, ptr, dataLength)))
1456 return res;
1457 }
1458 else
1459 {
1460 if ((res = readVarData_drop6(buf_ptr, ptr, dataLength)))
1461 return res;
1462 }
1463
1464 return 0;
1465 }
1466
1467 int
readVarData(Uint32 * buf_ptr,Uint32 * ptr,Uint32 dataLength)1468 RestoreDataIterator::readVarData(Uint32 *buf_ptr, Uint32 *ptr,
1469 Uint32 dataLength)
1470 {
1471 while (ptr + 2 < buf_ptr + dataLength)
1472 {
1473 typedef BackupFormat::DataFile::VariableData VarData;
1474 VarData * data = (VarData *)ptr;
1475 Uint32 sz = ntohl(data->Sz);
1476 Uint32 attrId = ntohl(data->Id); // column_no
1477
1478 AttributeData * attr_data = m_tuple.getData(attrId);
1479 const AttributeDesc * attr_desc = m_tuple.getDesc(attrId);
1480
1481 // just a reminder - remove when backwards compat implemented
1482 if (m_currentTable->backupVersion < MAKE_VERSION(5,1,3) &&
1483 attr_desc->m_column->getNullable())
1484 {
1485 const Uint32 ind = attr_desc->m_nullBitIndex;
1486 if(BitmaskImpl::get(m_currentTable->m_nullBitmaskSize,
1487 buf_ptr,ind))
1488 {
1489 attr_data->null = true;
1490 attr_data->void_value = NULL;
1491 continue;
1492 }
1493 }
1494
1495 if (m_currentTable->backupVersion < MAKE_VERSION(5,1,3))
1496 {
1497 sz *= 4;
1498 }
1499
1500 attr_data->null = false;
1501 attr_data->void_value = &data->Data[0];
1502 attr_data->size = sz;
1503
1504 //convert the length of blob(v1) and text(v1)
1505 if(!Twiddle(attr_desc, attr_data))
1506 {
1507 return -1;
1508 }
1509
1510 ptr += ((sz + 3) >> 2) + 2;
1511 }
1512
1513 assert(ptr == buf_ptr + dataLength);
1514
1515 return 0;
1516 }
1517
1518
1519 int
readVarData_drop6(Uint32 * buf_ptr,Uint32 * ptr,Uint32 dataLength)1520 RestoreDataIterator::readVarData_drop6(Uint32 *buf_ptr, Uint32 *ptr,
1521 Uint32 dataLength)
1522 {
1523 Uint32 i;
1524 for (i = 0; i < m_currentTable->m_variableAttribs.size(); i++)
1525 {
1526 const Uint32 attrId = m_currentTable->m_variableAttribs[i]->attrId;
1527
1528 AttributeData * attr_data = m_tuple.getData(attrId);
1529 const AttributeDesc * attr_desc = m_tuple.getDesc(attrId);
1530
1531 if(attr_desc->m_column->getNullable())
1532 {
1533 const Uint32 ind = attr_desc->m_nullBitIndex;
1534 if(BitmaskImpl::get(m_currentTable->m_nullBitmaskSize,
1535 buf_ptr,ind))
1536 {
1537 attr_data->null = true;
1538 attr_data->void_value = NULL;
1539 continue;
1540 }
1541 }
1542
1543 assert(ptr < buf_ptr + dataLength);
1544
1545 typedef BackupFormat::DataFile::VariableData VarData;
1546 VarData * data = (VarData *)ptr;
1547 Uint32 sz = ntohl(data->Sz);
1548 assert(ntohl(data->Id) == attrId);
1549
1550 attr_data->null = false;
1551 attr_data->void_value = &data->Data[0];
1552
1553 if (!Twiddle(attr_desc, attr_data))
1554 {
1555 return -1;
1556 }
1557 ptr += (sz + 2);
1558 }
1559 assert(ptr == buf_ptr + dataLength);
1560 return 0;
1561 }
1562
BackupFile(void (* _free_data_callback)(void *),void * ctx)1563 BackupFile::BackupFile(void (* _free_data_callback)(void*), void *ctx)
1564 : free_data_callback(_free_data_callback), m_ctx(ctx)
1565 {
1566 memset(&m_file,0,sizeof(m_file));
1567 m_path[0] = 0;
1568 m_fileName[0] = 0;
1569
1570 m_buffer_sz = BUFFER_SIZE;
1571 m_buffer = malloc(m_buffer_sz);
1572 m_buffer_ptr = m_buffer;
1573 m_buffer_data_left = 0;
1574
1575 m_file_size = 0;
1576 m_file_pos = 0;
1577 m_is_undolog = false;
1578
1579 m_part_count = 1;
1580 #ifdef ERROR_INSERT
1581 m_error_insert = 0;
1582 #endif
1583 }
1584
1585 bool
validateBackupFile()1586 BackupFile::validateBackupFile()
1587 {
1588 if (!m_buffer)
1589 {
1590 restoreLogger.log_error("m_buffer is NULL");
1591 return false;
1592 }
1593 return true;
1594 }
1595
~BackupFile()1596 BackupFile::~BackupFile()
1597 {
1598 (void)ndbzclose(&m_file);
1599
1600 if(m_buffer != 0)
1601 free(m_buffer);
1602 }
1603
1604 bool
openFile()1605 BackupFile::openFile(){
1606 (void)ndbzclose(&m_file);
1607 m_file_size = 0;
1608 m_file_pos = 0;
1609
1610 info.setLevel(254);
1611 restoreLogger.log_info("Opening file '%s'", m_fileName);
1612 int r= ndbzopen(&m_file, m_fileName, O_RDONLY);
1613
1614 if(r != 1)
1615 return false;
1616
1617 size_t size;
1618 if (ndbz_file_size(&m_file, &size) == 0)
1619 {
1620 m_file_size = (Uint64)size;
1621 restoreLogger.log_info("File size %llu bytes", m_file_size);
1622 }
1623 else
1624 {
1625 restoreLogger.log_info("Progress reporting degraded output since fstat failed,"
1626 "errno: %u", errno);
1627 m_file_size = 0;
1628 }
1629
1630 return true;
1631 }
1632
buffer_get_ptr_ahead(void ** p_buf_ptr,Uint32 size,Uint32 nmemb)1633 Uint32 BackupFile::buffer_get_ptr_ahead(void **p_buf_ptr, Uint32 size, Uint32 nmemb)
1634 {
1635 Uint32 sz = size*nmemb;
1636 if (sz > m_buffer_data_left) {
1637
1638 flush_and_reset_buffers();
1639
1640 if (m_is_undolog)
1641 {
1642 /* move the left data to the end of buffer
1643 */
1644 size_t r = 0;
1645 int error;
1646 /* move the left data to the end of buffer
1647 * m_buffer_ptr point the end of the left data. buffer_data_start point the start of left data
1648 * m_buffer_data_left is the length of left data.
1649 */
1650 Uint64 file_left_entry_data = 0;
1651 Uint32 buffer_free_space = m_buffer_sz - m_buffer_data_left;
1652 void * buffer_end = (char *)m_buffer + m_buffer_sz;
1653 void * buffer_data_start = (char *)m_buffer_ptr - m_buffer_data_left;
1654
1655 memmove((char *)buffer_end - m_buffer_data_left, buffer_data_start, m_buffer_data_left);
1656 buffer_data_start = (char *)buffer_end - m_buffer_data_left;
1657 /*
1658 * For undo log file we should read log entris backwards from log file.
1659 * That mean the first entries should start at sizeof(m_fileHeader).
1660 * The end of the last entries should be the end of log file(EOF-1).
1661 * If ther are entries left in log file to read.
1662 * m_file_pos should bigger than sizeof(m_fileHeader).
1663 * If the length of left log entries less than the residual length of buffer,
1664 * we just need to read all the left entries from log file into the buffer.
1665 * and all the left entries in log file should been read into buffer. Or
1666 * If the length of left entries is bigger than the residual length of buffer,
1667 * we should fill the buffer because the current buffer can't contain
1668 all the left log entries, we should read more times.
1669 *
1670 */
1671 if (m_file_pos > sizeof(m_fileHeader))
1672 {
1673 /*
1674 * We read(consume) data from the end of the buffer.
1675 * If the left data is not enough for next read in buffer,
1676 * we move the residual data to the end of buffer.
1677 * Then we will fill the start of buffer with new data from log file.
1678 * eg. If the buffer length is 10. "+" denotes useless content.
1679 * top end
1680 * Bytes in file abcdefgh0123456789
1681 * Byte in buffer 0123456789 --after first read
1682 * Consume datas... (6789) (2345)
1683 * Bytes in buffer 01++++++++ --after several consumes
1684 * Move data to end ++++++++01
1685 * Bytes in buffer abcdefgh01 --after second read
1686 */
1687 file_left_entry_data = m_file_pos - sizeof(m_fileHeader);
1688 if (file_left_entry_data <= buffer_free_space)
1689 {
1690 /* All remaining data fits in space available in buffer.
1691 * Read data into buffer before existing data.
1692 */
1693 // Move to the start of data to be read
1694 ndbzseek(&m_file, sizeof(m_fileHeader), SEEK_SET);
1695 r = ndbzread(&m_file,
1696 (char *)buffer_data_start - file_left_entry_data,
1697 Uint32(file_left_entry_data),
1698 &error);
1699 //move back
1700 ndbzseek(&m_file, sizeof(m_fileHeader), SEEK_SET);
1701 }
1702 else
1703 {
1704 // Fill remaing space at start of buffer with data from file.
1705 ndbzseek(&m_file, m_file_pos-buffer_free_space, SEEK_SET);
1706 r = ndbzread(&m_file, ((char *)m_buffer), buffer_free_space, &error);
1707 ndbzseek(&m_file, m_file_pos-buffer_free_space, SEEK_SET);
1708 }
1709 }
1710 m_file_pos -= r;
1711 m_buffer_data_left += (Uint32)r;
1712 //move to the end of buffer
1713 m_buffer_ptr = buffer_end;
1714 }
1715 else
1716 {
1717 memmove(m_buffer, m_buffer_ptr, m_buffer_data_left);
1718 int error;
1719 Uint32 r = ndbzread(&m_file,
1720 ((char *)m_buffer) + m_buffer_data_left,
1721 m_buffer_sz - m_buffer_data_left, &error);
1722 m_file_pos += r;
1723 m_buffer_data_left += r;
1724 m_buffer_ptr = m_buffer;
1725 }
1726
1727 if (sz > m_buffer_data_left)
1728 sz = size * (m_buffer_data_left / size);
1729 }
1730
1731 /*
1732 * For undolog, the m_buffer_ptr points to the end of the left data.
1733 * After we get data from the end of buffer, the data-end move forward.
1734 * So we should move m_buffer_ptr to the right place.
1735 */
1736 if(m_is_undolog)
1737 *p_buf_ptr = (char *)m_buffer_ptr - sz;
1738 else
1739 *p_buf_ptr = m_buffer_ptr;
1740
1741 return sz/size;
1742 }
buffer_get_ptr(void ** p_buf_ptr,Uint32 size,Uint32 nmemb)1743 Uint32 BackupFile::buffer_get_ptr(void **p_buf_ptr, Uint32 size, Uint32 nmemb)
1744 {
1745 Uint32 r = buffer_get_ptr_ahead(p_buf_ptr, size, nmemb);
1746
1747 if(m_is_undolog)
1748 {
1749 /* we read from end of buffer to start of buffer.
1750 * m_buffer_ptr keep at the end of real data in buffer.
1751 */
1752 m_buffer_ptr = ((char*)m_buffer_ptr)-(r*size);
1753 m_buffer_data_left -= (r*size);
1754 }
1755 else
1756 {
1757 m_buffer_ptr = ((char*)m_buffer_ptr)+(r*size);
1758 m_buffer_data_left -= (r*size);
1759 }
1760
1761 return r;
1762 }
1763
buffer_read_ahead(void * ptr,Uint32 size,Uint32 nmemb)1764 Uint32 BackupFile::buffer_read_ahead(void *ptr, Uint32 size, Uint32 nmemb)
1765 {
1766 void *buf_ptr;
1767 Uint32 r = buffer_get_ptr_ahead(&buf_ptr, size, nmemb);
1768 memcpy(ptr, buf_ptr, r*size);
1769
1770 return r;
1771 }
1772
buffer_read(void * ptr,Uint32 size,Uint32 nmemb)1773 Uint32 BackupFile::buffer_read(void *ptr, Uint32 size, Uint32 nmemb)
1774 {
1775 void *buf_ptr;
1776 Uint32 r = buffer_get_ptr(&buf_ptr, size, nmemb);
1777 memcpy(ptr, buf_ptr, r*size);
1778
1779 return r;
1780 }
1781
1782 void
setCtlFile(Uint32 nodeId,Uint32 backupId,const char * path)1783 BackupFile::setCtlFile(Uint32 nodeId, Uint32 backupId, const char * path){
1784 m_nodeId = nodeId;
1785 m_expectedFileHeader.BackupId = backupId;
1786 m_expectedFileHeader.FileType = BackupFormat::CTL_FILE;
1787
1788 char name[PATH_MAX]; const Uint32 sz = sizeof(name);
1789 BaseString::snprintf(name, sz, "BACKUP-%u.%d.ctl", backupId, nodeId);
1790
1791 if (m_part_count > 1)
1792 {
1793 char multiset_name[PATH_MAX];
1794 BaseString::snprintf(multiset_name, sizeof(multiset_name),
1795 "BACKUP-%u-PART-%u-OF-%u%s%s", backupId, m_part_id, m_part_count, DIR_SEPARATOR, name);
1796 setName(path, multiset_name);
1797 }
1798 else
1799 {
1800 setName(path, name);
1801 }
1802 }
1803
1804 void
setDataFile(const BackupFile & bf,Uint32 no)1805 BackupFile::setDataFile(const BackupFile & bf, Uint32 no){
1806 m_nodeId = bf.m_nodeId;
1807 m_expectedFileHeader = bf.m_fileHeader;
1808 m_expectedFileHeader.FileType = BackupFormat::DATA_FILE;
1809
1810 char name[PATH_MAX]; const Uint32 sz = sizeof(name);
1811 Uint32 backupId = m_expectedFileHeader.BackupId;
1812 if (bf.m_part_count > 1)
1813 {
1814 BaseString::snprintf(name, sz, "BACKUP-%u-PART-%d-OF-%d%sBACKUP-%u-%u.%d.Data",
1815 backupId, bf.m_part_id, bf.m_part_count, DIR_SEPARATOR, backupId, no, m_nodeId);
1816 }
1817 else
1818 {
1819 BaseString::snprintf(name, sz, "BACKUP-%u-%u.%d.Data",
1820 backupId, no, m_nodeId);
1821 }
1822 setName(bf.m_path, name);
1823 }
1824
1825 void
setLogFile(const BackupFile & bf,Uint32 no)1826 BackupFile::setLogFile(const BackupFile & bf, Uint32 no){
1827 m_nodeId = bf.m_nodeId;
1828 m_expectedFileHeader = bf.m_fileHeader;
1829 m_expectedFileHeader.FileType = BackupFormat::LOG_FILE;
1830
1831 char name[PATH_MAX]; const Uint32 sz = sizeof(name);
1832 Uint32 backupId = m_expectedFileHeader.BackupId;
1833 if (bf.m_part_count > 1)
1834 {
1835 BaseString::snprintf(name, sz, "BACKUP-%u-PART-%d-OF-%d%sBACKUP-%u.%d.log",
1836 backupId, bf.m_part_id, bf.m_part_count, DIR_SEPARATOR, backupId, m_nodeId);
1837 }
1838 else
1839 {
1840 BaseString::snprintf(name, sz, "BACKUP-%u.%d.log",
1841 backupId, m_nodeId);
1842 }
1843 setName(bf.m_path, name);
1844 }
1845
1846 void
setName(const char * p,const char * n)1847 BackupFile::setName(const char * p, const char * n){
1848 const Uint32 sz = sizeof(m_path);
1849 if(p != 0 && strlen(p) > 0){
1850 if(p[strlen(p)-1] == DIR_SEPARATOR[0]){
1851 BaseString::snprintf(m_path, sz, "%s", p);
1852 } else {
1853 BaseString::snprintf(m_path, sz, "%s%s", p, DIR_SEPARATOR);
1854 }
1855 } else {
1856 m_path[0] = 0;
1857 }
1858
1859 BaseString::snprintf(m_fileName, sizeof(m_fileName), "%s%s", m_path, n);
1860 restoreLogger.log_debug("Filename = %s", m_fileName);
1861 }
1862
1863 bool
readHeader()1864 BackupFile::readHeader(){
1865 if(!openFile()){
1866 return false;
1867 }
1868
1869 Uint32 oldsz = sizeof(BackupFormat::FileHeader_pre_backup_version);
1870 if(buffer_read(&m_fileHeader, oldsz, 1) != 1){
1871 restoreLogger.log_error("readDataFileHeader: Error reading header");
1872 return false;
1873 }
1874
1875 // Convert from network to host byte order for platform compatibility
1876 /*
1877 Due to some optimization going on when using gcc 4.2.3 we
1878 have to read 'backup_version' into tmp variable. If
1879 'm_fileHeader.BackupVersion' is used directly in the if statement
1880 below it will have the wrong value.
1881 */
1882 Uint32 backup_version = ntohl(m_fileHeader.BackupVersion);
1883 m_fileHeader.BackupVersion = backup_version;
1884 m_fileHeader.SectionType = ntohl(m_fileHeader.SectionType);
1885 m_fileHeader.SectionLength = ntohl(m_fileHeader.SectionLength);
1886 m_fileHeader.FileType = ntohl(m_fileHeader.FileType);
1887 m_fileHeader.BackupId = ntohl(m_fileHeader.BackupId);
1888 m_fileHeader.BackupKey_0 = ntohl(m_fileHeader.BackupKey_0);
1889 m_fileHeader.BackupKey_1 = ntohl(m_fileHeader.BackupKey_1);
1890
1891 if (backup_version >= NDBD_RAW_LCP)
1892 {
1893 if (buffer_read(&m_fileHeader.NdbVersion,
1894 sizeof(m_fileHeader) - oldsz, 1) != 1)
1895 {
1896 restoreLogger.log_error("readDataFileHeader: Error reading header");
1897 return false;
1898 }
1899
1900 m_fileHeader.NdbVersion = ntohl(m_fileHeader.NdbVersion);
1901 m_fileHeader.MySQLVersion = ntohl(m_fileHeader.MySQLVersion);
1902 }
1903 else
1904 {
1905 m_fileHeader.NdbVersion = m_fileHeader.BackupVersion;
1906 m_fileHeader.MySQLVersion = 0;
1907 }
1908
1909 restoreLogger.log_debug("FileHeader: %s %u %u %u %u %u %u %u %u",
1910 m_fileHeader.Magic,
1911 m_fileHeader.BackupVersion,
1912 m_fileHeader.SectionType,
1913 m_fileHeader.SectionLength,
1914 m_fileHeader.FileType,
1915 m_fileHeader.BackupId,
1916 m_fileHeader.BackupKey_0,
1917 m_fileHeader.BackupKey_1,
1918 m_fileHeader.ByteOrder);
1919
1920 restoreLogger.log_debug("ByteOrder is %u", m_fileHeader.ByteOrder);
1921 restoreLogger.log_debug("magicByteOrder is %u", magicByteOrder);
1922
1923
1924 if (m_fileHeader.FileType != m_expectedFileHeader.FileType &&
1925 !(m_expectedFileHeader.FileType == BackupFormat::LOG_FILE &&
1926 m_fileHeader.FileType == BackupFormat::UNDO_FILE)){
1927 // UNDO_FILE will do in case where we expect LOG_FILE
1928 abort();
1929 }
1930
1931 if(m_fileHeader.FileType == BackupFormat::UNDO_FILE){
1932 m_is_undolog = true;
1933 /* move pointer to end of data part.
1934 move 4 bytes from the end of file
1935 because footer contain 4 bytes 0 at the end of file.
1936 we discard the remain data stored in m_buffer.
1937 */
1938 size_t size;
1939 if (ndbz_file_size(&m_file, &size) == 0)
1940 m_file_size = (Uint64)size;
1941 ndbzseek(&m_file, 4, SEEK_END);
1942 m_file_pos = m_file_size - 4;
1943 m_buffer_data_left = 0;
1944 m_buffer_ptr = m_buffer;
1945 }
1946
1947 // Check for BackupFormat::FileHeader::ByteOrder if swapping is needed
1948 if (m_fileHeader.ByteOrder == magicByteOrder) {
1949 m_hostByteOrder = true;
1950 } else if (m_fileHeader.ByteOrder == swappedMagicByteOrder){
1951 m_hostByteOrder = false;
1952 } else {
1953 abort();
1954 }
1955
1956 return true;
1957 } // BackupFile::readHeader
1958
1959 bool
validateFooter()1960 BackupFile::validateFooter(){
1961 return true;
1962 }
1963
1964 #ifdef ERROR_INSERT
error_insert(unsigned int code)1965 void BackupFile::error_insert(unsigned int code)
1966 {
1967 if(code == NDB_RESTORE_ERROR_INSERT_SMALL_BUFFER)
1968 {
1969 // Reduce size of buffer to test buffer overflow
1970 // handling. The buffer must still be large enough to
1971 // accommodate the file header.
1972 m_buffer_sz = 256;
1973 m_error_insert = NDB_RESTORE_ERROR_INSERT_SMALL_BUFFER;
1974 }
1975 }
1976 #endif
1977
readFragmentHeader(int & ret,Uint32 * fragmentId)1978 bool RestoreDataIterator::readFragmentHeader(int & ret, Uint32 *fragmentId)
1979 {
1980 BackupFormat::DataFile::FragmentHeader Header;
1981
1982 restoreLogger.log_debug("RestoreDataIterator::getNextFragment");
1983
1984 while (1)
1985 {
1986 /* read first part of header */
1987 if (buffer_read(&Header, 8, 1) != 1)
1988 {
1989 ret = 0;
1990 return false;
1991 } // if
1992
1993 /* skip if EMPTY_ENTRY */
1994 Header.SectionType = ntohl(Header.SectionType);
1995 Header.SectionLength = ntohl(Header.SectionLength);
1996 if (Header.SectionType == BackupFormat::EMPTY_ENTRY)
1997 {
1998 void *tmp;
1999 if (Header.SectionLength < 2)
2000 {
2001 restoreLogger.log_error("getFragmentFooter:Error reading fragment footer");
2002 return false;
2003 }
2004 if (Header.SectionLength > 2)
2005 buffer_get_ptr(&tmp, Header.SectionLength*4-8, 1);
2006 continue;
2007 }
2008 break;
2009 }
2010 /* read rest of header */
2011 if (buffer_read(((char*)&Header)+8, Header.SectionLength*4-8, 1) != 1)
2012 {
2013 ret = 0;
2014 return false;
2015 }
2016 Header.TableId = ntohl(Header.TableId);
2017 Header.FragmentNo = ntohl(Header.FragmentNo);
2018 Header.ChecksumType = ntohl(Header.ChecksumType);
2019
2020 restoreLogger.log_debug("FragmentHeader: %u %u %u %u %u",
2021 Header.SectionType,
2022 Header.SectionLength,
2023 Header.TableId,
2024 Header.FragmentNo,
2025 Header.ChecksumType);
2026
2027 m_currentTable = m_metaData.getTable(Header.TableId);
2028 if(m_currentTable == 0){
2029 ret = -1;
2030 return false;
2031 }
2032
2033 if(!m_tuple.prepareRecord(*m_currentTable))
2034 {
2035 ret =-1;
2036 return false;
2037 }
2038
2039 calc_row_extra_storage_words(m_currentTable);
2040 info.setLevel(254);
2041 restoreLogger.log_info("_____________________________________________________"
2042 "\nProcessing data in table: %s(%u) fragment %u",
2043 m_currentTable->getTableName(),
2044 Header.TableId, Header.FragmentNo);
2045
2046 m_count = 0;
2047 ret = 0;
2048 *fragmentId = Header.FragmentNo;
2049 return true;
2050 } // RestoreDataIterator::getNextFragment
2051
2052
2053 bool
validateFragmentFooter()2054 RestoreDataIterator::validateFragmentFooter() {
2055 BackupFormat::DataFile::FragmentFooter footer;
2056
2057 if (buffer_read(&footer, sizeof(footer), 1) != 1){
2058 restoreLogger.log_error("getFragmentFooter:Error reading fragment footer");
2059 return false;
2060 }
2061
2062 // TODO: Handle footer, nothing yet
2063 footer.SectionType = ntohl(footer.SectionType);
2064 footer.SectionLength = ntohl(footer.SectionLength);
2065 footer.TableId = ntohl(footer.TableId);
2066 footer.FragmentNo = ntohl(footer.FragmentNo);
2067 footer.NoOfRecords = ntohl(footer.NoOfRecords);
2068 footer.Checksum = ntohl(footer.Checksum);
2069
2070 assert(m_count == footer.NoOfRecords);
2071
2072 return true;
2073 } // RestoreDataIterator::getFragmentFooter
2074
AttributeDesc(NdbDictionary::Column * c)2075 AttributeDesc::AttributeDesc(NdbDictionary::Column *c)
2076 : m_column(c), transform(NULL), truncation_detected(false)
2077 {
2078 size = 8*NdbColumnImpl::getImpl(* c).m_attrSize;
2079 arraySize = NdbColumnImpl::getImpl(* c).m_arraySize;
2080 staging = false;
2081 parameterSz = 0;
2082 }
2083
~AttributeDesc()2084 AttributeDesc::~AttributeDesc()
2085 {
2086 delete transform;
2087 transform = NULL;
2088 }
2089
createAttr(NdbDictionary::Column * column)2090 void TableS::createAttr(NdbDictionary::Column *column)
2091 {
2092 AttributeDesc * d = new AttributeDesc(column);
2093 if(d == NULL) {
2094 restoreLogger.log_error("Restore: Failed to allocate memory");
2095 abort();
2096 }
2097 d->attrId = allAttributesDesc.size();
2098 d->convertFunc = NULL;
2099 d->parameter = NULL;
2100 d->m_exclude = false;
2101 allAttributesDesc.push_back(d);
2102
2103 if (d->m_column->getAutoIncrement())
2104 m_auto_val_attrib = d;
2105
2106 if(d->m_column->getPrimaryKey() && backupVersion <= MAKE_VERSION(4,1,7))
2107 {
2108 m_fixedKeys.push_back(d);
2109 return;
2110 }
2111
2112 if (d->m_column->getArrayType() == NDB_ARRAYTYPE_FIXED &&
2113 ! d->m_column->getNullable())
2114 {
2115 m_fixedAttribs.push_back(d);
2116 return;
2117 }
2118
2119 // just a reminder - does not solve backwards compat
2120 if (backupVersion < MAKE_VERSION(5,1,3) || ndbd_drop6(backupVersion))
2121 {
2122 d->m_nullBitIndex = m_noOfNullable;
2123 m_noOfNullable++;
2124 m_nullBitmaskSize = (m_noOfNullable + 31) / 32;
2125 }
2126 if ((d->m_column->getType() == NdbDictionary::Column::Blob) ||
2127 (d->m_column->getType() == NdbDictionary::Column::Text))
2128 {
2129 if (d->m_column->getPartSize() > 0)
2130 {
2131 m_has_blobs = true;
2132 }
2133 }
2134 m_variableAttribs.push_back(d);
2135 } // TableS::createAttr
2136
2137 bool
get_auto_data(const TupleS & tuple,Uint32 * syskey,Uint64 * nextid) const2138 TableS::get_auto_data(const TupleS & tuple, Uint32 * syskey, Uint64 * nextid) const
2139 {
2140 /*
2141 Read current (highest) auto_increment value for
2142 a table. Currently there can only be one per table.
2143 The values are stored in sustable SYSTAB_0 as
2144 {SYSKEY,NEXTID} values where SYSKEY (32-bit) is
2145 the table_id and NEXTID (64-bit) is the next auto_increment
2146 value in the sequence (note though that sequences of
2147 values can have been fetched and that are cached in NdbAPI).
2148 SYSTAB_0 can contain other data so we need to check that
2149 the found SYSKEY value is a valid table_id (< 0x10000000).
2150 */
2151 AttributeData * attr_data = tuple.getData(0);
2152 AttributeDesc * attr_desc = tuple.getDesc(0);
2153 const AttributeS attr1 = {attr_desc, *attr_data};
2154 memcpy(syskey ,attr1.Data.u_int32_value, sizeof(Uint32));
2155 attr_data = tuple.getData(1);
2156 attr_desc = tuple.getDesc(1);
2157 const AttributeS attr2 = {attr_desc, *attr_data};
2158 memcpy(nextid, attr2.Data.u_int64_value, sizeof(Uint64));
2159 if (*syskey < 0x10000000)
2160 {
2161 return true;
2162 }
2163 return false;
2164 }
2165
Twiddle16(Uint16 in)2166 Uint16 Twiddle16(Uint16 in)
2167 {
2168 Uint16 retVal = 0;
2169
2170 retVal = ((in & 0xFF00) >> 8) |
2171 ((in & 0x00FF) << 8);
2172
2173 return(retVal);
2174 } // Twiddle16
2175
Twiddle32(Uint32 in)2176 Uint32 Twiddle32(Uint32 in)
2177 {
2178 Uint32 retVal = 0;
2179
2180 retVal = ((in & 0x000000FF) << 24) |
2181 ((in & 0x0000FF00) << 8) |
2182 ((in & 0x00FF0000) >> 8) |
2183 ((in & 0xFF000000) >> 24);
2184
2185 return(retVal);
2186 } // Twiddle32
2187
Twiddle64(Uint64 in)2188 Uint64 Twiddle64(Uint64 in)
2189 {
2190 Uint64 retVal = 0;
2191
2192 retVal =
2193 ((in & (Uint64)0x00000000000000FFLL) << 56) |
2194 ((in & (Uint64)0x000000000000FF00LL) << 40) |
2195 ((in & (Uint64)0x0000000000FF0000LL) << 24) |
2196 ((in & (Uint64)0x00000000FF000000LL) << 8) |
2197 ((in & (Uint64)0x000000FF00000000LL) >> 8) |
2198 ((in & (Uint64)0x0000FF0000000000LL) >> 24) |
2199 ((in & (Uint64)0x00FF000000000000LL) >> 40) |
2200 ((in & (Uint64)0xFF00000000000000LL) >> 56);
2201
2202 return(retVal);
2203 } // Twiddle64
2204
RestoreLogIterator(const RestoreMetaData & md)2205 RestoreLogIterator::RestoreLogIterator(const RestoreMetaData & md)
2206 : m_metaData(md)
2207 {
2208 restoreLogger.log_debug("RestoreLog constructor");
2209 setLogFile(md, 0);
2210
2211 m_count = 0;
2212 m_last_gci = 0;
2213 m_rowBuffIndex = 0;
2214 }
2215
2216 const LogEntry *
getNextLogEntry(int & res)2217 RestoreLogIterator::getNextLogEntry(int & res) {
2218 // Read record length
2219 const Uint32 startGCP = m_metaData.getStartGCP();
2220 const Uint32 stopGCP = m_metaData.getStopGCP();
2221 Uint32 tableId;
2222 Uint32 triggerEvent;
2223 Uint32 frag_id;
2224 Uint32 *attr_data;
2225 Uint32 attr_data_len;
2226 bool skip_entry = false;
2227 do {
2228 Uint32 len;
2229 Uint32 *logEntryPtr;
2230 if(m_is_undolog){
2231 int read_result = 0;
2232 read_result = buffer_read(&len, sizeof(Uint32), 1);
2233 //no more log data to read
2234 if (read_result == 0 ) {
2235 res = 0;
2236 return 0;
2237 }
2238 if (read_result != 1) {
2239 res= -1;
2240 return 0;
2241 }
2242 }
2243 else{
2244 if (buffer_read_ahead(&len, sizeof(Uint32), 1) != 1){
2245 res= -1;
2246 return 0;
2247 }
2248 }
2249 len= ntohl(len);
2250
2251 Uint32 data_len = sizeof(Uint32) + len*4;
2252 if (buffer_get_ptr((void **)(&logEntryPtr), 1, data_len) != data_len) {
2253 res= -2;
2254 return 0;
2255 }
2256
2257 if(len == 0){
2258 res= 0;
2259 return 0;
2260 }
2261
2262 const Uint32 backup_file_version = m_metaData.getFileHeader().NdbVersion;
2263 if (unlikely(!ndbd_backup_file_fragid(backup_file_version)))
2264 {
2265 /*
2266 FragId was introduced in LogEntry in version
2267 5.1.6
2268 We set FragId to 0 in older versions (these versions
2269 do not support restore of user defined partitioned
2270 tables.
2271 */
2272 typedef BackupFormat::LogFile::LogEntry_no_fragid LogE_no_fragid;
2273 LogE_no_fragid * logE_no_fragid= (LogE_no_fragid *)logEntryPtr;
2274 tableId= ntohl(logE_no_fragid->TableId);
2275 triggerEvent= ntohl(logE_no_fragid->TriggerEvent);
2276 frag_id= 0;
2277 attr_data= &logE_no_fragid->Data[0];
2278 attr_data_len=
2279 len - BackupFormat::LogFile::LogEntry_no_fragid::HEADER_LENGTH_WORDS;
2280 }
2281 else /* normal case */
2282 {
2283 typedef BackupFormat::LogFile::LogEntry LogE;
2284 LogE * logE= (LogE *)logEntryPtr;
2285 tableId= ntohl(logE->TableId);
2286 triggerEvent= ntohl(logE->TriggerEvent);
2287 frag_id= ntohl(logE->FragId);
2288 attr_data= &logE->Data[0];
2289 attr_data_len=
2290 len - BackupFormat::LogFile::LogEntry::HEADER_LENGTH_WORDS;
2291 }
2292
2293 const bool hasGcp= (triggerEvent & 0x10000) != 0;
2294 triggerEvent &= 0xFFFF;
2295
2296 if(hasGcp){
2297 // last attr_data is gci info
2298 attr_data_len--;
2299 m_last_gci = ntohl(*(attr_data + attr_data_len));
2300 }
2301 if (m_is_undolog)
2302 {
2303 // Do not apply anything from startGCP or lower
2304 skip_entry = (m_last_gci <= startGCP);
2305 }
2306 else
2307 {
2308 // Do not apply anything after stopGCP
2309 skip_entry = (m_last_gci > stopGCP);
2310 }
2311 // Skip entries instead of stopping scan since entries are not ordered
2312 // by GCP. Entries from different GCPs may be interleaved, so scan till
2313 // EOF to read all matching entries.
2314 } while (skip_entry);
2315
2316 m_logEntry.m_table = m_metaData.getTable(tableId);
2317 /* We should 'invert' the operation type when we restore an Undo log.
2318 * To undo an insert operation, a delete is required.
2319 * To undo a delete operation, an insert is required.
2320 * The backup have collected 'before values' for undoing 'delete+update' to make this work.
2321 * To undo insert, we only need primary key.
2322 */
2323 switch(triggerEvent){
2324 case TriggerEvent::TE_INSERT:
2325 if(m_is_undolog)
2326 m_logEntry.m_type = LogEntry::LE_DELETE;
2327 else
2328 m_logEntry.m_type = LogEntry::LE_INSERT;
2329 break;
2330 case TriggerEvent::TE_UPDATE:
2331 m_logEntry.m_type = LogEntry::LE_UPDATE;
2332 break;
2333 case TriggerEvent::TE_DELETE:
2334 if(m_is_undolog)
2335 m_logEntry.m_type = LogEntry::LE_INSERT;
2336 else
2337 m_logEntry.m_type = LogEntry::LE_DELETE;
2338 break;
2339 default:
2340 res = -1;
2341 return NULL;
2342 }
2343
2344 const TableS * tab = m_logEntry.m_table;
2345 m_logEntry.clear();
2346 m_rowBuffIndex = 0;
2347
2348 AttributeHeader * ah = (AttributeHeader *)attr_data;
2349 AttributeHeader *end = (AttributeHeader *)(attr_data + attr_data_len);
2350 AttributeS * attr;
2351 m_logEntry.m_frag_id = frag_id;
2352 while(ah < end){
2353 attr = m_logEntry.add_attr();
2354 if(attr == NULL) {
2355 restoreLogger.log_error("Restore: Failed to allocate memory");
2356 res = -1;
2357 return 0;
2358 }
2359
2360 if(unlikely(!m_hostByteOrder))
2361 *(Uint32*)ah = Twiddle32(*(Uint32*)ah);
2362
2363 attr->Desc = tab->getAttributeDesc(ah->getAttributeId());
2364 assert(attr->Desc != 0);
2365
2366 const Uint32 sz = ah->getByteSize();
2367 if(sz == 0){
2368 attr->Data.null = true;
2369 attr->Data.void_value = NULL;
2370 attr->Data.size = 0;
2371 } else {
2372 attr->Data.null = false;
2373 attr->Data.void_value = ah->getDataPtr();
2374 attr->Data.size = sz;
2375 Twiddle(attr->Desc, &(attr->Data));
2376 }
2377
2378 if (attr->Desc->transform)
2379 {
2380 const int col_idx = ah->getAttributeId();
2381 const NdbDictionary::Column* col = tab->m_dictTable->getColumn(col_idx);
2382 void* dst_buf = m_rowBuff + m_rowBuffIndex;
2383 m_rowBuffIndex+= attr->Desc->getSizeInWords();
2384 assert(m_rowBuffIndex <= RowBuffWords);
2385
2386 if (!applyColumnTransform(col,
2387 attr->Desc,
2388 &attr->Data,
2389 dst_buf))
2390 {
2391 res = -1;
2392 return 0;
2393 }
2394 }
2395
2396 ah = ah->getNext();
2397 }
2398
2399 m_count ++;
2400 res = 0;
2401 return &m_logEntry;
2402 }
2403
2404 NdbOut &
operator <<(NdbOut & ndbout,const AttributeS & attr)2405 operator<<(NdbOut& ndbout, const AttributeS& attr){
2406 const AttributeData & data = attr.Data;
2407 const AttributeDesc & desc = *(attr.Desc);
2408
2409 if (data.null)
2410 {
2411 ndbout << g_ndbrecord_print_format.null_string;
2412 return ndbout;
2413 }
2414
2415 NdbRecAttr tmprec(0);
2416 tmprec.setup(desc.m_column, 0);
2417
2418 assert(desc.size % 8 == 0);
2419 #ifndef NDEBUG
2420 const Uint32 length = (desc.size)/8 * (desc.arraySize);
2421 #endif
2422 assert((desc.m_column->getArrayType() == NdbDictionary::Column::ArrayTypeFixed)
2423 ? (data.size == length)
2424 : (data.size <= length));
2425
2426 tmprec.receive_data((Uint32*)data.void_value, data.size);
2427
2428 ndbrecattr_print_formatted(ndbout, tmprec, g_ndbrecord_print_format);
2429
2430 return ndbout;
2431 }
2432
2433 // Print tuple data
2434 NdbOut&
operator <<(NdbOut & ndbout,const TupleS & tuple)2435 operator<<(NdbOut& ndbout, const TupleS& tuple)
2436 {
2437 for (int i = 0; i < tuple.getNoOfAttributes(); i++)
2438 {
2439 if (i > 0)
2440 ndbout << g_ndbrecord_print_format.fields_terminated_by;
2441 AttributeData * attr_data = tuple.getData(i);
2442 AttributeDesc * attr_desc = tuple.getDesc(i);
2443 const AttributeS attr = {attr_desc, *attr_data};
2444 debug << i << " " << attr_desc->m_column->getName();
2445 ndbout << attr;
2446 } // for
2447 return ndbout;
2448 }
2449
2450 // Print tuple data
2451 NdbOut&
operator <<(NdbOut & ndbout,const LogEntry & logE)2452 operator<<(NdbOut& ndbout, const LogEntry& logE)
2453 {
2454 switch(logE.m_type)
2455 {
2456 case LogEntry::LE_INSERT:
2457 ndbout << "INSERT " << logE.m_table->getTableName() << " ";
2458 break;
2459 case LogEntry::LE_DELETE:
2460 ndbout << "DELETE " << logE.m_table->getTableName() << " ";
2461 break;
2462 case LogEntry::LE_UPDATE:
2463 ndbout << "UPDATE " << logE.m_table->getTableName() << " ";
2464 break;
2465 default:
2466 ndbout << "Unknown log entry type (not insert, delete or update)" ;
2467 }
2468
2469 for (Uint32 i= 0; i < logE.size();i++)
2470 {
2471 const AttributeS * attr = logE[i];
2472 ndbout << attr->Desc->m_column->getName() << "=";
2473 ndbout << (* attr);
2474 if (i < (logE.size() - 1))
2475 ndbout << ", ";
2476 }
2477 return ndbout;
2478 }
2479
2480 void
printAttributeValue() const2481 AttributeS::printAttributeValue() const {
2482 NdbDictionary::Column::Type columnType =
2483 this->Desc->m_column->getType();
2484 switch(columnType)
2485 {
2486 case NdbDictionary::Column::Char:
2487 case NdbDictionary::Column::Varchar:
2488 case NdbDictionary::Column::Binary:
2489 case NdbDictionary::Column::Varbinary:
2490 case NdbDictionary::Column::Datetime:
2491 case NdbDictionary::Column::Date:
2492 case NdbDictionary::Column::Longvarchar:
2493 case NdbDictionary::Column::Longvarbinary:
2494 case NdbDictionary::Column::Time:
2495 case NdbDictionary::Column::Timestamp:
2496 case NdbDictionary::Column::Time2:
2497 case NdbDictionary::Column::Datetime2:
2498 case NdbDictionary::Column::Timestamp2:
2499 ndbout << "\'" << (* this) << "\'";
2500 break;
2501 default:
2502 ndbout << (* this);
2503 }
2504 }
2505
2506 void
printSqlLog() const2507 LogEntry::printSqlLog() const {
2508 /* Extract the table name from log entry which is stored in
2509 * database/schema/table and convert to database.table format
2510 */
2511 BaseString tableName(m_table->getTableName());
2512 Vector<BaseString> tableNameParts;
2513 Uint32 noOfPK = m_table->m_dictTable->getNoOfPrimaryKeys();
2514 tableName.split(tableNameParts, "/");
2515 tableName.assign("");
2516 tableName.assign(tableNameParts[0]);
2517 tableName.append(".");
2518 tableName.append(tableNameParts[2]);
2519 switch(m_type)
2520 {
2521 case LE_INSERT:
2522 ndbout << "INSERT INTO " << tableName.c_str() << " VALUES(";
2523 for (Uint32 i = noOfPK; i < size(); i++)
2524 {
2525 /* Skip the first field(s) which contains additional
2526 * instance of the primary key */
2527 const AttributeS * attr = m_values[i];
2528 attr->printAttributeValue();
2529 if (i < (size() - 1))
2530 ndbout << ",";
2531 }
2532 ndbout << ")";
2533 break;
2534 case LE_DELETE:
2535 ndbout << "DELETE FROM " << tableName.c_str() << " WHERE ";
2536 for (Uint32 i = 0; i < size();i++)
2537 {
2538 /* Primary key(s) clauses */
2539 const AttributeS * attr = m_values[i];
2540 const char* columnName = attr->Desc->m_column->getName();
2541 ndbout << columnName << "=";
2542 attr->printAttributeValue();
2543 if (i < (size() - 1))
2544 ndbout << " AND ";
2545 }
2546 break;
2547 case LE_UPDATE:
2548 ndbout << "UPDATE " << tableName.c_str() << " SET ";
2549 for (Uint32 i = noOfPK; i < size(); i++)
2550 {
2551 /* Print column(s) being set*/
2552 const AttributeS * attr = m_values[i];
2553 const char* columnName = attr->Desc->m_column->getName();
2554 ndbout << columnName << "=";
2555 attr->printAttributeValue();
2556 if (i < (size() - 1))
2557 ndbout << ", ";
2558 }
2559 /*Print where clause with primary key(s)*/
2560 ndbout << " WHERE ";
2561 for (Uint32 i = 0; i < noOfPK; i++)
2562 {
2563 const AttributeS * attr = m_values[i];
2564 const char* columnName = attr->Desc->m_column->getName();
2565 ndbout << columnName << "=";
2566 attr->printAttributeValue();
2567 if(i < noOfPK-1)
2568 ndbout << " AND ";
2569 }
2570 break;
2571 default:
2572 ndbout << "Unknown log entry type (not insert, delete or update)" ;
2573 }
2574 ndbout << ";";
2575 }
2576
RestoreLogger()2577 RestoreLogger::RestoreLogger()
2578 {
2579 m_mutex = NdbMutex_Create();
2580 }
2581
~RestoreLogger()2582 RestoreLogger::~RestoreLogger()
2583 {
2584 NdbMutex_Destroy(m_mutex);
2585 }
2586
log_error(const char * fmt,...)2587 void RestoreLogger::log_error(const char* fmt, ...)
2588 {
2589 va_list ap;
2590 va_start(ap, fmt);
2591 char buf[LOG_MSGLEN];
2592 vsnprintf(buf, sizeof(buf), fmt, ap);
2593 va_end(ap);
2594
2595 NdbMutex_Lock(m_mutex);
2596 err << getThreadPrefix() << buf << endl;
2597 NdbMutex_Unlock(m_mutex);
2598 }
2599
log_info(const char * fmt,...)2600 void RestoreLogger::log_info(const char* fmt, ...)
2601 {
2602 va_list ap;
2603 va_start(ap, fmt);
2604 char buf[LOG_MSGLEN];
2605 vsnprintf(buf, sizeof(buf), fmt, ap);
2606 va_end(ap);
2607
2608 NdbMutex_Lock(m_mutex);
2609 info << getThreadPrefix() << buf << endl;
2610 NdbMutex_Unlock(m_mutex);
2611 }
2612
log_debug(const char * fmt,...)2613 void RestoreLogger::log_debug(const char* fmt, ...)
2614 {
2615 va_list ap;
2616 va_start(ap, fmt);
2617 char buf[LOG_MSGLEN];
2618 vsnprintf(buf, sizeof(buf), fmt, ap);
2619 va_end(ap);
2620
2621 NdbMutex_Lock(m_mutex);
2622 debug << getThreadPrefix() << buf << endl;
2623 NdbMutex_Unlock(m_mutex);
2624 }
2625
2626 void
setThreadPrefix(const char * prefix)2627 RestoreLogger::setThreadPrefix(const char* prefix)
2628 {
2629 /* Reuse 'JAM buffer' Tls key for a per-thread prefix string buffer pointer */
2630 NDB_THREAD_TLS_JAM = (EmulatedJamBuffer*)prefix;
2631 }
2632
2633 const char*
getThreadPrefix() const2634 RestoreLogger::getThreadPrefix() const
2635 {
2636 const char* prefix = (const char*) NDB_THREAD_TLS_JAM;
2637 if (prefix == NULL)
2638 {
2639 prefix = "";
2640 }
2641 return prefix;
2642 }
2643
2644 NdbOut &
operator <<(NdbOut & ndbout,const TableS & table)2645 operator<<(NdbOut& ndbout, const TableS & table)
2646 {
2647 ndbout << "-- " << table.getTableName() << " --" << endl;
2648 ndbout << *(table.m_dictTable) << endl;
2649 return ndbout;
2650 }
2651
2652 template class Vector<TableS*>;
2653 template class Vector<AttributeS*>;
2654 template class Vector<AttributeDesc*>;
2655 template class Vector<FragmentInfo*>;
2656 template class Vector<DictObject>;
2657