Beispiel #1
0
/*
 * FindRandomNodeNotInList finds a random node from the shared hash that is not
 * a member of the current node list. The caller is responsible for making the
 * necessary node count checks to ensure that such a node exists.
 *
 * Note that this function has a selection bias towards nodes whose positions in
 * the shared hash are sequentially adjacent to the positions of nodes that are
 * in the current node list. This bias follows from our decision to first pick a
 * random node in the hash, and if that node is a member of the current list, to
 * simply iterate to the next node in the hash. Overall, this approach trades in
 * some selection bias for simplicity in design and for bounded execution time.
 */
static WorkerNode *
FindRandomNodeNotInList(HTAB *WorkerNodesHash, List *currentNodeList)
{
	WorkerNode *workerNode = NULL;
	HASH_SEQ_STATUS status;
	uint32 workerNodeCount = 0;
	uint32 currentNodeCount PG_USED_FOR_ASSERTS_ONLY = 0;
	bool lookForWorkerNode = true;
	uint32 workerPosition = 0;
	uint32 workerIndex = 0;

	workerNodeCount = hash_get_num_entries(WorkerNodesHash);
	currentNodeCount = list_length(currentNodeList);
	Assert(workerNodeCount > currentNodeCount);

	/*
	 * We determine a random position within the worker hash between [1, N],
	 * assuming that the number of elements in the hash is N. We then get to
	 * this random position by iterating over the worker hash. Please note that
	 * the random seed has already been set by the postmaster when starting up.
	 */
	workerPosition = (random() % workerNodeCount) + 1;
	hash_seq_init(&status, WorkerNodesHash);

	for (workerIndex = 0; workerIndex < workerPosition; workerIndex++)
	{
		workerNode = (WorkerNode *) hash_seq_search(&status);
	}

	while (lookForWorkerNode)
	{
		bool listMember = ListMember(currentNodeList, workerNode);

		if (workerNode->inWorkerFile && !listMember)
		{
			lookForWorkerNode = false;
		}
		else
		{
			/* iterate to the next worker node in the hash */
			workerNode = (WorkerNode *) hash_seq_search(&status);

			/* reached end of hash; start from the beginning */
			if (workerNode == NULL)
			{
				hash_seq_init(&status, WorkerNodesHash);
				workerNode = (WorkerNode *) hash_seq_search(&status);
			}
		}
	}

	/* we stopped scanning before completion; therefore clean up scan */
	hash_seq_term(&status);

	return workerNode;
}
Beispiel #2
0
/** 
 * Return the next variable from a scan of the hash of variables.  Note
 * that this function is not re-entrant.
 * 
 * @param prev The last variable retrieved by a scan, or NULL if
 * starting a new scan.
 * 
 * @return The next variable encountered in the scan.  NULL if we have
 * finished.
 */
veil_variable_t *
vl_next_variable(veil_variable_t *prev)
{
	static bool doing_shared;
	static HTAB *hash;
	static HASH_SEQ_STATUS status;
	static veil_variable_t result;
	VarEntry *var;

	if (!session_hash) {
		session_hash = create_session_hash();
	}

	if (!prev) {
		doing_shared = true;
		/* Initialise a scan of the shared hash. */
		hash = vl_get_shared_hash();

		hash_seq_init(&status, hash);
	}

	var = hash_seq_search(&status);

	if (!var) {
		/* No more entries from that hash. */
		if (doing_shared) {
			/* Switch to, and get var from, the session hash. */
			doing_shared = false;
			hash = session_hash;
			hash_seq_init(&status, hash);
			var = hash_seq_search(&status);
		}
	}

	if (var) {
		/* Yay, we have an entry. */
		result.name = var->key;
		result.shared = var->shared;
		if (var->obj) {
			result.type = vl_ObjTypeName(var->obj->type);
		}
		else {
			result.type = vl_ObjTypeName(OBJ_UNDEFINED);;
		}
		return &result;
	}
	else {
		/* Thats all.  There are no more entries */
		return NULL;
	}
}
Beispiel #3
0
/*
 * Abort processing for portals.
 *
 * At this point we reset the "active" flags and run the cleanup hook if
 * present, but we can't release memory until the cleanup call.
 *
 * The reason we need to reset active is so that we can replace the unnamed
 * portal, else we'll fail to execute ROLLBACK when it arrives.  Also, we
 * want to run the cleanup hook now to be certain it knows that we had an
 * error abort and not successful conclusion.
 */
