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