/* * performs all necessary setup required for Greenplum Database mode. * * This includes cdblink_setup() and initializing the Motion Layer. */ void cdb_setup(void) { elog(DEBUG1, "Initializing Greenplum components..."); cdblink_setup(); /* If gp_role is UTILITY, skip this call. */ if (Gp_role != GP_ROLE_UTILITY) { /* Initialize the Motion Layer IPC subsystem. */ InitMotionLayerIPC(); } if (Gp_role == GP_ROLE_DISPATCH) { /* check mirrored entry db configuration */ buildMirrorQDDefinition(); if (isQDMirroringPendingCatchup()) { /* * Do a checkpoint to cause a checkpoint xlog record to * to be written and force the QD mirror to get * synchronized. */ RequestCheckpoint(true, false); } /* * This call will generate a warning if master mirroring * is not synchronized. */ QDMirroringWriteCheck(); } }
FaultInjectorType_e FaultInjector_InjectFaultIfSet( FaultInjectorIdentifier_e identifier, DDLStatement_e ddlStatement, char* databaseName, char* tableName) { FaultInjectorEntry_s *entryShared, localEntry, *entryLocal = &localEntry; char databaseNameLocal[NAMEDATALEN]; char tableNameLocal[NAMEDATALEN]; int ii = 0; int cnt = 3600; /* * Return immediately if no fault has been injected ever. It is * important to not touch the spinlock, especially if this is the * postmaster process. If one of the backend processes dies while * holding the spin lock, and postmaster comes here before resetting * the shared memory, it waits without holder process and eventually * goes into PANIC. Also this saves a few cycles to acquire the spin * lock and look into the shared hash table. * * Although this is a race condition without lock, a false negative is * ok given this framework is purely for dev/testing. */ if (faultInjectorShmem->faultInjectorSlots == 0) return FALSE; getFileRepRoleAndState(&fileRepRole, &segmentState, &dataState, NULL, NULL); FiLockAcquire(); entryShared = FaultInjector_LookupHashEntry(identifier); if (entryShared != NULL) memcpy(entryLocal, entryShared, sizeof(FaultInjectorEntry_s)); FiLockRelease(); /* Verify if fault injection is set */ if (entryShared == NULL) /* fault injection is not set */ return FALSE; if (entryLocal->ddlStatement != ddlStatement) /* fault injection is not set for the specified DDL */ return FALSE; snprintf(databaseNameLocal, sizeof(databaseNameLocal), "%s", databaseName); if (strcmp(entryLocal->databaseName, databaseNameLocal) != 0) /* fault injection is not set for the specified database name */ return FALSE; snprintf(tableNameLocal, sizeof(tableNameLocal), "%s", tableName); if (strcmp(entryLocal->tableName, tableNameLocal) != 0) /* fault injection is not set for the specified table name */ return FALSE; if (entryLocal->faultInjectorState == FaultInjectorStateTriggered || entryLocal->faultInjectorState == FaultInjectorStateCompleted || entryLocal->faultInjectorState == FaultInjectorStateFailed) { /* fault injection was already executed */ return FALSE; } /* Update the injection fault entry in hash table */ if (entryLocal->occurrence != FILEREP_UNDEFINED) { if (entryLocal->occurrence > 1) { entryLocal->occurrence--; FaultInjector_UpdateHashEntry(entryLocal); return FALSE; } entryLocal->faultInjectorState = FaultInjectorStateTriggered; FaultInjector_UpdateHashEntry(entryLocal); } /* Inject fault */ switch (entryLocal->faultInjectorType) { case FaultInjectorTypeNotSpecified: break; case FaultInjectorTypeSleep: ereport(LOG, (errmsg("fault triggered, fault name:'%s' fault type:'%s' ", FaultInjectorIdentifierEnumToString[entryLocal->faultInjectorIdentifier], FaultInjectorTypeEnumToString[entryLocal->faultInjectorType]))); pg_usleep(entryLocal->sleepTime * 1000000L); break; case FaultInjectorTypeFault: switch (entryLocal->faultInjectorIdentifier) { case FileRepConsumer: case FileRepConsumerVerification: case FileRepSender: case FileRepReceiver: case FileRepResync: case FileRepResyncInProgress: case FileRepResyncWorker: case FileRepResyncWorkerRead: case FileRepTransitionToInResyncMirrorReCreate: case FileRepTransitionToInResyncMarkReCreated: case FileRepTransitionToInResyncMarkCompleted: case FileRepTransitionToInSyncBegin: case FileRepTransitionToInSync: case FileRepTransitionToInSyncMarkCompleted: case FileRepTransitionToInSyncBeforeCheckpoint: case FileRepIsOperationCompleted: FileRep_SetSegmentState(SegmentStateFault, FaultTypeMirror); break; case FileRepTransitionToChangeTracking: FileRep_SetPostmasterReset(); break; default: FileRep_SetSegmentState(SegmentStateFault, FaultTypeIO); break; } ereport(LOG, (errmsg("fault triggered, fault name:'%s' fault type:'%s' ", FaultInjectorIdentifierEnumToString[entryLocal->faultInjectorIdentifier], FaultInjectorTypeEnumToString[entryLocal->faultInjectorType]))); break; case FaultInjectorTypeFatal: /* * If it's one time occurrence then disable the fault before it's * actually triggered because this fault errors out the transaction * and hence we wont get a chance to disable it or put it in completed * state. */ if (entryLocal->occurrence != FILEREP_UNDEFINED) { entryLocal->faultInjectorState = FaultInjectorStateCompleted; FaultInjector_UpdateHashEntry(entryLocal); } ereport(FATAL, (errmsg("fault triggered, fault name:'%s' fault type:'%s' ", FaultInjectorIdentifierEnumToString[entryLocal->faultInjectorIdentifier], FaultInjectorTypeEnumToString[entryLocal->faultInjectorType]))); break; case FaultInjectorTypePanic: /* * If it's one time occurrence then disable the fault before it's * actually triggered because this fault errors out the transaction * and hence we wont get a chance to disable it or put it in completed * state. For PANIC it may be unnecessary though. */ if (entryLocal->occurrence != FILEREP_UNDEFINED) { entryLocal->faultInjectorState = FaultInjectorStateCompleted; FaultInjector_UpdateHashEntry(entryLocal); } ereport(PANIC, (errmsg("fault triggered, fault name:'%s' fault type:'%s' ", FaultInjectorIdentifierEnumToString[entryLocal->faultInjectorIdentifier], FaultInjectorTypeEnumToString[entryLocal->faultInjectorType]))); break; case FaultInjectorTypeError: /* * If it's one time occurrence then disable the fault before it's * actually triggered because this fault errors out the transaction * and hence we wont get a chance to disable it or put it in completed * state. */ if (entryLocal->occurrence != FILEREP_UNDEFINED) { entryLocal->faultInjectorState = FaultInjectorStateCompleted; FaultInjector_UpdateHashEntry(entryLocal); } ereport(ERROR, (errmsg("fault triggered, fault name:'%s' fault type:'%s' ", FaultInjectorIdentifierEnumToString[entryLocal->faultInjectorIdentifier], FaultInjectorTypeEnumToString[entryLocal->faultInjectorType]))); break; case FaultInjectorTypeInfiniteLoop: ereport(LOG, (errmsg("fault triggered, fault name:'%s' fault type:'%s' ", FaultInjectorIdentifierEnumToString[entryLocal->faultInjectorIdentifier], FaultInjectorTypeEnumToString[entryLocal->faultInjectorType]))); if (entryLocal->faultInjectorIdentifier == FileRepImmediateShutdownRequested) cnt = entryLocal->sleepTime; for (ii=0; ii < cnt; ii++) { pg_usleep(1000000L); // sleep for 1 sec (1 sec * 3600 = 1 hour) getFileRepRoleAndState(NULL, &segmentState, NULL, NULL, NULL); if ((entryLocal->faultInjectorIdentifier != FileRepImmediateShutdownRequested) && (segmentState == SegmentStateShutdownFilerepBackends || segmentState == SegmentStateImmediateShutdown || segmentState == SegmentStateShutdown || IsFtsShudownRequested())) { break; } } break; case FaultInjectorTypeDataCorruption: ereport(LOG, (errmsg("fault triggered, fault name:'%s' fault type:'%s' ", FaultInjectorIdentifierEnumToString[entryLocal->faultInjectorIdentifier], FaultInjectorTypeEnumToString[entryLocal->faultInjectorType]))); break; case FaultInjectorTypeSuspend: { FaultInjectorEntry_s *entry; ereport(LOG, (errmsg("fault triggered, fault name:'%s' fault type:'%s' ", FaultInjectorIdentifierEnumToString[entryLocal->faultInjectorIdentifier], FaultInjectorTypeEnumToString[entryLocal->faultInjectorType]))); while ((entry = FaultInjector_LookupHashEntry(entryLocal->faultInjectorIdentifier)) != NULL && entry->faultInjectorType != FaultInjectorTypeResume) { pg_usleep(1000000L); // 1 sec } if (entry != NULL) { ereport(LOG, (errmsg("fault triggered, fault name:'%s' fault type:'%s' ", FaultInjectorIdentifierEnumToString[entryLocal->faultInjectorIdentifier], FaultInjectorTypeEnumToString[entry->faultInjectorType]))); } else { ereport(LOG, (errmsg("fault 'NULL', fault name:'%s' ", FaultInjectorIdentifierEnumToString[entryLocal->faultInjectorIdentifier]))); /* * Since the entry is gone already, we should NOT update * the entry below. (There could be other places in this * function that are under the same situation, but I'm too * tired to look for them...) */ return entryLocal->faultInjectorType; } break; } case FaultInjectorTypeSkip: ereport(LOG, (errmsg("fault triggered, fault name:'%s' fault type:'%s' ", FaultInjectorIdentifierEnumToString[entryLocal->faultInjectorIdentifier], FaultInjectorTypeEnumToString[entryLocal->faultInjectorType]))); break; case FaultInjectorTypeMemoryFull: { char *buffer = NULL; ereport(LOG, (errmsg("fault triggered, fault name:'%s' fault type:'%s' ", FaultInjectorIdentifierEnumToString[entryLocal->faultInjectorIdentifier], FaultInjectorTypeEnumToString[entryLocal->faultInjectorType]))); buffer = (char*) palloc(BLCKSZ); while (buffer != NULL) { buffer = (char*) palloc(BLCKSZ); } break; } case FaultInjectorTypeReset: case FaultInjectorTypeStatus: ereport(LOG, (errmsg("unexpected error, fault triggered, fault name:'%s' fault type:'%s' ", FaultInjectorIdentifierEnumToString[entryLocal->faultInjectorIdentifier], FaultInjectorTypeEnumToString[entryLocal->faultInjectorType]))); Assert(0); break; case FaultInjectorTypeResume: break; case FaultInjectorTypeSegv: { *(int *) 0 = 1234; break; } case FaultInjectorTypeInterrupt: { /* * The place where this type of fault is injected must have * has HOLD_INTERRUPTS() .. RESUME_INTERRUPTS() around it, otherwise * the interrupt could be handled inside the fault injector itself */ ereport(LOG, (errmsg("fault triggered, fault name:'%s' fault type:'%s' ", FaultInjectorIdentifierEnumToString[entryLocal->faultInjectorIdentifier], FaultInjectorTypeEnumToString[entryLocal->faultInjectorType]))); InterruptPending = true; QueryCancelPending = true; break; } case FaultInjectorTypeCheckpointAndPanic: { if (entryLocal->occurrence != FILEREP_UNDEFINED) { entryLocal->faultInjectorState = FaultInjectorStateCompleted; FaultInjector_UpdateHashEntry(entryLocal); } RequestCheckpoint(true, false); ereport(PANIC, (errmsg("fault triggered, fault name:'%s' fault type:'%s' ", FaultInjectorIdentifierEnumToString[entryLocal->faultInjectorIdentifier], FaultInjectorTypeEnumToString[entryLocal->faultInjectorType]))); break; } default: ereport(LOG, (errmsg("unexpected error, fault triggered, fault name:'%s' fault type:'%s' ", FaultInjectorIdentifierEnumToString[entryLocal->faultInjectorIdentifier], FaultInjectorTypeEnumToString[entryLocal->faultInjectorType]))); Assert(0); break; } if (entryLocal->occurrence != FILEREP_UNDEFINED) { entryLocal->faultInjectorState = FaultInjectorStateCompleted; } FaultInjector_UpdateHashEntry(entryLocal); return (entryLocal->faultInjectorType); }
/* * Drop a table space * * Be careful to check that the tablespace is empty. */ void DropTableSpace(DropTableSpaceStmt *stmt) { #ifdef HAVE_SYMLINK char *tablespacename = stmt->tablespacename; HeapScanDesc scandesc; Relation rel; HeapTuple tuple; ScanKeyData entry[1]; Oid tablespaceoid; /* * Find the target tuple */ rel = heap_open(TableSpaceRelationId, RowExclusiveLock); ScanKeyInit(&entry[0], Anum_pg_tablespace_spcname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(tablespacename)); scandesc = heap_beginscan_catalog(rel, 1, entry); tuple = heap_getnext(scandesc, ForwardScanDirection); if (!HeapTupleIsValid(tuple)) { if (!stmt->missing_ok) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("tablespace \"%s\" does not exist", tablespacename))); } else { ereport(NOTICE, (errmsg("tablespace \"%s\" does not exist, skipping", tablespacename))); /* XXX I assume I need one or both of these next two calls */ heap_endscan(scandesc); heap_close(rel, NoLock); } return; } tablespaceoid = HeapTupleGetOid(tuple); /* Must be tablespace owner */ if (!pg_tablespace_ownercheck(tablespaceoid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE, tablespacename); /* Disallow drop of the standard tablespaces, even by superuser */ if (tablespaceoid == GLOBALTABLESPACE_OID || tablespaceoid == DEFAULTTABLESPACE_OID) aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, tablespacename); /* DROP hook for the tablespace being removed */ InvokeObjectDropHook(TableSpaceRelationId, tablespaceoid, 0); /* * Remove the pg_tablespace tuple (this will roll back if we fail below) */ simple_heap_delete(rel, &tuple->t_self); heap_endscan(scandesc); /* * Remove any comments or security labels on this tablespace. */ DeleteSharedComments(tablespaceoid, TableSpaceRelationId); DeleteSharedSecurityLabel(tablespaceoid, TableSpaceRelationId); /* * Remove dependency on owner. */ deleteSharedDependencyRecordsFor(TableSpaceRelationId, tablespaceoid, 0); /* * Acquire TablespaceCreateLock to ensure that no TablespaceCreateDbspace * is running concurrently. */ LWLockAcquire(TablespaceCreateLock, LW_EXCLUSIVE); /* * Try to remove the physical infrastructure. */ if (!destroy_tablespace_directories(tablespaceoid, false)) { /* * Not all files deleted? However, there can be lingering empty files * in the directories, left behind by for example DROP TABLE, that * have been scheduled for deletion at next checkpoint (see comments * in mdunlink() for details). We could just delete them immediately, * but we can't tell them apart from important data files that we * mustn't delete. So instead, we force a checkpoint which will clean * out any lingering files, and try again. * * XXX On Windows, an unlinked file persists in the directory listing * until no process retains an open handle for the file. The DDL * commands that schedule files for unlink send invalidation messages * directing other PostgreSQL processes to close the files. DROP * TABLESPACE should not give up on the tablespace becoming empty * until all relevant invalidation processing is complete. */ RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT); if (!destroy_tablespace_directories(tablespaceoid, false)) { /* Still not empty, the files must be important then */ ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("tablespace \"%s\" is not empty", tablespacename))); } } /* Record the filesystem change in XLOG */ { xl_tblspc_drop_rec xlrec; xlrec.ts_id = tablespaceoid; XLogBeginInsert(); XLogRegisterData((char *) &xlrec, sizeof(xl_tblspc_drop_rec)); (void) XLogInsert(RM_TBLSPC_ID, XLOG_TBLSPC_DROP); } /* * Note: because we checked that the tablespace was empty, there should be * no need to worry about flushing shared buffers or free space map * entries for relations in the tablespace. */ /* * Force synchronous commit, to minimize the window between removing the * files on-disk and marking the transaction committed. It's not great * that there is any window at all, but definitely we don't want to make * it larger than necessary. */ ForceSyncCommit(); /* * Allow TablespaceCreateDbspace again. */ LWLockRelease(TablespaceCreateLock); /* We keep the lock on pg_tablespace until commit */ heap_close(rel, NoLock); #else /* !HAVE_SYMLINK */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("tablespaces are not supported on this platform"))); #endif /* HAVE_SYMLINK */ }