void
AtAbort_Portals(void)
{
	HASH_SEQ_STATUS status;
	PortalHashEnt *hentry;
	TransactionId xact = GetCurrentTransactionId();

	hash_seq_init(&status, PortalHashTable);

	while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
	{
		Portal		portal = hentry->portal;

		portal->portalActive = false;

		/*
		 * Do nothing else to cursors held over from a previous
		 * transaction. (This test must include checking CURSOR_OPT_HOLD,
		 * else we will fail to clean up a VACUUM portal if it fails after
		 * its first sub-transaction.)
		 */
		if (portal->createXact != xact &&
			(portal->cursorOptions & CURSOR_OPT_HOLD))
			continue;

		/* let portalcmds.c clean up the state it knows about */
		if (PointerIsValid(portal->cleanup))
		{
			(*portal->cleanup) (portal, true);
			portal->cleanup = NULL;
		}
	}
}
Beispiel #4
0
/* Forget any invalid pages >= minblkno, because they've been dropped */
static void
forget_invalid_pages(RelFileNode node, ForkNumber forkno, BlockNumber minblkno)
{
	HASH_SEQ_STATUS status;
	xl_invalid_page *hentry;

	if (invalid_page_tab == NULL)
		return;					/* nothing to do */

	hash_seq_init(&status, invalid_page_tab);

	while ((hentry = (xl_invalid_page *) hash_seq_search(&status)) != NULL)
	{
		if (RelFileNodeEquals(hentry->key.node, node) &&
			hentry->key.forkno == forkno &&
			hentry->key.blkno >= minblkno)
		{
			if (log_min_messages <= DEBUG2 || client_min_messages <= DEBUG2)
			{
				char	   *path = relpath(hentry->key.node, forkno);

				elog(DEBUG2, "page %u of relation %s has been dropped",
					 hentry->key.blkno, path);
				pfree(path);
			}

			if (hash_search(invalid_page_tab,
							(void *) &hentry->key,
							HASH_REMOVE, NULL) == NULL)
				elog(ERROR, "hash table corrupted");
		}
	}
}
/*
 * PersistentFilespace_LookupMirrorDbid()
 *
 * Check the gp_persistent_filespace table to identify what dbid it contains
 * that does not match the primary dbid.  If there are no filespaces currently
 * defined this check will return 0 even if there is an active mirror, because
 * the segment doesn't know any better.
 */
int16
PersistentFilespace_LookupMirrorDbid(int16 primaryDbid)
{
	HASH_SEQ_STATUS		status;
	FilespaceDirEntry   dirEntry;
	int16				mirrorDbid = 0;

	PersistentFilespace_VerifyInitScan();

	/* Start scan */
	hash_seq_init(&status, persistentFilespaceSharedHashTable);
	dirEntry = (FilespaceDirEntry) hash_seq_search(&status);
	if (dirEntry != NULL)
	{
		if (dirEntry->dbId1 == primaryDbid)
		{
			mirrorDbid = dirEntry->dbId2;
		}
		else if (dirEntry->dbId2 == primaryDbid)
		{
			mirrorDbid = dirEntry->dbId1;
		}
		else
		{
			elog(FATAL,
				 "dbid %d not found in gp_persistent_filespace_node",
				 (int) primaryDbid);
		}

		/* Terminate the scan early */
		hash_seq_term(&status);
	}

	return mirrorDbid;
}
char *
serialize_filesystem_credentials(int *size)
{
	HASH_SEQ_STATUS status;
	struct FileSystemCredential *entry;
	StringInfoData buffer;

    HTAB * currentFilesystemCredentials;
    MemoryContext currentFilesystemCredentialsMemoryContext;

    get_current_credential_cache_and_memcxt(&currentFilesystemCredentials,
            &currentFilesystemCredentialsMemoryContext);

    Insist(NULL != currentFilesystemCredentials);
    Insist(NULL != currentFilesystemCredentialsMemoryContext);


	initStringInfo(&buffer);
	hash_seq_init(&status, currentFilesystemCredentials);

	while (NULL != (entry = hash_seq_search(&status)))
		serialize_filesystem_credential(&buffer, entry);

	*size = buffer.len;
	return buffer.data;
}
Beispiel #7
0
/* Forget any invalid pages in a whole database */
static void
forget_invalid_pages_db(Oid dbid)
{
	HASH_SEQ_STATUS status;
	xl_invalid_page *hentry;

	if (invalid_page_tab == NULL)
		return;					/* nothing to do */

	hash_seq_init(&status, invalid_page_tab);

	while ((hentry = (xl_invalid_page *) hash_seq_search(&status)) != NULL)
	{
		if (hentry->key.node.dbNode == dbid)
		{
			elog(DEBUG2, "page %u of relation %u/%u/%u has been dropped",
				 hentry->key.blkno, hentry->key.node.spcNode,
				 hentry->key.node.dbNode, hentry->key.node.relNode);

			if (hash_search(invalid_page_tab,
							(void *) &hentry->key,
							HASH_REMOVE, NULL) == NULL)
				elog(ERROR, "hash table corrupted");
		}
	}
}
Beispiel #8
0
void
FileRepAckPrimary_ShmemReInit(void)
{
	HASH_SEQ_STATUS				hash_status;
	FileRepAckHashEntry_s		*entry;
	
	if (fileRepAckHashShmem == NULL) {
		ereport(ERROR,
				(errcode(ERRCODE_OUT_OF_MEMORY),
				 (errmsg("not enough shared memory for mirroring"))));
	}
		
	fileRepAckHashShmem->ipcArrayIndex = IndexIpcArrayAckHashShmem;
		
	if (fileRepAckHashShmem->hash == NULL) {
		ereport(ERROR, 
				(errcode(ERRCODE_OUT_OF_MEMORY),
				 (errmsg("not enough shared memory for mirroring"))));
	}
	
	LWLockAcquire(FileRepAckHashShmemLock, LW_EXCLUSIVE);

	hash_seq_init(&hash_status, fileRepAckHashShmem->hash);
	
	while ((entry = (FileRepAckHashEntry_s *) hash_seq_search(&hash_status)) != NULL) {
		
		FileRepAckPrimary_RemoveHashEntry(entry->fileName);
	}
	
	LWLockRelease(FileRepAckHashShmemLock);
	
	return;						  
}
Beispiel #9
0
/*
 * WorkerGetNodeWithName finds and returns a node from the membership list that
 * has the given hostname. The function returns null if no such node exists.
 */
