Beispiel #1
0
/*
 * AtSubCommit_Notify() --- Take care of subtransaction commit.
 *
 * Reassign all items in the pending notifies list to the parent transaction.
 */
void
AtSubCommit_Notify(void)
{
	List	   *parentPendingNotifies;

	parentPendingNotifies = (List *) linitial(upperPendingNotifies);
	upperPendingNotifies = list_delete_first(upperPendingNotifies);

	Assert(list_length(upperPendingNotifies) ==
		   GetCurrentTransactionNestLevel() - 2);

	/*
	 * We could try to eliminate duplicates here, but it seems not worthwhile.
	 */
	pendingNotifies = list_concat(parentPendingNotifies, pendingNotifies);
}
/*
 *	smgrDoPendingDeletes() -- Take care of relation deletes at end of xact.
 *
 * This also runs when aborting a subxact; we want to clean up a failed
 * subxact immediately.
 */
void
smgrDoPendingDeletes(bool isCommit)
{
	int			nestLevel = GetCurrentTransactionNestLevel();
	PendingRelDelete *pending;
	PendingRelDelete *prev;
	PendingRelDelete *next;

	prev = NULL;
	for (pending = pendingDeletes; pending != NULL; pending = next)
	{
		next = pending->next;
		if (pending->nestLevel < nestLevel)
		{
			/* outer-level entries should not be processed yet */
			prev = pending;
		}
		else
		{
			/* unlink list entry first, so we don't retry on failure */
			if (prev)
				prev->next = next;
			else
				pendingDeletes = next;
			/* do deletion if called for */
			if (pending->atCommit == isCommit)
			{
				SMgrRelation srel;
				int			i;

				srel = smgropen(pending->relnode);
				for (i = 0; i <= MAX_FORKNUM; i++)
				{
					if (smgrexists(srel, i))
						smgrdounlink(srel,
									 i,
									 pending->isTemp,
									 false);
				}
				smgrclose(srel);
			}
			/* must explicitly free the list entry */
			pfree(pending);
			/* prev does not change */
		}
	}
}
Beispiel #3
0
/*
 * AtSubStart_Notify() --- Take care of subtransaction start.
 *
 * Push empty state for the new subtransaction.
 */
void
AtSubStart_Notify(void)
{
	MemoryContext old_cxt;

	/* Keep the list-of-lists in TopTransactionContext for simplicity */
	old_cxt = MemoryContextSwitchTo(TopTransactionContext);

	upperPendingNotifies = lcons(pendingNotifies, upperPendingNotifies);

	Assert(list_length(upperPendingNotifies) ==
		   GetCurrentTransactionNestLevel() - 1);

	pendingNotifies = NIL;

	MemoryContextSwitchTo(old_cxt);
}
Beispiel #4
0
static void
subxact_callback(SubXactEvent event,
                 SubTransactionId mySubid,
                 SubTransactionId parentSubid,
                 void *arg)
{
    char              sql[1024]; //fixme
    HASH_SEQ_STATUS   scan;
    PlxConnHashEntry *entry = NULL;
    int               curlevel;

    /* Nothing to do at subxact start, nor after commit. */
    if (!is_remote_subtransaction ||
        !(event == SUBXACT_EVENT_PRE_COMMIT_SUB ||
          event == SUBXACT_EVENT_ABORT_SUB))
        return;

    curlevel = GetCurrentTransactionNestLevel();

    if (event == SUBXACT_EVENT_PRE_COMMIT_SUB)
        snprintf(sql, sizeof(sql), "release savepoint s%d", curlevel);
    else
        snprintf(sql, sizeof(sql),
                 "rollback to savepoint s%d; release savepoint s%d",
                 curlevel, curlevel);

    hash_seq_init(&scan, plx_conn_cache);
    while ((entry = (PlxConnHashEntry *) hash_seq_search(&scan)))
    {
        PlxConn *plx_conn = entry->plx_conn;
        if (plx_conn->xlevel < curlevel)
            continue;

        if (plx_conn->xlevel > curlevel)
            ereport(ERROR,
                    (errcode(ERRCODE_RAISE_EXCEPTION),
                     errmsg("missed cleaning up remote subtransaction at level")));

        if (!PQexec(plx_conn->pq_conn, sql))
            ereport(ERROR,
                    (errcode(ERRCODE_RAISE_EXCEPTION),
                     errmsg("error on %s", sql)));
        plx_conn->xlevel--;
    }
}
Beispiel #5
0
/*
 * RelationMapUpdateMap
 *
 * Install a new relfilenode mapping for the specified relation.
 *
 * If immediate is true (or we're bootstrapping), the mapping is activated
 * immediately.  Otherwise it is made pending until CommandCounterIncrement.
 */
