/*
 * Reconcile and resolve conflicts for incoming versioning events.
 *
 * This function handles both events generated locally and remotely by other
 * backends.
 *
 * When a new versioning event is received at the Local MDVSN,
 * look up if the same object has a conflicting version locally.
 *
 * If a conflict is detected, resolve by generating a new version for
 * the "combined" object. We don't generate a new VE for the conflict.
 * This means the combined object version is only visible to the
 * current backend.
 *
 *   event: The new event to be considered
 *   local_entry: The conflicting entry in the Local MDVSN cache
 */
static void
mdver_localhandler_reconcile(mdver_event *event, mdver_entry *local_entry)
{

#ifdef MD_VERSIONING_INSTRUMENTATION
	char *mdev_str = mdver_event_str(event);
	elog(gp_mdversioning_loglevel, "Local VE Handler: Reconcile: Local entry = %d: (%d, %d). Incoming event %s",
			local_entry->key,
			(int) local_entry->ddl_version,
			(int) local_entry->dml_version,
			mdev_str);
	pfree(mdev_str);
#endif

	uint64 new_ddl_version = event->new_ddl_version;
	uint64 new_dml_version = event->new_dml_version;
	bool conflict = false;

	if (local_entry->ddl_version != event->old_ddl_version)
	{
		new_ddl_version = mdver_next_global_version();
		conflict = true;
	}

	if (local_entry->dml_version != event->old_dml_version)
	{
		new_dml_version = mdver_next_global_version();
		conflict = true;
	}

#if MD_VERSIONING_INSTRUMENTATION
	if (conflict)
	{
		elog(gp_mdversioning_loglevel, "Local VE Handler: Conflict resolved. New"
				"version generated, updated local entry to %d : (%d,%d) -> (%d, %d)",
				local_entry->key,
				(int) local_entry->ddl_version, (int) local_entry->dml_version,
				(int) new_ddl_version, (int) new_dml_version);

	}
	else
	{
		elog(gp_mdversioning_loglevel, "Local VE Handler: No conflict. Update local entry to %d : (%d,%d) -> (%d, %d)",
				local_entry->key,
				(int) event->old_ddl_version, (int) event->old_dml_version,
				(int) event->new_ddl_version, (int) event->new_dml_version);
	}
#endif

	/* Update local entry with the resolved versions */
	local_entry->ddl_version = new_ddl_version;
	local_entry->dml_version = new_dml_version;
}
Example #2
0
/*
 * When a backend is requesting the more recent version of an object,
 * if the Local MDVSN cache doesn't have the version, and if a NUKE event
 * has been encountered in the current transaction, a new version is
 * generated and returned for the object. A new versioning event is also
 * produced.
 *
 *   key: The key of the looked-up object
 *   ddl_version: used to return the ddl version for the object
 *   dml_version: used to return the dml version for the object
 *
 */
static void
mdver_request_after_nuke(Oid key, uint64 *ddl_version, uint64 *dml_version)
{
	Assert(NULL != ddl_version);
	Assert(NULL != dml_version);

	/* Generate new version */
	*ddl_version = mdver_next_global_version();
	*dml_version = mdver_next_global_version();

	mdver_event *new_event = (mdver_event *) palloc0(sizeof(mdver_event));
	new_event->key = key;
	new_event->new_ddl_version = *ddl_version;
	new_event->new_dml_version = *dml_version;
	new_event->old_ddl_version = INVALID_MD_VERSION;
	new_event->old_dml_version = INVALID_MD_VERSION;

#ifdef MD_VERSIONING_INSTRUMENTATION
	/* Add my current process id as the originating backend pid */
	new_event->backend_pid = MyProcPid;
#endif

	/* Annotate Versioning Event with the current version from Global MDVSN if exists */
	mdver_entry *crt_entry = mdver_glob_mdvsn_find(key);
	if (NULL != crt_entry)
	{
		new_event->old_ddl_version = crt_entry->ddl_version;
		new_event->old_dml_version = crt_entry->dml_version;
	}

	CacheAddVersioningEvent(new_event);

#ifdef MD_VERSIONING_INSTRUMENTATION
	char *mdev_str = mdver_event_str(new_event);
	ereport(gp_mdversioning_loglevel,
			(errmsg("mdver_consume_after_nuke: generated new VE %s",
					mdev_str),
					errprintstack(false)));
	pfree(mdev_str);
#endif

	/* A copy of the event is added to the queue above. We can pfree our local copy */
	pfree(new_event);
}
/*
 * Entry point for the Local Versioning Event Handler. This gets called
 * for every message that is executed locally at a backend.
 */
extern void
mdver_localhandler_new_event(SharedInvalidationMessage *msg)
{
	Assert(NULL != msg);
	Assert(SHAREDVERSIONINGMSG_ID == msg->id);

#ifdef MD_VERSIONING_INSTRUMENTATION
	char *mdev_str = mdver_event_str(&msg->ve.verEvent);
	ereport(gp_mdversioning_loglevel,
			(errmsg("LocalExecuteVE: got %s event %s",
					msg->ve.local ? "LOCAL" : "REMOTE",
					mdev_str),
					errprintstack(false)));
	pfree(mdev_str);
#endif

	/*
	 * There are some cases where we don't have a transInvalInfo structure,
	 * and thus we don't have a Local MDVSN. For example:
	 *  - an auxiliary process (fts prober comes to mind) that queries
	 *    catalog tables directly using heap functions (no transaction)
	 *  - updating persistent tables during transaction commit
	 *    (transInvalInfo has already been reset).
	 *  - bootstrap
	 *
	 * In other cases, we simply don't have a Local MDVSN since we don't
	 * cache versions:
	 *  - a QE process running on the master or segments will have a
	 *    syscache, but not a Metadata Version cache
	 *
	 * In those cases we don't care about versioning, so skip adding
	 * to local MDVSN.
	 */

	mdver_local_mdvsn *local_mdvsn = GetCurrentLocalMDVSN();
	if (NULL != local_mdvsn)
	{

		mdver_event *event = &msg->ve.verEvent;

		if (mdver_is_nuke_event(event))
		{
			elog(gp_mdversioning_loglevel, "Local VE Handler: Received NUKE event");
			mdver_local_mdvsn_nuke(local_mdvsn);
			return;
		}

		if (msg->ve.local)
		{
			/*
			 * Locally generated event, we must add or update the version
			 * in the Local MDVSN.
			 */
			mdver_entry entry;
			entry.key = event->key;

			/* FIXME gcaragea 7/4/2014: Can we assert anything here? */
			entry.ddl_version = event->new_ddl_version;
			entry.dml_version = event->new_dml_version;

			mdver_local_mdvsn_add(local_mdvsn, &entry, msg->ve.local);
		}
		else
		{
			/*
			 * An event coming from the global queue (GVQ)
			 * If we are interested in this object, add / update
			 * version in Local MDVSN.
			 *
			 */

			mdver_entry *local_entry = mdver_local_mdvsn_find(local_mdvsn, event->key);
			if (NULL != local_entry)
			{

				/*
				 * A VE came from SVQ for a key that we already have locally.
				 * Need to reconcile and record.
				 */
				mdver_localhandler_reconcile(event, local_entry);
			}
			else
			{
				elog(gp_mdversioning_loglevel, "Local VE Handler: Ignoring remote event for object not of interest key=%d", event->key);
			}

			/* TODO gcaragea 5/27/2014: For subtransactions, keep all messages (MPP-22935) */
		}

	}
}