WorkerNode *
WorkerGetNodeWithName(const char *hostname)
{
	WorkerNode *workerNode = NULL;

	HASH_SEQ_STATUS status;
	hash_seq_init(&status, WorkerNodesHash);

	workerNode = (WorkerNode *) hash_seq_search(&status);
	while (workerNode != NULL)
	{
		if (workerNode->inWorkerFile)
		{
			int nameCompare = strncmp(workerNode->workerName, hostname, WORKER_LENGTH);
			if (nameCompare == 0)
			{
				hash_seq_term(&status);
				break;
			}
		}

		workerNode = (WorkerNode *) hash_seq_search(&status);
	}

	return workerNode;
}
/*
 * Clears the contents of the entire Local MDVSN specified.
 */
void
mdver_local_mdvsn_nuke(mdver_local_mdvsn *local_mdvsn)
{
	Assert(NULL != local_mdvsn);
	Assert(NULL != local_mdvsn->htable);

	HASH_SEQ_STATUS iterator;
	hash_seq_init(&iterator, local_mdvsn->htable);
	mdver_entry *entry = NULL;
	int num_deleted = 0;

	while ((entry = (mdver_entry *) hash_seq_search(&iterator)) != NULL)
	{
#if USE_ASSERT_CHECKING
		mdver_entry *result = (mdver_entry *)
#endif
		hash_search(local_mdvsn->htable,
				(void *) &(entry->key),
				HASH_REMOVE,
				NULL);

		Assert(NULL != result);

		num_deleted++;

	}

#ifdef MD_VERSIONING_INSTRUMENTATION
	elog(gp_mdversioning_loglevel, "Nuke at Local MDVSN deleted %d entries", num_deleted);
#endif

	local_mdvsn->nuke_happened = true;

	return;
}
Beispiel #11
0
/*
 * Post-abort cleanup for portals.
 *
 * Delete all portals not held over from prior transactions.
 */
void
AtCleanup_Portals(void)
{
	HASH_SEQ_STATUS status;
	PortalHashEnt *hentry;
	TransactionId xact = GetCurrentTransactionId();

	hash_seq_init(&status, PortalHashTable);

	while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
	{
		Portal		portal = hentry->portal;

		/*
		 * Let's just make sure no one's active...
		 */
		portal->portalActive = false;

		/*
		 * Do nothing else to cursors held over from a previous
		 * transaction. (This test must include checking CURSOR_OPT_HOLD,
		 * else we will fail to clean up a VACUUM portal if it fails after
		 * its first sub-transaction.)
		 */
		if (portal->createXact != xact &&
			(portal->cursorOptions & CURSOR_OPT_HOLD))
			continue;

		/* Else zap it with prejudice. */
		PortalDrop(portal, true);
	}
}
Beispiel #12
0
/* Forget any invalid pages in a whole database */
static void
forget_invalid_pages_db(Oid dbid)
{
	HASH_SEQ_STATUS status;
	xl_invalid_page *hentry;

	if (invalid_page_tab == NULL)
		return;					/* nothing to do */

	hash_seq_init(&status, invalid_page_tab);

	while ((hentry = (xl_invalid_page *) hash_seq_search(&status)) != NULL)
	{
		if (hentry->key.node.dbNode == dbid)
		{
			if (log_min_messages <= DEBUG2 || client_min_messages <= DEBUG2)
			{
				char	   *path = relpathperm(hentry->key.node, hentry->key.forkno);

				elog(DEBUG2, "page %u of relation %s has been dropped",
					 hentry->key.blkno, path);
				pfree(path);
			}

			if (hash_search(invalid_page_tab,
							(void *) &hentry->key,
							HASH_REMOVE, NULL) == NULL)
				elog(ERROR, "hash table corrupted");
		}
	}
}
/*
 * RelfilenodeMapInvalidateCallback
 *		Flush mapping entries when pg_class is updated in a relevant fashion.
 */
