1 /* Copyright (C) 2014 InfiniDB, Inc.
2
3 This program is free software; you can redistribute it and/or
4 modify it under the terms of the GNU General Public License
5 as published by the Free Software Foundation; version 2 of
6 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 Street, Fifth Floor, Boston,
16 MA 02110-1301, USA. */
17
18 /*
19 * $Id: we_rbmetawriter.cpp 4737 2013-08-14 20:45:46Z bwilkinson $
20 */
21
22 #include "we_rbmetawriter.h"
23
24 #include <cerrno>
25 #include <iostream>
26 #include <sstream>
27 #include <unistd.h>
28 #include <boost/filesystem/path.hpp>
29 #include <boost/filesystem/convenience.hpp>
30
31 #include "we_config.h"
32 #include "we_convertor.h"
33 #include "we_define.h"
34 #include "we_log.h"
35 #include "we_bulkrollbackmgr.h"
36 #include "idbcompress.h"
37 using namespace compress;
38 using namespace execplan;
39 #include "IDBDataFile.h"
40 #include "IDBFileSystem.h"
41 #include "IDBPolicy.h"
42 using namespace idbdatafile;
43
44 namespace
45 {
46 const char* DATA_DIR_SUFFIX = "_data";
47 const char* TMP_FILE_SUFFIX = ".tmp";
48
49 const char* VERSION3_REC = "# VERSION: 3";
50 const int VERSION3_REC_LEN = 12;
51 const char* VERSION4_REC = "# VERSION: 4";
52 const int VERSION4_REC_LEN = 12;
53 const char* COLUMN1_REC = "COLUM1"; // HWM extent for a DBRoot
54 const int COLUMN1_REC_LEN = 6;
55 const char* COLUMN2_REC = "COLUM2"; // Placeholder for empty DBRoot
56 const int COLUMN2_REC_LEN = 6;
57 const char* DSTORE1_REC = "DSTOR1"; // HWM extent for a DBRoot
58 const int DSTORE1_REC_LEN = 6;
59 const char* DSTORE2_REC = "DSTOR2"; // Placeholder for empty DBRoot
60 const int DSTORE2_REC_LEN = 6;
61
62 //--------------------------------------------------------------------------
63 // Local Function that prints contents of an RBChunkInfo object
64 //--------------------------------------------------------------------------
operator <<(std::ostream & os,const WriteEngine::RBChunkInfo & chk)65 std::ostream& operator<<(std::ostream& os,
66 const WriteEngine::RBChunkInfo& chk)
67 {
68 os << "OID-" << chk.fOid <<
69 "; DBRoot-" << chk.fDbRoot <<
70 "; Part-" << chk.fPartition <<
71 "; Seg-" << chk.fSegment <<
72 "; HWM-" << chk.fHwm;
73
74 return os;
75 }
76 }
77
78 namespace WriteEngine
79 {
80
81 //------------------------------------------------------------------------------
82 // Compare function used for set of RBChunkInfo objects.
83 //------------------------------------------------------------------------------
operator ()(const RBChunkInfo & lhs,const RBChunkInfo & rhs) const84 bool RBChunkInfoCompare::operator()
85 (const RBChunkInfo& lhs, const RBChunkInfo& rhs) const
86 {
87 if (lhs.fOid < rhs.fOid)
88 {
89 return true;
90 }
91
92 if ((lhs.fOid == rhs.fOid) && (lhs.fSegment < rhs.fSegment))
93 {
94 return true;
95 }
96
97 return false;
98 }
99
100 //------------------------------------------------------------------------------
101 // RBMetaWriter constructor
102 //------------------------------------------------------------------------------
RBMetaWriter(const std::string & appDesc,Log * logger)103 RBMetaWriter::RBMetaWriter (
104 const std::string& appDesc,
105 Log* logger ) : fMetaDataFile(NULL), fAppDesc(appDesc), fLog(logger), fCreatedSubDir(false)
106 {
107 }
108
109 //------------------------------------------------------------------------------
110 // Initialize this meta data file object using the specified table OID and name.
111 // We assume the application code calling this function, was able to acquire a
112 // table lock, meaning if there should happen to be any leftoever metadata files
113 // from a previous job, they can be deleted.
114 //------------------------------------------------------------------------------
init(OID tableOID,const std::string & tableName)115 void RBMetaWriter::init (
116 OID tableOID,
117 const std::string& tableName )
118 {
119 fTableOID = tableOID;
120 fTableName = tableName;
121
122 std::vector<uint16_t> dbRoots;
123 Config::getRootIdList( dbRoots );
124
125 std::string metaFileName;
126 std::ostringstream oss;
127 oss << "/" << fTableOID;
128
129 // Delete any files that collide with the file names we are going to need.
130 // Construct the filenames; we will use a temporary file name until we are
131 // finished creating, at which time we will rename the temp files.
132 for (unsigned m = 0; m < dbRoots.size(); m++)
133 {
134 std::string bulkRollbackPath( Config::getDBRootByNum( dbRoots[m] ) );
135 bulkRollbackPath += '/';
136 bulkRollbackPath += DBROOT_BULK_ROLLBACK_SUBDIR;
137 metaFileName = bulkRollbackPath;
138 metaFileName += oss.str();
139
140 std::string tmpMetaFileName = metaFileName;
141 tmpMetaFileName += TMP_FILE_SUFFIX;
142
143 // Delete any files that collide with the filenames we intend to use
144 IDBPolicy::remove( metaFileName.c_str() );
145 IDBPolicy::remove( tmpMetaFileName.c_str() );
146
147 // Clear out any data subdirectory
148 deleteSubDir( metaFileName );
149 }
150 }
151
152 //------------------------------------------------------------------------------
153 // Saves snapshot of extentmap into a bulk rollback meta data file, for
154 // use in a bulk rollback. Function was closely modeled after function
155 // of similar name in bulk/we_tableinfo.cpp. API was modified to help
156 // facilitate its use by DML.
157 //
158 // columns - Column vector with information about column in table.
159 // Includes information about the initial HWM extent, so that
160 // the corresponding HWM chunk can be backed up.
161 // dctnryStoreOids - Dictionary store OIDs that correspond to columns.
162 // dbRootHWMInfoVecCol - vector of last local HWM info for each DBRoot
163 // (asssigned to current PM) for each column in tblOid.
164 //------------------------------------------------------------------------------
saveBulkRollbackMetaData(const std::vector<Column> & columns,const std::vector<OID> & dctnryStoreOids,const std::vector<BRM::EmDbRootHWMInfo_v> & dbRootHWMInfoVecCol)165 void RBMetaWriter::saveBulkRollbackMetaData(
166 const std::vector<Column>& columns,
167 const std::vector<OID>& dctnryStoreOids,
168 const std::vector<BRM::EmDbRootHWMInfo_v>& dbRootHWMInfoVecCol )
169 {
170 int rc = NO_ERROR;
171 bool bOpenedFile = false;
172
173 try
174 {
175 std::vector<uint16_t> dbRoots;
176 Config::getRootIdList( dbRoots );
177
178 // Loop through DBRoot HWMs for this PM
179 for (unsigned m = 0; m < dbRoots.size(); m++)
180 {
181 std::string metaFileName = openMetaFile( dbRoots[m] );
182 bOpenedFile = true;
183 fCreatedSubDir = false;
184
185 // Loop through the columns in the specified table
186 for ( size_t i = 0; i < columns.size(); i++ )
187 {
188 const BRM::EmDbRootHWMInfo_v& dbRootHWMInfo =
189 dbRootHWMInfoVecCol[i];
190
191 // Select dbRootHWMInfo that matches DBRoot for this iteration
192 unsigned k = 0;
193
194 for (; k < dbRootHWMInfo.size(); k++)
195 {
196 if (dbRoots[m] == dbRootHWMInfo[k].dbRoot)
197 break;
198 }
199
200 if (k >= dbRootHWMInfo.size()) // logic error; should not happen
201 {
202 std::ostringstream oss;
203 oss << "Error creating meta file; DBRoot" << dbRoots[m] <<
204 " listed in Calpont config file, but not in extentmap"
205 " for OID " << columns[i].dataFile.oid;
206 throw WeException( oss.str(), ERR_INVALID_PARAM );
207 }
208
209 uint16_t dbRoot = dbRootHWMInfo[k].dbRoot;
210 uint32_t partition = 0;
211 uint16_t segment = 0;
212 HWM localHWM = 0;
213 bool bExtentWithData = false;
214
215 // For empty DBRoot (totalBlocks == 0),
216 // leave partition, segment, and HWM set to 0
217 if ((dbRootHWMInfo[k].totalBlocks > 0) ||
218 (dbRootHWMInfo[k].status == BRM::EXTENTOUTOFSERVICE))
219 {
220 partition = dbRootHWMInfo[k].partitionNum;
221 segment = dbRootHWMInfo[k].segmentNum;
222 localHWM = dbRootHWMInfo[k].localHWM;
223 bExtentWithData = true;
224 }
225
226 // Save column meta-data info to support bulk rollback
227 writeColumnMetaData(
228 metaFileName,
229 bExtentWithData,
230 columns[i].dataFile.oid,
231 dbRoot,
232 partition,
233 segment,
234 localHWM,
235 columns[i].colDataType,
236 ColDataTypeStr[ columns[i].colDataType ],
237 columns[i].colWidth,
238 columns[i].compressionType );
239
240 // Save dctnry store meta-data info to support bulk rollback
241 if ( dctnryStoreOids[i] > 0 )
242 {
243 std::vector<uint32_t> segList;
244 std::string segFileListErrMsg;
245
246 if (bExtentWithData)
247 {
248 std::string dirName;
249 FileOp fileOp(false);
250 rc = fileOp.getDirName( dctnryStoreOids[i],
251 dbRoot, partition, dirName );
252
253 if (rc != NO_ERROR)
254 {
255 WErrorCodes ec;
256 std::ostringstream oss;
257 oss << "Bulk rollback error constructing path "
258 "for dictionary " << dctnryStoreOids[i] <<
259 "; dbRoot-" << dbRoot <<
260 "; partition-" << partition <<
261 "; " << ec.errorString(rc);
262
263 throw WeException( oss.str(), rc );
264 }
265
266 rc = BulkRollbackMgr::getSegFileList(dirName, false,
267 segList,
268 segFileListErrMsg);
269
270 if (rc != NO_ERROR)
271 {
272 WErrorCodes ec;
273 std::ostringstream oss;
274 oss << "Bulk rollback error for dictionary " <<
275 dctnryStoreOids[i] <<
276 "; directory-" << dirName <<
277 "; " << segFileListErrMsg <<
278 "; " << ec.errorString(rc);
279
280 throw WeException( oss.str(), rc );
281 }
282 } // end of "if (bExtentWithData)"
283
284 if (segList.size() == 0)
285 {
286 writeDictionaryStoreMetaNoDataMarker(
287 columns[i].dataFile.oid,
288 dctnryStoreOids[i],
289 dbRoot,
290 partition,
291 0, // segment
292 columns[i].compressionType );
293 }
294 else
295 {
296 // Loop thru dictionary store seg files for this DBRoot
297 for (unsigned int kk = 0; kk < segList.size(); kk++)
298 {
299 unsigned int segDictionary = segList[kk];
300
301 // check HWM for dictionary store file
302 HWM dictHWMStore;
303 int extState;
304 rc = BRMWrapper::getInstance()->getLocalHWM(
305 dctnryStoreOids[i],
306 partition,
307 segDictionary,
308 dictHWMStore,
309 extState );
310
311 if (rc != NO_ERROR)
312 {
313 WErrorCodes ec;
314 std::ostringstream oss;
315 oss << "Error getting rollback HWM for "
316 "dictionary file " << dctnryStoreOids[i] <<
317 "; partition-" << partition <<
318 "; segment-" << segDictionary <<
319 "; " << ec.errorString(rc);
320 throw WeException( oss.str(), rc );
321 }
322
323 writeDictionaryStoreMetaData(
324 columns[i].dataFile.oid,
325 dctnryStoreOids[i],
326 dbRoot,
327 partition,
328 segDictionary,
329 dictHWMStore,
330 columns[i].compressionType );
331
332 } // loop thru dictionary store seg files in this DBRoot
333 } // dictionary OID has 1 or more seg files in partition
334 } // if dictionary column
335
336 // For a compressed column, backup the starting HWM chunk if the
337 // starting HWM block is not on an empty DBRoot (or outOfSrvc)
338 if ( (columns[i].compressionType) &&
339 (columns[i].dataFile.fDbRoot == dbRootHWMInfo[k].dbRoot) &&
340 (dbRootHWMInfo[k].totalBlocks > 0) &&
341 (dbRootHWMInfo[k].status != BRM::EXTENTOUTOFSERVICE) )
342 {
343 backupColumnHWMChunk(
344 columns[i].dataFile.oid,
345 columns[i].dataFile.fDbRoot,
346 columns[i].dataFile.fPartition,
347 columns[i].dataFile.fSegment,
348 columns[i].dataFile.hwm );
349 }
350
351 } // End of loop through columns
352
353 // time to dump the string stream to file
354 std::string data(fMetaDataStream.str());
355
356 // this is to cover partical writes
357 // no need for retry if low layer takes care partial writes.
358 const char* p = data.c_str(); // buffer contents
359 size_t s = data.size(); // buffer size
360 size_t w = 0; // total bytes written so far
361 ssize_t n = 0; // bytes written in one write
362
363 for (int i = 0; i < 10 && w < s; i++)
364 {
365 n = fMetaDataFile->write(p + w, s - w);
366
367 if (n < 0)
368 break;
369
370 w += n;
371 }
372
373 if (w != s)
374 {
375 int errRc = errno;
376 std::ostringstream oss;
377 oss << "Error writing bulk rollback meta-data file "
378 << metaFileName << "; written/expect:" << w << "/" << s
379 << "; err-" << errRc << "; " << strerror( errRc );
380 throw WeException(oss.str(), ERR_FILE_WRITE);
381 }
382
383 fMetaDataStream.str("");
384 closeMetaFile( );
385 bOpenedFile = false;
386
387 } // End of loop through DBRoot HWMs for this PM
388
389 renameMetaFile( ); // rename meta files from temporary filenames
390 }
391 catch (WeException& ex) // catch exception to close file, then rethrow
392 {
393 if (bOpenedFile)
394 closeMetaFile( );
395
396 // If any error occurred, then go back and try to delete all meta files.
397 // We catch and drop any exception, and return the original exception,
398 // since we are already in error-mode at this point.
399 try
400 {
401 deleteFile( );
402 }
403 catch (...)
404 {
405 }
406
407 throw WeException( ex.what(), ex.errorCode() );
408 }
409 }
410
411 //------------------------------------------------------------------------------
412 // Open a meta data file to save info about the specified table OID.
413 //------------------------------------------------------------------------------
openMetaFile(uint16_t dbRoot)414 std::string RBMetaWriter::openMetaFile ( uint16_t dbRoot )
415 {
416 std::string bulkRollbackPath( Config::getDBRootByNum( dbRoot ) );
417 bulkRollbackPath += '/';
418 bulkRollbackPath += DBROOT_BULK_ROLLBACK_SUBDIR;
419
420 if ( !IDBPolicy::exists( bulkRollbackPath.c_str() ) )
421 {
422 if ( IDBPolicy::mkdir( bulkRollbackPath.c_str() ) != 0 )
423 {
424 std::ostringstream oss;
425 oss << "Error creating bulk rollback directory " <<
426 bulkRollbackPath << ";" << std::endl;
427 throw WeException( oss.str(), ERR_DIR_CREATE );
428 }
429 }
430
431 // Open the file
432 std::ostringstream oss;
433 oss << "/" << fTableOID;
434 std::string metaFileName( bulkRollbackPath );
435 metaFileName += oss.str();
436 fMetaFileNames.insert( make_pair(dbRoot, metaFileName) );
437
438 std::string tmpMetaFileName( metaFileName );
439 tmpMetaFileName += TMP_FILE_SUFFIX;
440 fMetaDataFile = IDBDataFile::open(IDBPolicy::getType(tmpMetaFileName.c_str(),
441 IDBPolicy::WRITEENG),
442 tmpMetaFileName.c_str(), "wb", 0);
443
444 if ( !fMetaDataFile )
445 {
446 int errRc = errno;
447 std::ostringstream oss;
448 std::string eMsg;
449 Convertor::mapErrnoToString(errRc, eMsg);
450 oss << "Error opening bulk rollback file " <<
451 tmpMetaFileName << "; " << eMsg;
452 throw WeException( oss.str(), ERR_FILE_OPEN );
453 }
454
455 {
456 std::ostringstream ossChown;
457 idbdatafile::IDBFileSystem& fs = IDBPolicy::getFs(tmpMetaFileName.c_str());
458 if (chownPath(ossChown, tmpMetaFileName, fs)
459 || chownPath(ossChown, bulkRollbackPath, fs))
460 {
461 throw WeException(ossChown.str(), ERR_FILE_CHOWN);
462 }
463 }
464
465 fMetaDataStream <<
466 "# VERSION: 4" << std::endl <<
467 "# APPLICATION: " << fAppDesc << std::endl <<
468 "# PID: " << ::getpid() << std::endl <<
469 "# TABLE: " << fTableName << std::endl <<
470 "# COLUM1: coloid,"
471 "dbroot,part,seg,lastLocalHWM,type,typename,width,comp" <<
472 std::endl <<
473 "# COLUM2: coloid,"
474 "dbroot,part,seg,type,typename,width,comp" <<
475 std::endl <<
476 "# DSTOR1: coloid,dctoid,"
477 "dbroot,part,seg,localHWM,comp" << std::endl <<
478 "# DSTOR2: coloid,dctoid,"
479 "dbroot,part,seg,comp" << std::endl;
480
481 // Clear out any data subdirectory
482 // This is redundant because init() also calls deleteSubDir(), but it can't
483 // hurt to call twice. We "really" want to make sure we start with a clean
484 // slate (no leftover backup chunk files from a previous import job).
485 deleteSubDir( metaFileName );
486
487 return metaFileName;
488 }
489
490 //------------------------------------------------------------------------------
491 // Close the currently open "temporary named" meta data file used during
492 // construction. We will rename all the meta data files (for the various
493 // dbroots) to their eventual file names later, in renameMetaFile().
494 //------------------------------------------------------------------------------
closeMetaFile()495 void RBMetaWriter::closeMetaFile ( )
496 {
497 delete fMetaDataFile;
498 fMetaDataFile = NULL;
499 }
500
501 //------------------------------------------------------------------------------
502 // Rename temporary metafile names to their permanent name, taking file names
503 // from fMetaFileNames. In the normal case there will be one file name per
504 // DBRoot for the local PM we are running on.
505 //------------------------------------------------------------------------------
renameMetaFile()506 void RBMetaWriter::renameMetaFile ( )
507 {
508 for (std::map<uint16_t, std::string>::const_iterator iter =
509 fMetaFileNames.begin(); iter != fMetaFileNames.end(); ++iter)
510 {
511 const std::string& metaFileName = iter->second;
512
513 if (!metaFileName.empty())
514 {
515 std::string tmpMetaFileName = metaFileName;
516 tmpMetaFileName += TMP_FILE_SUFFIX;
517
518 if ( IDBPolicy::rename(tmpMetaFileName.c_str(), metaFileName.c_str()) )
519 {
520 int errRc = errno;
521 std::ostringstream oss;
522 std::string eMsg;
523 Convertor::mapErrnoToString(errRc, eMsg);
524 oss << "Error renaming meta data file-" <<
525 tmpMetaFileName << "; will be deleted; " << eMsg;
526 throw WeException( oss.str(), ERR_METADATABKUP_FILE_RENAME );
527 }
528 }
529 }
530 }
531
532 //------------------------------------------------------------------------------
533 // Delete the meta data files for the specified table OID. We loop through all
534 // the DBRoots for the local PM, deleting the applicable meta data files.
535 // If the call to deleteSubDir() should throw an exception, we might not want
536 // to consider that a fatal error, but we go ahead and let the exception
537 // go up the call-stack so that the caller can log the corresponding message.
538 // The application code can then decide whether they want to consider this
539 // condition as fatal or not.
540 //------------------------------------------------------------------------------
deleteFile()541 void RBMetaWriter::deleteFile ( )
542 {
543 for (std::map<uint16_t, std::string>::const_iterator iter =
544 fMetaFileNames.begin(); iter != fMetaFileNames.end(); ++iter)
545 {
546 const std::string& metaFileName = iter->second;
547
548 if (!metaFileName.empty())
549 {
550 std::string tmpMetaFileName = metaFileName;
551 tmpMetaFileName += TMP_FILE_SUFFIX;
552
553 IDBPolicy::remove( metaFileName.c_str() );
554 IDBPolicy::remove( tmpMetaFileName.c_str() );
555
556 deleteSubDir( metaFileName ); // can throw an exception
557 }
558 }
559
560 fMetaFileNames.clear( );
561 }
562
563 //------------------------------------------------------------------------------
564 // New version of writeColumnMetaData for Shared-Nothing
565 //------------------------------------------------------------------------------
writeColumnMetaData(const std::string & metaFileName,bool withHWM,OID columnOID,uint16_t dbRoot,uint32_t partition,uint16_t segment,HWM lastLocalHwm,CalpontSystemCatalog::ColDataType colType,const std::string & colTypeName,int colWidth,int compressionType)566 void RBMetaWriter::writeColumnMetaData (
567 const std::string& metaFileName,
568 bool withHWM,
569 OID columnOID,
570 uint16_t dbRoot,
571 uint32_t partition,
572 uint16_t segment,
573 HWM lastLocalHwm,
574 CalpontSystemCatalog::ColDataType colType,
575 const std::string& colTypeName,
576 int colWidth,
577 int compressionType )
578 {
579 if (withHWM)
580 {
581 fMetaDataStream << "COLUM1: " <<
582 columnOID << ' ' <<
583 dbRoot << ' ' <<
584 partition << ' ' <<
585 segment << ' ' <<
586 lastLocalHwm << ' ' <<
587 colType << ' ' <<
588 colTypeName << ' ' <<
589 colWidth;
590 }
591 else
592 {
593 fMetaDataStream << "COLUM2: " <<
594 columnOID << ' ' <<
595 dbRoot << ' ' <<
596 partition << ' ' <<
597 segment << ' ' <<
598 colType << ' ' <<
599 colTypeName << ' ' <<
600 colWidth;
601 }
602
603 if (compressionType)
604 fMetaDataStream << ' ' << compressionType << ' ';
605
606 fMetaDataStream << std::endl;
607
608 // If column is compressed, then create directory for storing HWM chunks
609 if (compressionType)
610 {
611 if (!fCreatedSubDir)
612 {
613 // @bug 5572 - Don't need db backup files for HDFS;
614 // use hdfs buffer file
615 if (!IDBPolicy::useHdfs())
616 createSubDir( metaFileName );
617 }
618 }
619 }
620
621 //------------------------------------------------------------------------------
622 // New version of writeDictionaryStoreMetaData for Shared-Nothing.
623 //------------------------------------------------------------------------------
writeDictionaryStoreMetaData(OID columnOID,OID dictionaryStoreOID,uint16_t dbRoot,uint32_t partition,uint16_t segment,HWM localHwm,int compressionType)624 void RBMetaWriter::writeDictionaryStoreMetaData (
625 OID columnOID,
626 OID dictionaryStoreOID,
627 uint16_t dbRoot,
628 uint32_t partition,
629 uint16_t segment,
630 HWM localHwm,
631 int compressionType )
632 {
633 fMetaDataStream << "DSTOR1: " <<
634 columnOID << ' ' <<
635 dictionaryStoreOID << ' ' <<
636 dbRoot << ' ' <<
637 partition << ' ' <<
638 segment << ' ' <<
639 localHwm;
640
641 if (compressionType)
642 fMetaDataStream << ' ' << compressionType << ' ';
643
644 fMetaDataStream << std::endl;
645
646 // Save dictionary meta data for later use in backing up the HWM chunks
647 if (compressionType)
648 {
649 RBChunkInfo chunkInfo(
650 dictionaryStoreOID, dbRoot, partition, segment, localHwm);
651 fRBChunkDctnrySet.insert( chunkInfo );
652
653 if ( (fLog) && (fLog->isDebug(DEBUG_1)) )
654 printDctnryChunkList(chunkInfo, "after adding ");
655 }
656 }
657
658 //------------------------------------------------------------------------------
659 // New version of writeDictionaryStoreMetaNoDataMarker for Shared-Nothing.
660 //------------------------------------------------------------------------------
writeDictionaryStoreMetaNoDataMarker(OID columnOID,OID dictionaryStoreOID,uint16_t dbRoot,uint32_t partition,uint16_t segment,int compressionType)661 void RBMetaWriter::writeDictionaryStoreMetaNoDataMarker (
662 OID columnOID,
663 OID dictionaryStoreOID,
664 uint16_t dbRoot,
665 uint32_t partition,
666 uint16_t segment,
667 int compressionType )
668 {
669 fMetaDataStream << "DSTOR2: " <<
670 columnOID << ' ' <<
671 dictionaryStoreOID << ' ' <<
672 dbRoot << ' ' <<
673 partition << ' ' <<
674 segment;
675
676 if (compressionType)
677 fMetaDataStream << ' ' << compressionType << ' ';
678
679 fMetaDataStream << std::endl;
680 }
681
682 //------------------------------------------------------------------------------
683 // Create the subdirectory we will use to backup data needed for rollback.
684 //------------------------------------------------------------------------------
createSubDir(const std::string & metaFileName)685 void RBMetaWriter::createSubDir( const std::string& metaFileName )
686 {
687 std::string bulkRollbackSubPath( metaFileName );
688 bulkRollbackSubPath += DATA_DIR_SUFFIX;
689
690 if ( IDBPolicy::mkdir( bulkRollbackSubPath.c_str() ) != 0 )
691 {
692 std::ostringstream oss;
693 oss << "Error creating bulk rollback data subdirectory " <<
694 bulkRollbackSubPath << ";";
695 throw WeException( oss.str(), ERR_DIR_CREATE );
696 }
697
698 fCreatedSubDir = true;
699 }
700
701 //------------------------------------------------------------------------------
702 // Delete the subdirectory used to backup data needed for rollback.
703 //------------------------------------------------------------------------------
deleteSubDir(const std::string & metaFileName)704 void RBMetaWriter::deleteSubDir( const std::string& metaFileName )
705 {
706 std::string bulkRollbackSubPath( metaFileName );
707 bulkRollbackSubPath += DATA_DIR_SUFFIX;
708
709 if ( IDBPolicy::remove( bulkRollbackSubPath.c_str() ) != 0 )
710 {
711 std::ostringstream oss;
712 oss << "Error deleting bulk rollback data subdirectory " <<
713 bulkRollbackSubPath << ";";
714 throw WeException( oss.str(), ERR_FILE_DELETE );
715 }
716 }
717
718 //------------------------------------------------------------------------------
719 // Backup the contents of the HWM chunk for the specified column OID extent,
720 // so that the chunk is available for bulk rollback.
721 // This operation is only performed for compressed columns.
722 //------------------------------------------------------------------------------
backupColumnHWMChunk(OID columnOID,uint16_t dbRoot,uint32_t partition,uint16_t segment,HWM startingHWM)723 void RBMetaWriter::backupColumnHWMChunk(
724 OID columnOID,
725 uint16_t dbRoot,
726 uint32_t partition,
727 uint16_t segment,
728 HWM startingHWM)
729 {
730 // @bug 5572 - Don't need db backup file for HDFS; we use hdfs buffer file
731 if (!IDBPolicy::useHdfs())
732 {
733 backupHWMChunk( true,
734 columnOID, dbRoot, partition, segment, startingHWM );
735 }
736 }
737
738 //------------------------------------------------------------------------------
739 // Backup the contents of the HWM chunk for the specified dictionary store OID
740 // extent, so that the chunk is available for bulk rollback.
741 // This operation is only performed for compressed columns. Once the chunk is
742 // saved, we remove that OID, partition, and segment from the internal list
743 // (fRBChunkDctnrySet) that is maintained.
744 // Return value indicates whether the specified file needs to be backed up or
745 // not.
746 //
747 // This function MUST be maintained to be thread-safe so that multiple threads
748 // can concurrently call this function, with each thread managing a different
749 // dictionary column.
750 //------------------------------------------------------------------------------
751 // @bug 5572 - HDFS usage: add return flag to indicate backup status
backupDctnryHWMChunk(OID dctnryOID,uint16_t dbRoot,uint32_t partition,uint16_t segment)752 bool RBMetaWriter::backupDctnryHWMChunk(
753 OID dctnryOID,
754 uint16_t dbRoot,
755 uint32_t partition,
756 uint16_t segment)
757 {
758 bool bBackupApplies = false;
759
760 if (fRBChunkDctnrySet.size() > 0)
761 {
762 RBChunkInfo chunkInfo(
763 dctnryOID, 0, partition, segment, 0);
764 RBChunkInfo chunkInfoFound(0, 0, 0, 0, 0);
765 bool bFound = false;
766
767 {
768 // Use scoped lock to perform "find"
769 boost::mutex::scoped_lock lock( fRBChunkDctnryMutex );
770
771 if ( (fLog) && (fLog->isDebug(DEBUG_1)) )
772 printDctnryChunkList(chunkInfo, "when searching ");
773
774 RBChunkSet::iterator iter = fRBChunkDctnrySet.find ( chunkInfo );
775
776 if (iter != fRBChunkDctnrySet.end())
777 {
778 bFound = true;
779 chunkInfoFound = *iter;
780 }
781 }
782
783 if (bFound)
784 {
785 if (chunkInfoFound.fPartition == partition)
786 {
787 // @bug 5572 - Don't need db backup file for HDFS;
788 // we use hdfs buffer file. Set backup flag
789 // so application knows to use tmp buffer file.
790 bBackupApplies = true;
791
792 if (!IDBPolicy::useHdfs())
793 {
794 backupHWMChunk(false, dctnryOID,
795 dbRoot, partition, segment, chunkInfoFound.fHwm);
796 }
797 }
798 else
799 {
800 // How could this happen? Ended up asking for different
801 // partition than expected for the first instance of this
802 // OID and segment file. Perhaps initial blockskipping
803 // or something caused us to advance to another segment file
804 // without ever changing the expected extent. At any rate
805 // we still fall through and delete our entry because we
806 // apparently did not end up changing the chunk referenced
807 // by this RBChunkInfo object.
808 }
809
810 {
811 // Use scoped lock to perform "erase"
812 boost::mutex::scoped_lock lock( fRBChunkDctnryMutex );
813 fRBChunkDctnrySet.erase( chunkInfoFound );
814
815 if ( (fLog) && (fLog->isDebug(DEBUG_1)) )
816 printDctnryChunkList(chunkInfoFound, "after deleting ");
817 }
818 }
819 }
820
821 return bBackupApplies;
822 }
823
824 //------------------------------------------------------------------------------
825 // Backup entire contents of HWM file for the specified columnOID,dbRoot,etc,
826 // so that the file is available for bulk rollback. This function is used for
827 // HDFS files only. This operation is only performed for compressed columns.
828 //
829 // This function MUST be kept thread-safe in support of backupDctnryHWMChunk().
830 // See that function description for more details. This is the reason
831 // backupHWMChunk() has to have a local FileOp object. We can't share/reuse
832 // a FileOp data member variable unless we want to employ a mutex.
833 //------------------------------------------------------------------------------
834 // @bug 5572 - Stopped using backupHWMFile().
835 // Don't need db backup file for HDFS; we use hdfs buffer file
backupHWMFile(bool bColumnFile,OID columnOID,uint16_t dbRoot,uint32_t partition,uint16_t segment,HWM startingHWM)836 void RBMetaWriter::backupHWMFile(
837 bool bColumnFile, // is this a column (vs dictionary) file
838 OID columnOID, // OID of column or dictionary store
839 uint16_t dbRoot, // DB Root for db segment file
840 uint32_t partition, // partition for db segment file
841 uint16_t segment, // segment for db segment file
842 HWM startingHWM) // starting HWM for db segment file
843 {
844 std::string fileType("column");
845
846 if (!bColumnFile)
847 fileType = "dictionary";
848
849 FileOp fileOp; // @bug 4960: to keep thread-safe, we use local FileOp
850
851 // Construct file name for db file to be backed up
852 char dbFileName[FILE_NAME_SIZE];
853 int rc = fileOp.getFileName( columnOID, dbFileName,
854 dbRoot, partition, segment );
855
856 if (rc != NO_ERROR)
857 {
858 std::ostringstream oss;
859 oss << "Error creating backup " << fileType <<
860 " file for OID " << columnOID <<
861 "; Can't construct file name for DBRoot" << dbRoot <<
862 "; partition-" << partition <<
863 "; segment-" << segment;
864 throw WeException( oss.str(), rc );
865 }
866
867 // Construct file name for backup copy of db file
868 std::ostringstream ossFile;
869 ossFile << "/" << columnOID << ".p" << partition << ".s" << segment;
870 std::string backupFileName;
871 rc = getSubDirPath( dbRoot, backupFileName );
872
873 if (rc != NO_ERROR)
874 {
875 std::ostringstream oss;
876 oss << "Error creating backup " << fileType <<
877 " file for OID " << columnOID <<
878 "; Can't find matching meta file for DBRoot" << dbRoot;
879 throw WeException( oss.str(), rc );
880 }
881
882 backupFileName += ossFile.str();
883
884 std::string backupFileNameTmp = backupFileName;
885 backupFileNameTmp += TMP_FILE_SUFFIX;
886
887 //if ( (fLog) && (fLog->isDebug(DEBUG_1)) )
888 if (fLog)
889 {
890 std::ostringstream oss;
891 oss << "Backing up HWM file for " << fileType <<
892 " file for OID " << columnOID <<
893 "; file-" << backupFileNameTmp <<
894 "; HWM-" << startingHWM;
895 fLog->logMsg( oss.str(), MSGLVL_INFO2 );
896 }
897
898 // Copy the db file to a temporary name
899 IDBFileSystem& fs = IDBPolicy::getFs( backupFileNameTmp.c_str() );
900
901 if ( !fs.exists(dbFileName) )
902 {
903 std::ostringstream oss;
904 oss << "Error creating backup " << fileType <<
905 " file for OID " << columnOID <<
906 "; dbfile does not exist for DBRoot" << dbRoot <<
907 "; partition-" << partition <<
908 "; segment-" << segment;
909 throw WeException( oss.str(), ERR_FILE_NOT_EXIST );
910 }
911
912 rc = fs.copyFile( dbFileName, backupFileNameTmp.c_str() );
913
914 if (rc != 0)
915 {
916 std::ostringstream oss;
917 oss << "Error copying backup for " << fileType <<
918 " OID-" << columnOID <<
919 "; DBRoot-" << dbRoot <<
920 "; partition-" << partition <<
921 "; segment-" << segment <<
922 "; rc-" << rc;
923
924 fs.remove( backupFileNameTmp.c_str() );
925 throw WeException( oss.str(), ERR_METADATABKUP_COMP_WRITE_BULK_BKUP );
926 }
927
928 // Rename temporary named backup file to final name
929 rc = fs.rename( backupFileNameTmp.c_str(), backupFileName.c_str() );
930
931 if (rc != 0)
932 {
933 std::ostringstream oss;
934 oss << "Error renaming temp backup for " << fileType <<
935 " OID-" << columnOID <<
936 "; DBRoot-" << dbRoot <<
937 "; partition-" << partition <<
938 "; segment-" << segment <<
939 "; rc-" << rc;
940
941 fs.remove( backupFileNameTmp.c_str() );
942 fs.remove( backupFileName.c_str() );
943 throw WeException( oss.str(), ERR_METADATABKUP_COMP_RENAME );
944 }
945 }
946
947 //------------------------------------------------------------------------------
948 // Backup the contents of the HWM chunk for the specified columnOID,dbRoot,etc,
949 // so that the chunk is available for bulk rollback. This function is used for
950 // non-hdfs files. This operation is only performed for compressed columns.
951 //
952 // This function MUST be kept thread-safe in support of backupDctnryHWMChunk().
953 // See that function description for more details. This is the reason
954 // backupHWMChunk() has to have a local FileOp object. We can't share/reuse
955 // a FileOp data member variable unless we want to employ a mutex.
956 //------------------------------------------------------------------------------
backupHWMChunk(bool bColumnFile,OID columnOID,uint16_t dbRoot,uint32_t partition,uint16_t segment,HWM startingHWM)957 void RBMetaWriter::backupHWMChunk(
958 bool bColumnFile, // is this a column (vs dictionary) file
959 OID columnOID, // OID of column or dictionary store
960 uint16_t dbRoot, // DB Root for db segment file
961 uint32_t partition, // partition for db segment file
962 uint16_t segment, // segment for db segment file
963 HWM startingHWM) // starting HWM for db segment file
964 {
965 std::string fileType("column");
966
967 if (!bColumnFile)
968 fileType = "dictionary";
969
970 // Open the applicable database column segment file
971 std::string segFile;
972 FileOp fileOp; // @bug 4960: to keep thread-safe, we use local FileOp
973 IDBDataFile* dbFile = fileOp.openFile( columnOID,
974 dbRoot,
975 partition,
976 segment,
977 segFile,
978 "rb" );
979
980 if ( !dbFile )
981 {
982 std::ostringstream oss;
983 oss << "Backup error opening " << fileType <<
984 " file for OID-" << columnOID <<
985 "; DBRoot-" << dbRoot <<
986 "; partition-" << partition <<
987 "; segment-" << segment;
988 throw WeException( oss.str(), ERR_FILE_OPEN );
989 }
990
991 // Get the size of the file, so we know where to truncate back to.
992 long long fileSizeBytes;
993 int rc = fileOp.getFileSize( dbFile, fileSizeBytes);
994
995 if (rc != NO_ERROR)
996 {
997 WErrorCodes ec;
998 std::ostringstream oss;
999 oss << "Backup error getting file size for " << fileType <<
1000 " OID-" << columnOID <<
1001 "; DBRoot-" << dbRoot <<
1002 "; partition-" << partition <<
1003 "; segment-" << segment <<
1004 "; " << ec.errorString(rc);
1005 fileOp.closeFile( dbFile );
1006 throw WeException( oss.str(), rc );
1007 }
1008
1009 // Read Control header
1010 char controlHdr[ IDBCompressInterface::HDR_BUF_LEN ];
1011 rc = fileOp.readFile( dbFile, (unsigned char*)controlHdr,
1012 IDBCompressInterface::HDR_BUF_LEN );
1013
1014 if (rc != NO_ERROR)
1015 {
1016 WErrorCodes ec;
1017 std::ostringstream oss;
1018 oss << "Backup error reading " << fileType <<
1019 " file control hdr for OID-" << columnOID <<
1020 "; DBRoot-" << dbRoot <<
1021 "; partition-" << partition <<
1022 "; segment-" << segment <<
1023 "; " << ec.errorString(rc);
1024 fileOp.closeFile( dbFile );
1025 throw WeException( oss.str(), rc );
1026 }
1027
1028 IDBCompressInterface compressor;
1029 int rc1 = compressor.verifyHdr( controlHdr );
1030
1031 if (rc1 != 0)
1032 {
1033 rc = ERR_METADATABKUP_COMP_VERIFY_HDRS;
1034
1035 WErrorCodes ec;
1036 std::ostringstream oss;
1037 oss << "Backup error verifying " << fileType <<
1038 " file control hdr for OID-" << columnOID <<
1039 "; DBRoot-" << dbRoot <<
1040 "; partition-" << partition <<
1041 "; segment-" << segment <<
1042 "; " << ec.errorString(rc) <<
1043 "; rc: " << rc1;
1044 fileOp.closeFile( dbFile );
1045 throw WeException( oss.str(), rc );
1046 }
1047
1048 // Read Pointer header data
1049 uint64_t hdrSize = compressor.getHdrSize(controlHdr);
1050 uint64_t ptrHdrSize = hdrSize - IDBCompressInterface::HDR_BUF_LEN;
1051 char* pointerHdr = new char[ptrHdrSize];
1052 rc = fileOp.readFile( dbFile, (unsigned char*)pointerHdr, ptrHdrSize );
1053
1054 if (rc != NO_ERROR)
1055 {
1056 WErrorCodes ec;
1057 std::ostringstream oss;
1058 oss << "Backup error reading " << fileType <<
1059 " file pointer hdr for OID-" << columnOID <<
1060 "; DBRoot-" << dbRoot <<
1061 "; partition-" << partition <<
1062 "; segment-" << segment <<
1063 "; " << ec.errorString(rc);
1064 delete[] pointerHdr;
1065 fileOp.closeFile( dbFile );
1066 throw WeException( oss.str(), rc );
1067 }
1068
1069 CompChunkPtrList chunkPtrs;
1070 rc = compressor.getPtrList(pointerHdr, ptrHdrSize, chunkPtrs );
1071 delete[] pointerHdr;
1072
1073 if (rc != 0)
1074 {
1075 std::ostringstream oss;
1076 oss << "Backup error getting " << fileType <<
1077 " file hdr for OID-" << columnOID <<
1078 "; DBRoot-" << dbRoot <<
1079 "; partition-" << partition <<
1080 "; segment-" << segment;
1081 fileOp.closeFile( dbFile );
1082 throw WeException( oss.str(), ERR_METADATABKUP_COMP_PARSE_HDRS );
1083 }
1084
1085 // Locate HWM chunk
1086 unsigned int chunkIndex = 0;
1087 unsigned int blockOffsetWithinChunk = 0;
1088 unsigned char* buffer = 0;
1089 uint64_t chunkSize = 0;
1090 compressor.locateBlock(startingHWM, chunkIndex, blockOffsetWithinChunk);
1091
1092 if (chunkIndex < chunkPtrs.size())
1093 {
1094 chunkSize = chunkPtrs[chunkIndex].second;
1095
1096 // Read the HWM chunk
1097 rc = fileOp.setFileOffset(dbFile, chunkPtrs[chunkIndex].first, SEEK_SET);
1098
1099 if (rc != NO_ERROR)
1100 {
1101 WErrorCodes ec;
1102 std::ostringstream oss;
1103 oss << "Backup error seeking in " << fileType <<
1104 " file for OID-" << columnOID <<
1105 "; DBRoot-" << dbRoot <<
1106 "; partition-" << partition <<
1107 "; segment-" << segment <<
1108 "; " << ec.errorString(rc);
1109 fileOp.closeFile( dbFile );
1110 throw WeException( oss.str(), rc );
1111 }
1112
1113 buffer = new unsigned char[ chunkPtrs[chunkIndex].second ];
1114 rc = fileOp.readFile( dbFile, buffer, chunkPtrs[chunkIndex].second );
1115
1116 if (rc != NO_ERROR)
1117 {
1118 WErrorCodes ec;
1119 std::ostringstream oss;
1120 oss << "Backup error reading in " << fileType <<
1121 " file for OID-" << columnOID <<
1122 "; DBRoot-" << dbRoot <<
1123 "; partition-" << partition <<
1124 "; segment-" << segment <<
1125 "; " << ec.errorString(rc);
1126 delete []buffer;
1127 fileOp.closeFile( dbFile );
1128 throw WeException( oss.str(), rc );
1129 }
1130 }
1131 else if (startingHWM == 0)
1132 {
1133 // Okay to proceed. Empty file with no chunks. Save 0 length chunk.
1134 }
1135 else
1136 {
1137 rc = ERR_METADATABKUP_COMP_CHUNK_NOT_FOUND;
1138
1139 WErrorCodes ec;
1140 std::ostringstream oss;
1141 oss << "Backup error for " << fileType <<
1142 " file for OID-" << columnOID <<
1143 "; DBRoot-" << dbRoot <<
1144 "; partition-" << partition <<
1145 "; segment-" << segment <<
1146 "; hwm-" << startingHWM <<
1147 "; chunkIdx-" << chunkIndex <<
1148 "; numPtrs-" << chunkPtrs.size() <<
1149 "; not in hdrPtrs" <<
1150 "; " << ec.errorString(rc);
1151 fileOp.closeFile( dbFile );
1152 throw WeException( oss.str(), rc );
1153 }
1154
1155 // Backup the HWM chunk
1156 std::string errMsg;
1157 rc = writeHWMChunk(bColumnFile, columnOID, dbRoot, partition, segment,
1158 buffer, chunkSize, fileSizeBytes, startingHWM, errMsg);
1159
1160 if (rc != NO_ERROR)
1161 {
1162 std::ostringstream oss;
1163 oss << "Backup error writing backup for " << fileType <<
1164 " OID-" << columnOID <<
1165 "; DBRoot-" << dbRoot <<
1166 "; partition-" << partition <<
1167 "; segment-" << segment <<
1168 "; " << errMsg;
1169 delete []buffer;
1170 fileOp.closeFile( dbFile );
1171 throw WeException( oss.str(), rc );
1172 }
1173
1174 // Close the applicable database column segment file and free memory
1175 delete []buffer;
1176 fileOp.closeFile( dbFile );
1177 }
1178
1179 //------------------------------------------------------------------------------
1180 // Writes out the specified HWM chunk to disk, in case we need it for bulk
1181 // rollback. If an error occurs, errMsg will contain the error message.
1182 // This function is careful not to create a corrupt file (should the system
1183 // crash in the middle of writing the file for example). It's imperative
1184 // that during a failure of any kind, that we not "accidentally" create and
1185 // leave around a corrupt or incomplete HWM backup file that could cause a
1186 // bulk rollback to fail, and eventually corrupt a data base file.
1187 // So this function first creates the HWM backup file to a temp file, and
1188 // after it is successfully created, it is it renamed to the final destination.
1189 // If anything goes wrong, we try to delete any files we were creating.
1190 //
1191 // This function MUST be kept thread-safe in support of backupDctnryHWMChunk().
1192 // See that function description for more details.
1193 //------------------------------------------------------------------------------
writeHWMChunk(bool bColumnFile,OID columnOID,uint16_t dbRoot,uint32_t partition,uint16_t segment,const unsigned char * compressedOutBuf,uint64_t chunkSize,uint64_t fileSize,HWM chunkHWM,std::string & errMsg) const1194 int RBMetaWriter::writeHWMChunk(
1195 bool bColumnFile, // is this a column (vs dictionary) file
1196 OID columnOID, // OID of column or dictionary store
1197 uint16_t dbRoot, // dbroot for db segment file
1198 uint32_t partition, // partition for db segment file
1199 uint16_t segment, // segment for db segment file
1200 const unsigned char* compressedOutBuf, // compressed chunk to be written
1201 uint64_t chunkSize, // number of bytes in compressedOutBuf
1202 uint64_t fileSize, // size of file in bytes
1203 HWM chunkHWM, // HWM in the chunk being written
1204 std::string& errMsg) const// error msg if error occurs
1205 {
1206 std::ostringstream ossFile;
1207 ossFile << "/" << columnOID << ".p" << partition << ".s" << segment;
1208 std::string fileName;
1209 std::string dirPath;
1210 int rc = getSubDirPath( dbRoot, fileName );
1211
1212 if (rc != NO_ERROR)
1213 {
1214 std::ostringstream oss;
1215 oss << "Error creating backup file for OID " << columnOID <<
1216 "; Can't find matching meta file for DBRoot" << dbRoot;
1217 errMsg = oss.str();
1218 return ERR_METADATABKUP_COMP_OPEN_BULK_BKUP;
1219 }
1220
1221 dirPath = fileName;
1222
1223 fileName += ossFile.str();
1224
1225 std::string fileNameTmp = fileName;
1226 fileNameTmp += TMP_FILE_SUFFIX;
1227
1228 //if ( (fLog) && (fLog->isDebug(DEBUG_1)) )
1229 if (fLog)
1230 {
1231 std::string fileType("column");
1232
1233 if (!bColumnFile)
1234 fileType = "dictionary";
1235
1236 std::ostringstream oss;
1237 oss << "Backing up HWM chunk for " << fileType <<
1238 " OID-" << columnOID <<
1239 "; file-" << fileNameTmp <<
1240 "; HWM-" << chunkHWM <<
1241 "; bytes-" << chunkSize <<
1242 "; fileSize-" << fileSize;
1243 fLog->logMsg( oss.str(), MSGLVL_INFO2 );
1244 }
1245
1246 IDBDataFile* backupFile = IDBDataFile::open(
1247 IDBPolicy::getType( fileNameTmp.c_str(), IDBPolicy::WRITEENG ),
1248 fileNameTmp.c_str(),
1249 "w+b",
1250 0 );
1251
1252 if (!backupFile)
1253 {
1254 int errRc = errno;
1255 WErrorCodes ec;
1256 std::ostringstream oss;
1257 std::string eMsg;
1258 Convertor::mapErrnoToString(errRc, eMsg);
1259 oss << ec.errorString(ERR_METADATABKUP_COMP_OPEN_BULK_BKUP) <<
1260 "; " << eMsg;
1261 errMsg = oss.str();
1262 return ERR_METADATABKUP_COMP_OPEN_BULK_BKUP;
1263 }
1264
1265 IDBFileSystem& fs = IDBPolicy::getFs( fileNameTmp.c_str() );
1266
1267 // Format of backup compressed chunk file:
1268 // 8 byte unsigned int carrying chunk size
1269 // 8 byte unsigned int carrying original file size
1270 // N bytes containing compressed chunk
1271 uint64_t sizeHdr[2];
1272 sizeHdr[0] = chunkSize;
1273 sizeHdr[1] = fileSize;
1274 size_t itemsWritten = backupFile->write(sizeHdr, sizeof(uint64_t) * 2) / (sizeof(uint64_t) * 2);
1275
1276 if (itemsWritten != 1)
1277 {
1278 int errRc = errno;
1279 WErrorCodes ec;
1280 std::ostringstream oss;
1281 std::string eMsg;
1282 Convertor::mapErrnoToString(errRc, eMsg);
1283 oss << ec.errorString(ERR_METADATABKUP_COMP_WRITE_BULK_BKUP) <<
1284 "; " << eMsg;
1285 errMsg = oss.str();
1286
1287 delete backupFile;
1288 fs.remove( fileNameTmp.c_str() );
1289 return ERR_METADATABKUP_COMP_WRITE_BULK_BKUP;
1290 }
1291
1292 if (chunkSize > 0)
1293 {
1294 itemsWritten = backupFile->write(compressedOutBuf, chunkSize ) / chunkSize;
1295
1296 if (itemsWritten != 1)
1297 {
1298 int errRc = errno;
1299 WErrorCodes ec;
1300 std::ostringstream oss;
1301 std::string eMsg;
1302 Convertor::mapErrnoToString(errRc, eMsg);
1303 oss << ec.errorString(ERR_METADATABKUP_COMP_WRITE_BULK_BKUP) <<
1304 "; " << eMsg;
1305 errMsg = oss.str();
1306
1307 delete backupFile;
1308 fs.remove( fileNameTmp.c_str() );
1309 return ERR_METADATABKUP_COMP_WRITE_BULK_BKUP;
1310 }
1311 }
1312
1313 backupFile->flush();
1314 // IDBDataFile flush() does a sync where appropriate
1315 delete backupFile;
1316
1317 #ifdef _MSC_VER
1318 //Windows rename() behaves differently from Linux: it will return an error
1319 // if the target exists
1320 //FIXME: The Linux version seems a bit safer, perhaps implement a better
1321 // Windows port?
1322 unlink(fileName.c_str());
1323 #endif
1324
1325 // Rename HWM backup file to final name.
1326 if ( fs.rename(fileNameTmp.c_str(), fileName.c_str()) )
1327 {
1328 int errRc = errno;
1329 WErrorCodes ec;
1330 std::ostringstream oss;
1331 std::string eMsg;
1332 Convertor::mapErrnoToString(errRc, eMsg);
1333 oss << ec.errorString(ERR_METADATABKUP_COMP_RENAME) << "; " << eMsg;
1334 errMsg = oss.str();
1335
1336 fs.remove( fileNameTmp.c_str() );
1337 fs.remove( fileName.c_str() );
1338 return ERR_METADATABKUP_COMP_RENAME;
1339 }
1340
1341 {
1342 std::ostringstream ossChown;
1343 idbdatafile::IDBFileSystem& fs = IDBPolicy::getFs(fileName.c_str());
1344 if (chownPath(ossChown, fileName, fs)
1345 || chownPath(ossChown, dirPath, fs))
1346 {
1347 throw WeException(ossChown.str(), ERR_FILE_CHOWN);
1348 }
1349 }
1350
1351 return NO_ERROR;
1352 }
1353 //------------------------------------------------------------------------------
1354 // Returns the directory path to be used for storing any backup data files.
1355 //
1356 // This function MUST be kept thread-safe in support of backupDctnryHWMChunk().
1357 // See that function description for more details.
1358 //------------------------------------------------------------------------------
getSubDirPath(uint16_t dbRoot,std::string & bulkRollbackSubPath) const1359 int RBMetaWriter::getSubDirPath( uint16_t dbRoot,
1360 std::string& bulkRollbackSubPath ) const
1361 {
1362 std::map<uint16_t, std::string>::const_iterator iter =
1363 fMetaFileNames.find( dbRoot );
1364
1365 if (iter == fMetaFileNames.end())
1366 {
1367 return ERR_INVALID_PARAM;
1368 }
1369
1370 bulkRollbackSubPath = iter->second;
1371 bulkRollbackSubPath += DATA_DIR_SUFFIX;
1372
1373 return NO_ERROR;
1374 }
1375
1376 //------------------------------------------------------------------------------
1377 // Prints list of compressed dictionary HWM chunks that we are tracking,
1378 // in order to backup to disk as needed, before we start adding rows to a
1379 // previously existing chunk.
1380 //------------------------------------------------------------------------------
printDctnryChunkList(const RBChunkInfo & rbChk,const char * assocAction)1381 void RBMetaWriter::printDctnryChunkList(
1382 const RBChunkInfo& rbChk,
1383 const char* assocAction)
1384 {
1385 if (fLog)
1386 {
1387 std::ostringstream oss;
1388 oss << "Dumping metaDictHWMChunks " << assocAction <<
1389 rbChk << ":";
1390
1391 if (fRBChunkDctnrySet.size() > 0)
1392 {
1393 RBChunkSet::iterator iter = fRBChunkDctnrySet.begin();
1394 int k = 1;
1395
1396 while (iter != fRBChunkDctnrySet.end())
1397 {
1398 oss << std::endl;
1399 oss << '\t' << k << ". " << *iter;
1400
1401 ++k;
1402 ++iter;
1403 }
1404 }
1405 else
1406 {
1407 oss << std::endl;
1408 oss << '\t' << "Empty list";
1409 }
1410
1411 fLog->logMsg( oss.str(), MSGLVL_INFO2 );
1412 }
1413 }
1414
1415 //------------------------------------------------------------------------------
1416 // Verify that specified string represents Version 3 file format
1417 //------------------------------------------------------------------------------
1418 /* static */
verifyVersion3(const char * versionRec)1419 bool RBMetaWriter::verifyVersion3(const char* versionRec)
1420 {
1421 if (strncmp(versionRec, VERSION3_REC, VERSION3_REC_LEN) == 0)
1422 return true;
1423 else
1424 return false;
1425 }
1426
1427 //------------------------------------------------------------------------------
1428 // Verify that specified string represents Version 4 file format
1429 //------------------------------------------------------------------------------
1430 /* static */
verifyVersion4(const char * versionRec)1431 bool RBMetaWriter::verifyVersion4(const char* versionRec)
1432 {
1433 if (strncmp(versionRec, VERSION4_REC, VERSION4_REC_LEN) == 0)
1434 return true;
1435 else
1436 return false;
1437 }
1438
1439 //------------------------------------------------------------------------------
1440 // Verify that specified record type is a Column1 record
1441 //------------------------------------------------------------------------------
1442 /* static */
verifyColumn1Rec(const char * recType)1443 bool RBMetaWriter::verifyColumn1Rec(const char* recType)
1444 {
1445 if (strncmp(recType, COLUMN1_REC, COLUMN1_REC_LEN) == 0)
1446 return true;
1447 else
1448 return false;
1449 }
1450
1451 //------------------------------------------------------------------------------
1452 // Verify that specified record type is a Column2 record
1453 //------------------------------------------------------------------------------
1454 /* static */
verifyColumn2Rec(const char * recType)1455 bool RBMetaWriter::verifyColumn2Rec(const char* recType)
1456 {
1457 if (strncmp(recType, COLUMN2_REC, COLUMN2_REC_LEN) == 0)
1458 return true;
1459 else
1460 return false;
1461 }
1462
1463 //------------------------------------------------------------------------------
1464 // Verify that specified record type is a DStore1 record
1465 //------------------------------------------------------------------------------
1466 /* static */
verifyDStore1Rec(const char * recType)1467 bool RBMetaWriter::verifyDStore1Rec(const char* recType)
1468 {
1469 if (strncmp(recType, DSTORE1_REC, DSTORE1_REC_LEN) == 0)
1470 return true;
1471 else
1472 return false;
1473 }
1474
1475 //------------------------------------------------------------------------------
1476 // Verify that specified record type is a DStore2 record
1477 //------------------------------------------------------------------------------
1478 /* static */
verifyDStore2Rec(const char * recType)1479 bool RBMetaWriter::verifyDStore2Rec(const char* recType)
1480 {
1481 if (strncmp(recType, DSTORE2_REC, DSTORE2_REC_LEN) == 0)
1482 return true;
1483 else
1484 return false;
1485 }
1486
1487 } // end of namespace
1488