void PersistentStore_Scan( PersistentStoreData *storeData, PersistentStoreSharedData *storeSharedData, PersistentStoreScanTupleCallback scanTupleCallback) { WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE; PersistentStoreScan storeScan; ItemPointerData persistentTid; int64 persistentSerialNum = 0; Datum *values; values = (Datum*)palloc(storeData->numAttributes * sizeof(Datum)); WRITE_PERSISTENT_STATE_ORDERED_LOCK; PersistentStore_BeginScan( storeData, storeSharedData, &storeScan); while (PersistentStore_GetNext( &storeScan, values, &persistentTid, &persistentSerialNum)) { bool okToContinue; okToContinue = (*scanTupleCallback)( &persistentTid, persistentSerialNum, values); if (!okToContinue) break; } PersistentStore_EndScan(&storeScan); WRITE_PERSISTENT_STATE_ORDERED_UNLOCK; pfree(values); }
static void PersistentStore_DoInitScan( PersistentStoreData *storeData, PersistentStoreSharedData *storeSharedData) { PersistentStoreScan storeScan; ItemPointerData persistentTid; int64 persistentSerialNum; ItemPointerData previousFreeTid; Datum *values; int64 globalSequenceNum; values = (Datum*)palloc(storeData->numAttributes * sizeof(Datum)); MemSet(&storeSharedData->maxTid, 0, sizeof(ItemPointerData)); PersistentStore_BeginScan( storeData, storeSharedData, &storeScan); while (PersistentStore_GetNext( &storeScan, values, &persistentTid, &persistentSerialNum)) { /* * We are scanning from low to high TID. */ Assert( PersistentStore_IsZeroTid(&storeSharedData->maxTid) || ItemPointerCompare( &storeSharedData->maxTid, &persistentTid) == -1); // Less-Than. storeSharedData->maxTid = persistentTid; PersistentStore_ExtractOurTupleData( storeData, values, &persistentSerialNum, &previousFreeTid); if (Debug_persistent_recovery_print) (*storeData->printTupleCallback)( PersistentRecovery_DebugPrintLevel(), "SCAN", &persistentTid, values); if (!PersistentStore_IsZeroTid(&previousFreeTid)) { /* * Non-zero previousFreeTid implies a free entry. */ if (storeSharedData->maxFreeOrderNum < persistentSerialNum) { storeSharedData->maxFreeOrderNum = persistentSerialNum; storeSharedData->freeTid = persistentTid; } if (!gp_persistent_skip_free_list) { PersistentStore_InitScanAddFreeEntry( &persistentTid, &previousFreeTid, /* freeOrderNum */ persistentSerialNum); } } else { storeSharedData->inUseCount++; if (storeSharedData->maxInUseSerialNum < persistentSerialNum) { storeSharedData->maxInUseSerialNum = persistentSerialNum; storeData->myHighestSerialNum = storeSharedData->maxInUseSerialNum; } } if (storeData->scanTupleCallback != NULL) (*storeData->scanTupleCallback)( &persistentTid, persistentSerialNum, values); } PersistentStore_EndScan(&storeScan); pfree(values); globalSequenceNum = GlobalSequence_Current(storeData->gpGlobalSequence); /* * Note: Originally the below IF STMT was guarded with a InRecovery flag check. * However, this routine should not be called during recovery since the entries are * not consistent... */ Assert(!InRecovery); if (globalSequenceNum < storeSharedData->maxInUseSerialNum) { /* * We seem to have a corruption problem. * * Use the gp_persistent_repair_global_sequence GUC to get the system up. */ if (gp_persistent_repair_global_sequence) { elog(LOG, "Need to Repair global sequence number " INT64_FORMAT " so use scanned maximum value " INT64_FORMAT " ('%s')", globalSequenceNum, storeSharedData->maxInUseSerialNum, storeData->tableName); } else { elog(ERROR, "Global sequence number " INT64_FORMAT " less than maximum value " INT64_FORMAT " found in scan ('%s')", globalSequenceNum, storeSharedData->maxInUseSerialNum, storeData->tableName); } } else { storeSharedData->maxCachedSerialNum = globalSequenceNum; } if (Debug_persistent_recovery_print) elog(PersistentRecovery_DebugPrintLevel(), "PersistentStore_DoInitScan ('%s'): maximum in-use serial number " INT64_FORMAT ", maximum free order number " INT64_FORMAT ", free TID %s, maximum known TID %s", storeData->tableName, storeSharedData->maxInUseSerialNum, storeSharedData->maxFreeOrderNum, ItemPointerToString(&storeSharedData->freeTid), ItemPointerToString2(&storeSharedData->maxTid)); if (!gp_persistent_skip_free_list) { PersistentStore_InitScanVerifyFreeEntries( storeData, storeSharedData); } else { if (Debug_persistent_recovery_print) elog(PersistentRecovery_DebugPrintLevel(), "PersistentStore_DoInitScan ('%s'): Skipping verification because gp_persistent_skip_free_list GUC is ON", storeData->tableName); } }
static void PersistentStore_DoInitScan( PersistentStoreData *storeData, PersistentStoreSharedData *storeSharedData) { PersistentStoreScan storeScan; ItemPointerData persistentTid; int64 persistentSerialNum; Datum *values; int64 globalSequenceNum; values = (Datum*)palloc(storeData->numAttributes * sizeof(Datum)); PersistentStore_BeginScan( storeData, storeSharedData, &storeScan); while (PersistentStore_GetNext( &storeScan, values, &persistentTid, &persistentSerialNum)) { /* * We are scanning from low to high TID. */ PersistentStore_ExtractOurTupleData( storeData, values, &persistentSerialNum); if (Debug_persistent_recovery_print) (*storeData->printTupleCallback)( PersistentRecovery_DebugPrintLevel(), "SCAN", &persistentTid, values); storeSharedData->inUseCount++; if (storeSharedData->maxInUseSerialNum < persistentSerialNum) { storeSharedData->maxInUseSerialNum = persistentSerialNum; storeData->myHighestSerialNum = storeSharedData->maxInUseSerialNum; } if (storeData->scanTupleCallback != NULL) (*storeData->scanTupleCallback)( &persistentTid, persistentSerialNum, values); } PersistentStore_EndScan(&storeScan); pfree(values); globalSequenceNum = GlobalSequence_Current(storeData->gpGlobalSequence); /* * Note: Originally the below IF STMT was guarded with a InRecovery flag check. * However, this routine should not be called during recovery since the entries are * not consistent... */ Assert(!InRecovery); if (globalSequenceNum < storeSharedData->maxInUseSerialNum) { /* * We seem to have a corruption problem. * * Use the gp_persistent_repair_global_sequence GUC to get the * system up. */ if (gp_persistent_repair_global_sequence) { elog(LOG, "need to repair global sequence number " INT64_FORMAT " so use scanned maximum value " INT64_FORMAT " ('%s')", globalSequenceNum, storeSharedData->maxInUseSerialNum, storeData->tableName); } else { elog(ERROR, "global sequence number " INT64_FORMAT " less than " "maximum value " INT64_FORMAT " found in scan ('%s')", globalSequenceNum, storeSharedData->maxInUseSerialNum, storeData->tableName); } } else { storeSharedData->maxInUseSerialNum = globalSequenceNum; } if (Debug_persistent_recovery_print) elog(PersistentRecovery_DebugPrintLevel(), "PersistentStore_DoInitScan ('%s'): maximum in-use serial number " INT64_FORMAT , storeData->tableName, storeSharedData->maxInUseSerialNum); }
/* * Rebuild free TID list based on freeEntryHashTable. Returns number * of free tuples in the rebuilt free list. */ uint64 PersistentStore_RebuildFreeList( PersistentStoreData *storeData, PersistentStoreSharedData *storeSharedData) { Datum *values; PersistentStoreScan storeScan; ItemPointerData persistentTid; ItemPointerData previousFreeTid; ItemPointerData previousTid; uint64 persistentSerialNum; uint64 freeOrderNum; values = (Datum*)palloc(storeData->numAttributes * sizeof(Datum)); /* * PT shared data must be already initialized, even when we are * called during recovery. */ Assert(!PersistentStore_IsZeroTid(&storeSharedData->maxTid)); if (storeSharedData->maxFreeOrderNum < 1) { elog(LOG, "no free tuples in %s, not building any free list", storeData->tableName); return 0; } elog(LOG, "rebuilding free list in %s with " INT64_FORMAT " free tuples", storeData->tableName, storeSharedData->maxFreeOrderNum); /* * Scan PT for free entries (in TID order) and establish links * with previous free entry as we go on. */ previousTid.ip_posid = 0; freeOrderNum = 0; PersistentStore_BeginScan(storeData, storeSharedData, &storeScan); while (PersistentStore_GetNext( &storeScan, values, &persistentTid, (int64 *)&persistentSerialNum)) { /* * We are scanning from low to high TID. All TIDs we * encounter should be smaller or equal to the known * maxTid. */ Assert(ItemPointerCompare( &storeSharedData->maxTid, &persistentTid) >= 0); PersistentStore_ExtractOurTupleData( storeData, values, (int64 *)&persistentSerialNum, &previousFreeTid); if (!PersistentStore_IsZeroTid(&previousFreeTid)) { values[storeData->attNumPersistentSerialNum - 1] = Int64GetDatum(++freeOrderNum); values[storeData->attNumPreviousFreeTid - 1] = ItemPointerIsValid(&previousTid) ? PointerGetDatum(&previousTid) : PointerGetDatum(&persistentTid); #ifdef FAULT_INJECTOR /* * Inject fault after free list is partially built - a few * tuples are updated but at least one is yet to be * updated. */ if (freeOrderNum > 3) { FaultInjector_InjectFaultIfSet( RebuildPTDB, DDLNotSpecified, "", // databaseName ""); // tableName } #endif PersistentStore_UpdateTuple( storeData, storeSharedData, &persistentTid, values, true); ItemPointerCopy(&persistentTid, &previousTid); } } PersistentStore_EndScan(&storeScan); pfree(values); if (ItemPointerIsValid(&previousTid)) { Assert(freeOrderNum > 0); ItemPointerCopy(&previousTid, &storeSharedData->freeTid); storeSharedData->maxFreeOrderNum = freeOrderNum; elog(LOG, "rebuilt free list in %s: maxFreeOrderNum = " INT64_FORMAT " freeTid = %s", storeData->tableName, freeOrderNum, ItemPointerToString(&persistentTid)); } return freeOrderNum; }
static void PersistentStore_DiagnoseDumpTable( PersistentStoreData *storeData, PersistentStoreSharedData *storeSharedData) { if (disable_persistent_diagnostic_dump) { return; } MIRROREDLOCK_BUFMGR_DECLARE; PersistentStoreScan storeScan; ItemPointerData persistentTid; int64 persistentSerialNum; Datum *values; BlockNumber lastDisplayedBlockNum; bool displayedOne; BlockNumber currentBlockNum; elog(LOG, "Diagnostic dump of persistent table ('%s'): maximum in-use serial number " INT64_FORMAT ", maximum free order number " INT64_FORMAT ", free TID %s, maximum known TID %s", storeData->tableName, storeSharedData->maxInUseSerialNum, storeSharedData->maxFreeOrderNum, ItemPointerToString(&storeSharedData->freeTid), ItemPointerToString2(&storeSharedData->maxTid)); values = (Datum*)palloc(storeData->numAttributes * sizeof(Datum)); PersistentStore_BeginScan( storeData, storeSharedData, &storeScan); lastDisplayedBlockNum = 0; displayedOne = false; while (PersistentStore_GetNext( &storeScan, values, &persistentTid, &persistentSerialNum)) { /* * Use the BlockIdGetBlockNumber routine because ItemPointerGetBlockNumber * asserts for valid TID. */ currentBlockNum = BlockIdGetBlockNumber(&persistentTid.ip_blkid); if (!displayedOne || currentBlockNum != lastDisplayedBlockNum) { Buffer buffer; PageHeader page; XLogRecPtr lsn; /* * Fetch the block and display the LSN. */ // -------- MirroredLock ---------- MIRROREDLOCK_BUFMGR_LOCK; buffer = ReadBuffer( storeScan.persistentRel, currentBlockNum); page = (PageHeader) BufferGetPage(buffer); lsn = PageGetLSN(page); ReleaseBuffer(buffer); MIRROREDLOCK_BUFMGR_UNLOCK; // -------- MirroredLock ---------- elog(LOG, "Diagnostic LSN %s of page %u", XLogLocationToString(&lsn), currentBlockNum); lastDisplayedBlockNum = currentBlockNum; displayedOne = true; } /* * Display the persistent tuple. */ (*storeData->printTupleCallback)( LOG, "DIAGNOSE", &persistentTid, values); } PersistentStore_EndScan(&storeScan); pfree(values); }
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); }