static void
RelfilenodeMapInvalidateCallback(Datum arg, Oid relid)
{
	HASH_SEQ_STATUS status;
	RelfilenodeMapEntry *entry;

	/* nothing to do if not active or deleted */
	if (RelfilenodeMapHash == NULL)
		return;

	/* if relid is InvalidOid, we must invalidate the entire cache */
	if (relid == InvalidOid)
	{
		hash_destroy(RelfilenodeMapHash);
		RelfilenodeMapHash = NULL;
		return;
	}

	hash_seq_init(&status, RelfilenodeMapHash);
	while ((entry = (RelfilenodeMapEntry *) hash_seq_search(&status)) != NULL)
	{
		/* Same OID may occur in more than one tablespace. */
		if (entry->relid == relid)
		{
			if (hash_search(RelfilenodeMapHash,
							(void *) &entry->key,
							HASH_REMOVE,
							NULL) == NULL)
				elog(ERROR, "hash table corrupted");
		}
	}
}
Beispiel #14
0
/* Complain about any remaining invalid-page entries */
void
XLogCheckInvalidPages(void)
{
	HASH_SEQ_STATUS status;
	xl_invalid_page *hentry;
	bool		foundone = false;

	if (invalid_page_tab == NULL)
		return;					/* nothing to do */

	hash_seq_init(&status, invalid_page_tab);

	/*
	 * Our strategy is to emit WARNING messages for all remaining entries and
	 * only PANIC after we've dumped all the available info.
	 */
	while ((hentry = (xl_invalid_page *) hash_seq_search(&status)) != NULL)
	{
		report_invalid_page(WARNING, hentry->key.node, hentry->key.forkno,
							hentry->key.blkno, hentry->present);
		foundone = true;
	}

	if (foundone)
		elog(PANIC, "WAL contains references to invalid pages");

	hash_destroy(invalid_page_tab);
	invalid_page_tab = NULL;
}
Beispiel #15
0
/*
 * DynamicScan_CreateIterator
 * 		Creates an iterator state (i.e., DynamicPartitionIterator)
 * 		and saves it to the estate's DynamicTableScanInfo.
 */
static void
DynamicScan_CreateIterator(ScanState *scanState, Scan *scan)
{
	EState *estate = scanState->ps.state;
	Assert(NULL != estate);
	DynamicTableScanInfo *partitionInfo = estate->dynamicTableScanInfo;

	/*
	 * Ensure that the dynahash exists even if the partition selector
	 * didn't choose any partition for current scan node [MPP-24169].
	 */
	InsertPidIntoDynamicTableScanInfo(scan->partIndex, InvalidOid, InvalidPartitionSelectorId);

	Assert(NULL != partitionInfo && NULL != partitionInfo->pidIndexes);
	Assert(partitionInfo->numScans >= scan->partIndex);
	Assert(NULL == partitionInfo->iterators[scan->partIndex - 1]);

	DynamicPartitionIterator *iterator = palloc(sizeof(DynamicPartitionIterator));
	iterator->curRelOid = InvalidOid;
	iterator->partitionMemoryContext = AllocSetContextCreate(CurrentMemoryContext,
			 "DynamicTableScanPerPartition",
			 ALLOCSET_DEFAULT_MINSIZE,
			 ALLOCSET_DEFAULT_INITSIZE,
			 ALLOCSET_DEFAULT_MAXSIZE);
	iterator->partitionOids = partitionInfo->pidIndexes[scan->partIndex - 1];
	Assert(iterator->partitionOids != NULL);
	iterator->shouldCallHashSeqTerm = true;

	HASH_SEQ_STATUS *partitionIterator = palloc(sizeof(HASH_SEQ_STATUS));
	hash_seq_init(partitionIterator, iterator->partitionOids);

	iterator->partitionIterator = partitionIterator;

	partitionInfo->iterators[scan->partIndex - 1] = iterator;
}
Beispiel #16
0
/* Forget any invalid pages in a whole database */
static void
forget_invalid_pages_db(Oid tblspc, Oid dbid)
{
	HASH_SEQ_STATUS status;
	xl_invalid_page *hentry;

	if (invalid_page_tab == NULL)
		return;					/* nothing to do */

	hash_seq_init(&status, invalid_page_tab);

	while ((hentry = (xl_invalid_page *) hash_seq_search(&status)) != NULL)
	{
		if ((!OidIsValid(tblspc) || hentry->key.node.spcNode == tblspc) &&
			hentry->key.node.dbNode == dbid)
		{
			elog(DEBUG2, "page %u of relation %u/%u/%u has been dropped",
				 hentry->key.blkno, hentry->key.node.spcNode,
				 hentry->key.node.dbNode, hentry->key.node.relNode);
			if (Debug_persistent_recovery_print)
				elog(PersistentRecovery_DebugPrintLevel(), 
					 "forget_invalid_pages_db: %u of relation %u/%u/%u has been dropped",
					 hentry->key.blkno,
					 hentry->key.node.spcNode,
					 hentry->key.node.dbNode, 
					 hentry->key.node.relNode);

			if (hash_search(invalid_page_tab,
							(void *) &hentry->key,
							HASH_REMOVE, NULL) == NULL)
				elog(ERROR, "hash table corrupted");
		}
	}
}
Beispiel #17
0
/*
 * Release connection created by calling GetConnection.
 */
