/* * Verify that a freshly-read page looks sane. */ void gistcheckpage(Relation rel, Buffer buf) { Page page = BufferGetPage(buf); /* * ReadBuffer verifies that every newly-read page passes * PageHeaderIsValid, which means it either contains a reasonably sane * page header or is all-zero. We have to defend against the all-zero * case, however. */ if (PageIsNew(page)) ereport(ERROR, (errcode(ERRCODE_INDEX_CORRUPTED), errmsg("index \"%s\" contains unexpected zero page at block %u", RelationGetRelationName(rel), BufferGetBlockNumber(buf)), errhint("Please REINDEX it."), errSendAlert(true))); /* * Additionally check that the special area looks sane. */ if (((PageHeader) (page))->pd_special != (BLCKSZ - MAXALIGN(sizeof(GISTPageOpaqueData)))) ereport(ERROR, (errcode(ERRCODE_INDEX_CORRUPTED), errmsg("index \"%s\" contains corrupted page at block %u", RelationGetRelationName(rel), BufferGetBlockNumber(buf)), errhint("Please REINDEX it."), errSendAlert(true))); }
int FileRepConnServer_StartListener( char *hostAddress, int portLocal) { int status = STATUS_OK; int i; for (i=0; i < FILEREP_MAX_LISTEN; i++) { listenSocket[i] = -1; } /* NOTE check if family AF_UNIX has to be considered as well */ status = StreamServerPort( AF_UNSPEC, hostAddress, (unsigned short) portLocal, NULL, listenSocket, FILEREP_MAX_LISTEN); if (status != STATUS_OK) { ereport(WARNING, (errcode_for_socket_access(), errmsg("could not start listener, host:'%s' port:'%d': %m", hostAddress, portLocal), errSendAlert(true), FileRep_errcontext())); } return status; }
void FtsHandleNetFailure(SegmentDatabaseDescriptor ** segDB, int numOfFailed) { elog(LOG, "FtsHandleNetFailure: numOfFailed %d", numOfFailed); ereport(ERROR, (errmsg_internal("MPP detected %d segment failures, system is reconnected", numOfFailed), errSendAlert(true))); }
int FileRepConnClient_EstablishConnection( char *hostAddress, int port, bool reportError) { int status = STATUS_OK; char portbuf[11]; char timeoutbuf[11]; const char *keys[5]; const char *vals[5]; /* FileRepConnClient_CloseConnection();*/ snprintf(portbuf, sizeof(portbuf), "%d", port); snprintf(timeoutbuf, sizeof(timeoutbuf), "%d", gp_segment_connect_timeout); keys[0] = "host"; vals[0] = hostAddress; keys[1] = "port"; vals[1] = portbuf; keys[2] = "dbname"; vals[2] = "postgres"; keys[3] = "connect_timeout"; vals[3] = timeoutbuf; keys[4] = NULL; vals[4] = NULL; filerep_conn = PQconnectdbParams(keys, vals, false); if (PQstatus(filerep_conn) != CONNECTION_OK) { if (reportError || Debug_filerep_print) ereport(WARNING, (errcode_for_socket_access(), errmsg("could not establish connection with server, host:'%s' port:'%d' err:'%s' : %m", hostAddress, port, PQerrorMessage(filerep_conn)), errSendAlert(true), FileRep_errcontext())); status = STATUS_ERROR; if (filerep_conn) { PQfinish(filerep_conn); filerep_conn = NULL; } } /* NOTE Handle error message see ftsprobe.c */ return status; }
/* * Re-Configure the system: if someone has noticed that the status * version has been updated, they call this to verify that they've got * the right configuration. * * NOTE: This *always* destroys gangs. And also attempts to inform the * fault-prober to do a full scan. */ void FtsReConfigureMPP(bool create_new_gangs) { /* need to scan to pick up the latest view */ detectFailedConnections(); local_fts_statusVersion = ftsProbeInfo->fts_statusVersion; ereport(LOG, (errmsg_internal("FTS: reconfiguration is in progress"), errSendAlert(true))); disconnectAndDestroyAllGangs(); /* Caller should throw an error. */ return; }
/* * ProcessRoleGUC -- * We now process pg_authid.rolconfig separately from InitializeSessionUserId, * since it's too early to access toast table before initializing all * relcaches in phase3. */ static void ProcessRoleGUC(void) { cqContext *pcqCtx; Oid roleId; HeapTuple roleTup; Datum datum; bool isnull; /* This should have been set by now */ roleId = GetUserId(); Assert(OidIsValid(roleId)); pcqCtx = caql_beginscan( NULL, cql("SELECT * FROM pg_authid " " WHERE oid = :1", ObjectIdGetDatum(roleId))); roleTup = caql_getnext(pcqCtx); if (!HeapTupleIsValid(roleTup)) ereport(FATAL, (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), errmsg("role %u does not exist", roleId), errSendAlert(false))); /* * Set up user-specific configuration variables. This is a good place to * do it so we don't have to read pg_authid twice during session startup. */ datum = caql_getattr(pcqCtx, Anum_pg_authid_rolconfig, &isnull); if (!isnull) { ArrayType *a = DatumGetArrayTypeP(datum); /* * We process all the options at SUSET level. We assume that the * right to insert an option into pg_authid was checked when it was * inserted. */ ProcessGUCArray(a, PGC_SUSET, PGC_S_USER, GUC_ACTION_SET); } caql_endscan(pcqCtx); }
bool QDMirroringWriteCheck(void) { bool giveWarning = false; QDMIRRORDisabledReason disabledReason = QDMIRROR_DISABLEDREASON_NONE; struct timeval lastLogTimeVal = {0, 0}; if (ftsQDMirrorInfo == NULL) return false; // Don't know yet. LWLockAcquire(ftsQDMirrorLock, LW_EXCLUSIVE); if (ftsQDMirrorInfo->state == QDMIRROR_STATE_SYNCHRONIZED) { LWLockRelease(ftsQDMirrorLock); return true; } if (ftsQDMirrorInfo->QDMirroringNotSynchronizedWarningGiven == false && ftsQDMirrorInfo->state == QDMIRROR_STATE_DISABLED) { giveWarning = true; ftsQDMirrorInfo->QDMirroringNotSynchronizedWarningGiven = true; disabledReason = ftsQDMirrorInfo->disabledReason; lastLogTimeVal = ftsQDMirrorInfo->lastLogTimeVal; } LWLockRelease(ftsQDMirrorLock); if (giveWarning) { char logTimeStr[100]; QDMirroringFormatTime(logTimeStr, sizeof(logTimeStr), &lastLogTimeVal); ereport(LOG, (errcode(ERRCODE_GP_INTERCONNECTION_ERROR), errmsg("Master mirroring is not synchronized as of %s (%s). " "The GPDB system is currently not highly-available", logTimeStr, QDMirroringDisabledReasonToString(disabledReason)), errSendAlert(true))); } return false; }
/* * FtsHandleGangConnectionFailure is called by createGang during * creating connections return true if error need to be thrown */ bool FtsHandleGangConnectionFailure(SegmentDatabaseDescriptor * segdbDesc, int size) { int i; bool dtx_active; bool reportError = false; bool realFaultFound = false; bool forceRescan=true; for (i = 0; i < size; i++) { if (PQstatus(segdbDesc[i].conn) != CONNECTION_OK) { CdbComponentDatabaseInfo *segInfo = segdbDesc[i].segment_database_info; elog(DEBUG2, "FtsHandleGangConnectionFailure: looking for real fault on segment dbid %d", segInfo->dbid); if (!FtsTestConnection(segInfo, forceRescan)) { elog(DEBUG2, "found fault with segment dbid %d", segInfo->dbid); realFaultFound = true; /* that at least one fault exists is enough, for now */ break; } forceRescan = false; /* only force the rescan on the first call. */ } } if (!realFaultFound) { /* If we successfully tested the gang and didn't notice a * failure, our caller must've seen some kind of transient * failure when the gang was originally constructed ... */ elog(DEBUG2, "FtsHandleGangConnectionFailure: no real fault found!"); return false; } if (!isFTSEnabled()) { return false; } ereport(LOG, (errmsg_internal("FTS: reconfiguration is in progress"))); forceRescan = true; for (i = 0; i < size; i++) { CdbComponentDatabaseInfo *segInfo = segdbDesc[i].segment_database_info; if (PQstatus(segdbDesc[i].conn) != CONNECTION_OK) { if (!FtsTestConnection(segInfo, forceRescan)) { ereport(LOG, (errmsg_internal("FTS: found bad segment with dbid %d", segInfo->dbid), errSendAlert(true))); /* probe process has already marked segment down. */ } forceRescan = false; /* only force rescan on first call. */ } } if (gangsExist()) { reportError = true; disconnectAndDestroyAllGangs(); } /* * KLUDGE: Do not error out if we are attempting a DTM protocol retry */ if (DistributedTransactionContext == DTX_CONTEXT_QD_RETRY_PHASE_2) { return false; } /* is there a transaction active ? */ dtx_active = isCurrentDtxActive(); /* When the error is raised, it will abort the current DTM transaction */ if (dtx_active) { elog((Debug_print_full_dtm ? LOG : DEBUG5), "FtsHandleGangConnectionFailure found an active DTM transaction (returning true)."); return true; } /* * error out if this sets read only flag, at this stage the read only * transaction checking has passed, so error out, but do not error out if * tm is in recovery */ if ((*ftsReadOnlyFlag && !isTMInRecovery()) || reportError) return true; elog((Debug_print_full_dtm ? LOG : DEBUG5), "FtsHandleGangConnectionFailure returning false."); return false; }
/* -------------------------------- * InitPostgres * Initialize POSTGRES. * * The database can be specified by name, using the in_dbname parameter, or by * OID, using the dboid parameter. In the latter case, the computed database * name is passed out to the caller as a palloc'ed string in out_dbname. * * In bootstrap mode no parameters are used. * * The return value indicates whether the userID is a superuser. (That * can only be tested inside a transaction, so we want to do it during * the startup transaction rather than doing a separate one in postgres.c.) * * As of PostgreSQL 8.2, we expect InitProcess() was already called, so we * already have a PGPROC struct ... but it's not filled in yet. * * Note: * Be very careful with the order of calls in the InitPostgres function. * -------------------------------- */ bool InitPostgres(const char *in_dbname, Oid dboid, const char *username, char **out_dbname) { bool bootstrap = IsBootstrapProcessingMode(); bool autovacuum = IsAutoVacuumProcess(); bool am_superuser; char *fullpath; char dbname[NAMEDATALEN]; /* * Set up the global variables holding database id and path. But note we * won't actually try to touch the database just yet. * * We take a shortcut in the bootstrap case, otherwise we have to look up * the db name in pg_database. */ if (bootstrap) { MyDatabaseId = TemplateDbOid; MyDatabaseTableSpace = DEFAULTTABLESPACE_OID; } else { /* * Find tablespace of the database we're about to open. Since we're * not yet up and running we have to use one of the hackish * FindMyDatabase variants, which look in the flat-file copy of * pg_database. * * If the in_dbname param is NULL, lookup database by OID. */ if (in_dbname == NULL) { if (!FindMyDatabaseByOid(dboid, dbname, &MyDatabaseTableSpace)) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database %u does not exist", dboid), errSendAlert(false))); MyDatabaseId = dboid; /* pass the database name to the caller */ *out_dbname = pstrdup(dbname); } else { if (!FindMyDatabase(in_dbname, &MyDatabaseId, &MyDatabaseTableSpace)) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", in_dbname), errOmitLocation(true), errSendAlert(false))); /* our database name is gotten from the caller */ strlcpy(dbname, in_dbname, NAMEDATALEN); } } fullpath = GetDatabasePath(MyDatabaseId, MyDatabaseTableSpace); SetDatabasePath(fullpath); /* * Finish filling in the PGPROC struct, and add it to the ProcArray. (We * need to know MyDatabaseId before we can do this, since it's entered * into the PGPROC struct.) * * Once I have done this, I am visible to other backends! */ InitProcessPhase2(); // get temporary directory for QD if (!bootstrap && Gp_role == GP_ROLE_DISPATCH) { if (get_tmpdir_from_rm) { getLocalTmpDirFromMasterRM(); } else { getLocalTmpDirFromMasterConfig(gp_session_id); elog(LOG, "getLocalTmpDirFromMasterConfig session_id:%d tmpdir:%s", gp_session_id, LocalTempPath); } } /* Initialize SessionState entry */ SessionState_Init(); /* Initialize memory protection */ GPMemoryProtect_Init(); /* * Initialize my entry in the shared-invalidation manager's array of * per-backend data. * * Sets up MyBackendId, a unique backend identifier. */ MyBackendId = InvalidBackendId; SharedInvalBackendInit(false); if (MyBackendId > MaxBackends || MyBackendId <= 0) elog(FATAL, "bad backend id: %d", MyBackendId); /* Now that we have a BackendId, we can participate in ProcSignal */ ProcSignalInit(MyBackendId); /* * bufmgr needs another initialization call too */ InitBufferPoolBackend(); /* * Initialize local process's access to XLOG. In bootstrap case we may * skip this since StartupXLOG() was run instead. */ if (!bootstrap) InitXLOGAccess(); /* * Initialize the relation cache and the system catalog caches. Note that * no catalog access happens here; we only set up the hashtable structure. * We must do this before starting a transaction because transaction abort * would try to touch these hashtables. */ RelationCacheInitialize(); InitCatalogCache(); /* Initialize portal manager */ EnablePortalManager(); /* Initialize stats collection --- must happen before first xact */ if (!bootstrap) pgstat_initialize(); /* * Set up process-exit callback to do pre-shutdown cleanup. This has to * be after we've initialized all the low-level modules like the buffer * manager, because during shutdown this has to run before the low-level * modules start to close down. On the other hand, we want it in place * before we begin our first transaction --- if we fail during the * initialization transaction, as is entirely possible, we need the * AbortTransaction call to clean up. */ on_shmem_exit(ShutdownPostgres, 0); /* * Start a new transaction here before first access to db, and get a * snapshot. We don't have a use for the snapshot itself, but we're * interested in the secondary effect that it sets RecentGlobalXmin. */ if (!bootstrap) { StartTransactionCommand(); (void) GetTransactionSnapshot(); } /* * Now that we have a transaction, we can take locks. Take a writer's * lock on the database we are trying to connect to. If there is a * concurrently running DROP DATABASE on that database, this will block us * until it finishes (and has updated the flat file copy of pg_database). * * Note that the lock is not held long, only until the end of this startup * transaction. This is OK since we are already advertising our use of * the database in the PGPROC array; anyone trying a DROP DATABASE after * this point will see us there. * * Note: use of RowExclusiveLock here is reasonable because we envision * our session as being a concurrent writer of the database. If we had a * way of declaring a session as being guaranteed-read-only, we could use * AccessShareLock for such sessions and thereby not conflict against * CREATE DATABASE. */ if (!bootstrap) { if (MyDatabaseId == TemplateDbOid) LockSharedObject(DatabaseRelationId, MyDatabaseId, 0, AccessShareLock); else LockSharedObject(DatabaseRelationId, MyDatabaseId, 0, RowExclusiveLock); } /* * Recheck the flat file copy of pg_database to make sure the target * database hasn't gone away. If there was a concurrent DROP DATABASE, * this ensures we will die cleanly without creating a mess. */ if (!bootstrap) { Oid dbid2; Oid tsid2; if (!FindMyDatabase(dbname, &dbid2, &tsid2) || dbid2 != MyDatabaseId || tsid2 != MyDatabaseTableSpace) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname), errdetail("It seems to have just been dropped or renamed."))); } /* * Now we should be able to access the database directory safely. Verify * it's there and looks reasonable. */ if (!bootstrap) { if (access(fullpath, F_OK) == -1) { if (errno == ENOENT) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname), errdetail("The database subdirectory \"%s\" is missing.", fullpath))); else ereport(FATAL, (errcode_for_file_access(), errmsg("could not access directory \"%s\": %m", fullpath))); } ValidatePgVersion(fullpath); } /* * It's now possible to do real access to the system catalogs. * * Load relcache entries for the system catalogs. This must create at * least the minimum set of "nailed-in" cache entries. */ RelationCacheInitializePhase2(); /* * Figure out our postgres user id, and see if we are a superuser. * * In standalone mode and in the autovacuum process, we use a fixed id, * otherwise we figure it out from the authenticated user name. */ if (bootstrap || autovacuum) { InitializeSessionUserIdStandalone(); am_superuser = true; } else if (!IsUnderPostmaster) { InitializeSessionUserIdStandalone(); am_superuser = true; if (!ThereIsAtLeastOneRole()) ereport(WARNING, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("no roles are defined in this database system"), errhint("You should immediately run CREATE USER \"%s\" CREATEUSER;.", username))); } else { /* normal multiuser case */ InitializeSessionUserId(username); am_superuser = superuser(); } /* set up ACL framework (so CheckMyDatabase can check permissions) */ initialize_acl(); /* * Read the real pg_database row for our database, check permissions and * set up database-specific GUC settings. We can't do this until all the * database-access infrastructure is up. (Also, it wants to know if the * user is a superuser, so the above stuff has to happen first.) */ if (!bootstrap) CheckMyDatabase(dbname, am_superuser); /* * Check a normal user hasn't connected to a superuser reserved slot. */ if (!am_superuser && ReservedBackends > 0 && !HaveNFreeProcs(ReservedBackends)) ereport(FATAL, (errcode(ERRCODE_TOO_MANY_CONNECTIONS), errmsg("connection limit exceeded for non-superusers"), errOmitLocation(true), errSendAlert(true))); /* * Initialize various default states that can't be set up until we've * selected the active user and gotten the right GUC settings. */ /* set default namespace search path */ InitializeSearchPath(); /* initialize client encoding */ InitializeClientEncoding(); /* report this backend in the PgBackendStatus array */ if (!bootstrap) pgstat_bestart(); /* * MPP package setup * * Primary function is to establish connctions to the qExecs. * This is SKIPPED when the database is in bootstrap mode or * Is not UnderPostmaster. */ if (!bootstrap && IsUnderPostmaster) { cdb_setup(); on_proc_exit( cdb_cleanup, 0 ); } /* close the transaction we started above */ if (!bootstrap) CommitTransactionCommand(); return am_superuser; }
/* * CheckMyDatabase -- fetch information from the pg_database entry for our DB */ static void CheckMyDatabase(const char *name, bool am_superuser) { HeapTuple tup; Form_pg_database dbform; /* Fetch our real pg_database row */ tup = SearchSysCache(DATABASEOID, ObjectIdGetDatum(MyDatabaseId), 0, 0, 0); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for database %u", MyDatabaseId); dbform = (Form_pg_database) GETSTRUCT(tup); /* This recheck is strictly paranoia */ if (strcmp(name, NameStr(dbform->datname)) != 0) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" has disappeared from pg_database", name), errdetail("Database OID %u now seems to belong to \"%s\".", MyDatabaseId, NameStr(dbform->datname)))); /* * Check permissions to connect to the database. * * These checks are not enforced when in standalone mode, so that there is * a way to recover from disabling all access to all databases, for * example "UPDATE pg_database SET datallowconn = false;". * * We do not enforce them for the autovacuum worker processes either. */ if (IsUnderPostmaster && !IsAutoVacuumProcess()) { /* * Check that the database is currently allowing connections. * (exception during upgrade_mode) */ if (gp_upgrade_mode && !dbform->datallowconn) elog(INFO, "Connecting to no-connection db in upgrade mode."); if (!dbform->datallowconn && !gp_upgrade_mode) ereport(FATAL, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("database \"%s\" is not currently accepting connections", name), errOmitLocation(true), errSendAlert(false))); /* * Check privilege to connect to the database. (The am_superuser test * is redundant, but since we have the flag, might as well check it * and save a few cycles.) */ if (!am_superuser && pg_database_aclcheck(MyDatabaseId, GetUserId(), ACL_CONNECT) != ACLCHECK_OK) ereport(FATAL, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied for database \"%s\"", name), errdetail("User does not have CONNECT privilege."), errOmitLocation(true), errSendAlert(false))); /* * Check connection limit for this database. * * There is a race condition here --- we create our PGPROC before * checking for other PGPROCs. If two backends did this at about the * same time, they might both think they were over the limit, while * ideally one should succeed and one fail. Getting that to work * exactly seems more trouble than it is worth, however; instead we * just document that the connection limit is approximate. */ if (dbform->datconnlimit >= 0 && !am_superuser && CountDBBackends(MyDatabaseId) > dbform->datconnlimit) ereport(FATAL, (errcode(ERRCODE_TOO_MANY_CONNECTIONS), errmsg("too many connections for database \"%s\"", name), errOmitLocation(true), errSendAlert(false))); } /* * OK, we're golden. Next to-do item is to save the encoding info out of * the pg_database tuple. */ if (GpIdentity.segindex == UNINITIALIZED_GP_IDENTITY_VALUE || GpIdentity.segindex == MASTER_CONTENT_ID) SetDatabaseEncoding(dbform->encoding); else SetDatabaseEncoding(MyProcPort->encoding); /* Record it as a GUC internal option, too */ SetConfigOption("server_encoding", GetDatabaseEncodingName(), PGC_INTERNAL, PGC_S_OVERRIDE); /* If we have no other source of client_encoding, use server encoding */ SetConfigOption("client_encoding", GetDatabaseEncodingName(), PGC_BACKEND, PGC_S_DEFAULT); /* Use the right encoding in translated messages */ #ifdef ENABLE_NLS pg_bind_textdomain_codeset(textdomain(NULL)); #endif /* * Lastly, set up any database-specific configuration variables. */ if (IsUnderPostmaster) { Datum datum; bool isnull; datum = SysCacheGetAttr(DATABASEOID, tup, Anum_pg_database_datconfig, &isnull); if (!isnull) { ArrayType *a = DatumGetArrayTypeP(datum); ProcessGUCArray(a, PGC_S_DATABASE); } } ReleaseSysCache(tup); }
/* * * FileRepAckPrimary_StartReceiver */ void FileRepAckPrimary_StartReceiver(void) { int status = STATUS_OK; struct timeval currentTime; pg_time_t beginTime = 0; pg_time_t endTime = 0; int retval = 0; FileRep_InsertConfigLogEntry("start receiver ack"); { char tmpBuf[FILEREP_MAX_LOG_DESCRIPTION_LEN]; snprintf(tmpBuf, sizeof(tmpBuf), "primary address(port) '%s(%d)' mirror address(port) '%s(%d)' ", fileRepPrimaryHostAddress, fileRepPrimaryPort, fileRepMirrorHostAddress, fileRepMirrorPort); FileRep_InsertConfigLogEntry(tmpBuf); } FileRepAckPrimary_ShmemReInit(); Insist(fileRepRole == FileRepPrimaryRole); if (filerep_inject_listener_fault) { status = STATUS_ERROR; ereport(WARNING, (errmsg("mirror failure, " "injected fault by guc filerep_inject_listener_fault, " "failover requested"), FileRep_errcontext())); FileRep_SetSegmentState(SegmentStateFault, FaultTypeMirror); FileRepSubProcess_SetState(FileRepStateFault); FileRepSubProcess_ProcessSignals(); return; } status = FileRepConnServer_StartListener( fileRepPrimaryHostAddress, fileRepPrimaryPort); gettimeofday(¤tTime, NULL); beginTime = (pg_time_t) currentTime.tv_sec; while (1) { if (status != STATUS_OK) { FileRep_SetSegmentState(SegmentStateFault, FaultTypeMirror); FileRepSubProcess_SetState(FileRepStateFault); } while (FileRepSubProcess_GetState() == FileRepStateFault) { FileRepSubProcess_ProcessSignals(); pg_usleep(50000L); /* 50 ms */ } if (FileRepSubProcess_GetState() == FileRepStateShutdown) { break; } PG_SETMASK(&BlockSig); retval = FileRepConnServer_Select(); PG_SETMASK(&UnBlockSig); gettimeofday(¤tTime, NULL); endTime = (pg_time_t) currentTime.tv_sec; if ((endTime - beginTime) > gp_segment_connect_timeout) { ereport(WARNING, (errmsg("mirror failure, " "no connection was established from client from mirror, " "primary address(port) '%s(%d)' mirror address(port) '%s(%d)' timeout reached '%d' " "failover requested", fileRepPrimaryHostAddress, fileRepPrimaryPort, fileRepMirrorHostAddress, fileRepMirrorPort, gp_segment_connect_timeout), errSendAlert(true), FileRep_errcontext())); status = STATUS_ERROR; continue; } /* * check and process any signals received * The routine returns TRUE if the received signal requests * process shutdown. */ if (FileRepSubProcess_ProcessSignals()) { continue; } if (retval < 0) { status = STATUS_ERROR; continue; } if (retval == 0) { continue; } Assert(retval > 0); status = FileRepConnServer_CreateConnection(); if (status != STATUS_OK) { continue; } status = FileRepConnServer_ReceiveStartupPacket(); if (status != STATUS_OK) { continue; } fileRepShmemArray[0]->state = FileRepStateInitialization; status = FileRepAckPrimary_RunReceiver(); } // while(1) FileRepConnServer_CloseConnection(); return; }
/* * PageIndexMultiDelete * * This routine handles the case of deleting multiple tuples from an * index page at once. It is considerably faster than a loop around * PageIndexTupleDelete ... however, the caller *must* supply the array * of item numbers to be deleted in item number order! */ void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems) { PageHeader phdr = (PageHeader) page; Offset pd_lower = phdr->pd_lower; Offset pd_upper = phdr->pd_upper; Offset pd_special = phdr->pd_special; itemIdSort itemidbase, itemidptr; ItemId lp; int nline, nused; int i; Size totallen; Offset upper; Size size; unsigned offset; int nextitm; OffsetNumber offnum; /* * If there aren't very many items to delete, then retail * PageIndexTupleDelete is the best way. Delete the items in reverse * order so we don't have to think about adjusting item numbers for * previous deletions. * * TODO: tune the magic number here */ if (nitems <= 2) { while (--nitems >= 0) PageIndexTupleDelete(page, itemnos[nitems]); return; } /* * As with PageRepairFragmentation, paranoia seems justified. */ if (pd_lower < SizeOfPageHeaderData || pd_lower > pd_upper || pd_upper > pd_special || pd_special > BLCKSZ || pd_special != MAXALIGN(pd_special)) ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), errmsg("corrupted page pointers: lower = %u, upper = %u, special = %u", pd_lower, pd_upper, pd_special), errSendAlert(true))); /* * Scan the item pointer array and build a list of just the ones we are * going to keep. Notice we do not modify the page yet, since we are * still validity-checking. */ nline = PageGetMaxOffsetNumber(page); itemidbase = (itemIdSort) palloc(sizeof(itemIdSortData) * nline); itemidptr = itemidbase; totallen = 0; nused = 0; nextitm = 0; for (offnum = 1; offnum <= nline; offnum++) { lp = PageGetItemId(page, offnum); size = ItemIdGetLength(lp); offset = ItemIdGetOffset(lp); if (offset < pd_upper || (offset + size) > pd_special || offset != MAXALIGN(offset)) ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), errmsg("corrupted item pointer: offset = %u, size = %u", offset, (unsigned int) size), errSendAlert(true))); if (nextitm < nitems && offnum == itemnos[nextitm]) { /* skip item to be deleted */ nextitm++; } else { itemidptr->offsetindex = nused; /* where it will go */ itemidptr->itemoff = offset; itemidptr->olditemid = *lp; itemidptr->alignedlen = MAXALIGN(size); totallen += itemidptr->alignedlen; itemidptr++; nused++; } } /* this will catch invalid or out-of-order itemnos[] */ if (nextitm != nitems) elog(ERROR, "incorrect index offsets supplied"); if (totallen > (Size) (pd_special - pd_lower)) ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), errmsg("corrupted item lengths: total %u, available space %u", (unsigned int) totallen, pd_special - pd_lower), errSendAlert(true))); /* sort itemIdSortData array into decreasing itemoff order */ qsort((char *) itemidbase, nused, sizeof(itemIdSortData), itemoffcompare); /* compactify page and install new itemids */ upper = pd_special; for (i = 0, itemidptr = itemidbase; i < nused; i++, itemidptr++) { lp = PageGetItemId(page, itemidptr->offsetindex + 1); upper -= itemidptr->alignedlen; memmove((char *) page + upper, (char *) page + itemidptr->itemoff, itemidptr->alignedlen); *lp = itemidptr->olditemid; lp->lp_off = upper; } phdr->pd_lower = SizeOfPageHeaderData + nused * sizeof(ItemIdData); phdr->pd_upper = upper; pfree(itemidbase); }
/* * PageIndexTupleDelete * * This routine does the work of removing a tuple from an index page. * * Unlike heap pages, we compact out the line pointer for the removed tuple. */ void PageIndexTupleDelete(Page page, OffsetNumber offnum) { PageHeader phdr = (PageHeader) page; char *addr; ItemId tup; Size size; unsigned offset; int nbytes; int offidx; int nline; /* * As with PageRepairFragmentation, paranoia seems justified. */ if (phdr->pd_lower < SizeOfPageHeaderData || phdr->pd_lower > phdr->pd_upper || phdr->pd_upper > phdr->pd_special || phdr->pd_special > BLCKSZ) ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), errmsg("corrupted page pointers: lower = %u, upper = %u, special = %u", phdr->pd_lower, phdr->pd_upper, phdr->pd_special), errSendAlert(true))); nline = PageGetMaxOffsetNumber(page); if ((int) offnum <= 0 || (int) offnum > nline) elog(ERROR, "invalid index offnum: %u", offnum); /* change offset number to offset index */ offidx = offnum - 1; tup = PageGetItemId(page, offnum); size = ItemIdGetLength(tup); offset = ItemIdGetOffset(tup); if (offset < phdr->pd_upper || (offset + size) > phdr->pd_special || offset != MAXALIGN(offset) || size != MAXALIGN(size)) ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), errmsg("corrupted item pointer: offset = %u, size = %u", offset, (unsigned int) size), errSendAlert(true))); /* * First, we want to get rid of the pd_linp entry for the index tuple. We * copy all subsequent linp's back one slot in the array. We don't use * PageGetItemId, because we are manipulating the _array_, not individual * linp's. */ nbytes = phdr->pd_lower - ((char *) &phdr->pd_linp[offidx + 1] - (char *) phdr); if (nbytes > 0) memmove((char *) &(phdr->pd_linp[offidx]), (char *) &(phdr->pd_linp[offidx + 1]), nbytes); /* * Now move everything between the old upper bound (beginning of tuple * space) and the beginning of the deleted tuple forward, so that space in * the middle of the page is left free. If we've just deleted the tuple * at the beginning of tuple space, then there's no need to do the copy * (and bcopy on some architectures SEGV's if asked to move zero bytes). */ /* beginning of tuple space */ addr = (char *) page + phdr->pd_upper; if (offset > phdr->pd_upper) memmove(addr + size, addr, (int) (offset - phdr->pd_upper)); /* adjust free space boundary pointers */ phdr->pd_upper += size; phdr->pd_lower -= sizeof(ItemIdData); /* * Finally, we need to adjust the linp entries that remain. * * Anything that used to be before the deleted tuple's data was moved * forward by the size of the deleted tuple. */ if (!PageIsEmpty(page)) { int i; nline--; /* there's one less than when we started */ for (i = 1; i <= nline; i++) { ItemId ii = PageGetItemId(phdr, i); if (ItemIdGetOffset(ii) <= offset) ii->lp_off += size; } } }
/* * PageRepairFragmentation * * Frees fragmented space on a page. * It doesn't remove unused line pointers! Please don't change this. * * This routine is usable for heap pages only, but see PageIndexMultiDelete. * * Returns number of unused line pointers on page. If "unused" is not NULL * then the unused[] array is filled with indexes of unused line pointers. */ int PageRepairFragmentation(Page page, OffsetNumber *unused) { Offset pd_lower = ((PageHeader) page)->pd_lower; Offset pd_upper = ((PageHeader) page)->pd_upper; Offset pd_special = ((PageHeader) page)->pd_special; itemIdSort itemidbase, itemidptr; ItemId lp; int nline, nused; int i; Size totallen; Offset upper; /* * It's worth the trouble to be more paranoid here than in most places, * because we are about to reshuffle data in (what is usually) a shared * disk buffer. If we aren't careful then corrupted pointers, lengths, * etc could cause us to clobber adjacent disk buffers, spreading the data * loss further. So, check everything. */ if (pd_lower < SizeOfPageHeaderData || pd_lower > pd_upper || pd_upper > pd_special || pd_special > BLCKSZ || pd_special != MAXALIGN(pd_special)) ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), errmsg("corrupted page pointers: lower = %u, upper = %u, special = %u", pd_lower, pd_upper, pd_special), errSendAlert(true))); nline = PageGetMaxOffsetNumber(page); nused = 0; for (i = 0; i < nline; i++) { lp = PageGetItemId(page, i + 1); if (ItemIdDeleted(lp)) /* marked for deletion */ lp->lp_flags &= ~(LP_USED | LP_DELETE); if (ItemIdIsUsed(lp)) nused++; else if (unused) unused[i - nused] = (OffsetNumber) i; } if (nused == 0) { /* Page is completely empty, so just reset it quickly */ for (i = 0; i < nline; i++) { lp = PageGetItemId(page, i + 1); lp->lp_len = 0; /* indicate unused & deallocated */ } ((PageHeader) page)->pd_upper = pd_special; } else { /* nused != 0 */ /* Need to compact the page the hard way */ itemidbase = (itemIdSort) palloc(sizeof(itemIdSortData) * nused); itemidptr = itemidbase; totallen = 0; for (i = 0; i < nline; i++) { lp = PageGetItemId(page, i + 1); if (ItemIdIsUsed(lp)) { itemidptr->offsetindex = i; itemidptr->itemoff = ItemIdGetOffset(lp); if (itemidptr->itemoff < (int) pd_upper || itemidptr->itemoff >= (int) pd_special) ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), errmsg("corrupted item pointer: %u", itemidptr->itemoff), errSendAlert(true))); itemidptr->alignedlen = MAXALIGN(ItemIdGetLength(lp)); totallen += itemidptr->alignedlen; itemidptr++; } else { lp->lp_len = 0; /* indicate unused & deallocated */ } } if (totallen > (Size) (pd_special - pd_lower)) ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), errmsg("corrupted item lengths: total %u, available space %u", (unsigned int) totallen, pd_special - pd_lower), errSendAlert(true))); /* sort itemIdSortData array into decreasing itemoff order */ qsort((char *) itemidbase, nused, sizeof(itemIdSortData), itemoffcompare); /* compactify page */ upper = pd_special; for (i = 0, itemidptr = itemidbase; i < nused; i++, itemidptr++) { lp = PageGetItemId(page, itemidptr->offsetindex + 1); upper -= itemidptr->alignedlen; memmove((char *) page + upper, (char *) page + itemidptr->itemoff, itemidptr->alignedlen); lp->lp_off = upper; } ((PageHeader) page)->pd_upper = upper; pfree(itemidbase); } /* Set hint bit for PageAddItem */ if (nused < nline) PageSetHasFreeLinePointers(page); else PageClearHasFreeLinePointers(page); return (nline - nused); }
/* * _bitmap_init() -- initialize the bitmap index. * * Create the meta page, a new heap which stores the distinct values for * the attributes to be indexed, a btree index on this new heap for searching * those distinct values, and the first LOV page. */ void _bitmap_init(Relation rel, Oid comptypeOid, Oid heapOid, Oid indexOid, Oid heapRelfilenode, Oid indexRelfilenode, bool use_wal) { MIRROREDLOCK_BUFMGR_DECLARE; BMMetaPage metapage; Buffer metabuf; Page page; Buffer buf; BMLOVItem lovItem; OffsetNumber newOffset; Page currLovPage; OffsetNumber o; /* sanity check */ if (RelationGetNumberOfBlocks(rel) != 0) ereport(ERROR, (errcode(ERRCODE_INDEX_CORRUPTED), errmsg("cannot initialize non-empty bitmap index \"%s\"", RelationGetRelationName(rel)), errSendAlert(true))); // -------- MirroredLock ---------- MIRROREDLOCK_BUFMGR_LOCK; /* create the metapage */ metabuf = _bitmap_getbuf(rel, P_NEW, BM_WRITE); page = BufferGetPage(metabuf); Assert(PageIsNew(page)); /* initialize the LOV metadata */ _bitmap_create_lov_heapandindex(rel, comptypeOid, &(heapOid), &(indexOid), heapRelfilenode, indexRelfilenode); START_CRIT_SECTION(); MarkBufferDirty(metabuf); /* initialize the metapage */ PageInit(page, BufferGetPageSize(metabuf), 0); metapage = (BMMetaPage) PageGetContents(page); metapage->bm_magic = BITMAP_MAGIC; metapage->bm_version = BITMAP_VERSION; metapage->bm_lov_heapId = heapOid; metapage->bm_lov_indexId = indexOid; if (use_wal) _bitmap_log_metapage(rel, page); /* allocate the first LOV page. */ buf = _bitmap_getbuf(rel, P_NEW, BM_WRITE); _bitmap_init_lovpage(rel, buf); MarkBufferDirty(buf); currLovPage = BufferGetPage(buf); /* set the first item to support NULL value */ lovItem = _bitmap_formitem(0); newOffset = OffsetNumberNext(PageGetMaxOffsetNumber(currLovPage)); /* * XXX: perhaps this could be a special page, with more efficient storage * after all, we have fixed size data */ o = PageAddItem(currLovPage, (Item)lovItem, sizeof(BMLOVItemData), newOffset, LP_USED); if (o == InvalidOffsetNumber) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("failed to add LOV item to \"%s\"", RelationGetRelationName(rel)))); metapage->bm_lov_lastpage = BufferGetBlockNumber(buf); if(use_wal) _bitmap_log_lovitem(rel, buf, newOffset, lovItem, metabuf, true); END_CRIT_SECTION(); _bitmap_wrtbuf(buf); _bitmap_wrtbuf(metabuf); MIRROREDLOCK_BUFMGR_UNLOCK; // -------- MirroredLock ---------- pfree(lovItem); }
/* * Backend checks if acknowledgement that its operation is completed * is received from mirror. * If acknowledgement is received (state == FileRepAckStateCompleted) then * a) entry is removed from hash * b) TRUE is returned */ bool FileRepAckPrimary_IsOperationCompleted( FileRepIdentifier_u fileRepIdentifier, FileRepRelationType_e fileRepRelationType) { FileRepAckHashEntry_s *entry = NULL; bool isCompleted = FALSE; bool isRemoved; FileName fileName = NULL; int retry = 0; bool retval = FALSE; bool wait = FALSE; fileName = FileRep_GetFileName(fileRepIdentifier, fileRepRelationType); while ((isCompleted == FALSE) && FileRep_IsRetry(retry)) { LWLockAcquire(FileRepAckHashShmemLock, LW_EXCLUSIVE); entry = FileRepAckPrimary_LookupHashEntry(fileName); if (entry == NULL) { LWLockRelease(FileRepAckHashShmemLock); break; } if (! FileRep_IsIpcSleep(entry->fileRepOperation)) { if (wait == TRUE) { wait = FALSE; } } switch (entry->fileRepAckState) { case FileRepAckStateWaiting: /* No Operation */ break; case FileRepAckStateCompleted: retval = TRUE; xLogEof = entry->xLogEof; mirrorStatus = entry->mirrorStatus; /* no BREAK */ case FileRepAckStateMirrorInFault: isCompleted = TRUE; isRemoved = FileRepAckPrimary_RemoveHashEntry(fileName); Assert(isRemoved == TRUE); break; default: break; } if (isCompleted == false) { if (! FileRep_IsIpcSleep(entry->fileRepOperation)) { fileRepIpcArray[fileRepAckHashShmem->ipcArrayIndex]->refCountSemP++; wait = TRUE; } } LWLockRelease(FileRepAckHashShmemLock); if (isCompleted == false) { if (FileRepSubProcess_IsStateTransitionRequested()) { break; } if (FileRep_IsIpcSleep(entry->fileRepOperation)) { FileRep_Sleep1ms(retry); if (retry == (3 * file_rep_retry / 4)) ereport(WARNING, (errmsg("threshold '75' percent of 'gp_segment_connect_timeout=%d' is reached, " "mirror may not be able to keep up with primary, " "primary may transition to change tracking", gp_segment_connect_timeout), errhint("increase guc 'gp_segment_connect_timeout' by 'gpconfig' and 'gpstop -u' "), errSendAlert(true))); FileRep_IncrementRetry(retry); } else { FileRep_IpcWait(fileRepIpcArray[fileRepAckHashShmem->ipcArrayIndex]->semP, &fileRepIpcArray[fileRepAckHashShmem->ipcArrayIndex]->refCountSemP, FileRepAckHashShmemLock); } /* * if the message was from the main filerep process then it is a * graceful shutdown message to the mirror. We don't want to stall * shutdown if the mirror is unavailable so we wait a smaller amount * of time */ if ( entry->fileRepOperation == FileRepOperationShutdown && retry == 50) { FileRepAckPrimary_RemoveHashEntry(fileName); break; } } } if (retval == FALSE) { mirrorStatus = FileRepStatusMirrorLossOccurred; if (! primaryMirrorIsIOSuspended()) { ereport(WARNING, (errmsg("mirror failure, " "could not complete mirrored request identifier '%s' ack state '%s', " "failover requested", (fileName == NULL) ? "<null>" : fileName, (entry == NULL) ? "<entry not found>" : FileRepAckStateToString[entry->fileRepAckState]), errhint("run gprecoverseg to re-establish mirror connectivity"), FileRep_errdetail_ShmemAck(), FileRep_errcontext())); } } if (fileName) { pfree(fileName); fileName = NULL; } return retval; }
/* -------------------------------- * InitPostgres * Initialize POSTGRES. * * The database can be specified by name, using the in_dbname parameter, or by * OID, using the dboid parameter. In the latter case, the actual database * name can be returned to the caller in out_dbname. If out_dbname isn't * NULL, it must point to a buffer of size NAMEDATALEN. * * In bootstrap mode no parameters are used. * * The return value indicates whether the userID is a superuser. (That * can only be tested inside a transaction, so we want to do it during * the startup transaction rather than doing a separate one in postgres.c.) * * As of PostgreSQL 8.2, we expect InitProcess() was already called, so we * already have a PGPROC struct ... but it's not filled in yet. * * Note: * Be very careful with the order of calls in the InitPostgres function. * -------------------------------- */ void InitPostgres(const char *in_dbname, Oid dboid, const char *username, char *out_dbname) { bool bootstrap = IsBootstrapProcessingMode(); bool autovacuum = IsAutoVacuumProcess(); bool am_superuser; char *fullpath; char dbname[NAMEDATALEN]; /* * Add my PGPROC struct to the ProcArray. * * Once I have done this, I am visible to other backends! */ InitProcessPhase2(); /* Initialize SessionState entry */ SessionState_Init(); /* Initialize memory protection */ GPMemoryProtect_Init(); /* * Initialize my entry in the shared-invalidation manager's array of * per-backend data. * * Sets up MyBackendId, a unique backend identifier. */ MyBackendId = InvalidBackendId; SharedInvalBackendInit(false); if (MyBackendId > MaxBackends || MyBackendId <= 0) elog(FATAL, "bad backend id: %d", MyBackendId); /* Now that we have a BackendId, we can participate in ProcSignal */ ProcSignalInit(MyBackendId); /* * bufmgr needs another initialization call too */ InitBufferPoolBackend(); /* * Initialize local process's access to XLOG. In bootstrap case we may * skip this since StartupXLOG() was run instead. */ if (!bootstrap) InitXLOGAccess(); /* * Initialize the relation cache and the system catalog caches. Note that * no catalog access happens here; we only set up the hashtable structure. * We must do this before starting a transaction because transaction abort * would try to touch these hashtables. */ RelationCacheInitialize(); InitCatalogCache(); /* Initialize portal manager */ EnablePortalManager(); /* Initialize stats collection --- must happen before first xact */ if (!bootstrap) pgstat_initialize(); /* * Load relcache entries for the shared system catalogs. This must create * at least entries for pg_database and catalogs used for authentication. */ RelationCacheInitializePhase2(); /* * Set up process-exit callback to do pre-shutdown cleanup. This has to * be after we've initialized all the low-level modules like the buffer * manager, because during shutdown this has to run before the low-level * modules start to close down. On the other hand, we want it in place * before we begin our first transaction --- if we fail during the * initialization transaction, as is entirely possible, we need the * AbortTransaction call to clean up. */ on_shmem_exit(ShutdownPostgres, 0); /* TODO: autovacuum launcher should be done here? */ /* * Start a new transaction here before first access to db, and get a * snapshot. We don't have a use for the snapshot itself, but we're * interested in the secondary effect that it sets RecentGlobalXmin. */ if (!bootstrap) { StartTransactionCommand(); (void) GetTransactionSnapshot(); } /* * Figure out our postgres user id, and see if we are a superuser. * * In standalone mode and in the autovacuum process, we use a fixed id, * otherwise we figure it out from the authenticated user name. */ if (bootstrap || autovacuum) { InitializeSessionUserIdStandalone(); am_superuser = true; } else if (!IsUnderPostmaster) { InitializeSessionUserIdStandalone(); am_superuser = true; if (!ThereIsAtLeastOneRole()) ereport(WARNING, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("no roles are defined in this database system"), errhint("You should immediately run CREATE USER \"%s\" CREATEUSER;.", username))); } else { /* normal multiuser case */ Assert(MyProcPort != NULL); PerformAuthentication(MyProcPort); InitializeSessionUserId(username); am_superuser = superuser(); } /* * Check a normal user hasn't connected to a superuser reserved slot. */ if (!am_superuser && ReservedBackends > 0 && !HaveNFreeProcs(ReservedBackends)) ereport(FATAL, (errcode(ERRCODE_TOO_MANY_CONNECTIONS), errmsg("connection limit exceeded for non-superusers"), errSendAlert(true))); /* * If walsender, we don't want to connect to any particular database. Just * finish the backend startup by processing any options from the startup * packet, and we're done. */ if (am_walsender) { Assert(!bootstrap); /* * We don't have replication role, which existed in postgres. */ if (!superuser()) ereport(FATAL, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser role to start walsender"))); /* process any options passed in the startup packet */ if (MyProcPort != NULL) process_startup_options(MyProcPort, am_superuser); /* Apply PostAuthDelay as soon as we've read all options */ if (PostAuthDelay > 0) pg_usleep(PostAuthDelay * 1000000L); /* initialize client encoding */ InitializeClientEncoding(); /* report this backend in the PgBackendStatus array */ pgstat_bestart(); /* close the transaction we started above */ CommitTransactionCommand(); return; } /* * Set up the global variables holding database id and path. But note we * won't actually try to touch the database just yet. * * We take a shortcut in the bootstrap case, otherwise we have to look up * the db name in pg_database. */ if (bootstrap) { MyDatabaseId = TemplateDbOid; MyDatabaseTableSpace = DEFAULTTABLESPACE_OID; } else if (in_dbname != NULL) { HeapTuple tuple; Form_pg_database dbform; tuple = GetDatabaseTuple(in_dbname); if (!HeapTupleIsValid(tuple)) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", in_dbname))); dbform = (Form_pg_database) GETSTRUCT(tuple); MyDatabaseId = HeapTupleGetOid(tuple); MyDatabaseTableSpace = dbform->dattablespace; /* take database name from the caller, just for paranoia */ strlcpy(dbname, in_dbname, sizeof(dbname)); pfree(tuple); } else { /* caller specified database by OID */ HeapTuple tuple; Form_pg_database dbform; tuple = GetDatabaseTupleByOid(dboid); if (!HeapTupleIsValid(tuple)) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database %u does not exist", dboid))); dbform = (Form_pg_database) GETSTRUCT(tuple); MyDatabaseId = HeapTupleGetOid(tuple); MyDatabaseTableSpace = dbform->dattablespace; Assert(MyDatabaseId == dboid); strlcpy(dbname, NameStr(dbform->datname), sizeof(dbname)); /* pass the database name back to the caller */ if (out_dbname) strcpy(out_dbname, dbname); pfree(tuple); } /* Now we can mark our PGPROC entry with the database ID */ /* (We assume this is an atomic store so no lock is needed) */ MyProc->databaseId = MyDatabaseId; /* * Now, take a writer's lock on the database we are trying to connect to. * If there is a concurrently running DROP DATABASE on that database, this * will block us until it finishes (and has committed its update of * pg_database). * * Note that the lock is not held long, only until the end of this startup * transaction. This is OK since we are already advertising our use of * the database in the PGPROC array; anyone trying a DROP DATABASE after * this point will see us there. * * Note: use of RowExclusiveLock here is reasonable because we envision * our session as being a concurrent writer of the database. If we had a * way of declaring a session as being guaranteed-read-only, we could use * AccessShareLock for such sessions and thereby not conflict against * CREATE DATABASE. */ if (!bootstrap) LockSharedObject(DatabaseRelationId, MyDatabaseId, 0, RowExclusiveLock); /* * Recheck pg_database to make sure the target database hasn't gone away. * If there was a concurrent DROP DATABASE, this ensures we will die * cleanly without creating a mess. */ if (!bootstrap) { HeapTuple tuple; tuple = GetDatabaseTuple(dbname); if (!HeapTupleIsValid(tuple) || MyDatabaseId != HeapTupleGetOid(tuple) || MyDatabaseTableSpace != ((Form_pg_database) GETSTRUCT(tuple))->dattablespace) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname), errdetail("It seems to have just been dropped or renamed."))); } fullpath = GetDatabasePath(MyDatabaseId, MyDatabaseTableSpace); if (!bootstrap) { if (access(fullpath, F_OK) == -1) { if (errno == ENOENT) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname), errdetail("The database subdirectory \"%s\" is missing.", fullpath))); else ereport(FATAL, (errcode_for_file_access(), errmsg("could not access directory \"%s\": %m", fullpath))); } ValidatePgVersion(fullpath); } SetDatabasePath(fullpath); /* * It's now possible to do real access to the system catalogs. * * Load relcache entries for the system catalogs. This must create at * least the minimum set of "nailed-in" cache entries. */ RelationCacheInitializePhase3(); /* * Now we have full access to catalog including toast tables, * we can process pg_authid.rolconfig. This ought to come before * processing startup options so that it can override the settings. */ if (!bootstrap) ProcessRoleGUC(); /* set up ACL framework (so CheckMyDatabase can check permissions) */ initialize_acl(); /* * Re-read the pg_database row for our database, check permissions and set * up database-specific GUC settings. We can't do this until all the * database-access infrastructure is up. (Also, it wants to know if the * user is a superuser, so the above stuff has to happen first.) */ if (!bootstrap) CheckMyDatabase(dbname, am_superuser); /* * Now process any command-line switches and any additional GUC variable * settings passed in the startup packet. We couldn't do this before * because we didn't know if client is a superuser. */ if (MyProcPort != NULL) process_startup_options(MyProcPort, am_superuser); /* * Maintenance Mode: allow superuser to connect when * gp_maintenance_conn GUC is set. We cannot check it until * process_startup_options parses the GUC. */ if (gp_maintenance_mode && Gp_role == GP_ROLE_DISPATCH && !(superuser() && gp_maintenance_conn)) ereport(FATAL, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("maintenance mode: connected by superuser only"), errSendAlert(false))); /* * MPP: If we were started in utility mode then we only want to allow * incoming sessions that specify gp_session_role=utility as well. This * lets the bash scripts start the QD in utility mode and connect in but * protect ourselves from normal clients who might be trying to connect to * the system while we startup. */ if ((Gp_role == GP_ROLE_UTILITY) && (Gp_session_role != GP_ROLE_UTILITY)) { ereport(FATAL, (errcode(ERRCODE_CANNOT_CONNECT_NOW), errmsg("System was started in master-only utility mode - only utility mode connections are allowed"))); } /* Apply PostAuthDelay as soon as we've read all options */ if (PostAuthDelay > 0) pg_usleep(PostAuthDelay * 1000000L); /* set default namespace search path */ InitializeSearchPath(); /* initialize client encoding */ InitializeClientEncoding(); /* report this backend in the PgBackendStatus array */ if (!bootstrap) pgstat_bestart(); /* * MPP package setup * * Primary function is to establish connctions to the qExecs. * This is SKIPPED when the database is in bootstrap mode or * Is not UnderPostmaster. */ if (!bootstrap && IsUnderPostmaster) { cdb_setup(); on_proc_exit( cdb_cleanup, 0 ); } /* * MPP SharedSnapshot Setup */ if (Gp_role == GP_ROLE_DISPATCH) { addSharedSnapshot("Query Dispatcher", gp_session_id); } else if (Gp_role == GP_ROLE_DISPATCHAGENT) { SharedLocalSnapshotSlot = NULL; } else if (Gp_segment == -1 && Gp_role == GP_ROLE_EXECUTE && !Gp_is_writer) { /* * Entry db singleton QE is a user of the shared snapshot -- not a creator. * The lookup will occur once the distributed snapshot has been received. */ lookupSharedSnapshot("Entry DB Singleton", "Query Dispatcher", gp_session_id); } else if (Gp_role == GP_ROLE_EXECUTE) { if (Gp_is_writer) { addSharedSnapshot("Writer qExec", gp_session_id); } else { /* * NOTE: This assumes that the Slot has already been * allocated by the writer. Need to make sure we * always allocate the writer qExec first. */ lookupSharedSnapshot("Reader qExec", "Writer qExec", gp_session_id); } } /* close the transaction we started above */ if (!bootstrap) CommitTransactionCommand(); return; }
/* * FileRepAckPrimary_RunConsumer() */ static int FileRepAckPrimary_RunConsumer(void) { FileRepShmemMessageDescr_s *fileRepShmemMessageDescr = NULL; FileRepMessageHeader_s *fileRepMessageHeader = NULL; pg_crc32 *fileRepMessageHeaderCrc; pg_crc32 messageHeaderCrcLocal = 0; int status = STATUS_OK; bool movePositionConsume = FALSE; FileRepShmem_s *fileRepAckShmem = NULL; FileRep_InsertConfigLogEntry("run consumer"); fileRepAckShmem = fileRepAckShmemArray[FILEREP_ACKSHMEM_MESSAGE_SLOT_PRIMARY_ACK]; while (1) { LWLockAcquire(FileRepAckShmemLock, LW_EXCLUSIVE); if (movePositionConsume) { fileRepAckShmem->positionConsume = fileRepAckShmem->positionConsume + fileRepShmemMessageDescr->messageLength + sizeof(FileRepShmemMessageDescr_s); if (fileRepAckShmem->positionConsume == fileRepAckShmem->positionWraparound && fileRepAckShmem->positionInsert != fileRepAckShmem->positionWraparound) { fileRepAckShmem->positionConsume = fileRepAckShmem->positionBegin; fileRepAckShmem->positionWraparound = fileRepAckShmem->positionEnd; } FileRep_IpcSignal(fileRepIpcArray[fileRepAckShmem->ipcArrayIndex]->semP, &fileRepIpcArray[fileRepAckShmem->ipcArrayIndex]->refCountSemP); } fileRepShmemMessageDescr = (FileRepShmemMessageDescr_s*) fileRepAckShmem->positionConsume; while ((fileRepAckShmem->positionConsume == fileRepAckShmem->positionInsert) || ((fileRepAckShmem->positionConsume != fileRepAckShmem->positionInsert) && (fileRepShmemMessageDescr->messageState != FileRepShmemMessageStateReady))) { fileRepIpcArray[fileRepAckShmem->ipcArrayIndex]->refCountSemC++; LWLockRelease(FileRepAckShmemLock); FileRepSubProcess_ProcessSignals(); if (FileRepSubProcess_GetState() != FileRepStateReady && FileRepSubProcess_GetState() != FileRepStateInitialization) { LWLockAcquire(FileRepAckShmemLock, LW_EXCLUSIVE); break; } FileRep_IpcWait(fileRepIpcArray[fileRepAckShmem->ipcArrayIndex]->semC, &fileRepIpcArray[fileRepAckShmem->ipcArrayIndex]->refCountSemC, FileRepAckShmemLock); LWLockAcquire(FileRepAckShmemLock, LW_EXCLUSIVE); if (fileRepAckShmem->positionConsume == fileRepAckShmem->positionWraparound && fileRepAckShmem->positionInsert != fileRepAckShmem->positionWraparound) { fileRepAckShmem->positionConsume = fileRepAckShmem->positionBegin; fileRepAckShmem->positionWraparound = fileRepAckShmem->positionEnd; } /* Re-assign to find if messageState is changed */ fileRepShmemMessageDescr = (FileRepShmemMessageDescr_s*) fileRepAckShmem->positionConsume; } // internal while fileRepAckShmem->consumeCount++; LWLockRelease(FileRepAckShmemLock); FileRepSubProcess_ProcessSignals(); if (FileRepSubProcess_GetState() != FileRepStateReady && FileRepSubProcess_GetState() != FileRepStateInitialization) { break; } SIMPLE_FAULT_INJECTOR(FileRepConsumer); /* Calculate and compare FileRepMessageHeader_s Crc */ fileRepMessageHeader = (FileRepMessageHeader_s*) (fileRepAckShmem->positionConsume + sizeof(FileRepShmemMessageDescr_s)); FileRep_CalculateCrc((char *) fileRepMessageHeader, sizeof(FileRepMessageHeader_s), &messageHeaderCrcLocal); fileRepMessageHeaderCrc = (pg_crc32 *) (fileRepAckShmem->positionConsume + sizeof(FileRepMessageHeader_s) + sizeof(FileRepShmemMessageDescr_s)); if (*fileRepMessageHeaderCrc != messageHeaderCrcLocal) { status = STATUS_ERROR; ereport(WARNING, (errmsg("mirror failure, " "could not match ack message header checksum between primary '%u' and mirror '%u', " "failover requested", *fileRepMessageHeaderCrc, messageHeaderCrcLocal), errhint("run gprecoverseg to re-establish mirror connectivity"), FileRep_errdetail(fileRepMessageHeader->fileRepIdentifier, fileRepMessageHeader->fileRepRelationType, fileRepMessageHeader->fileRepOperation, fileRepMessageHeader->messageCount), FileRep_errdetail_ShmemAck(), FileRep_errcontext())); break; } /* Write operation is never acknowledged. * That means message should never have body. * CRC of body should be always 0. */ Assert(fileRepMessageHeader->fileRepOperation != FileRepOperationWrite); Assert(fileRepMessageHeader->fileRepMessageBodyCrc == 0); switch (fileRepMessageHeader->fileRepOperation) { case FileRepOperationReconcileXLogEof: xLogEof = fileRepMessageHeader->fileRepOperationDescription.reconcile.xLogEof; if (Debug_filerep_print) ereport(LOG, (errmsg("ack reconcile xlogid '%d' xrecoff '%d' ", xLogEof.xlogid, xLogEof.xrecoff))); break; case FileRepOperationValidation: mirrorStatus = fileRepMessageHeader->fileRepOperationDescription.validation.mirrorStatus; if (Debug_filerep_print) ereport(LOG, (errmsg("ack validation status '%s' ", FileRepStatusToString[mirrorStatus]))); break; case FileRepOperationCreate: mirrorStatus = fileRepMessageHeader->fileRepOperationDescription.create.mirrorStatus; if (Debug_filerep_print) ereport(LOG, (errmsg("ack create status '%s' ", FileRepStatusToString[mirrorStatus]))); break; case FileRepOperationStartSlruChecksum: mirrorStatus = fileRepMessageHeader->fileRepOperationDescription.startChecksum.mirrorStatus; if (Debug_filerep_print) { ereport(LOG, (errmsg("ack start SLRU checksum: status = '%s', directory = '%s' ", FileRepStatusToString[mirrorStatus], fileRepMessageHeader->fileRepIdentifier.fileRepFlatFileIdentifier.directorySimpleName))); } break; case FileRepOperationVerifySlruDirectoryChecksum: mirrorStatus = fileRepMessageHeader->fileRepOperationDescription.verifyDirectoryChecksum.mirrorStatus; if (Debug_filerep_print) { ereport(LOG, (errmsg("ack verify SLRU directory checksum: status = '%s', directory = '%s' ", FileRepStatusToString[mirrorStatus], fileRepMessageHeader->fileRepIdentifier.fileRepFlatFileIdentifier.directorySimpleName))); } break; default: break; } if (fileRepMessageHeader->fileRepAckState != FileRepAckStateCompleted) { status = STATUS_ERROR; ereport(WARNING, (errmsg("mirror failure, " "could not complete operation on mirror ack state '%s', " "failover requested", FileRepAckStateToString[fileRepMessageHeader->fileRepAckState]), errhint("run gprecoverseg to re-establish mirror connectivity"), errSendAlert(true), FileRep_errdetail(fileRepMessageHeader->fileRepIdentifier, fileRepMessageHeader->fileRepRelationType, fileRepMessageHeader->fileRepOperation, fileRepMessageHeader->messageCount), FileRep_errdetail_Shmem(), FileRep_errdetail_ShmemAck(), FileRep_errcontext())); /* * FAULT has to be set before entry is updated in ack hash table * in order to suspend backend process. */ FileRep_SetSegmentState(SegmentStateFault, FaultTypeMirror); FileRepSubProcess_ProcessSignals(); } if (FileRepAckPrimary_UpdateHashEntry( fileRepMessageHeader->fileRepIdentifier, fileRepMessageHeader->fileRepRelationType, fileRepMessageHeader->fileRepAckState) != STATUS_OK) { status = STATUS_ERROR; ereport(WARNING, (errmsg("mirror failure, " "could not update ack state '%s' in ack hash table, " "failover requested", FileRepAckStateToString[fileRepMessageHeader->fileRepAckState]), errhint("run gprecoverseg to re-establish mirror connectivity"), errSendAlert(true), FileRep_errdetail(fileRepMessageHeader->fileRepIdentifier, fileRepMessageHeader->fileRepRelationType, fileRepMessageHeader->fileRepOperation, fileRepMessageHeader->messageCount), FileRep_errdetail_Shmem(), FileRep_errdetail_ShmemAck(), FileRep_errcontext())); } FileRep_InsertLogEntry( "P_RunConsumer", fileRepMessageHeader->fileRepIdentifier, fileRepMessageHeader->fileRepRelationType, fileRepMessageHeader->fileRepOperation, messageHeaderCrcLocal, fileRepMessageHeader->fileRepMessageBodyCrc, fileRepMessageHeader->fileRepAckState, FILEREP_UNDEFINED, fileRepMessageHeader->messageCount); if (status != STATUS_OK) { break; } movePositionConsume = TRUE; } // while(1) return status; }
void disableQDMirroring(char *detail, char *errorMessage, QDMIRRORDisabledReason disabledReason) { struct timeval lastLogTimeVal; Assert(ftsQDMirrorInfo != NULL); LWLockAcquire(ftsQDMirrorLock, LW_EXCLUSIVE); /* * Don't overwrite. */ if (ftsQDMirrorInfo->state != QDMIRROR_STATE_DISABLED) { ftsQDMirrorInfo->state = QDMIRROR_STATE_DISABLED; ftsQDMirrorInfo->disabledReason = disabledReason; switch (disabledReason) { case QDMIRROR_DISABLEDREASON_TOOFARBEHIND: case QDMIRROR_DISABLEDREASON_CONNECTIONERROR: case QDMIRROR_DISABLEDREASON_WALSENDSERVERERROR: case QDMIRROR_DISABLEDREASON_ADMINISTRATORDISABLED: case QDMIRROR_DISABLEDREASON_UNEXPECTEDERROR: if (disabledReason == QDMIRROR_DISABLEDREASON_ADMINISTRATORDISABLED) ereport(NOTICE, (errcode(ERRCODE_GP_INTERCONNECTION_ERROR), errmsg("Master mirroring not synchronized because the standby master was not started by the administrator"))); else ereport(WARNING, (errcode(ERRCODE_GP_INTERCONNECTION_ERROR), errSendAlert(true), errmsg("Master mirroring synchronization lost"), errdetail("%s\nThe Greenplum Database is no longer highly available.", detail))); gettimeofday(&lastLogTimeVal, NULL); ftsQDMirrorInfo->QDMirroringNotSynchronizedWarningGiven = true; if (ftsQDMirrorInfo->valid) { /* * Only do the update if we need to. */ ftsQDMirrorInfo->updateMask |= QDMIRROR_UPDATEMASK_VALIDFLAG; } ftsQDMirrorInfo->updateMask |= QDMIRROR_UPDATEMASK_MASTERMIRRORING; ftsQDMirrorInfo->lastLogTimeVal = lastLogTimeVal; /* * Not specified or too long error message string will end up NULL * in gp_master_mirroring table. */ if (errorMessage == NULL || strlen(errorMessage) + 1 >= sizeof(ftsQDMirrorInfo->errorMessage)) strcpy(ftsQDMirrorInfo->errorMessage, ""); else strcpy(ftsQDMirrorInfo->errorMessage, errorMessage); break; case QDMIRROR_DISABLEDREASON_SHUTDOWN: break; default: elog(ERROR, "Unknown disabled reason %d", (int)disabledReason); } } LWLockRelease(ftsQDMirrorLock); }
/* * _hash_checkpage -- sanity checks on the format of all hash pages */ void _hash_checkpage(Relation rel, Buffer buf, int flags) { Page page = BufferGetPage(buf); /* * ReadBuffer verifies that every newly-read page passes * PageHeaderIsValid, which means it either contains a reasonably sane * page header or is all-zero. We have to defend against the all-zero * case, however. */ if (PageIsNew(page)) ereport(ERROR, (errcode(ERRCODE_INDEX_CORRUPTED), errmsg("index \"%s\" contains unexpected zero page at block %u", RelationGetRelationName(rel), BufferGetBlockNumber(buf)), errhint("Please REINDEX it."), errSendAlert(true))); /* * Additionally check that the special area looks sane. */ if (((PageHeader) (page))->pd_special != (BLCKSZ - MAXALIGN(sizeof(HashPageOpaqueData)))) ereport(ERROR, (errcode(ERRCODE_INDEX_CORRUPTED), errmsg("index \"%s\" contains corrupted page at block %u", RelationGetRelationName(rel), BufferGetBlockNumber(buf)), errhint("Please REINDEX it."), errSendAlert(true))); if (flags) { HashPageOpaque opaque = (HashPageOpaque) PageGetSpecialPointer(page); if ((opaque->hasho_flag & flags) == 0) ereport(ERROR, (errcode(ERRCODE_INDEX_CORRUPTED), errmsg("index \"%s\" contains corrupted page at block %u", RelationGetRelationName(rel), BufferGetBlockNumber(buf)), errhint("Please REINDEX it."), errSendAlert(true))); } /* * When checking the metapage, also verify magic number and version. */ if (flags == LH_META_PAGE) { HashMetaPage metap = (HashMetaPage) page; if (metap->hashm_magic != HASH_MAGIC) ereport(ERROR, (errcode(ERRCODE_INDEX_CORRUPTED), errmsg("index \"%s\" is not a hash index", RelationGetRelationName(rel)))); if (metap->hashm_version != HASH_VERSION) ereport(ERROR, (errcode(ERRCODE_INDEX_CORRUPTED), errmsg("index \"%s\" has wrong hash version", RelationGetRelationName(rel)), errhint("Please REINDEX it."), errSendAlert(true))); } }
/** * Marks the given db as in-sync in the segment configuration. */ void FtsMarkSegmentsInSync(CdbComponentDatabaseInfo *primary, CdbComponentDatabaseInfo *mirror) { if (!FTS_STATUS_ISALIVE(primary->dbid, ftsProbeInfo->fts_status) || !FTS_STATUS_ISALIVE(mirror->dbid, ftsProbeInfo->fts_status) || !FTS_STATUS_ISPRIMARY(primary->dbid, ftsProbeInfo->fts_status) || FTS_STATUS_ISPRIMARY(mirror->dbid, ftsProbeInfo->fts_status) || FTS_STATUS_IS_SYNCED(primary->dbid, ftsProbeInfo->fts_status) || FTS_STATUS_IS_SYNCED(mirror->dbid, ftsProbeInfo->fts_status) || FTS_STATUS_IS_CHANGELOGGING(primary->dbid, ftsProbeInfo->fts_status) || FTS_STATUS_IS_CHANGELOGGING(mirror->dbid, ftsProbeInfo->fts_status)) { FtsRequestPostmasterShutdown(primary, mirror); } if (ftsProbeInfo->fts_pauseProbes) { return; } uint8 segStatus=0; Relation configrel; Relation histrel; ScanKeyData scankey; SysScanDesc sscan; HeapTuple configtuple; HeapTuple newtuple; HeapTuple histtuple; Datum configvals[Natts_gp_segment_configuration]; bool confignulls[Natts_gp_segment_configuration] = { false }; bool repls[Natts_gp_segment_configuration] = { false }; Datum histvals[Natts_gp_configuration_history]; bool histnulls[Natts_gp_configuration_history] = { false }; char *desc = "FTS: changed segment to insync from resync."; /* * Commit/abort transaction below will destroy * CurrentResourceOwner. We need it for catalog reads. */ ResourceOwner save = CurrentResourceOwner; StartTransactionCommand(); /* update primary */ segStatus = ftsProbeInfo->fts_status[primary->dbid]; segStatus |= FTS_STATUS_SYNCHRONIZED; ftsProbeInfo->fts_status[primary->dbid] = segStatus; /* update mirror */ segStatus = ftsProbeInfo->fts_status[mirror->dbid]; segStatus |= FTS_STATUS_SYNCHRONIZED; ftsProbeInfo->fts_status[mirror->dbid] = segStatus; histrel = heap_open(GpConfigHistoryRelationId, RowExclusiveLock); configrel = heap_open(GpSegmentConfigRelationId, RowExclusiveLock); /* update gp_segment_configuration to insync */ ScanKeyInit(&scankey, Anum_gp_segment_configuration_dbid, BTEqualStrategyNumber, F_INT2EQ, Int16GetDatum(primary->dbid)); sscan = systable_beginscan(configrel, GpSegmentConfigDbidIndexId, true, SnapshotNow, 1, &scankey); configtuple = systable_getnext(sscan); if (!HeapTupleIsValid(configtuple)) { elog(ERROR,"FTS cannot find dbid (%d, %d) in %s", primary->dbid, mirror->dbid, RelationGetRelationName(configrel)); } configvals[Anum_gp_segment_configuration_mode-1] = CharGetDatum('s'); repls[Anum_gp_segment_configuration_mode-1] = true; newtuple = heap_modify_tuple(configtuple, RelationGetDescr(configrel), configvals, confignulls, repls); simple_heap_update(configrel, &configtuple->t_self, newtuple); CatalogUpdateIndexes(configrel, newtuple); systable_endscan(sscan); ScanKeyInit(&scankey, Anum_gp_segment_configuration_dbid, BTEqualStrategyNumber, F_INT2EQ, Int16GetDatum(mirror->dbid)); sscan = systable_beginscan(configrel, GpSegmentConfigDbidIndexId, true, SnapshotNow, 1, &scankey); configtuple = systable_getnext(sscan); if (!HeapTupleIsValid(configtuple)) { elog(ERROR,"FTS cannot find dbid (%d, %d) in %s", primary->dbid, mirror->dbid, RelationGetRelationName(configrel)); } newtuple = heap_modify_tuple(configtuple, RelationGetDescr(configrel), configvals, confignulls, repls); simple_heap_update(configrel, &configtuple->t_self, newtuple); CatalogUpdateIndexes(configrel, newtuple); systable_endscan(sscan); /* update configuration history */ histvals[Anum_gp_configuration_history_time-1] = TimestampTzGetDatum(GetCurrentTimestamp()); histvals[Anum_gp_configuration_history_dbid-1] = Int16GetDatum(primary->dbid); histvals[Anum_gp_configuration_history_desc-1] = CStringGetTextDatum(desc); histtuple = heap_form_tuple(RelationGetDescr(histrel), histvals, histnulls); simple_heap_insert(histrel, histtuple); CatalogUpdateIndexes(histrel, histtuple); histvals[Anum_gp_configuration_history_dbid-1] = Int16GetDatum(mirror->dbid); histtuple = heap_form_tuple(RelationGetDescr(histrel), histvals, histnulls); simple_heap_insert(histrel, histtuple); CatalogUpdateIndexes(histrel, histtuple); ereport(LOG, (errmsg("FTS: resynchronization of mirror (dbid=%d, content=%d) on %s:%d has completed.", mirror->dbid, mirror->segindex, mirror->address, mirror->port ), errSendAlert(true))); heap_close(histrel, RowExclusiveLock); heap_close(configrel, RowExclusiveLock); /* * Do not block shutdown. We will always get a change to update * gp_segment_configuration in subsequent probes upon database * restart. */ if (shutdown_requested) { elog(LOG, "Shutdown in progress, ignoring FTS prober updates."); return; } CommitTransactionCommand(); CurrentResourceOwner = save; }