static bool PersistentStore_GetFreeTuple( PersistentStoreData *storeData, PersistentStoreSharedData *storeSharedData, ItemPointer freeTid) { ItemPointerData previousFreeTid; MemSet(freeTid, 0, sizeof(ItemPointerData)); if (Debug_persistent_store_print) elog(PersistentStore_DebugPrintLevel(), "PersistentStore_GetFreeTuple: Enter: maximum free order number " INT64_FORMAT ", free TID %s ('%s')", storeSharedData->maxFreeOrderNum, ItemPointerToString(&storeSharedData->freeTid), storeData->tableName); if (storeSharedData->maxFreeOrderNum == 0) { return false; /* No free tuples. */ } if (gp_persistent_skip_free_list) { if (Debug_persistent_store_print) elog(PersistentStore_DebugPrintLevel(), "PersistentStore_GetFreeTuple: Skipping because gp_persistent_skip_free_list GUC is ON ('%s')", storeData->tableName); return false; /* Pretend no free tuples. */ } Assert(storeSharedData->freeTid.ip_posid != 0); if (!PersistentStore_ValidateFreeTID( storeData, storeSharedData, &previousFreeTid)) return false; *freeTid = storeSharedData->freeTid; storeSharedData->maxFreeOrderNum--; ItemPointerCopy(&previousFreeTid /* previousFreeTid set inside the ValidateFreeTID function */, &storeSharedData->freeTid); if (Debug_persistent_store_print) elog(PersistentStore_DebugPrintLevel(), "PersistentStore_GetFreeTuple: Exit: maximum free order number " INT64_FORMAT ", free TID %s ('%s')", storeSharedData->maxFreeOrderNum, ItemPointerToString(&storeSharedData->freeTid), storeData->tableName); if (validate_previous_free_tid && !PersistentStore_ValidateFreeTID( storeData, storeSharedData, &previousFreeTid)) return false; return true; }
void PersistentEndXactRec_Print( char *procName, PersistentEndXactRecObjects *objects) { int i; elog(Persistent_DebugPrintLevel(), "%s: file-system action count %d, Append-Only mirror resync EOFs count %d", procName, objects->typed.fileSysActionInfosCount, objects->typed.appendOnlyMirrorResyncEofsCount); for (i = 0; i < objects->typed.fileSysActionInfosCount; i++) { PersistentEndXactFileSysActionInfo *fileSysActionInfos = &objects->typed.fileSysActionInfos[i]; elog(Persistent_DebugPrintLevel(), "%s: [%d] action '%s' %s, relation storage manager '%s', persistent serial num " INT64_FORMAT ", TID %s", procName, i, PersistentEndXactFileSysAction_Name(fileSysActionInfos->action), PersistentFileSysObjName_TypeAndObjectName(&fileSysActionInfos->fsObjName), PersistentFileSysRelStorageMgr_Name(fileSysActionInfos->relStorageMgr), fileSysActionInfos->persistentSerialNum, ItemPointerToString(&fileSysActionInfos->persistentTid)); } for (i = 0; i < objects->typed.appendOnlyMirrorResyncEofsCount; i++) { PersistentEndXactAppendOnlyMirrorResyncEofs *eofs = &objects->typed.appendOnlyMirrorResyncEofs[i]; elog(Persistent_DebugPrintLevel(), "%s: [%d] Append-Only Mirror Resync EOFs %u/%u/%u, segment file #%d -- persistent serial num " INT64_FORMAT ", TID %s, mirror loss EOF " INT64_FORMAT ", mirror new EOF " INT64_FORMAT, procName, i, eofs->relFileNode.spcNode, eofs->relFileNode.dbNode, eofs->relFileNode.relNode, eofs->segmentFileNum, eofs->persistentSerialNum, ItemPointerToString(&eofs->persistentTid), eofs->mirrorLossEof, eofs->mirrorNewEof); } }
static void AppendOnlyMirrorResyncEofs_Remove(char *procName, AppendOnlyMirrorResyncEofs *entry) { Assert(AppendOnlyMirrorResyncEofsTable != NULL); if (Debug_persistent_print || Debug_persistent_appendonly_commit_count_print) elog(Persistent_DebugPrintLevel(), "Storage Manager (%s): Remove Append-Only mirror resync eofs entry: " "%u/%u/%u, segment file #%d, relation name '%s' (transaction nest level %d, persistent TID %s, persistent serial number " INT64_FORMAT ", mirror catchup required %s, saved mirror new EOF " INT64_FORMAT ")", procName, entry->key.relFileNode.spcNode, entry->key.relFileNode.dbNode, entry->key.relFileNode.relNode, entry->key.segmentFileNum, (entry->relationName == NULL ? "<null>" : entry->relationName), entry->key.nestLevel, ItemPointerToString(&entry->persistentTid), entry->persistentSerialNum, (entry->mirrorCatchupRequired ? "true" : "false"), entry->mirrorNewEof); if (entry->relationName != NULL) pfree(entry->relationName); hash_search(AppendOnlyMirrorResyncEofsTable, (void *) &entry->key, HASH_REMOVE, NULL); }
/* * DatabaseInfo_Trace() * Output debugging information about the DatabaseInfo */ void DatabaseInfo_Trace(DatabaseInfo *info) { int t; int sr; int rsf; int grn; int m; for (t = 0; t < info->tablespacesCount; t++) elog(WARNING, "Database Info: Tablespace #%d is %u", t, info->tablespaces[t]); for (sr = 0; sr < info->pgClassStoredRelationsCount; sr++) elog(WARNING, "Database Info: Stored relation (tablespace %u, relation %u, isBufferPoolRealtion %s, TID %s)", info->pgClassStoredRelations[sr].tablespaceRelFile.tablespace, info->pgClassStoredRelations[sr].tablespaceRelFile.relation, (info->pgClassStoredRelations[sr].isBufferPoolRelation ? "true" : "false"), ItemPointerToString(&info->pgClassStoredRelations[sr].pgClassTid)); for (rsf = 0; rsf < info->relSegFilesCount; rsf++) elog(WARNING, "Database Info: Relation segment file (tablespace %u, relation %u, segment file num %d)", info->relSegFiles[rsf].tablespaceRelFile.tablespace, info->relSegFiles[rsf].tablespaceRelFile.relation, info->relSegFiles[rsf].segmentFileNum); for (grn = 0; grn < info->gpRelationNodesCount; grn++) elog(WARNING, "Database Info: Tablespace %u, relation %u node information (persistent TID %s, perstent serial number " INT64_FORMAT ")", info->gpRelationNodes[grn].tablespaceRelFile.tablespace, info->gpRelationNodes[grn].tablespaceRelFile.relation, ItemPointerToString(&info->gpRelationNodes[grn].persistentTid), info->gpRelationNodes[grn].persistentSerialNum); for (m = 0; m < info->miscEntriesCount; m++) elog(WARNING, "Database Info: Misc entry #%d (tablespace %u, directory = %s, name '%s')", m, info->miscEntries[m].tablespace, (info->miscEntries[m].isDir ? "true" : "false"), info->miscEntries[m].name); }
void PersistentTablespace_Reset(void) { WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE; HASH_SEQ_STATUS stat; TablespaceDirEntry tablespaceDirEntry; hash_seq_init(&stat, persistentTablespaceSharedHashTable); WRITE_PERSISTENT_STATE_ORDERED_LOCK; WRITE_TABLESPACE_HASH_LOCK; while (true) { TablespaceDirEntry removeTablespaceDirEntry; PersistentFileSysObjName fsObjName; tablespaceDirEntry = hash_seq_search(&stat); if (tablespaceDirEntry == NULL) break; PersistentFileSysObjName_SetTablespaceDir( &fsObjName, tablespaceDirEntry->key.tablespaceOid); if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "Persistent tablespace directory: Resetting '%s' serial number " INT64_FORMAT " at TID %s", PersistentFileSysObjName_ObjectName(&fsObjName), tablespaceDirEntry->persistentSerialNum, ItemPointerToString(&tablespaceDirEntry->persistentTid)); removeTablespaceDirEntry = (TablespaceDirEntry) hash_search(persistentTablespaceSharedHashTable, (void *) &tablespaceDirEntry->key, HASH_REMOVE, NULL); if (removeTablespaceDirEntry == NULL) elog(ERROR, "Trying to delete entry that does not exist"); } WRITE_TABLESPACE_HASH_UNLOCK; WRITE_PERSISTENT_STATE_ORDERED_UNLOCK; }
static void PersistentStore_InsertTuple( PersistentStoreData *storeData, PersistentStoreSharedData *storeSharedData, Datum *values, bool flushToXLog, /* When true, the XLOG record for this change will be flushed to disk. */ ItemPointer persistentTid) /* TID of the stored tuple. */ { Relation persistentRel; #ifdef USE_ASSERT_CHECKING if (storeSharedData == NULL || !PersistentStoreSharedData_EyecatcherIsValid(storeSharedData)) elog(ERROR, "Persistent store shared-memory not valid"); #endif if (Debug_persistent_store_print) elog(PersistentStore_DebugPrintLevel(), "PersistentStore_InsertTuple: Going to insert new tuple ('%s', shared data %p)", storeData->tableName, storeSharedData); persistentRel = (*storeData->openRel)(); PersistentStore_DoInsertTuple( storeData, storeSharedData, persistentRel, values, flushToXLog, persistentTid); (*storeData->closeRel)(persistentRel); if (Debug_persistent_store_print) { elog(PersistentStore_DebugPrintLevel(), "PersistentStore_InsertTuple: Inserted new tuple at TID %s ('%s')", ItemPointerToString(persistentTid), storeData->tableName); (*storeData->printTupleCallback)( PersistentStore_DebugPrintLevel(), "STORE INSERT TUPLE", persistentTid, values); } }
void MirroredBufferPool_BeginBulkLoad( RelFileNode *relFileNode, /* The tablespace, database, and relation OIDs for the relation. */ ItemPointer persistentTid, int64 persistentSerialNum, MirroredBufferPoolBulkLoadInfo *bulkLoadInfo) { MIRROREDLOCK_BUFMGR_DECLARE; MemSet(bulkLoadInfo, 0, sizeof(MirroredBufferPoolBulkLoadInfo)); // -------- MirroredLock ---------- MIRROREDLOCK_BUFMGR_LOCK; /* * Make this call while under the MirroredLock (unless we are a resync worker). */ bulkLoadInfo->mirrorDataLossTrackingState = FileRepPrimary_GetMirrorDataLossTrackingSessionNum( &bulkLoadInfo->mirrorDataLossTrackingSessionNum); MIRROREDLOCK_BUFMGR_UNLOCK; // -------- MirroredLock ---------- bulkLoadInfo->relFileNode = *relFileNode; bulkLoadInfo->persistentTid = *persistentTid; bulkLoadInfo->persistentSerialNum = persistentSerialNum; if (Debug_persistent_print) { SUPPRESS_ERRCONTEXT_DECLARE; SUPPRESS_ERRCONTEXT_PUSH(); elog(Persistent_DebugPrintLevel(), "MirroredBufferPool_BeginBulkLoad %u/%u/%u: mirror data loss tracking (state '%s', session num " INT64_FORMAT "), persistent serial num " INT64_FORMAT ", TID %s", relFileNode->spcNode, relFileNode->dbNode, relFileNode->relNode, MirrorDataLossTrackingState_Name(bulkLoadInfo->mirrorDataLossTrackingState), bulkLoadInfo->mirrorDataLossTrackingSessionNum, persistentSerialNum, ItemPointerToString(persistentTid)); SUPPRESS_ERRCONTEXT_POP(); } }
void PersistentRelation_Reset(void) { HASH_SEQ_STATUS stat; RelationDirEntry relationDirEntry; hash_seq_init(&stat, persistentRelationSharedHashTable); while (true) { RelationDirEntry removeRelationDirEntry; PersistentFileSysObjName fsObjName; RelFileNode relFileNode; relationDirEntry = hash_seq_search(&stat); if (relationDirEntry == NULL) { break; } relFileNode.spcNode = relationDirEntry->key.tablespaceOid; relFileNode.dbNode = relationDirEntry->key.databaseOid; relFileNode.relNode = relationDirEntry->key.relfilenodeOid; PersistentFileSysObjName_SetRelationDir( &fsObjName, &relFileNode, is_tablespace_shared); if (Debug_persistent_print) { elog(Persistent_DebugPrintLevel(), "Persistent relation directory: Resetting '%s' serial number " INT64_FORMAT " at TID %s", PersistentFileSysObjName_ObjectName(&fsObjName), relationDirEntry->persistentSerialNum, ItemPointerToString(&relationDirEntry->persistentTid)); } removeRelationDirEntry = (RelationDirEntry) hash_search(persistentRelationSharedHashTable, (void *) &relationDirEntry->key, HASH_REMOVE, NULL); if (removeRelationDirEntry == NULL) { elog(ERROR, "Trying to delete entry that does not exist"); } } }
void PersistentStore_FreeTuple( PersistentStoreData *storeData, PersistentStoreSharedData *storeSharedData, ItemPointer persistentTid, /* TID of the stored tuple. */ Datum *freeValues, bool flushToXLog) /* When true, the XLOG record for this change will be flushed to disk. */ { Relation persistentRel; XLogRecPtr xlogEndLoc; /* The end location of the UPDATE XLOG record. */ Assert( LWLockHeldByMe(PersistentObjLock) ); #ifdef USE_ASSERT_CHECKING if (storeSharedData == NULL || !PersistentStoreSharedData_EyecatcherIsValid(storeSharedData)) elog(ERROR, "Persistent store shared-memory not valid"); #endif if (Debug_persistent_store_print) elog(PersistentStore_DebugPrintLevel(), "PersistentStore_FreeTuple: Going to free tuple at TID %s ('%s', shared data %p)", ItemPointerToString(persistentTid), storeData->tableName, storeSharedData); Assert(ItemPointerIsValid(persistentTid)); persistentRel = (*storeData->openRel)(); simple_heap_delete_xid(persistentRel, persistentTid, FrozenTransactionId); /* * XLOG location of the UPDATE tuple's XLOG record. */ xlogEndLoc = XLogLastInsertEndLoc(); (*storeData->closeRel)(persistentRel); storeSharedData->inUseCount--; if (flushToXLog) { XLogFlush(xlogEndLoc); XLogRecPtr_Zero(&nowaitXLogEndLoc); } else nowaitXLogEndLoc = xlogEndLoc; }
extern void PersistentDatabase_Reset(void) { DatabaseDirEntry databaseDirEntry; databaseDirEntry = NULL; SharedOidSearch_Iterate( &persistentDatabaseSharedData->databaseDirSearchTable, (SharedOidSearchObjHeader**)&databaseDirEntry); while (true) { PersistentFileSysObjName fsObjName; DatabaseDirEntry nextDatabaseDirEntry; if (databaseDirEntry == NULL) { break; } PersistentFileSysObjName_SetDatabaseDir( &fsObjName, /* tablespaceOid */ databaseDirEntry->header.oid2, /* databaseOid */ databaseDirEntry->header.oid1, NULL); if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "Persistent database directory: Resetting '%s' serial number " INT64_FORMAT " at TID %s", PersistentFileSysObjName_ObjectName(&fsObjName), databaseDirEntry->persistentSerialNum, ItemPointerToString(&databaseDirEntry->persistentTid)); nextDatabaseDirEntry = databaseDirEntry; SharedOidSearch_Iterate( &persistentDatabaseSharedData->databaseDirSearchTable, (SharedOidSearchObjHeader**)&nextDatabaseDirEntry); SharedOidSearch_Delete( &persistentDatabaseSharedData->databaseDirSearchTable, &databaseDirEntry->header); databaseDirEntry = nextDatabaseDirEntry; } }
static void PersistentStore_InitScanAddFreeEntry( PersistentStoreData *storeData, PersistentStoreSharedData *storeSharedData, ItemPointer persistentTid, ItemPointer previousFreeTid, int64 freeOrderNum) { PersistentFreeEntryKey key; PersistentFreeEntry *entry; bool found; if (PersistentStore_IsZeroTid(persistentTid)) { PersistentStore_DiagnoseDumpTable(storeData, storeSharedData); elog(ERROR, "Expected persistent TID to not be (0,0)"); } if (PersistentStore_IsZeroTid(previousFreeTid)) { elog(ERROR, "Expected previous free TID to not be (0,0)"); } if (freeEntryHashTable == NULL) PersistentStore_FreeEntryHashTableInit(); MemSet(&key, 0, sizeof(key)); key.persistentTid = *persistentTid; entry = (PersistentFreeEntry*) hash_search(freeEntryHashTable, (void *) &key, HASH_ENTER, &found); if (found) { PersistentStore_DiagnoseDumpTable(storeData, storeSharedData); elog(ERROR, "Duplicate free persistent TID entry %s", ItemPointerToString(persistentTid)); } entry->previousFreeTid = *previousFreeTid; entry->freeOrderNum = freeOrderNum; }
void PersistentFilespace_Reset(void) { HASH_SEQ_STATUS stat; FilespaceDirEntry filespaceDirEntry; hash_seq_init(&stat, persistentFilespaceSharedHashTable); while (true) { FilespaceDirEntry removeFilespaceDirEntry; PersistentFileSysObjName fsObjName; filespaceDirEntry = hash_seq_search(&stat); if (filespaceDirEntry == NULL) break; PersistentFileSysObjName_SetFilespaceDir( &fsObjName, filespaceDirEntry->key.filespaceOid, is_filespace_shared); if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "Persistent filespace directory: Resetting '%s' serial number " INT64_FORMAT " at TID %s", PersistentFileSysObjName_ObjectName(&fsObjName), filespaceDirEntry->persistentSerialNum, ItemPointerToString(&filespaceDirEntry->persistentTid)); removeFilespaceDirEntry = (FilespaceDirEntry) hash_search(persistentFilespaceSharedHashTable, (void *) &filespaceDirEntry->key, HASH_REMOVE, NULL); if (removeFilespaceDirEntry == NULL) elog(ERROR, "Trying to delete entry that does not exist"); } }
static void GlobalSequence_ReadTuple( GpGlobalSequence gpGlobalSequence, int64 *currentSequenceNum) { Relation gpGlobalSequenceRel; bool nulls[Anum_gp_global_sequence_sequence_num]; Datum values[Anum_gp_global_sequence_sequence_num]; HeapTupleData globalSequenceTuple; Buffer buffer; gpGlobalSequenceRel = DirectOpen_GpGlobalSequenceOpenShared(); GlobalSequence_MakeTid( gpGlobalSequence, &globalSequenceTuple.t_self); if (!heap_fetch(gpGlobalSequenceRel, SnapshotAny, &globalSequenceTuple, &buffer, false, NULL)) elog(ERROR, "Failed to fetch global sequence tuple at %s", ItemPointerToString(&globalSequenceTuple.t_self)); heap_deform_tuple( &globalSequenceTuple, gpGlobalSequenceRel->rd_att, values, nulls); GpGlobalSequence_GetValues( values, currentSequenceNum); ReleaseBuffer(buffer); DirectOpen_GpGlobalSequenceClose(gpGlobalSequenceRel); }
/* * Indicate we intend to create a tablespace file as part of the current transaction. * * An XLOG IntentToCreate record is generated that will guard the subsequent file-system * create in case the transaction aborts. * * After 1 or more calls to this routine to mark intention about tablespace files that are going * to be created, call ~_DoPendingCreates to do the actual file-system creates. (See its * note on XLOG flushing). */ void PersistentTablespace_MarkCreatePending( Oid filespaceOid, /* The filespace where the tablespace lives. */ Oid tablespaceOid, /* The tablespace OID for the create. */ MirroredObjectExistenceState mirrorExistenceState, ItemPointer persistentTid, /* TID of the gp_persistent_rel_files tuple for the rel file */ int64 *persistentSerialNum, bool flushToXLog) /* When true, the XLOG record for this change will be flushed to disk. */ { WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE; PersistentFileSysObjName fsObjName; TablespaceDirEntry tablespaceDirEntry; TransactionId topXid; if (Persistent_BeforePersistenceWork()) { if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "Skipping persistent tablespace %u because we are before persistence work", tablespaceOid); return; /* * The initdb process will load the persistent table once we out of * bootstrap mode. */ } PersistentTablespace_VerifyInitScan(); PersistentFileSysObjName_SetTablespaceDir(&fsObjName, tablespaceOid); topXid = GetTopTransactionId(); WRITE_PERSISTENT_STATE_ORDERED_LOCK; PersistentTablespace_AddTuple( filespaceOid, tablespaceOid, PersistentFileSysState_CreatePending, /* createMirrorDataLossTrackingSessionNum */ 0, mirrorExistenceState, /* reserved */ 0, /* parentXid */ topXid, flushToXLog, persistentTid, persistentSerialNum); WRITE_TABLESPACE_HASH_LOCK; tablespaceDirEntry = PersistentTablespace_CreateEntryUnderLock(filespaceOid, tablespaceOid); Assert(tablespaceDirEntry != NULL); tablespaceDirEntry->state = PersistentFileSysState_CreatePending; ItemPointerCopy(persistentTid, &tablespaceDirEntry->persistentTid); tablespaceDirEntry->persistentSerialNum = *persistentSerialNum; WRITE_TABLESPACE_HASH_UNLOCK; /* * This XLOG must be generated under the persistent write-lock. */ #ifdef MASTER_MIRROR_SYNC mmxlog_log_create_tablespace( filespaceOid, tablespaceOid); #endif SIMPLE_FAULT_INJECTOR(FaultBeforePendingDeleteTablespaceEntry); /* * MPP-18228 To make adding 'Create Pending' entry to persistent table and * adding to the PendingDelete list atomic */ PendingDelete_AddCreatePendingEntryWrapper( &fsObjName, persistentTid, *persistentSerialNum); WRITE_PERSISTENT_STATE_ORDERED_UNLOCK; if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "Persistent tablespace directory: Add '%s' in state 'Created', mirror existence state '%s', serial number " INT64_FORMAT " at TID %s", PersistentFileSysObjName_ObjectName(&fsObjName), MirroredObjectExistenceState_Name(mirrorExistenceState), *persistentSerialNum, ItemPointerToString(persistentTid)); }
static void PersistentStore_InsertTuple( PersistentStoreData *storeData, PersistentStoreSharedData *storeSharedData, Datum *values, bool flushToXLog, /* When true, the XLOG record for this change will be flushed to disk. */ ItemPointer persistentTid) /* TID of the stored tuple. */ { Relation persistentRel; #ifdef USE_ASSERT_CHECKING if (storeSharedData == NULL || !PersistentStoreSharedData_EyecatcherIsValid(storeSharedData)) elog(ERROR, "Persistent store shared-memory not valid"); #endif if (Debug_persistent_store_print) elog(PersistentStore_DebugPrintLevel(), "PersistentStore_InsertTuple: Going to insert new tuple ('%s', shared data %p)", storeData->tableName, storeSharedData); persistentRel = (*storeData->openRel)(); PersistentStore_DoInsertTuple( storeData, storeSharedData, persistentRel, values, flushToXLog, persistentTid); #ifdef FAULT_INJECTOR if (FaultInjector_InjectFaultIfSet(SyncPersistentTable, DDLNotSpecified, "" /* databaseName */, "" /* tableName */)== FaultInjectorTypeSkip) { FlushRelationBuffers(persistentRel); smgrimmedsync(persistentRel->rd_smgr); } #endif (*storeData->closeRel)(persistentRel); if (Debug_persistent_store_print) { elog(PersistentStore_DebugPrintLevel(), "PersistentStore_InsertTuple: Inserted new tuple at TID %s ('%s')", ItemPointerToString(persistentTid), storeData->tableName); (*storeData->printTupleCallback)( PersistentStore_DebugPrintLevel(), "STORE INSERT TUPLE", persistentTid, values); } }
int smgrGetAppendOnlyMirrorResyncEofs(EndXactRecKind endXactRecKind, PersistentEndXactAppendOnlyMirrorResyncEofs **ptr) { int nestLevel = GetCurrentTransactionNestLevel(); int nentries; PersistentEndXactAppendOnlyMirrorResyncEofs *rptr; HASH_SEQ_STATUS iterateStatus; AppendOnlyMirrorResyncEofs *entry; int entryIndex; if (endXactRecKind == EndXactRecKind_Abort) { /* * No Append-Only Mirror Resync EOF information needed on abort. */ *ptr = NULL; return 0; } nentries = 0; if (AppendOnlyMirrorResyncEofsTable != NULL) { hash_seq_init(&iterateStatus, AppendOnlyMirrorResyncEofsTable); while ((entry = hash_seq_search(&iterateStatus)) != NULL) { if (entry->key.nestLevel >= nestLevel) nentries++; } } if (nentries == 0) { *ptr = NULL; return 0; } if (Debug_persistent_print || Debug_persistent_appendonly_commit_count_print) elog(Persistent_DebugPrintLevel(), "Storage Manager: Get Append-Only mirror resync eofs list entries (current transaction nest level %d, Append-Only commit work system count %d)", nestLevel, FileRepPrimary_GetAppendOnlyCommitWorkCount()); rptr = (PersistentEndXactAppendOnlyMirrorResyncEofs *) palloc(nentries * sizeof(PersistentEndXactAppendOnlyMirrorResyncEofs)); *ptr = rptr; entryIndex = 0; hash_seq_init(&iterateStatus, AppendOnlyMirrorResyncEofsTable); while ((entry = hash_seq_search(&iterateStatus)) != NULL) { MIRRORED_LOCK_DECLARE; bool returned; int resultSystemAppendOnlyCommitCount; returned = false; if (entry->key.nestLevel >= nestLevel) { MIRRORED_LOCK; MirroredAppendOnly_EndXactCatchup(entryIndex, &entry->key.relFileNode, entry->key.segmentFileNum, entry->key.nestLevel, entry->relationName, &entry->persistentTid, entry->persistentSerialNum, &mirroredLockLocalVars, entry->mirrorCatchupRequired, entry->mirrorDataLossTrackingState, entry->mirrorDataLossTrackingSessionNum, entry->mirrorNewEof); /* * See if the mirror situation for this Append-Only segment file * has changed since we flushed it to disk. */ rptr->relFileNode = entry->key.relFileNode; rptr->segmentFileNum = entry->key.segmentFileNum; rptr->persistentTid = entry->persistentTid; rptr->persistentSerialNum = entry->persistentSerialNum; if (entry->mirrorCatchupRequired) { rptr->mirrorLossEof = INT64CONST(-1); } else { rptr->mirrorLossEof = entry->mirrorNewEof; } rptr->mirrorNewEof = entry->mirrorNewEof; rptr++; returned = true; START_CRIT_SECTION(); LWLockAcquire(FileRepAppendOnlyCommitCountLock, LW_EXCLUSIVE); resultSystemAppendOnlyCommitCount = FileRepPrimary_IntentAppendOnlyCommitWork(); /* Set this inside the Critical Section. */ entry->didIncrementCommitCount = true; if (endXactRecKind == EndXactRecKind_Prepare) { char gid[TMGIDSIZE]; if (!getDistributedTransactionIdentifier(gid)) elog(ERROR, "Unable to obtain gid during prepare"); PrepareIntentAppendOnlyCommitWork(gid); entry->isDistributedTransaction = true; memcpy(entry->gid, gid, TMGIDSIZE); } pendingAppendOnlyMirrorResyncIntentCount++; } else { MIRRORED_LOCK; START_CRIT_SECTION(); LWLockAcquire(FileRepAppendOnlyCommitCountLock, LW_EXCLUSIVE); resultSystemAppendOnlyCommitCount = FileRepPrimary_GetAppendOnlyCommitWorkCount(); } if (Debug_persistent_print || Debug_persistent_appendonly_commit_count_print) { if (entry->relationName == NULL) elog(Persistent_DebugPrintLevel(), "Storage Manager: Get Append-Only mirror resync eofs list entry #%d: %u/%u/%u, segment file #%d " "(returned %s, result system Append-Only commit count %d, transaction nest level %d, persistent TID %s, persistent serial number " INT64_FORMAT ", mirror catchup required %s, mirror new EOF " INT64_FORMAT ")", entryIndex, entry->key.relFileNode.spcNode, entry->key.relFileNode.dbNode, entry->key.relFileNode.relNode, entry->key.segmentFileNum, (returned ? "true" : "false"), resultSystemAppendOnlyCommitCount, entry->key.nestLevel, ItemPointerToString(&entry->persistentTid), entry->persistentSerialNum, (entry->mirrorCatchupRequired ? "true" : "false"), entry->mirrorNewEof); else elog(Persistent_DebugPrintLevel(), "Storage Manager: Get Append-Only mirror resync eofs list entry #%d: %u/%u/%u, segment file #%d, relation name '%s' " "(returned %s, result system Append-Only commit count %d, transaction nest level %d, persistent TID %s, persistent serial number " INT64_FORMAT ", mirror catchup required %s, mirror new EOF " INT64_FORMAT ")", entryIndex, entry->key.relFileNode.spcNode, entry->key.relFileNode.dbNode, entry->key.relFileNode.relNode, entry->key.segmentFileNum, entry->relationName, (returned ? "true" : "false"), resultSystemAppendOnlyCommitCount, entry->key.nestLevel, ItemPointerToString(&entry->persistentTid), entry->persistentSerialNum, (entry->mirrorCatchupRequired ? "true" : "false"), entry->mirrorNewEof); } LWLockRelease(FileRepAppendOnlyCommitCountLock); END_CRIT_SECTION(); MIRRORED_UNLOCK; entryIndex++; } return nentries; }
void smgrDoAppendOnlyResyncEofs(bool forCommit) { HASH_SEQ_STATUS iterateStatus; AppendOnlyMirrorResyncEofs *entry; AppendOnlyMirrorResyncEofs *entryExample = NULL; int appendOnlyMirrorResyncEofsCount; if (AppendOnlyMirrorResyncEofsTable == NULL) return; if (Debug_persistent_print || Debug_persistent_appendonly_commit_count_print) elog(Persistent_DebugPrintLevel(), "Storage Manager: Enter Append-Only mirror resync eofs list entries (Append-Only commit work count %d)", FileRepPrimary_GetAppendOnlyCommitWorkCount()); hash_seq_init( &iterateStatus, AppendOnlyMirrorResyncEofsTable); appendOnlyMirrorResyncEofsCount = 0; while ((entry = hash_seq_search(&iterateStatus)) != NULL) { if (entryExample == NULL) { entryExample = entry; } if (forCommit) { PersistentFileSysObj_UpdateAppendOnlyMirrorResyncEofs(&entry->key.relFileNode, entry->key.segmentFileNum, &entry->persistentTid, entry->persistentSerialNum, entry->mirrorCatchupRequired, entry->mirrorNewEof, /* recovery */ false, /* flushToXLog */ false); } else { /* * Abort case. */ if (entry->didIncrementCommitCount) { int systemAppendOnlyCommitWorkCount; LWLockAcquire(FileRepAppendOnlyCommitCountLock, LW_EXCLUSIVE); systemAppendOnlyCommitWorkCount = FileRepPrimary_FinishedAppendOnlyCommitWork(1); if (entry->isDistributedTransaction) { PrepareDecrAppendOnlyCommitWork(entry->gid); } if (Debug_persistent_print || Debug_persistent_appendonly_commit_count_print) elog(Persistent_DebugPrintLevel(), "Storage Manager: Append-Only Mirror Resync EOFs decrementing commit work for aborted transaction " "(system count %d). " "Relation %u/%u/%u, segment file #%d (persistent serial num " INT64_FORMAT ", TID %s) ", systemAppendOnlyCommitWorkCount, entry->key.relFileNode.spcNode, entry->key.relFileNode.dbNode, entry->key.relFileNode.relNode, entry->key.segmentFileNum, entry->persistentSerialNum, ItemPointerToString(&entry->persistentTid)); pendingAppendOnlyMirrorResyncIntentCount--; LWLockRelease(FileRepAppendOnlyCommitCountLock); } } if (Debug_persistent_print || Debug_persistent_appendonly_commit_count_print) elog(Persistent_DebugPrintLevel(), "Storage Manager: Append-Only mirror resync eofs list entry #%d: %u/%u/%u, segment file #%d, relation name '%s' " "(forCommit %s, persistent TID %s, persistent serial number " INT64_FORMAT ", mirror catchup required %s, mirror new EOF " INT64_FORMAT ")", appendOnlyMirrorResyncEofsCount, entry->key.relFileNode.spcNode, entry->key.relFileNode.dbNode, entry->key.relFileNode.relNode, entry->key.segmentFileNum, (entry->relationName == NULL ? "<null>" : entry->relationName), (forCommit ? "true" : "false"), ItemPointerToString(&entry->persistentTid), entry->persistentSerialNum, (entry->mirrorCatchupRequired ? "true" : "false"), entry->mirrorNewEof); appendOnlyMirrorResyncEofsCount++; } /* * If we collected Append-Only mirror resync EOFs and bumped the intent * count, we need to decrement the counts as part of our end transaction * work here. */ if (pendingAppendOnlyMirrorResyncIntentCount > 0) { MIRRORED_LOCK_DECLARE; int oldSystemAppendOnlyCommitWorkCount; int newSystemAppendOnlyCommitWorkCount; int resultSystemAppendOnlyCommitWorkCount; if (appendOnlyMirrorResyncEofsCount != pendingAppendOnlyMirrorResyncIntentCount) elog(ERROR, "Pending Append-Only Mirror Resync EOFs intent count mismatch (pending %d, table count %d)", pendingAppendOnlyMirrorResyncIntentCount, appendOnlyMirrorResyncEofsCount); if (entryExample == NULL) elog(ERROR, "Not expecting an empty Append-Only Mirror Resync hash table when the local intent count is non-zero (%d)", pendingAppendOnlyMirrorResyncIntentCount); MIRRORED_LOCK; /*NOTE: When we use the MirroredLock for the whole routine, this can go. */ LWLockAcquire(FileRepAppendOnlyCommitCountLock, LW_EXCLUSIVE); oldSystemAppendOnlyCommitWorkCount = FileRepPrimary_GetAppendOnlyCommitWorkCount(); newSystemAppendOnlyCommitWorkCount = oldSystemAppendOnlyCommitWorkCount - pendingAppendOnlyMirrorResyncIntentCount; if (newSystemAppendOnlyCommitWorkCount < 0) elog(ERROR, "Append-Only Mirror Resync EOFs intent count would go negative " "(system count %d, entry count %d). " "Example relation %u/%u/%u, segment file #%d (persistent serial num " INT64_FORMAT ", TID %s)", oldSystemAppendOnlyCommitWorkCount, pendingAppendOnlyMirrorResyncIntentCount, entryExample->key.relFileNode.spcNode, entryExample->key.relFileNode.dbNode, entryExample->key.relFileNode.relNode, entryExample->key.segmentFileNum, entryExample->persistentSerialNum, ItemPointerToString(&entryExample->persistentTid)); resultSystemAppendOnlyCommitWorkCount = FileRepPrimary_FinishedAppendOnlyCommitWork(pendingAppendOnlyMirrorResyncIntentCount); /* * Should match since we are under FileRepAppendOnlyCommitCountLock * EXCLUSIVE. */ Assert(newSystemAppendOnlyCommitWorkCount == resultSystemAppendOnlyCommitWorkCount); pendingAppendOnlyMirrorResyncIntentCount = 0; if (Debug_persistent_print || Debug_persistent_appendonly_commit_count_print) elog(Persistent_DebugPrintLevel(), "Storage Manager: Append-Only Mirror Resync EOFs intent count finishing %s work with system count %d remaining " "(enter system count %d, entry count %d, result system count %d). " "Example relation %u/%u/%u, segment file #%d (persistent serial num " INT64_FORMAT ", TID %s)", (forCommit ? "commit" : "abort"), newSystemAppendOnlyCommitWorkCount, oldSystemAppendOnlyCommitWorkCount, pendingAppendOnlyMirrorResyncIntentCount, resultSystemAppendOnlyCommitWorkCount, entryExample->key.relFileNode.spcNode, entryExample->key.relFileNode.dbNode, entryExample->key.relFileNode.relNode, entryExample->key.segmentFileNum, entryExample->persistentSerialNum, ItemPointerToString(&entryExample->persistentTid)); LWLockRelease(FileRepAppendOnlyCommitCountLock); MIRRORED_UNLOCK; } }
void PersistentStore_UpdateTuple( PersistentStoreData *storeData, PersistentStoreSharedData *storeSharedData, ItemPointer persistentTid, /* TID of the stored tuple. */ Datum *values, bool flushToXLog) /* When true, the XLOG record for this change will be flushed to disk. */ { Relation persistentRel; bool *nulls; HeapTuple persistentTuple = NULL; XLogRecPtr xlogUpdateEndLoc; #ifdef USE_ASSERT_CHECKING if (storeSharedData == NULL || !PersistentStoreSharedData_EyecatcherIsValid(storeSharedData)) elog(ERROR, "Persistent store shared-memory not valid"); #endif if (Debug_persistent_store_print) elog(PersistentStore_DebugPrintLevel(), "PersistentStore_ReplaceTuple: Going to update whole tuple at TID %s ('%s', shared data %p)", ItemPointerToString(persistentTid), storeData->tableName, storeSharedData); persistentRel = (*storeData->openRel)(); /* * In order to keep the tuples the exact same size to enable direct reuse of * free tuples, we do not use NULLs. */ nulls = (bool*)palloc0(storeData->numAttributes * sizeof(bool)); /* * Form the tuple. */ persistentTuple = heap_form_tuple(persistentRel->rd_att, values, nulls); if (!HeapTupleIsValid(persistentTuple)) elog(ERROR, "Failed to build persistent tuple ('%s')", storeData->tableName); persistentTuple->t_self = *persistentTid; frozen_heap_inplace_update(persistentRel, persistentTuple); /* * Return the XLOG location of the UPDATE tuple's XLOG record. */ xlogUpdateEndLoc = XLogLastInsertEndLoc(); heap_freetuple(persistentTuple); #ifdef FAULT_INJECTOR if (FaultInjector_InjectFaultIfSet(SyncPersistentTable, DDLNotSpecified, "" /* databaseName */, "" /* tableName */)== FaultInjectorTypeSkip) { FlushRelationBuffers(persistentRel); smgrimmedsync(persistentRel->rd_smgr); } #endif (*storeData->closeRel)(persistentRel); if (Debug_persistent_store_print) { elog(PersistentStore_DebugPrintLevel(), "PersistentStore_UpdateTuple: Updated whole tuple at TID %s ('%s')", ItemPointerToString(persistentTid), storeData->tableName); (*storeData->printTupleCallback)( PersistentStore_DebugPrintLevel(), "STORE UPDATED TUPLE", persistentTid, values); } if (flushToXLog) { XLogFlush(xlogUpdateEndLoc); XLogRecPtr_Zero(&nowaitXLogEndLoc); } else nowaitXLogEndLoc = xlogUpdateEndLoc; }
void AppendOnlyMirrorResyncEofs_Merge(RelFileNode *relFileNode, int32 segmentFileNum, int nestLevel, /* Transaction nesting level. */ char *relationName, ItemPointer persistentTid, int64 persistentSerialNum, bool mirrorCatchupRequired, MirrorDataLossTrackingState mirrorDataLossTrackingState, int64 mirrorDataLossTrackingSessionNum, int64 mirrorNewEof) { int64 previousMirrorNewEof = 0; AppendOnlyMirrorResyncEofsKey key; AppendOnlyMirrorResyncEofs *entry; bool found; if (AppendOnlyMirrorResyncEofsTable == NULL) AppendOnlyMirrorResyncEofs_HashTableInit(); AppendOnlyMirrorResyncEofs_InitKey( &key, relFileNode, segmentFileNum, nestLevel); entry = (AppendOnlyMirrorResyncEofs *) hash_search(AppendOnlyMirrorResyncEofsTable, (void *) &key, HASH_ENTER, &found); if (!found) { entry->relationName = MemoryContextStrdup(TopMemoryContext, relationName); entry->persistentSerialNum = persistentSerialNum; entry->persistentTid = *persistentTid; entry->didIncrementCommitCount = false; entry->isDistributedTransaction = false; entry->gid[0] = '\0'; entry->mirrorCatchupRequired = mirrorCatchupRequired; entry->mirrorDataLossTrackingState = mirrorDataLossTrackingState; entry->mirrorDataLossTrackingSessionNum = mirrorDataLossTrackingSessionNum; entry->mirrorNewEof = mirrorNewEof; } else { previousMirrorNewEof = entry->mirrorNewEof; /* * UNDONE: What is the purpose of this IF stmt? Shouldn't we always * set the new EOF? */ if (mirrorNewEof > entry->mirrorNewEof) entry->mirrorNewEof = mirrorNewEof; /* * We adopt the newer FileRep state because we accurately track the * state of mirror data. For example, the first write session might * have had loss because the mirror was down. But then the second * write session discovered we were in sync and copied both the first * and second write session to the mirror and flushed it. */ entry->mirrorCatchupRequired = mirrorCatchupRequired; entry->mirrorDataLossTrackingState = mirrorDataLossTrackingState; entry->mirrorDataLossTrackingSessionNum = mirrorDataLossTrackingSessionNum; } if (Debug_persistent_print || Debug_persistent_appendonly_commit_count_print) elog(Persistent_DebugPrintLevel(), "Storage Manager: %s Append-Only mirror resync eofs entry: %u/%u/%u, segment file #%d, relation name '%s' (transaction nest level %d, persistent TID %s, persistent serial number " INT64_FORMAT ", " "mirror data loss tracking (state '%s', session num " INT64_FORMAT "), " "previous mirror new EOF " INT64_FORMAT ", input mirror new EOF " INT64_FORMAT ", saved mirror new EOF " INT64_FORMAT ")", (found ? "Merge" : "New"), entry->key.relFileNode.spcNode, entry->key.relFileNode.dbNode, entry->key.relFileNode.relNode, entry->key.segmentFileNum, (entry->relationName == NULL ? "<null>" : entry->relationName), entry->key.nestLevel, ItemPointerToString(&entry->persistentTid), entry->persistentSerialNum, MirrorDataLossTrackingState_Name(mirrorDataLossTrackingState), mirrorDataLossTrackingSessionNum, previousMirrorNewEof, mirrorNewEof, entry->mirrorNewEof); }
/* * Indicate we are aborting the create of a relation file. * * This state will make sure the relation gets dropped after a system crash. */ PersistentFileSysObjStateChangeResult PersistentDatabase_MarkAbortingCreate( PersistentFileSysObjName *fsObjName, /* The tablespace and database OIDs for the aborting create. */ ItemPointer persistentTid, /* TID of the gp_persistent_rel_files tuple for the rel file */ int64 persistentSerialNum, /* Serial number for the relation. Distinquishes the uses of the tuple. */ bool retryPossible) { WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE; DbDirNode *dbDirNode = &fsObjName->variant.dbDirNode; DatabaseDirEntry databaseDirEntry; PersistentFileSysObjStateChangeResult stateChangeResult; if (Persistent_BeforePersistenceWork()) { if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "Skipping persistent database '%s' because we are before persistence work", GetDatabasePath( dbDirNode->database, dbDirNode->tablespace)); return false; // The initdb process will load the persistent table once we out of bootstrap mode. } PersistentDatabase_VerifyInitScan(); WRITE_PERSISTENT_STATE_ORDERED_LOCK; PersistentDatabase_LookupExistingDbDir( dbDirNode, &databaseDirEntry); if (databaseDirEntry->state != PersistentFileSysState_CreatePending) elog(ERROR, "Persistent database entry %s expected to be in 'Create Pending' (actual state '%s')", GetDatabasePath( dbDirNode->database, dbDirNode->tablespace), PersistentFileSysObjState_Name(databaseDirEntry->state)); stateChangeResult = PersistentFileSysObj_StateChange( fsObjName, persistentTid, persistentSerialNum, PersistentFileSysState_AbortingCreate, retryPossible, /* flushToXlog */ false, /* oldState */ NULL, /* verifiedActionCallback */ NULL); databaseDirEntry->state = PersistentFileSysState_AbortingCreate; WRITE_PERSISTENT_STATE_ORDERED_UNLOCK; if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "Persistent database directory: '%s' changed state from 'Create Pending' to 'Aborting Create', serial number " INT64_FORMAT " at TID %s (State-Change result '%s')", PersistentFileSysObjName_ObjectName(fsObjName), persistentSerialNum, ItemPointerToString(persistentTid), PersistentFileSysObjStateChangeResult_Name(stateChangeResult)); return stateChangeResult; }
void PersistentDatabase_AddCreated( DbDirNode *dbDirNode, /* The tablespace and database OIDs for the create. */ ItemPointer persistentTid, /* TID of the gp_persistent_rel_files tuple for the rel file */ bool flushToXLog) /* When true, the XLOG record for this change will be flushed to disk. */ { WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE; PersistentFileSysObjName fsObjName; DatabaseDirEntry databaseDirEntry; SharedOidSearchAddResult addResult; int64 persistentSerialNum; if (!Persistent_BeforePersistenceWork()) elog(ERROR, "We can only add to persistent meta-data when special states"); // Verify PersistentFileSysObj_BuildInitScan has been called. PersistentDatabase_VerifyInitScan(); PersistentFileSysObjName_SetDatabaseDir(&fsObjName,dbDirNode->tablespace,dbDirNode->database,is_tablespace_shared); WRITE_PERSISTENT_STATE_ORDERED_LOCK; /* * GpIdentity.segindex * In the initdb, GpIdentity.segindex is set to -10000. It will update this * value to the correct GpIdentity.segindex. */ databaseDirEntry = (DatabaseDirEntry) SharedOidSearch_Find( &persistentDatabaseSharedData->databaseDirSearchTable, dbDirNode->database, dbDirNode->tablespace); if (databaseDirEntry != NULL) elog(ERROR, "Persistent database entry '%s' already exists in state '%s'", GetDatabasePath( dbDirNode->database, dbDirNode->tablespace), PersistentFileSysObjState_Name(databaseDirEntry->state)); addResult = SharedOidSearch_Add( &persistentDatabaseSharedData->databaseDirSearchTable, dbDirNode->database, dbDirNode->tablespace, (SharedOidSearchObjHeader**)&databaseDirEntry); if (addResult == SharedOidSearchAddResult_NoMemory) { /* If out of shared memory, no need to promote to PANIC. */ WRITE_PERSISTENT_STATE_ORDERED_UNLOCK; ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("Out of shared-memory for persistent databases"), errhint("You may need to increase the gp_max_databases and " "gp_max_tablespaces value"), errOmitLocation(true))); } else if (addResult == SharedOidSearchAddResult_Exists) elog(PANIC, "Persistent database entry '%s' already exists in state '%s'", GetDatabasePath( dbDirNode->database, dbDirNode->tablespace), PersistentFileSysObjState_Name(databaseDirEntry->state)); else Assert(addResult == SharedOidSearchAddResult_Ok); databaseDirEntry->state = PersistentFileSysState_Created; databaseDirEntry->iteratorRefCount = 0; PersistentDatabase_AddTuple( databaseDirEntry, /* reserved */ 0, InvalidTransactionId, flushToXLog); *persistentTid = databaseDirEntry->persistentTid; persistentSerialNum = databaseDirEntry->persistentSerialNum; WRITE_PERSISTENT_STATE_ORDERED_UNLOCK; if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "Persistent database directory: Add '%s' in state 'Created', serial number " INT64_FORMAT " at TID %s", PersistentFileSysObjName_ObjectName(&fsObjName), persistentSerialNum, ItemPointerToString(persistentTid)); }
void PersistentStore_ReplaceTuple( PersistentStoreData *storeData, PersistentStoreSharedData *storeSharedData, ItemPointer persistentTid, /* TID of the stored tuple. */ HeapTuple tuple, Datum *newValues, bool *replaces, bool flushToXLog) /* When true, the XLOG record for this change will be flushed to disk. */ { Relation persistentRel; bool *nulls; HeapTuple replacementTuple = NULL; XLogRecPtr xlogUpdateEndLoc; #ifdef USE_ASSERT_CHECKING if (storeSharedData == NULL || !PersistentStoreSharedData_EyecatcherIsValid(storeSharedData)) elog(ERROR, "Persistent store shared-memory not valid"); #endif if (Debug_persistent_store_print) elog(PersistentStore_DebugPrintLevel(), "PersistentStore_ReplaceTuple: Going to replace set of columns in tuple at TID %s ('%s', shared data %p)", ItemPointerToString(persistentTid), storeData->tableName, storeSharedData); persistentRel = (*storeData->openRel)(); /* * In order to keep the tuples the exact same size to enable direct reuse of * free tuples, we do not use NULLs. */ nulls = (bool*)palloc0(storeData->numAttributes * sizeof(bool)); /* * Modify the tuple. */ replacementTuple = heap_modify_tuple(tuple, persistentRel->rd_att, newValues, nulls, replaces); replacementTuple->t_self = *persistentTid; frozen_heap_inplace_update(persistentRel, replacementTuple); /* * Return the XLOG location of the UPDATE tuple's XLOG record. */ xlogUpdateEndLoc = XLogLastInsertEndLoc(); heap_freetuple(replacementTuple); pfree(nulls); if (Debug_persistent_store_print) { Datum *readValues; bool *readNulls; HeapTupleData readTuple; Buffer buffer; HeapTuple readTupleCopy; elog(PersistentStore_DebugPrintLevel(), "PersistentStore_ReplaceTuple: Replaced set of columns in tuple at TID %s ('%s')", ItemPointerToString(persistentTid), storeData->tableName); readValues = (Datum*)palloc(storeData->numAttributes * sizeof(Datum)); readNulls = (bool*)palloc(storeData->numAttributes * sizeof(bool)); readTuple.t_self = *persistentTid; if (!heap_fetch(persistentRel, SnapshotAny, &readTuple, &buffer, false, NULL)) { elog(ERROR, "Failed to fetch persistent tuple at %s ('%s')", ItemPointerToString(&readTuple.t_self), storeData->tableName); } readTupleCopy = heaptuple_copy_to(&readTuple, NULL, NULL); ReleaseBuffer(buffer); heap_deform_tuple(readTupleCopy, persistentRel->rd_att, readValues, readNulls); (*storeData->printTupleCallback)( PersistentStore_DebugPrintLevel(), "STORE REPLACED TUPLE", persistentTid, readValues); heap_freetuple(readTupleCopy); pfree(readValues); pfree(readNulls); } (*storeData->closeRel)(persistentRel); if (flushToXLog) { XLogFlush(xlogUpdateEndLoc); XLogRecPtr_Zero(&nowaitXLogEndLoc); } else nowaitXLogEndLoc = xlogUpdateEndLoc; }
/* * Indicate the non-transaction just-in-time database create was NOT successful. */ void PersistentDatabase_AbandonJustInTimeCreatePending( DbDirNode *dbDirNode, ItemPointer persistentTid, /* TID of the gp_persistent_rel_files tuple for the rel file */ int64 persistentSerialNum) /* Serial number for the relation. Distinquishes the uses of the tuple. */ { WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE; PersistentFileSysObjName fsObjName; DatabaseDirEntry databaseDirEntry; PersistentFileSysObjStateChangeResult stateChangeResult; if (Persistent_BeforePersistenceWork()) { if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "Skipping persistent database '%s' because we are before persistence work", GetDatabasePath( dbDirNode->database, dbDirNode->tablespace)); return; // The initdb process will load the persistent table once we out of bootstrap mode. } PersistentDatabase_VerifyInitScan(); PersistentFileSysObjName_SetDatabaseDir(&fsObjName,dbDirNode->tablespace,dbDirNode->database,is_tablespace_shared); WRITE_PERSISTENT_STATE_ORDERED_LOCK; PersistentDatabase_LookupExistingDbDir( dbDirNode, &databaseDirEntry); if (databaseDirEntry->state != PersistentFileSysState_JustInTimeCreatePending) elog(ERROR, "Persistent database entry %s expected to be in 'Just-In-Time Create Pending' state (actual state '%s')", GetDatabasePath( dbDirNode->database, dbDirNode->tablespace), PersistentFileSysObjState_Name(databaseDirEntry->state)); stateChangeResult = PersistentFileSysObj_StateChange( &fsObjName, persistentTid, persistentSerialNum, PersistentFileSysState_Free, /* retryPossible */ false, /* flushToXlog */ false, /* oldState */ NULL, /* verifiedActionCallback */ NULL); databaseDirEntry->state = PersistentFileSysState_Free; if (databaseDirEntry->iteratorRefCount == 0) SharedOidSearch_Delete( &persistentDatabaseSharedData->databaseDirSearchTable, &databaseDirEntry->header); WRITE_PERSISTENT_STATE_ORDERED_UNLOCK; if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "Persistent database directory: Abandon '%s' in state 'Just-In-Time Create Pending', serial number " INT64_FORMAT " at TID %s (State-Change result '%s')", PersistentFileSysObjName_ObjectName(&fsObjName), persistentSerialNum, ItemPointerToString(persistentTid), PersistentFileSysObjStateChangeResult_Name(stateChangeResult)); }
/* * Indicate we physically removed the relation file. */ void PersistentDatabase_Dropped( PersistentFileSysObjName *fsObjName, /* The tablespace and database OIDs for the dropped relation. */ ItemPointer persistentTid, /* TID of the gp_persistent_rel_files tuple for the rel file */ int64 persistentSerialNum) /* Serial number for the relation. Distinquishes the uses of the tuple. */ { WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE; DbDirNode *dbDirNode = &fsObjName->variant.dbDirNode; DatabaseDirEntry databaseDirEntry; PersistentFileSysState oldState; PersistentFileSysObjStateChangeResult stateChangeResult; if (Persistent_BeforePersistenceWork()) { if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "Skipping persistent database '%s' because we are before persistence work", GetDatabasePath( dbDirNode->database, dbDirNode->tablespace)); return; // The initdb process will load the persistent table once we out of bootstrap mode. } PersistentDatabase_VerifyInitScan(); WRITE_PERSISTENT_STATE_ORDERED_LOCK; PersistentDatabase_LookupExistingDbDir( dbDirNode, &databaseDirEntry); if (databaseDirEntry->state != PersistentFileSysState_DropPending && databaseDirEntry->state != PersistentFileSysState_AbortingCreate) elog(ERROR, "Persistent database entry %s expected to be in 'Drop Pending' or 'Aborting Create' (actual state '%s')", GetDatabasePath( dbDirNode->database, dbDirNode->tablespace), PersistentFileSysObjState_Name(databaseDirEntry->state)); stateChangeResult = PersistentFileSysObj_StateChange( fsObjName, persistentTid, persistentSerialNum, PersistentFileSysState_Free, /* retryPossible */ false, /* flushToXlog */ false, &oldState, PersistentDatabase_DroppedVerifiedActionCallback); databaseDirEntry->state = PersistentFileSysState_Free; if (databaseDirEntry->iteratorRefCount == 0) SharedOidSearch_Delete( &persistentDatabaseSharedData->databaseDirSearchTable, &databaseDirEntry->header); WRITE_PERSISTENT_STATE_ORDERED_UNLOCK; if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "Persistent database directory: '%s' changed state from '%s' to (Free), serial number " INT64_FORMAT " at TID %s (State-Change result '%s')", PersistentFileSysObjName_ObjectName(fsObjName), PersistentFileSysObjState_Name(oldState), persistentSerialNum, ItemPointerToString(persistentTid), PersistentFileSysObjStateChangeResult_Name(stateChangeResult)); }
PersistentFileSysObjStateChangeResult PersistentRelation_MarkAbortingCreate( PersistentFileSysObjName *fsObjName, ItemPointer persistentTid, int64 persistentSerialNum, bool retryPossible) { WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE; RelFileNode *relFileNode = &fsObjName->variant.rel.relFileNode; RelationDirEntry relationDirEntry; PersistentFileSysObjStateChangeResult stateChangeResult; if (RelFileNode_IsEmpty(relFileNode)) { elog(ERROR, "Invalid RelFileNode (0,0,0)"); } if (Persistent_BeforePersistenceWork()) { if (Debug_persistent_print) { elog(Persistent_DebugPrintLevel(), "Skipping persistent relation '%s' because we are before persistence work", relpath(*relFileNode)); /* * The initdb process will load the persistent table once we out of bootstrap mode. */ return PersistentFileSysObjStateChangeResult_None; } } PersistentRelation_VerifyInitScan(); /* * Do this check after skipping out if in bootstrap mode. */ if (PersistentStore_IsZeroTid(persistentTid)) { elog(ERROR, "TID for persistent '%s' tuple for mark DROP pending is invalid (0,0)", PersistentFileSysObjName_TypeAndObjectName(fsObjName)); } if (persistentSerialNum == 0) { elog(ERROR, "Persistent '%s' serial number for mark DROP pending is invalid (0)", PersistentFileSysObjName_TypeAndObjectName(fsObjName)); } WRITE_PERSISTENT_STATE_ORDERED_LOCK; relationDirEntry = PersistentRelation_FindEntryUnderLock(relFileNode); if (relationDirEntry == NULL) { elog(ERROR, "Did not find persistent relation entry %u/%u/%u", relFileNode->spcNode, relFileNode->dbNode, relFileNode->relNode); } if (relationDirEntry->state != PersistentFileSysState_CreatePending) { elog(ERROR, "Persistent relation entry %u/%u/%u expected to be in 'Create Pending' (actual state '%s')", relFileNode->spcNode, relFileNode->dbNode, relFileNode->relNode, PersistentFileSysObjState_Name(relationDirEntry->state)); } stateChangeResult = PersistentFileSysObj_StateChange( fsObjName, persistentTid, persistentSerialNum, PersistentFileSysState_AbortingCreate, retryPossible, /* flushToXLog */ false, /* oldState */ NULL, /* verifiedActionCallback */ NULL); relationDirEntry->state = PersistentFileSysState_AbortingCreate; WRITE_PERSISTENT_STATE_ORDERED_UNLOCK; if (Debug_persistent_print) { elog(Persistent_DebugPrintLevel(), "Persistent relation: '%s' changed state from 'Create Pending' to 'Aborting Create', serial number " INT64_FORMAT " at TID %s (State-Change result '%s')", PersistentFileSysObjName_ObjectName(fsObjName), persistentSerialNum, ItemPointerToString(persistentTid), PersistentFileSysObjStateChangeResult_Name(stateChangeResult)); } return stateChangeResult; }
void PersistentTablespace_AddCreated( Oid filespaceOid, /* The filespace where the tablespace lives. */ Oid tablespaceOid, /* The tablespace OID to be added. */ MirroredObjectExistenceState mirrorExistenceState, bool flushToXLog) /* When true, the XLOG record for this change will be flushed to disk. */ { WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE; PersistentFileSysObjName fsObjName; ItemPointerData persistentTid; int64 persistentSerialNum; TablespaceDirEntry tablespaceDirEntry; if (Persistent_BeforePersistenceWork()) { if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "Skipping persistent tablespace %u because we are before persistence work", tablespaceOid); return; /* * The initdb process will load the persistent table once we out of * bootstrap mode. */ } PersistentTablespace_VerifyInitScan(); PersistentFileSysObjName_SetTablespaceDir(&fsObjName, tablespaceOid); WRITE_PERSISTENT_STATE_ORDERED_LOCK; PersistentTablespace_AddTuple( filespaceOid, tablespaceOid, PersistentFileSysState_Created, /* createMirrorDataLossTrackingSessionNum */ 0, mirrorExistenceState, /* reserved */ 0, InvalidTransactionId, flushToXLog, &persistentTid, &persistentSerialNum); WRITE_TABLESPACE_HASH_LOCK; tablespaceDirEntry = PersistentTablespace_CreateEntryUnderLock(filespaceOid, tablespaceOid); Assert(tablespaceDirEntry != NULL); tablespaceDirEntry->state = PersistentFileSysState_Created; ItemPointerCopy(&persistentTid, &tablespaceDirEntry->persistentTid); tablespaceDirEntry->persistentSerialNum = persistentSerialNum; WRITE_TABLESPACE_HASH_UNLOCK; WRITE_PERSISTENT_STATE_ORDERED_UNLOCK; if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "Persistent tablespace directory: Add '%s' in state 'Created', mirror existence state '%s', serial number " INT64_FORMAT " at TID '%s' ", PersistentFileSysObjName_ObjectName(&fsObjName), MirroredObjectExistenceState_Name(mirrorExistenceState), persistentSerialNum, ItemPointerToString(&persistentTid)); }
static void PersistentEndXactRec_VerifyFileSysActionInfos( EndXactRecKind endXactRecKind, PersistentEndXactFileSysActionInfo *fileSysActionInfos, int count) { int i; ItemPointerData maxTid; if (InRecovery || Persistent_BeforePersistenceWork()) return; for (i = 0; i < count; i++) { PersistentTidIsKnownResult persistentTidIsKnownResult; if (!PersistentEndXactFileSysAction_IsValid(fileSysActionInfos[i].action)) elog(ERROR, "Persistent file-system action is invalid (%d) (index %d, transaction kind '%s')", fileSysActionInfos[i].action, i, EndXactRecKind_Name(endXactRecKind)); if (!PersistentFsObjType_IsValid(fileSysActionInfos[i].fsObjName.type)) elog(ERROR, "Persistent file-system object type is invalid (%d) (index %d, transaction kind '%s')", fileSysActionInfos[i].fsObjName.type, i, EndXactRecKind_Name(endXactRecKind)); if (PersistentStore_IsZeroTid(&fileSysActionInfos[i].persistentTid)) elog(ERROR, "TID for persistent '%s' tuple is invalid (0,0) (index %d, transaction kind '%s')", PersistentFileSysObjName_TypeAndObjectName(&fileSysActionInfos[i].fsObjName), i, EndXactRecKind_Name(endXactRecKind)); persistentTidIsKnownResult = PersistentFileSysObj_TidIsKnown( fileSysActionInfos[i].fsObjName.type, &fileSysActionInfos[i].persistentTid, &maxTid); switch (persistentTidIsKnownResult) { case PersistentTidIsKnownResult_BeforePersistenceWork: elog(ERROR, "Shouldn't being trying to verify persistent TID before persistence work"); break; case PersistentTidIsKnownResult_ScanNotPerformedYet: // UNDONE: For now, just debug log this. if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "Can't verify persistent TID if we haven't done the persistent scan yet"); break; case PersistentTidIsKnownResult_MaxTidIsZero: // UNDONE: For now, just debug log this. if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "TID for persistent '%s' tuple TID %s and the last known TID zero (0,0) (index %d, transaction kind '%s')", PersistentFileSysObjName_TypeAndObjectName(&fileSysActionInfos[i].fsObjName), ItemPointerToString(&fileSysActionInfos[i].persistentTid), i, EndXactRecKind_Name(endXactRecKind)); break; case PersistentTidIsKnownResult_NotKnown: // UNDONE: For now, just debug log this. if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "TID for persistent '%s' tuple TID %s is beyond the last known TID %s (index %d, transaction kind '%s')", PersistentFileSysObjName_TypeAndObjectName(&fileSysActionInfos[i].fsObjName), ItemPointerToString(&fileSysActionInfos[i].persistentTid), ItemPointerToString2(&maxTid), i, EndXactRecKind_Name(endXactRecKind)); break; case PersistentTidIsKnownResult_Known: /* OK */ break; default: elog(ERROR, "Unexpected persistent file-system TID is known result: %d", persistentTidIsKnownResult); } if (fileSysActionInfos[i].persistentSerialNum == 0) elog(ERROR, "Persistent '%s' serial number is invalid (0) (index %d, transaction kind '%s')", PersistentFileSysObjName_TypeAndObjectName(&fileSysActionInfos[i].fsObjName), i, EndXactRecKind_Name(endXactRecKind)); if (fileSysActionInfos[i].fsObjName.type == PersistentFsObjType_RelationFile && !PersistentFileSysRelStorageMgr_IsValid(fileSysActionInfos[i].relStorageMgr)) elog(ERROR, "Persistent '%s' relation storage manager has invalid value (%d) (index %d, transaction kind '%s')", PersistentFileSysObjName_TypeAndObjectName(&fileSysActionInfos[i].fsObjName), fileSysActionInfos[i].relStorageMgr, i, EndXactRecKind_Name(endXactRecKind)); } }
bool ChangeTracking_PrintRelationChangeInfo( RmgrId xl_rmid, uint8 xl_info, void *data, XLogRecPtr *loc, bool weAreGeneratingXLogNow, bool printSkipIssuesOnly) { bool atLeastOneSkipIssue = false; int relationChangeInfoArrayCount; int i; int arrlen = ChangeTracking_GetInfoArrayDesiredMaxLength(xl_rmid, xl_info); RelationChangeInfo relationChangeInfoArray[arrlen]; ChangeTracking_GetRelationChangeInfoFromXlog( xl_rmid, xl_info, data, relationChangeInfoArray, &relationChangeInfoArrayCount, arrlen); for (i = 0; i < relationChangeInfoArrayCount; i++) { RelationChangeInfo *relationChangeInfo; int64 maxPersistentSerialNum; bool skip; bool zeroTid = false; bool invalidTid = false; bool zeroSerialNum = false; bool invalidSerialNum = false; bool skipIssue = false; relationChangeInfo = &relationChangeInfoArray[i]; if (weAreGeneratingXLogNow) maxPersistentSerialNum = PersistentRelfile_MyHighestSerialNum(); else maxPersistentSerialNum = PersistentRelfile_CurrentMaxSerialNum(); skip = GpPersistent_SkipXLogInfo(relationChangeInfo->relFileNode.relNode); if (!skip) { zeroTid = PersistentStore_IsZeroTid(&relationChangeInfo->persistentTid); if (!zeroTid) invalidTid = !ItemPointerIsValid(&relationChangeInfo->persistentTid); zeroSerialNum = (relationChangeInfo->persistentSerialNum == 0); if (!zeroSerialNum) { invalidSerialNum = (relationChangeInfo->persistentSerialNum < 0); /* * If we have'nt done the scan yet... do not do upper range check. */ if (maxPersistentSerialNum != 0 && relationChangeInfo->persistentSerialNum > maxPersistentSerialNum) invalidSerialNum = true; } skipIssue = (zeroTid || invalidTid || zeroSerialNum || invalidSerialNum); } if (!printSkipIssuesOnly || skipIssue) elog(LOG, "ChangeTracking_PrintRelationChangeInfo: [%d] xl_rmid %d, xl_info 0x%X, %u/%u/%u, block number %u, LSN %s, persistent serial num " INT64_FORMAT ", TID %s, maxPersistentSerialNum " INT64_FORMAT ", skip %s, zeroTid %s, invalidTid %s, zeroSerialNum %s, invalidSerialNum %s, skipIssue %s", i, xl_rmid, xl_info, relationChangeInfo->relFileNode.spcNode, relationChangeInfo->relFileNode.dbNode, relationChangeInfo->relFileNode.relNode, relationChangeInfo->blockNumber, XLogLocationToString(loc), relationChangeInfo->persistentSerialNum, ItemPointerToString(&relationChangeInfo->persistentTid), maxPersistentSerialNum, (skip ? "true" : "false"), (zeroTid ? "true" : "false"), (invalidTid ? "true" : "false"), (zeroSerialNum ? "true" : "false"), (invalidSerialNum ? "true" : "false"), (skipIssue ? "true" : "false")); if (skipIssue) atLeastOneSkipIssue = true; } return atLeastOneSkipIssue; }
/* * Indicate the transaction commited and the tablespace is officially created. */ void PersistentTablespace_Created( Oid tablespaceOid, /* The tablespace OID for the create. */ ItemPointer persistentTid, /* TID of the gp_persistent_rel_files tuple for the rel file */ int64 persistentSerialNum, /* Serial number for the tablespace. Distinquishes the uses of the tuple. */ bool retryPossible) { WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE; PersistentFileSysObjName fsObjName; TablespaceDirEntry tablespaceDirEntry; PersistentFileSysObjStateChangeResult stateChangeResult; if (Persistent_BeforePersistenceWork()) { if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "Skipping persistent tablespace %u because we are before persistence work", tablespaceOid); return; /* * The initdb process will load the persistent table once we out of * bootstrap mode. */ } PersistentTablespace_VerifyInitScan(); PersistentFileSysObjName_SetTablespaceDir(&fsObjName, tablespaceOid); WRITE_PERSISTENT_STATE_ORDERED_LOCK; WRITE_TABLESPACE_HASH_LOCK; tablespaceDirEntry = PersistentTablespace_FindEntryUnderLock(tablespaceOid); if (tablespaceDirEntry == NULL) elog(ERROR, "Did not find persistent tablespace entry %u", tablespaceOid); if (tablespaceDirEntry->state != PersistentFileSysState_CreatePending) elog(ERROR, "Persistent tablespace entry %u expected to be in 'Create Pending' state (actual state '%s')", tablespaceOid, PersistentFileSysObjState_Name(tablespaceDirEntry->state)); tablespaceDirEntry->state = PersistentFileSysState_Created; WRITE_TABLESPACE_HASH_UNLOCK; stateChangeResult = PersistentFileSysObj_StateChange( &fsObjName, persistentTid, persistentSerialNum, PersistentFileSysState_Created, retryPossible, /* flushToXlog */ false, /* oldState */ NULL, /* verifiedActionCallback */ NULL); WRITE_PERSISTENT_STATE_ORDERED_UNLOCK; if (Debug_persistent_print) elog(Persistent_DebugPrintLevel(), "Persistent tablespace directory: '%s' changed state from 'Create Pending' to 'Created', serial number " INT64_FORMAT " at TID %s (State-Change result '%s')", PersistentFileSysObjName_ObjectName(&fsObjName), persistentSerialNum, ItemPointerToString(persistentTid), PersistentFileSysObjStateChangeResult_Name(stateChangeResult)); }
void PersistentRelation_AddCreated( RelFileNode *relFileNode, ItemPointer persistentTid, bool flushToXLog) { WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE; PersistentFileSysObjName fsObjName; ItemPointerData previousFreeTid; int64 persistentSerialNum; RelationDirEntry relationDirEntry; Datum values[Natts_gp_persistent_relation_node]; if (RelFileNode_IsEmpty(relFileNode)) { elog(ERROR, "Invalid RelFileNode (0,0,0)"); } MemSet(&previousFreeTid, 0, sizeof(ItemPointerData)); if (!Persistent_BeforePersistenceWork()) { elog(ERROR, "We can only add to persistent meta-data when special states"); } /* Verify PersistentFileSysObj_BuildInitScan has been called */ PersistentRelation_VerifyInitScan(); PersistentFileSysObjName_SetRelationDir( &fsObjName, relFileNode, is_tablespace_shared); WRITE_PERSISTENT_STATE_ORDERED_LOCK; relationDirEntry = PersistentRelation_CreateEntryUnderLock(relFileNode); if (relationDirEntry == NULL) { /* If out of shared memory, no need to promote to PANIC. */ WRITE_PERSISTENT_STATE_ORDERED_UNLOCK; ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("Out of shared-memory for persistent relations"), errhint("You may need to increase the gp_max_relations value"), errOmitLocation(true))); } relationDirEntry->state = PersistentFileSysState_Created; GpPersistentRelationNode_SetDatumValues( values, relFileNode->spcNode, relFileNode->dbNode, relFileNode->relNode, PersistentFileSysState_Created, /* reserved */ 0, /* parentXid */ InvalidTransactionId, /* persistentSerialNum */ 0, &previousFreeTid, is_tablespace_shared(relFileNode->spcNode)); PersistentFileSysObj_AddTuple( PersistentFsObjType_RelationDir, values, flushToXLog, persistentTid, &persistentSerialNum); WRITE_PERSISTENT_STATE_ORDERED_UNLOCK; if (Debug_persistent_print) { elog(Persistent_DebugPrintLevel(), "Persistent relation: Add '%s', in state 'Created', serial number " INT64_FORMAT " at TID %s", PersistentFileSysObjName_ObjectName(&fsObjName), persistentSerialNum, ItemPointerToString(persistentTid)); } }