void
mysql_rel_connection(MYSQL *conn)
{
	HASH_SEQ_STATUS	scan;
	ConnCacheEntry *entry;

	if (ConnectionHash == NULL)
		return;

	hash_seq_init(&scan, ConnectionHash);
	while ((entry = (ConnCacheEntry *) hash_seq_search(&scan)))
	{
		if (entry->conn == NULL)
			continue;

		if (entry->conn == conn)
		{
			elog(DEBUG3, "disconnecting mysql_fdw connection %p", entry->conn);
			_mysql_close(entry->conn);
			entry->conn = NULL;
			hash_seq_term(&scan);
			break;
		}
	}
}
void
PersistentTablespace_ActivateStandby(int16 oldmaster, int16 newmaster)
{
	TablespaceDirEntry tablespaceDirEntry;
	HASH_SEQ_STATUS hstat;

	WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;

	hash_seq_init(&hstat, persistentTablespaceSharedHashTable);

	if (Persistent_BeforePersistenceWork())
		elog(ERROR, "persistent table changes forbidden");

	PersistentTablespace_VerifyInitScan();

	WRITE_PERSISTENT_STATE_ORDERED_LOCK;

	LWLockAcquire(TablespaceHashLock, LW_SHARED);
	while ((tablespaceDirEntry = hash_seq_search(&hstat)) != NULL)
	{
		PersistentFileSysObjName fsObjName;
		Oid			tblspc = tablespaceDirEntry->key.tablespaceOid;
		ItemPointerData persistentTid;
		uint64		persistentSerialNum;

		tablespaceDirEntry = PersistentTablespace_FindEntryUnderLock(tblspc);

		if (tablespaceDirEntry == NULL)
			elog(ERROR, "cannot find persistent tablespace entry %u",
				 tblspc);

		persistentSerialNum = tablespaceDirEntry->persistentSerialNum;
		ItemPointerCopy(&tablespaceDirEntry->persistentTid, &persistentTid);

		/*
		 * We release TablespaceHashLock in the middle of the loop and
		 * re-acquire it after doing persistent table change.  This is needed
		 * to prevent holding the lock for any purpose other than to protect
		 * the tablespace shared hash table.  Not releasing this lock could
		 * result in file I/O and potential deadlock due to other LW locks
		 * being acquired in the process.  Releasing the lock this way is safe
		 * because we are still holding PersistentObjLock in exclusive mode.
		 * Any change to the filespace shared hash table is also protected by
		 * PersistentObjLock.
		 */

		LWLockRelease(TablespaceHashLock);

		PersistentFileSysObjName_SetTablespaceDir(&fsObjName, tblspc);
		PersistentFileSysObj_ActivateStandby(&fsObjName,
											 &persistentTid,
											 persistentSerialNum,
											 oldmaster,
											 newmaster,
											  /* flushToXlog */ false);
		LWLockAcquire(TablespaceHashLock, LW_SHARED);
	}
	LWLockRelease(TablespaceHashLock);
	WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
}
Beispiel #19
0
/* Complain about any remaining invalid-page entries */
void
XLogCheckInvalidPages(void)
{
	HASH_SEQ_STATUS status;
	xl_invalid_page *hentry;
	bool		foundone = false;

	if (invalid_page_tab == NULL)
		return;					/* nothing to do */

	hash_seq_init(&status, invalid_page_tab);

	/*
	 * Our strategy is to emit WARNING messages for all remaining entries and
	 * only PANIC after we've dumped all the available info.
	 */
	while ((hentry = (xl_invalid_page *) hash_seq_search(&status)) != NULL)
	{
		if (hentry->present)
			elog(WARNING, "page %u of relation %u/%u/%u was uninitialized",
				 hentry->key.blkno, hentry->key.node.spcNode,
				 hentry->key.node.dbNode, hentry->key.node.relNode);
		else
			elog(WARNING, "page %u of relation %u/%u/%u did not exist",
				 hentry->key.blkno, hentry->key.node.spcNode,
				 hentry->key.node.dbNode, hentry->key.node.relNode);
		foundone = true;
	}

	if (foundone)
		elog(PANIC, "WAL contains references to invalid pages");
}
Beispiel #20
0
/*
 * Deallocate least used entries.
 * Caller must hold an exclusive lock on pgss->lock.
 */