void
RelationMapUpdateMap(Oid relationId, Oid fileNode, bool shared,
					 bool immediate)
{
	RelMapFile *map;

	if (IsBootstrapProcessingMode())
	{
		/*
		 * In bootstrap mode, the mapping gets installed in permanent map.
		 */
		if (shared)
			map = &shared_map;
		else
			map = &local_map;
	}
	else
	{
		/*
		 * We don't currently support map changes within subtransactions. This
		 * could be done with more bookkeeping infrastructure, but it doesn't
		 * presently seem worth it.
		 */
		if (GetCurrentTransactionNestLevel() > 1)
			elog(ERROR, "cannot change relation mapping within subtransaction");

		if (immediate)
		{
			/* Make it active, but only locally */
			if (shared)
				map = &active_shared_updates;
			else
				map = &active_local_updates;
		}
		else
		{
			/* Make it pending */
			if (shared)
				map = &pending_shared_updates;
			else
				map = &pending_local_updates;
		}
	}
	apply_map_update(map, relationId, fileNode, true);
}
Beispiel #6
0
static void KtBeginTransactionIfNeeded(KtConnCacheEntry* entry) {
    int curlevel = GetCurrentTransactionNestLevel(); //I dont think it should ever be less than 1;

    if(curlevel < 1) //I dont get something
        elog(ERROR, "Transaction level should not be less than one"); // I don't understand

    if(curlevel > 1) //kt does not support savepoints
        ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
            errmsg("Kyoto Tycoon does not support savepoints")));

    if (entry->xact_depth < curlevel){
        if(!ktbegin_transaction(entry->db))
            elog(ERROR,"Could not begin transaction from KT %s %s", ktgeterror(entry->db), ktgeterrormsg(entry->db));
        entry->xact_depth = curlevel; //1
        xact_got_connection = true;
    }

}
Beispiel #7
0
/*
 * AtEOSubXact_Inval
 *		Process queued-up invalidation messages at end of subtransaction.
 *
 * If isCommit, process CurrentCmdInvalidMsgs if any (there probably aren't),
 * and then attach both CurrentCmdInvalidMsgs and PriorCmdInvalidMsgs to the
 * parent's PriorCmdInvalidMsgs list.
 *
 * If not isCommit, we are aborting, and must locally process the messages
 * in PriorCmdInvalidMsgs.	No messages need be sent to other backends.
 * We can forget about CurrentCmdInvalidMsgs too, since those changes haven't
 * touched the caches yet.
 *
 * In any case, pop the transaction stack.	We need not physically free memory
 * here, since CurTransactionContext is about to be emptied anyway
 * (if aborting).  Beware of the possibility of aborting the same nesting
 * level twice, though.
 */
void
AtEOSubXact_Inval(bool isCommit)
{
	int			my_level = GetCurrentTransactionNestLevel();
	TransInvalidationInfo *myInfo = transInvalInfo;

	if (isCommit)
	{
		/* Must be at non-top of stack */
		Assert(myInfo != NULL && myInfo->parent != NULL);
		Assert(myInfo->my_level == my_level);

		/* If CurrentCmdInvalidMsgs still has anything, fix it */
		CommandEndInvalidationMessages();

		/* Pass up my inval messages to parent */
		AppendInvalidationMessages(&myInfo->parent->PriorCmdInvalidMsgs,
								   &myInfo->PriorCmdInvalidMsgs);

		/* Pending relcache inval becomes parent's problem too */
		if (myInfo->RelcacheInitFileInval)
			myInfo->parent->RelcacheInitFileInval = true;

		/* Pop the transaction state stack */
		transInvalInfo = myInfo->parent;

		/* Need not free anything else explicitly */
		pfree(myInfo);
	}
	else if (myInfo != NULL && myInfo->my_level == my_level)
	{
		/* Must be at non-top of stack */
		Assert(myInfo->parent != NULL);

		ProcessInvalidationMessages(&myInfo->PriorCmdInvalidMsgs,
									LocalExecuteInvalidationMessage);

		/* Pop the transaction state stack */
		transInvalInfo = myInfo->parent;

		/* Need not free anything else explicitly */
		pfree(myInfo);
	}
}
Beispiel #8
0
/*
 * RelationCreateStorage
 *		Create physical storage for a relation.
 *
 * Create the underlying disk file storage for the relation. This only
 * creates the main fork; additional forks are created lazily by the
 * modules that need them.
 *
 * This function is transactional. The creation is WAL-logged, and if the
 * transaction aborts later on, the storage will be destroyed.
 */
void
RelationCreateStorage(RelFileNode rnode, char relpersistence)
{
	PendingRelDelete *pending;
	SMgrRelation srel;
	BackendId	backend;
	bool		needs_wal;

	switch (relpersistence)
	{
		case RELPERSISTENCE_TEMP:
			backend = MyBackendId;
			needs_wal = false;
			break;
		case RELPERSISTENCE_UNLOGGED:
			backend = InvalidBackendId;
			needs_wal = false;
			break;
		case RELPERSISTENCE_PERMANENT:
			backend = InvalidBackendId;
			needs_wal = true;
			break;
		default:
			elog(ERROR, "invalid relpersistence: %c", relpersistence);
			return;				/* placate compiler */
	}

	srel = smgropen(rnode, backend);
	smgrcreate(srel, MAIN_FORKNUM, false);

	if (needs_wal)
		log_smgrcreate(&srel->smgr_rnode.node, MAIN_FORKNUM);

	/* Add the relation to the list of stuff to delete at abort */
	pending = (PendingRelDelete *)
		MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
	pending->relnode = rnode;
	pending->backend = backend;
	pending->atCommit = false;	/* delete if abort */
	pending->nestLevel = GetCurrentTransactionNestLevel();
	pending->next = pendingDeletes;
	pendingDeletes = pending;
}
Beispiel #9
0
/*
 * Request worker for specified sub/rel to be stopped on commit.
 */
