/* * after shared storage operation complete, update persistent table. */ void PostPerformSharedStorageOpTasks(SharedStorageOpTasks *tasks) { int i; Relation gp_relation_node; Assert(NULL != tasks); if (tasks->numTasks == 0) return; gp_relation_node = heap_open(GpRelfileNodeRelationId, RowExclusiveLock); for (i = 0; i < tasks->numTasks; ++i) { SharedStorageOpTask * task = &tasks->tasks[i]; InsertGpRelfileNodeTuple(gp_relation_node, /* relationId */0, task->relname, task->node.relNode, task->segno, /* updateIndex */true, &task->persistentTid, task->persistentSerialNum); } heap_close(gp_relation_node, RowExclusiveLock); }
static void PersistentBuild_ScanGpPersistentRelationNodeForGlobal( Relation gp_relation_node, int64 *count) { PersistentFileSysObjData *fileSysObjData; PersistentFileSysObjSharedData *fileSysObjSharedData; PersistentStoreScan storeScan; Datum values[Natts_gp_persistent_relfile_node]; ItemPointerData persistentTid; int64 persistentSerialNum; PersistentFileSysObj_GetDataPtrs( PersistentFsObjType_RelationFile, &fileSysObjData, &fileSysObjSharedData); PersistentStore_BeginScan( &fileSysObjData->storeData, &fileSysObjSharedData->storeSharedData, &storeScan); while (PersistentStore_GetNext( &storeScan, values, &persistentTid, &persistentSerialNum)) { RelFileNode relFileNode; int32 segmentFileNum; PersistentFileSysRelStorageMgr relationStorageManager; PersistentFileSysState persistentState; PersistentFileSysRelBufpoolKind relBufpoolKind; TransactionId parentXid; int64 serialNum; ItemPointerData previousFreeTid; PersistentFileSysObjName fsObjName; bool sharedStorage; GpPersistentRelfileNode_GetValues( values, &relFileNode.spcNode, &relFileNode.dbNode, &relFileNode.relNode, &segmentFileNum, &relationStorageManager, &persistentState, &relBufpoolKind, &parentXid, &serialNum, &previousFreeTid, &sharedStorage); if (persistentState == PersistentFileSysState_Free) continue; PersistentFileSysObjName_SetRelationFile( &fsObjName, &relFileNode, segmentFileNum, NULL); fsObjName.hasInited = true; fsObjName.sharedStorage = sharedStorage; if (relFileNode.spcNode != GLOBALTABLESPACE_OID) continue; if (relationStorageManager != PersistentFileSysRelStorageMgr_BufferPool) elog(ERROR, "Only expecting global tables to be Buffer Pool managed"); InsertGpRelfileNodeTuple( gp_relation_node, relFileNode.relNode, // pg_class OID /* relationName */ NULL, // Optional. relFileNode.relNode, // pg_class relfilenode /* segmentFileNum */ 0, /* updateIndex */ false, &persistentTid, persistentSerialNum); (*count)++; } PersistentStore_EndScan(&storeScan); }
static void PersistentBuild_PopulateGpRelationNode( DatabaseInfo *info, Oid defaultTablespace, int64 *count) { Relation gp_relfile_node; int r; RelFileNode indexRelFileNode; bool indexFound; Relation gp_relfile_node_index; struct IndexInfo *indexInfo; if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "PersistentBuild_PopulateGpRelationNode: Enter for dbOid %u", info->database); MemSet(&indexRelFileNode, 0, sizeof(RelFileNode)); indexFound = false; gp_relfile_node = DirectOpen_GpRelfileNodeOpen( defaultTablespace, info->database); for (r = 0; r < info->dbInfoRelArrayCount; r++) { DbInfoRel *dbInfoRel = &info->dbInfoRelArray[r]; RelFileNode relFileNode; PersistentFileSysRelStorageMgr relStorageMgr; ItemPointerData persistentTid; int64 persistentSerialNum; if (dbInfoRel->reltablespace == GLOBALTABLESPACE_OID && info->database != TemplateDbOid) continue; relFileNode.spcNode = dbInfoRel->reltablespace; relFileNode.dbNode = (dbInfoRel->reltablespace == GLOBALTABLESPACE_OID ? 0 : info->database); relFileNode.relNode = dbInfoRel->relfilenodeOid; if (dbInfoRel->relationOid == GpRelfileNodeOidIndexId) { indexRelFileNode = relFileNode; indexFound = true; } relStorageMgr = ( (dbInfoRel->relstorage == RELSTORAGE_AOROWS || dbInfoRel->relstorage == RELSTORAGE_PARQUET) ? PersistentFileSysRelStorageMgr_AppendOnly : PersistentFileSysRelStorageMgr_BufferPool); /* * The gp_relation_node mapping table is empty, so use the physical files as * the guide. */ if (relStorageMgr == PersistentFileSysRelStorageMgr_BufferPool) { PersistentFileSysRelStorageMgr localRelStorageMgr; PersistentFileSysRelBufpoolKind relBufpoolKind; GpPersistentRelfileNode_GetRelfileInfo( dbInfoRel->relkind, dbInfoRel->relstorage, dbInfoRel->relam, &localRelStorageMgr, &relBufpoolKind); Assert(localRelStorageMgr == PersistentFileSysRelStorageMgr_BufferPool); /* * Heap tables only ever add a single segment_file_num=0 entry to * gp_persistent_relation regardless of how many segment files there * really are. */ PersistentRelfile_AddCreated( &relFileNode, /* segmentFileNum */ 0, relStorageMgr, relBufpoolKind, dbInfoRel->relname, &persistentTid, &persistentSerialNum, /* flushToXLog */ false); InsertGpRelfileNodeTuple( gp_relfile_node, dbInfoRel->relationOid, // pg_class OID dbInfoRel->relname, relFileNode.relNode, // pg_class relfilenode /* segmentFileNum */ 0, /* updateIndex */ false, &persistentTid, persistentSerialNum); } else { int a; int p; /* * Append-Only. */ /*if (dbInfoRel->physicalSegmentFilesCount == 0 || dbInfoRel->physicalSegmentFiles[0].segmentFileNum != 0) { elog(ERROR, "Physical segment file #0 missing for relation '%s'", dbInfoRel->relname); }*/ /* * Merge physical file existence and ao[cs]seg catalog logical EOFs . */ a = 0; for (p = 0; p < dbInfoRel->physicalSegmentFilesCount; p++) { int physicalSegmentFileNum = dbInfoRel->physicalSegmentFiles[p].segmentFileNum; bool haveCatalogInfo; int64 logicalEof; /* * There is mostly a 1:1 matching of physical files and logical * files and we just have to match them up correctly. However * there are several cases where this can diverge that we have * to be able to handle. * * 1) Segment file 0 always exists as a physical file, but is * only cataloged when it actually contains data - this only * occurs for ao when data is inserted in utility mode. * * 2) Files created in aborted transactions where an initial * frozen tuple never made it to disk may have a physical file * with no logical file. * XXX - These are leaked files that should probably be * cleaned up at some point. * * 3) It is possible to have files that logically exist with a * logical EOF of 0 but not exist in the filesystem. * XXX - how does this happen, is it really safe? */ logicalEof = 0; haveCatalogInfo = false; /* If we exhaust the loop then we are in case 2 */ while (a < dbInfoRel->appendOnlyCatalogSegmentInfoCount) { DbInfoAppendOnlyCatalogSegmentInfo *logicalSegInfo = \ &dbInfoRel->appendOnlyCatalogSegmentInfo[a]; /* Normal Case: both exist */ if (logicalSegInfo->segmentFileNum == physicalSegmentFileNum) { logicalEof = logicalSegInfo->logicalEof; haveCatalogInfo = true; a++; break; /* found */ } /* case 0 or case 2 */ else if (logicalSegInfo->segmentFileNum > physicalSegmentFileNum) { logicalEof = 0; haveCatalogInfo = false; break; /* not found */ } /* case 3 - skip over logical segments w/o physical files */ else if (logicalSegInfo->logicalEof == 0) { a++; continue; /* keep looking */ } /* otherwise it is an error */ else { elog(ERROR, "logical EOF greater than zero (" INT64_FORMAT ") for segment file #%d in relation '%s' but physical file is missing", logicalSegInfo->logicalEof, logicalSegInfo->segmentFileNum, dbInfoRel->relname); } /* unreachable */ Assert(false); } /* * case 2) Ignore segment file left over from pre-Release 4.0 aborted * transaction whose initial frozen ao[cs]seg tuple never made it to * disk. This will be a file that can result in an upgrade complaint... */ if (physicalSegmentFileNum > 0 && !haveCatalogInfo) continue; PersistentRelfile_AddCreated( &relFileNode, physicalSegmentFileNum, relStorageMgr, PersistentFileSysRelBufpoolKind_None, dbInfoRel->relname, &persistentTid, &persistentSerialNum, /* flushToXLog */ false); InsertGpRelfileNodeTuple( gp_relfile_node, dbInfoRel->relationOid, // pg_class OID dbInfoRel->relname, relFileNode.relNode, // pg_class relfilenode physicalSegmentFileNum, /* updateIndex */ false, &persistentTid, persistentSerialNum); } } (*count)++; } if (info->database != TemplateDbOid) { PersistentBuild_ScanGpPersistentRelationNodeForGlobal( gp_relfile_node, count); } /* * Build the index for gp_relation_node. * * The problem is the session we are using is associated with one particular database * of the cluster, but we need to iterate through all the databases. So, unfortunately, * the solution has been to use the "Direct Open" stuff. * * We do this because MyDatabaseId, the default tablespace of the session should not be * changed. The various caches and many other implicit things assume the object is for * MyDatabaseId and the default tablespace. For example, we cannot use * CatalogUpdateIndexes called in InsertGpRelationNodeTuple because it will not do * the right thing. * * Also, if they re-indexed gp_relation_node, it will have a different relfilenode and so we * must have found it (above) and open it with dynamically. */ Assert(indexFound); PersistentBuild_NonTransactionTruncate( &indexRelFileNode); gp_relfile_node_index = DirectOpen_GpRelfileNodeIndexOpenDynamic( GpRelfileNodeOidIndexId, indexRelFileNode.spcNode, indexRelFileNode.dbNode, indexRelFileNode.relNode); indexInfo = makeNode(IndexInfo); indexInfo->ii_NumIndexAttrs = Natts_gp_relfile_node_index; indexInfo->ii_KeyAttrNumbers[0] = 1; indexInfo->ii_KeyAttrNumbers[1] = 2; indexInfo->ii_KeyAttrNumbers[2] = 6; indexInfo->ii_Unique = true; if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "PersistentBuild_PopulateGpRelationNode: building gp_relfile_node_index %u/%u/%u for gp_relfile_node %u/%u/%u", gp_relfile_node_index->rd_node.spcNode, gp_relfile_node_index->rd_node.dbNode, gp_relfile_node_index->rd_node.relNode, gp_relfile_node->rd_node.spcNode, gp_relfile_node->rd_node.dbNode, gp_relfile_node->rd_node.relNode); index_build( gp_relfile_node, gp_relfile_node_index, indexInfo, false); DirectOpen_GpRelfileNodeIndexClose(gp_relfile_node_index); DirectOpen_GpRelfileNodeClose(gp_relfile_node); if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "PersistentBuild_PopulateGpRelationNode: Exit for dbOid %u", info->database); }