static void
entry_dealloc(void)
{
	HASH_SEQ_STATUS hash_seq;
	pgssEntry **entries;
	pgssEntry  *entry;
	int			nvictims;
	int			i;

	/* Sort entries by usage and deallocate USAGE_DEALLOC_PERCENT of them. */

	entries = palloc(hash_get_num_entries(pgss_hash) * sizeof(pgssEntry *));

	i = 0;
	hash_seq_init(&hash_seq, pgss_hash);
	while ((entry = hash_seq_search(&hash_seq)) != NULL)
	{
		entries[i++] = entry;
		entry->counters.usage *= USAGE_DECREASE_FACTOR;
	}

	qsort(entries, i, sizeof(pgssEntry *), entry_cmp);
	nvictims = Max(10, i * USAGE_DEALLOC_PERCENT / 100);
	nvictims = Min(nvictims, i);

	for (i = 0; i < nvictims; i++)
	{
		hash_search(pgss_hash, &entries[i]->key, HASH_REMOVE, NULL);
	}

	pfree(entries);
}
/*
 * dumpDynamicTableScanPidIndex
 *   Write out pids for a given dynamic table scan.
 */
void
dumpDynamicTableScanPidIndex(int index)
{
	if (index < 0 ||
		dynamicTableScanInfo == NULL ||
		index > dynamicTableScanInfo->numScans ||
		dynamicTableScanInfo->pidIndexes[index] == NULL)
	{
		return;
	}
	
	Assert(dynamicTableScanInfo != NULL &&
		   index < dynamicTableScanInfo->numScans &&
		   dynamicTableScanInfo->pidIndexes[index] != NULL);
	
	HASH_SEQ_STATUS status;
	hash_seq_init(&status, dynamicTableScanInfo->pidIndexes[index]);

	StringInfoData pids;
	initStringInfo(&pids);

	Oid *partOid = NULL;
	while ((partOid = (Oid *)hash_seq_search(&status)) != NULL)
	{
		appendStringInfo(&pids, "%d ", *partOid);
	}

	elog(LOG, "Dynamic Table Scan %d pids: %s", index, pids.data);
	pfree(pids.data);
}
Beispiel #22
0
/*
 * smgrIsAppendOnlyMirrorResyncEofs() -- Returns true if there Append-Only Mirror Resync
 * EOF work that needs to be done post-commit or post-abort work.
 *
 * Note that the list does not include anything scheduled for termination
 * by upper-level transactions.
 */
bool
smgrIsAppendOnlyMirrorResyncEofs(EndXactRecKind endXactRecKind)
{
	int			nestLevel = GetCurrentTransactionNestLevel();
	HASH_SEQ_STATUS iterateStatus;
	AppendOnlyMirrorResyncEofs *entry;

	if (AppendOnlyMirrorResyncEofsTable == NULL)
	{
		return false;
	}

	hash_seq_init(&iterateStatus, AppendOnlyMirrorResyncEofsTable);

	while ((entry = hash_seq_search(&iterateStatus)) != NULL)
	{
		if (entry->key.nestLevel >= nestLevel)
		{
			/* Deregister seq scan and exit early. */
			hash_seq_term(&iterateStatus);
			return true;
		}
	}

	return false;
}
Beispiel #23
0
/*
 * RelfilenodeMapInvalidateCallback
 *		Flush mapping entries when pg_class is updated in a relevant fashion.
 */