void
logicalrep_worker_stop_at_commit(Oid subid, Oid relid)
{
	int			nestDepth = GetCurrentTransactionNestLevel();
	LogicalRepWorkerId *wid;
	MemoryContext oldctx;

	/* Make sure we store the info in context that survives until commit. */
	oldctx = MemoryContextSwitchTo(TopTransactionContext);

	/* Check that previous transactions were properly cleaned up. */
	Assert(on_commit_stop_workers == NULL ||
		   nestDepth >= on_commit_stop_workers->nestDepth);

	/*
	 * Push a new stack element if we don't already have one for the current
	 * nestDepth.
	 */
	if (on_commit_stop_workers == NULL ||
		nestDepth > on_commit_stop_workers->nestDepth)
	{
		StopWorkersData *newdata = palloc(sizeof(StopWorkersData));

		newdata->nestDepth = nestDepth;
		newdata->workers = NIL;
		newdata->parent = on_commit_stop_workers;
		on_commit_stop_workers = newdata;
	}

	/*
	 * Finally add a new worker into the worker list of the current
	 * subtransaction.
	 */
	wid = palloc(sizeof(LogicalRepWorkerId));
	wid->subid = subid;
	wid->relid = relid;
	on_commit_stop_workers->workers =
		lappend(on_commit_stop_workers->workers, wid);

	MemoryContextSwitchTo(oldctx);
}
Beispiel #10
0
/*
 * AtSubAbort_Notify() --- Take care of subtransaction abort.
 */
void
AtSubAbort_Notify(void)
{
	int			my_level = GetCurrentTransactionNestLevel();

	/*
	 * All we have to do is pop the stack --- the notifies made in this
	 * subxact are no longer interesting, and the space will be freed when
	 * CurTransactionContext is recycled.
	 *
	 * This routine could be called more than once at a given nesting level if
	 * there is trouble during subxact abort.  Avoid dumping core by using
	 * GetCurrentTransactionNestLevel as the indicator of how far we need to
	 * prune the list.
	 */
	while (list_length(upperPendingNotifies) > my_level - 2)
	{
		pendingNotifies = (List *) linitial(upperPendingNotifies);
		upperPendingNotifies = list_delete_first(upperPendingNotifies);
	}
}
Beispiel #11
0
void
smgrAppendOnlySubTransAbort(void)
{
	int			nestLevel = GetCurrentTransactionNestLevel();
	HASH_SEQ_STATUS iterateStatus;
	AppendOnlyMirrorResyncEofs *entry;

	/*
	 * Throw away sub-transaction Append-Only mirror resync EOFs.
	 */
	hash_seq_init(&iterateStatus,
				  AppendOnlyMirrorResyncEofsTable);

	while ((entry = hash_seq_search(&iterateStatus)) != NULL)
	{
		if (entry->key.nestLevel >= nestLevel)
		{
			AppendOnlyMirrorResyncEofs_Remove("smgrSubTransAbort",
											  entry);
		}
	}
}
Beispiel #12
0
/*
 * RelationCreateStorage
 *		Create physical storage for a relation.
 *
 * Create the underlying disk file storage for the relation. This only
 * creates the main fork; additional forks are created lazily by the
 * modules that need them.
 *
 * This function is transactional. The creation is WAL-logged, and if the
 * transaction aborts later on, the storage will be destroyed.
 */
void
RelationCreateStorage(RelFileNode rnode, bool istemp)
{
	PendingRelDelete *pending;
	XLogRecPtr	lsn;
	XLogRecData rdata;
	xl_smgr_create xlrec;
	SMgrRelation srel;

	srel = smgropen(rnode);
	smgrcreate(srel, MAIN_FORKNUM, false);

	if (!istemp)
	{
		/*
		 * Make an XLOG entry showing the file creation.  If we abort, the
		 * file will be dropped at abort time.
		 */
		xlrec.rnode = rnode;

		rdata.data = (char *) &xlrec;
		rdata.len = sizeof(xlrec);
		rdata.buffer = InvalidBuffer;
		rdata.next = NULL;

		lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE, &rdata);
	}

	/* Add the relation to the list of stuff to delete at abort */
	pending = (PendingRelDelete *)
		MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
	pending->relnode = rnode;
	pending->isTemp = istemp;
	pending->atCommit = false;	/* delete if abort */
	pending->nestLevel = GetCurrentTransactionNestLevel();
	pending->next = pendingDeletes;
	pendingDeletes = pending;
}
Beispiel #13
0
/*
 * Start remote transaction or subtransaction, if needed.
 *
 * Note that we always use at least REPEATABLE READ in the remote session.
 * This is so that, if a query initiates multiple scans of the same or
 * different foreign tables, we will get snapshot-consistent results from
 * those scans.  A disadvantage is that we can't provide sane emulation of
 * READ COMMITTED behavior --- it would be nice if we had some other way to
 * control which remote queries share a snapshot.
 */