static void
RelfilenodeMapInvalidateCallback(Datum arg, Oid relid)
{
	HASH_SEQ_STATUS status;
	RelfilenodeMapEntry *entry;

	/* callback only gets registered after creating the hash */
	Assert(RelfilenodeMapHash != NULL);

	hash_seq_init(&status, RelfilenodeMapHash);
	while ((entry = (RelfilenodeMapEntry *) hash_seq_search(&status)) != NULL)
	{
		/*
		 * If relid is InvalidOid, signalling a complete reset, we must remove
		 * all entries, otherwise just remove the specific relation's entry.
		 * Always remove negative cache entries.
		 */
		if (relid == InvalidOid ||		/* complete reset */
			entry->relid == InvalidOid ||		/* negative cache entry */
			entry->relid == relid)		/* individual flushed relation */
		{
			if (hash_search(RelfilenodeMapHash,
							(void *) &entry->key,
							HASH_REMOVE,
							NULL) == NULL)
				elog(ERROR, "hash table corrupted");
		}
	}
}
Beispiel #24
0
/* Forget any invalid pages >= minblkno, because they've been dropped */
static void
forget_invalid_pages(RelFileNode node, BlockNumber minblkno)
{
	HASH_SEQ_STATUS status;
	xl_invalid_page *hentry;

	if (invalid_page_tab == NULL)
		return;					/* nothing to do */

	hash_seq_init(&status, invalid_page_tab);

	while ((hentry = (xl_invalid_page *) hash_seq_search(&status)) != NULL)
	{
		if (RelFileNodeEquals(hentry->key.node, node) &&
			hentry->key.blkno >= minblkno)
		{
			elog(DEBUG2, "page %u of relation %u/%u/%u has been dropped",
				 hentry->key.blkno, hentry->key.node.spcNode,
				 hentry->key.node.dbNode, hentry->key.node.relNode);
			if (Debug_persistent_recovery_print)
				elog(PersistentRecovery_DebugPrintLevel(), 
					 "forget_invalid_pages: page %u of relation %u/%u/%u has been dropped",
					 hentry->key.blkno,
					 hentry->key.node.spcNode,
					 hentry->key.node.dbNode, 
					 hentry->key.node.relNode);

			if (hash_search(invalid_page_tab,
							(void *) &hentry->key,
							HASH_REMOVE, NULL) == NULL)
				elog(ERROR, "hash table corrupted");
		}
	}
}
Beispiel #25
0
/*
 * Pre-prepare processing for portals.
 *
 * Currently we refuse PREPARE if the transaction created any holdable
 * cursors, since it's quite unclear what to do with one.  However, this
 * has the same API as CommitHoldablePortals and is invoked in the same
 * way by xact.c, so that we can easily do something reasonable if anyone
 * comes up with something reasonable to do.
 *
 * Returns TRUE if any holdable cursors were processed, FALSE if not.
 */
bool
PrepareHoldablePortals(void)
{
	bool		result = false;
	HASH_SEQ_STATUS status;
	PortalHashEnt *hentry;

	hash_seq_init(&status, PortalHashTable);

	while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
	{
		Portal		portal = hentry->portal;

		/* Is it a holdable portal created in the current xact? */
		if ((portal->cursorOptions & CURSOR_OPT_HOLD) &&
			portal->createSubid != InvalidSubTransactionId &&
			portal->status == PORTAL_READY)
		{
			/*
			 * We are exiting the transaction that created a holdable cursor.
			 * Can't do PREPARE.
			 */
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					 errmsg("cannot PREPARE a transaction that has created a cursor WITH HOLD")));
		}
	}

	return result;
}
Beispiel #26
0
/*
 * shmem_shutdown hook: Dump statistics into file.
 *
 * Note: we don't bother with acquiring lock, because there should be no
 * other processes running when this is called.
 */
static void
pgss_shmem_shutdown(int code, Datum arg)
{
	FILE	   *file;
	HASH_SEQ_STATUS hash_seq;
	int32		num_entries;
	pgssEntry  *entry;

	/* Don't try to dump during a crash. */
	if (code)
		return;

	/* Safety check ... shouldn't get here unless shmem is set up. */
	if (!pgss || !pgss_hash)
		return;

	/* Don't dump if told not to. */
	if (!pgss_save)
		return;

	file = AllocateFile(PGSS_DUMP_FILE, PG_BINARY_W);
	if (file == NULL)
		goto error;

	if (fwrite(&PGSS_FILE_HEADER, sizeof(uint32), 1, file) != 1)
		goto error;
	num_entries = hash_get_num_entries(pgss_hash);
	if (fwrite(&num_entries, sizeof(int32), 1, file) != 1)
		goto error;

	hash_seq_init(&hash_seq, pgss_hash);
	while ((entry = hash_seq_search(&hash_seq)) != NULL)
	{
		int			len = entry->key.query_len;

		if (fwrite(entry, offsetof(pgssEntry, mutex), 1, file) != 1 ||
			fwrite(entry->query, 1, len, file) != len)
			goto error;
	}

	if (FreeFile(file))
	{
		file = NULL;
		goto error;
	}

	return;

error:
	ereport(LOG,
			(errcode_for_file_access(),
			 errmsg("could not write pg_stat_statement file \"%s\": %m",
					PGSS_DUMP_FILE)));
	if (file)
		FreeFile(file);
	unlink(PGSS_DUMP_FILE);
}
/*
 * initialize the seq search of the DispatchedFilespaceDirHashTable.
 */