static void
begin_remote_xact(ConnCacheEntry *entry)
{
    int         curlevel = GetCurrentTransactionNestLevel();

//TODO: Replace this code with JDBC Connection call
return;
    /* Start main transaction if we haven't yet */
    if (entry->xact_depth <= 0)
    {
        const char *sql;

        elog(DEBUG3, "starting remote transaction on connection %p",
             entry->conn);

        if (IsolationIsSerializable())
            sql = "START TRANSACTION ISOLATION LEVEL SERIALIZABLE";
        else
            sql = "START TRANSACTION ISOLATION LEVEL REPEATABLE READ";
        do_sql_command(entry->conn, sql);
        entry->xact_depth = 1;
    }

    /*
     * If we're in a subtransaction, stack up savepoints to match our level.
     * This ensures we can rollback just the desired effects when a
     * subtransaction aborts.
     */
    while (entry->xact_depth < curlevel)
    {
        char        sql[64];

        snprintf(sql, sizeof(sql), "SAVEPOINT s%d", entry->xact_depth + 1);
        do_sql_command(entry->conn, sql);
        entry->xact_depth++;
    }
}
Beispiel #14
0
void
smgrappendonlymirrorresynceofs(RelFileNode *relFileNode,
							   int32 segmentFileNum,
							   char *relationName,
							   ItemPointer persistentTid,
							   int64 persistentSerialNum,
							   bool mirrorCatchupRequired,
							   MirrorDataLossTrackingState mirrorDataLossTrackingState,
							   int64 mirrorDataLossTrackingSessionNum,
							   int64 mirrorNewEof)
{
	Assert(mirrorNewEof > 0);

	AppendOnlyMirrorResyncEofs_Merge(relFileNode,
									 segmentFileNum,
									 GetCurrentTransactionNestLevel(),
									 relationName,
									 persistentTid,
									 persistentSerialNum,
									 mirrorCatchupRequired,
									 mirrorDataLossTrackingState,
									 mirrorDataLossTrackingSessionNum,
									 mirrorNewEof);
}
Beispiel #15
0
/*
 *	smgrDoPendingDeletes() -- Take care of relation deletes at end of xact.
 *
 * This also runs when aborting a subxact; we want to clean up a failed
 * subxact immediately.
 */
void
smgrDoPendingDeletes(bool isCommit)
{
	int			nestLevel = GetCurrentTransactionNestLevel();
	PendingRelDelete *pending;
	PendingRelDelete *prev;
	PendingRelDelete *next;

	prev = NULL;
	for (pending = pendingDeletes; pending != NULL; pending = next)
	{
		next = pending->next;
		if (pending->nestLevel < nestLevel)
		{
			/* outer-level entries should not be processed yet */
			prev = pending;
		}
		else
		{
			/* unlink list entry first, so we don't retry on failure */
			if (prev)
				prev->next = next;
			else
				pendingDeletes = next;
			/* do deletion if called for */
			if (pending->atCommit == isCommit)
				smgr_internal_unlink(pending->relnode,
									 pending->which,
									 pending->isTemp,
									 false);
			/* must explicitly free the list entry */
			pfree(pending);
			/* prev does not change */
		}
	}
}
Beispiel #16
0
void
start_transaction(PlxConn *plx_conn)
{
    int        curlevel;
    StringInfo sql = NULL;

    if (!strcmp(plx_conn->plx_cluster->isolation_level, "auto commit"))
        return;

    curlevel = GetCurrentTransactionNestLevel();
    if (!is_remote_transaction)
    {
        RegisterXactCallback(xact_callback, NULL);
        RegisterSubXactCallback(subxact_callback, NULL);
        is_remote_transaction = true;
    }

    if (plx_conn->xlevel == 0)
    {
        sql = makeStringInfo();
        appendStringInfo(sql,
                         "start transaction isolation level %s;",
                         plx_conn->plx_cluster->isolation_level);
        plx_conn->xlevel = 1;
    }

    while (plx_conn->xlevel < curlevel)
    {
        if (!sql)
            sql = makeStringInfo();
        appendStringInfo(sql, "savepoint s%d; ", (int) ++(plx_conn->xlevel));
        is_remote_subtransaction = true;
    }
    if (sql)
        PQclear(PQexec(plx_conn->pq_conn, sql->data));
}
Beispiel #17
0
/*
 * pgfdw_subxact_callback --- cleanup at subtransaction end.
 */
static void
pgfdw_subxact_callback(SubXactEvent event, SubTransactionId mySubid,
					   SubTransactionId parentSubid, void *arg)
{
	HASH_SEQ_STATUS scan;
	ConnCacheEntry *entry;
	int			curlevel;

	/* Nothing to do at subxact start, nor after commit. */
	if (!(event == SUBXACT_EVENT_PRE_COMMIT_SUB ||
		  event == SUBXACT_EVENT_ABORT_SUB))
		return;

	/* Quick exit if no connections were touched in this transaction. */
	if (!xact_got_connection)
		return;

	/*
	 * Scan all connection cache entries to find open remote subtransactions
	 * of the current level, and close them.
	 */
	curlevel = GetCurrentTransactionNestLevel();
	hash_seq_init(&scan, ConnectionHash);
	while ((entry = (ConnCacheEntry *) hash_seq_search(&scan)))
	{
		PGresult   *res;
		char		sql[100];

		/*
		 * We only care about connections with open remote subtransactions of
		 * the current level.
		 */
		if (entry->conn == NULL || entry->xact_depth < curlevel)
			continue;

		if (entry->xact_depth > curlevel)
			elog(ERROR, "missed cleaning up remote subtransaction at level %d",
				 entry->xact_depth);

		if (event == SUBXACT_EVENT_PRE_COMMIT_SUB)
		{
			/* Commit all remote subtransactions during pre-commit */
			snprintf(sql, sizeof(sql), "RELEASE SAVEPOINT s%d", curlevel);
			do_sql_command(entry->conn, sql);
		}
		else
		{
			/* Assume we might have lost track of prepared statements */
			entry->have_error = true;

			/*
			 * If a command has been submitted to the remote server by using
			 * an asynchronous execution function, the command might not have
			 * yet completed.  Check to see if a command is still being
			 * processed by the remote server, and if so, request cancellation
			 * of the command.
			 */
			if (PQtransactionStatus(entry->conn) == PQTRANS_ACTIVE)
			{
				PGcancel   *cancel;
				char		errbuf[256];

				if ((cancel = PQgetCancel(entry->conn)))
				{
					if (!PQcancel(cancel, errbuf, sizeof(errbuf)))
						ereport(WARNING,
								(errcode(ERRCODE_CONNECTION_FAILURE),
								 errmsg("could not send cancel request: %s",
										errbuf)));
					PQfreeCancel(cancel);
				}
			}

			/* Rollback all remote subtransactions during abort */
			snprintf(sql, sizeof(sql),
					 "ROLLBACK TO SAVEPOINT s%d; RELEASE SAVEPOINT s%d",
					 curlevel, curlevel);
			res = PQexec(entry->conn, sql);
			if (PQresultStatus(res) != PGRES_COMMAND_OK)
				pgfdw_report_error(WARNING, res, entry->conn, true, sql);
			else
				PQclear(res);
		}

		/* OK, we're outta that level of subtransaction */
		entry->xact_depth--;
	}
}
Beispiel #18
0
void
DtxContextInfo_CreateOnMaster(DtxContextInfo *dtxContextInfo,
							  DistributedSnapshotWithLocalMapping *dslm,
							  CommandId curcid, int txnOptions)
{
	int i;

	DtxContextInfo_Reset(dtxContextInfo);

	dtxContextInfo->distributedXid = getDistributedTransactionId();

	if (dtxContextInfo->distributedXid != InvalidDistributedTransactionId)
	{
		if (syncCacheXid == dtxContextInfo->distributedXid)
			dtxContextInfo->segmateSync = ++syncCount;
		else
		{
			syncCacheXid = dtxContextInfo->distributedXid;
			dtxContextInfo->segmateSync = syncCount = 1;
		}

		dtxContextInfo->distributedTimeStamp = getDtxStartTime();

		getDistributedTransactionIdentifier(dtxContextInfo->distributedId);
		dtxContextInfo->curcid = curcid;
	}
	else
	{
		elog((Debug_print_full_dtm ? LOG : DEBUG5),
			 "DtxContextInfo_CreateOnMaster Gp_role is DISPATCH and distributed transaction is InvalidDistributedTransactionId");

		syncCacheXid = dtxContextInfo->distributedXid;
		dtxContextInfo->segmateSync = syncCount = 1;
	}

	dtxContextInfo->nestingLevel = GetCurrentTransactionNestLevel();

	elog((Debug_print_full_dtm ? LOG : DEBUG5),
		 "DtxContextInfo_CreateOnMaster: created dtxcontext with dxid %u/%u nestingLevel %d segmateSync %u/%u (current/cached)",
		 dtxContextInfo->distributedXid, syncCacheXid, dtxContextInfo->nestingLevel,
		 dtxContextInfo->segmateSync, syncCount);

	if (dslm == NULL)
		dtxContextInfo->haveDistributedSnapshot = false;
	else
	{
		DtxContextInfo_CopyDistributedSnapshot(&dtxContextInfo->distributedSnapshot, dslm);
		dtxContextInfo->haveDistributedSnapshot = true;
	}

	dtxContextInfo->distributedTxnOptions = txnOptions;

	if (DEBUG5 >= log_min_messages || Debug_print_full_dtm)
	{
		char gid[TMGIDSIZE];
		DistributedSnapshot *ds = &dtxContextInfo->distributedSnapshot;

		if (!getDistributedTransactionIdentifier(gid))
			memcpy(gid, "<empty>", 8);
		
		elog((Debug_print_full_dtm ? LOG : DEBUG5),
			 "DtxContextInfo_CreateOnMaster Gp_role is DISPATCH and have currentGxact = %s, gxid = %u --> have distributed snapshot",
			 gid, 
			 getDistributedTransactionId());
		elog((Debug_print_full_dtm ? LOG : DEBUG5),
			 "DtxContextInfo_CreateOnMaster distributedXid = %u, "
		     "distributedSnapshotHeader (xminAllDistributedSnapshots %u, xmin = %u, xmax = %u, count = %d, maxCount %d)",
			 dtxContextInfo->distributedXid,
			 ds->header.xminAllDistributedSnapshots,
			 ds->header.xmin, 
			 ds->header.xmax,
			 ds->header.count,
			 ds->header.maxCount);
		
		for (i = 0; i < ds->header.count; i++)
		{
			elog((Debug_print_full_dtm ? LOG : DEBUG5),
				 "....    distributedSnapshotData->xip[%d] = %u", 
			     i, ds->inProgressXidArray[i]);
		}
		elog((Debug_print_full_dtm ? LOG : DEBUG5),
			 "DtxContextInfo_CreateOnMaster curcid = %u",
			 dtxContextInfo->curcid);

		elog((Debug_print_full_dtm ? LOG : DEBUG5),
			 "DtxContextInfo_CreateOnMaster txnOptions = 0x%x, needTwoPhase = %s, explicitBegin = %s, isoLevel = %s, readOnly = %s.", 
			 txnOptions, 
			 (isMppTxOptions_NeedTwoPhase(txnOptions) ? "true" : "false"),
			 (isMppTxOptions_ExplicitBegin(txnOptions) ? "true" : "false"),
			 IsoLevelAsUpperString(mppTxOptions_IsoLevel(txnOptions)),
			 (isMppTxOptions_ReadOnly(txnOptions) ? "true" : "false")); 
	}
}
Beispiel #19
0
int
smgrGetAppendOnlyMirrorResyncEofs(EndXactRecKind endXactRecKind,
								  PersistentEndXactAppendOnlyMirrorResyncEofs **ptr)
{
	int			nestLevel = GetCurrentTransactionNestLevel();
	int			nentries;
	PersistentEndXactAppendOnlyMirrorResyncEofs *rptr;
	HASH_SEQ_STATUS iterateStatus;
	AppendOnlyMirrorResyncEofs *entry;
	int			entryIndex;

	if (endXactRecKind == EndXactRecKind_Abort)
	{
		/*
		 * No Append-Only Mirror Resync EOF information needed on abort.
		 */
		*ptr = NULL;
		return 0;
	}

	nentries = 0;

	if (AppendOnlyMirrorResyncEofsTable != NULL)
	{
		hash_seq_init(&iterateStatus,
					  AppendOnlyMirrorResyncEofsTable);

		while ((entry = hash_seq_search(&iterateStatus)) != NULL)
		{
			if (entry->key.nestLevel >= nestLevel)
				nentries++;
		}
	}
	if (nentries == 0)
	{
		*ptr = NULL;
		return 0;
	}

	if (Debug_persistent_print ||
		Debug_persistent_appendonly_commit_count_print)
		elog(Persistent_DebugPrintLevel(),
			 "Storage Manager: Get Append-Only mirror resync eofs list entries (current transaction nest level %d, Append-Only commit work system count %d)",
			 nestLevel,
			 FileRepPrimary_GetAppendOnlyCommitWorkCount());

	rptr = (PersistentEndXactAppendOnlyMirrorResyncEofs *)
		palloc(nentries * sizeof(PersistentEndXactAppendOnlyMirrorResyncEofs));
	*ptr = rptr;
	entryIndex = 0;
	hash_seq_init(&iterateStatus, AppendOnlyMirrorResyncEofsTable);

	while ((entry = hash_seq_search(&iterateStatus)) != NULL)
	{
		MIRRORED_LOCK_DECLARE;

		bool		returned;
		int			resultSystemAppendOnlyCommitCount;

		returned = false;
		if (entry->key.nestLevel >= nestLevel)
		{
			MIRRORED_LOCK;

			MirroredAppendOnly_EndXactCatchup(entryIndex,
											  &entry->key.relFileNode,
											  entry->key.segmentFileNum,
											  entry->key.nestLevel,
											  entry->relationName,
											  &entry->persistentTid,
											  entry->persistentSerialNum,
											  &mirroredLockLocalVars,
											  entry->mirrorCatchupRequired,
											  entry->mirrorDataLossTrackingState,
											  entry->mirrorDataLossTrackingSessionNum,
											  entry->mirrorNewEof);

			/*
			 * See if the mirror situation for this Append-Only segment file
			 * has changed since we flushed it to disk.
			 */
			rptr->relFileNode = entry->key.relFileNode;
			rptr->segmentFileNum = entry->key.segmentFileNum;

			rptr->persistentTid = entry->persistentTid;
			rptr->persistentSerialNum = entry->persistentSerialNum;

			if (entry->mirrorCatchupRequired)
			{
				rptr->mirrorLossEof = INT64CONST(-1);
			}
			else
			{
				rptr->mirrorLossEof = entry->mirrorNewEof;
			}
			rptr->mirrorNewEof = entry->mirrorNewEof;

			rptr++;
			returned = true;

			START_CRIT_SECTION();

			LWLockAcquire(FileRepAppendOnlyCommitCountLock, LW_EXCLUSIVE);

			resultSystemAppendOnlyCommitCount =
				FileRepPrimary_IntentAppendOnlyCommitWork();

			/* Set this inside the Critical Section. */
			entry->didIncrementCommitCount = true;

			if (endXactRecKind == EndXactRecKind_Prepare)
			{
				char		gid[TMGIDSIZE];

				if (!getDistributedTransactionIdentifier(gid))
					elog(ERROR, "Unable to obtain gid during prepare");

				PrepareIntentAppendOnlyCommitWork(gid);

				entry->isDistributedTransaction = true;
				memcpy(entry->gid, gid, TMGIDSIZE);
			}

			pendingAppendOnlyMirrorResyncIntentCount++;

		}
		else
		{
			MIRRORED_LOCK;

			START_CRIT_SECTION();

			LWLockAcquire(FileRepAppendOnlyCommitCountLock, LW_EXCLUSIVE);

			resultSystemAppendOnlyCommitCount =
				FileRepPrimary_GetAppendOnlyCommitWorkCount();
		}

		if (Debug_persistent_print ||
			Debug_persistent_appendonly_commit_count_print)
		{
			if (entry->relationName == NULL)
				elog(Persistent_DebugPrintLevel(),
					 "Storage Manager: Get Append-Only mirror resync eofs list entry #%d: %u/%u/%u, segment file #%d "
					 "(returned %s, result system Append-Only commit count %d, transaction nest level %d, persistent TID %s, persistent serial number " INT64_FORMAT ", mirror catchup required %s, mirror new EOF " INT64_FORMAT ")",
					 entryIndex,
					 entry->key.relFileNode.spcNode,
					 entry->key.relFileNode.dbNode,
					 entry->key.relFileNode.relNode,
					 entry->key.segmentFileNum,
					 (returned ? "true" : "false"),
					 resultSystemAppendOnlyCommitCount,
					 entry->key.nestLevel,
					 ItemPointerToString(&entry->persistentTid),
					 entry->persistentSerialNum,
					 (entry->mirrorCatchupRequired ? "true" : "false"),
					 entry->mirrorNewEof);
			else
				elog(Persistent_DebugPrintLevel(),
					 "Storage Manager: Get Append-Only mirror resync eofs list entry #%d: %u/%u/%u, segment file #%d, relation name '%s' "
					 "(returned %s, result system Append-Only commit count %d, transaction nest level %d, persistent TID %s, persistent serial number " INT64_FORMAT ", mirror catchup required %s, mirror new EOF " INT64_FORMAT ")",
					 entryIndex,
					 entry->key.relFileNode.spcNode,
					 entry->key.relFileNode.dbNode,
					 entry->key.relFileNode.relNode,
					 entry->key.segmentFileNum,
					 entry->relationName,
					 (returned ? "true" : "false"),
					 resultSystemAppendOnlyCommitCount,
					 entry->key.nestLevel,
					 ItemPointerToString(&entry->persistentTid),
					 entry->persistentSerialNum,
					 (entry->mirrorCatchupRequired ? "true" : "false"),
					 entry->mirrorNewEof);
		}

		LWLockRelease(FileRepAppendOnlyCommitCountLock);

		END_CRIT_SECTION();

		MIRRORED_UNLOCK;

		entryIndex++;
	}
	return nentries;
}
Beispiel #20
0
/*
 * pgfdw_subxact_callback --- cleanup at subtransaction end.
 */