static void
DispatchedFilespace_SeqSearch_Init(void)
{
	if (DispatchedFileSpace_SeqSearch_Initialized || (!DispatchedFilespaceDirHashTable))
	{
		return;
	}
	hash_seq_init(&DispatchedFileSpace_SeqSearch, DispatchedFilespaceDirHashTable);
	DispatchedFileSpace_SeqSearch_Initialized = true;
}
Beispiel #28
0
static void
xact_callback(XactEvent event, void *arg)
{
    HASH_SEQ_STATUS   scan;
    PlxConnHashEntry *entry = NULL;
    char             *sql   = NULL;

    switch (event)
    {
        case XACT_EVENT_PRE_COMMIT:
            sql = "commit;";
            break;
        case XACT_EVENT_ABORT:
            sql = "rollback;";
            break;
        case XACT_EVENT_PRE_PREPARE:
            ereport(ERROR,
                    (errcode(ERRCODE_RAISE_EXCEPTION),
                     errmsg("cannot prepare a transaction that modified remote tables")));
            break;
        case XACT_EVENT_COMMIT:
        case XACT_EVENT_PREPARE:
            /* Pre-commit should have closed the open transaction */
            ereport(ERROR,
                    (errcode(ERRCODE_RAISE_EXCEPTION),
                     errmsg("missed cleaning up connection during pre-commit"))); //FIXME cur_func in NULL
            break;
        default:
            return;
    }

    /*
     * Scan all connection cache entries to find open remote transactions, and
     * close them.
     */
    hash_seq_init(&scan, plx_conn_cache);
    while ((entry = (PlxConnHashEntry *) hash_seq_search(&scan)))
    {
        PlxConn *plx_conn = entry->plx_conn;

        if (plx_conn->xlevel > 0)
        {
            PGresult *pg_result;
            pg_result = PQexec(plx_conn->pq_conn, sql);
            if (pg_result)
                PQclear(pg_result);
            plx_conn->xlevel = 0;
        }

    }
    UnregisterXactCallback(xact_callback, NULL);
    UnregisterSubXactCallback(subxact_callback, NULL);
    is_remote_transaction = false;
}
Beispiel #29
0
/*
 * End a rewrite.
 *
 * state and any other resources are freed.
 */
void
end_heap_rewrite(RewriteState state)
{
	HASH_SEQ_STATUS seq_status;
	UnresolvedTup unresolved;

	/*
	 * Write any remaining tuples in the UnresolvedTups table. If we have any
	 * left, they should in fact be dead, but let's err on the safe side.
	 */
	hash_seq_init(&seq_status, state->rs_unresolved_tups);

	while ((unresolved = hash_seq_search(&seq_status)) != NULL)
	{
		ItemPointerSetInvalid(&unresolved->tuple->t_data->t_ctid);
		raw_heap_insert(state, unresolved->tuple);
	}

	/* Write the last page, if any */
	if (state->rs_buffer_valid)
	{
		if (state->rs_use_wal)
			log_newpage(&state->rs_new_rel->rd_node,
						MAIN_FORKNUM,
						state->rs_blockno,
						state->rs_buffer,
						true);
		RelationOpenSmgr(state->rs_new_rel);

		PageSetChecksumInplace(state->rs_buffer, state->rs_blockno);

		smgrextend(state->rs_new_rel->rd_smgr, MAIN_FORKNUM, state->rs_blockno,
				   (char *) state->rs_buffer, true);
	}

	/*
	 * If the rel is WAL-logged, must fsync before commit.	We use heap_sync
	 * to ensure that the toast table gets fsync'd too.
	 *
	 * It's obvious that we must do this when not WAL-logging. It's less
	 * obvious that we have to do it even if we did WAL-log the pages. The
	 * reason is the same as in tablecmds.c's copy_relation_data(): we're
	 * writing data that's not in shared buffers, and so a CHECKPOINT
	 * occurring during the rewriteheap operation won't have fsync'd data we
	 * wrote before the checkpoint.
	 */
	if (RelationNeedsWAL(state->rs_new_rel))
		heap_sync(state->rs_new_rel);

	/* Deleting the context frees everything */
	MemoryContextDelete(state->rs_cxt);
}
Beispiel #30
0
/*
 * Pre-commit processing for portals.
 *
 * Remove all non-holdable portals created in this transaction.
 * Portals remaining from prior transactions should be left untouched.
 */
void
AtCommit_Portals(void)
{
	HASH_SEQ_STATUS status;
	PortalHashEnt *hentry;

	hash_seq_init(&status, PortalHashTable);

	while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
	{
		Portal		portal = hentry->portal;

		/*
		 * Do not touch active portals --- this can only happen in the case of
		 * a multi-transaction utility command, such as VACUUM.
		 *
		 * Note however that any resource owner attached to such a portal is
		 * still going to go away, so don't leave a dangling pointer.
		 */
		if (portal->status == PORTAL_ACTIVE)
		{
			portal->resowner = NULL;
			continue;
		}

		/*
		 * Do nothing to cursors held over from a previous transaction
		 * (including holdable ones just frozen by CommitHoldablePortals).
		 */
		if (portal->createSubid == InvalidSubTransactionId)
			continue;

		/* Zap all non-holdable portals */
		PortalDrop(portal, true);

		/* Restart the iteration */
		hash_seq_init(&status, PortalHashTable);
	}
}