static void
pgfdw_subxact_callback(SubXactEvent event, SubTransactionId mySubid,
					   SubTransactionId parentSubid, void *arg)
{
	HASH_SEQ_STATUS scan;
	ConnCacheEntry *entry;
	int			curlevel;

	/* Nothing to do at subxact start, nor after commit. */
	if (!(event == SUBXACT_EVENT_PRE_COMMIT_SUB ||
		  event == SUBXACT_EVENT_ABORT_SUB))
		return;

	/* Quick exit if no connections were touched in this transaction. */
	if (!xact_got_connection)
		return;

	/*
	 * Scan all connection cache entries to find open remote subtransactions
	 * of the current level, and close them.
	 */
	curlevel = GetCurrentTransactionNestLevel();
	hash_seq_init(&scan, ConnectionHash);
	while ((entry = (ConnCacheEntry *) hash_seq_search(&scan)))
	{
		PGresult   *res;
		char		sql[100];

		/*
		 * We only care about connections with open remote subtransactions of
		 * the current level.
		 */
		if (entry->conn == NULL || entry->xact_depth < curlevel)
			continue;

		if (entry->xact_depth > curlevel)
			elog(ERROR, "missed cleaning up remote subtransaction at level %d",
				 entry->xact_depth);

		if (event == SUBXACT_EVENT_PRE_COMMIT_SUB)
		{
			/* Commit all remote subtransactions during pre-commit */
			snprintf(sql, sizeof(sql), "RELEASE SAVEPOINT s%d", curlevel);
			do_sql_command(entry->conn, sql);
		}
		else
		{
			/* Assume we might have lost track of prepared statements */
			entry->have_error = true;
			/* Rollback all remote subtransactions during abort */
			snprintf(sql, sizeof(sql),
					 "ROLLBACK TO SAVEPOINT s%d; RELEASE SAVEPOINT s%d",
					 curlevel, curlevel);
			res = PQexec(entry->conn, sql);
			if (PQresultStatus(res) != PGRES_COMMAND_OK)
				pgfdw_report_error(WARNING, res, true, sql);
			else
				PQclear(res);
		}

		/* OK, we're outta that level of subtransaction */
		entry->xact_depth--;
	}
}
Beispiel #21
0
/*
 *	smgrDoPendingDeletes() -- Take care of relation deletes at end of xact.
 *
 * This also runs when aborting a subxact; we want to clean up a failed
 * subxact immediately.
 *
 * Note: It's possible that we're being asked to remove a relation that has
 * no physical storage in any fork. In particular, it's possible that we're
 * cleaning up an old temporary relation for which RemovePgTempFiles has
 * already recovered the physical storage.
 */
void
smgrDoPendingDeletes(bool isCommit)
{
	int			nestLevel = GetCurrentTransactionNestLevel();
	PendingRelDelete *pending;
	PendingRelDelete *prev;
	PendingRelDelete *next;
	int			nrels = 0,
				i = 0,
				maxrels = 0;
	SMgrRelation *srels = NULL;

	prev = NULL;
	for (pending = pendingDeletes; pending != NULL; pending = next)
	{
		next = pending->next;
		if (pending->nestLevel < nestLevel)
		{
			/* outer-level entries should not be processed yet */
			prev = pending;
		}
		else
		{
			/* unlink list entry first, so we don't retry on failure */
			if (prev)
				prev->next = next;
			else
				pendingDeletes = next;
			/* do deletion if called for */
			if (pending->atCommit == isCommit)
			{
				SMgrRelation srel;

				srel = smgropen(pending->relnode, pending->backend);

				/* allocate the initial array, or extend it, if needed */
				if (maxrels == 0)
				{
					maxrels = 8;
					srels = palloc(sizeof(SMgrRelation) * maxrels);
				}
				else if (maxrels <= nrels)
				{
					maxrels *= 2;
					srels = repalloc(srels, sizeof(SMgrRelation) * maxrels);
				}

				srels[nrels++] = srel;
			}
			/* must explicitly free the list entry */
			pfree(pending);
			/* prev does not change */
		}
	}

	if (nrels > 0)
	{
		smgrdounlinkall(srels, nrels, false);

		for (i = 0; i < nrels; i++)
			smgrclose(srels[i]);

		pfree(srels);
	}
}
Beispiel #22
0
/*
 * AtEOSubXact_Inval
 *		Process queued-up invalidation messages at end of subtransaction.
 *
 * If isCommit, process CurrentCmdInvalidMsgs if any (there probably aren't),
 * and then attach both CurrentCmdInvalidMsgs and PriorCmdInvalidMsgs to the
 * parent's PriorCmdInvalidMsgs list.
 *
 * If not isCommit, we are aborting, and must locally process the messages
 * in PriorCmdInvalidMsgs.  No messages need be sent to other backends.
 * We can forget about CurrentCmdInvalidMsgs too, since those changes haven't
 * touched the caches yet.
 *
 * In any case, pop the transaction stack.  We need not physically free memory
 * here, since CurTransactionContext is about to be emptied anyway
 * (if aborting).  Beware of the possibility of aborting the same nesting
 * level twice, though.
 */
void
AtEOSubXact_Inval(bool isCommit)
{
	int			my_level;
	TransInvalidationInfo *myInfo = transInvalInfo;

	/* Quick exit if no messages. */
	if (myInfo == NULL)
		return;

	/* Also bail out quickly if messages are not for this level. */
	my_level = GetCurrentTransactionNestLevel();
	if (myInfo->my_level != my_level)
	{
		Assert(myInfo->my_level < my_level);
		return;
	}

	if (isCommit)
	{
		/* If CurrentCmdInvalidMsgs still has anything, fix it */
		CommandEndInvalidationMessages();

		/*
		 * We create invalidation stack entries lazily, so the parent might
		 * not have one.  Instead of creating one, moving all the data over,
		 * and then freeing our own, we can just adjust the level of our own
		 * entry.
		 */
		if (myInfo->parent == NULL || myInfo->parent->my_level < my_level - 1)
		{
			myInfo->my_level--;
			return;
		}

		/* Pass up my inval messages to parent */
		AppendInvalidationMessages(&myInfo->parent->PriorCmdInvalidMsgs,
								   &myInfo->PriorCmdInvalidMsgs);

		/* Pending relcache inval becomes parent's problem too */
		if (myInfo->RelcacheInitFileInval)
			myInfo->parent->RelcacheInitFileInval = true;

		/* Pop the transaction state stack */
		transInvalInfo = myInfo->parent;

		/* Need not free anything else explicitly */
		pfree(myInfo);
	}
	else
	{
		ProcessInvalidationMessages(&myInfo->PriorCmdInvalidMsgs,
									LocalExecuteInvalidationMessage);

		/* Pop the transaction state stack */
		transInvalInfo = myInfo->parent;

		/* Need not free anything else explicitly */
		pfree(myInfo);
	}
}