Example #1
0
/*
 * Main entry point for clients that request versions for objects. Returns
 * the most recent visible version of an object when requested by a
 * backend/client.
 *
 * If no version is found, a new version for the object is generated and
 * recorded in the caches. New versioning events are potentially generated
 * as well if needed.
 *
 * This function never returns INVALID_MD_VERSION as a result.
 *
 *   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
 *
 */
void
mdver_request_version(Oid key, uint64 *ddl_version, uint64 *dml_version)
{

	Assert(NULL != ddl_version);
	Assert(NULL != dml_version);

	*dml_version = INVALID_MD_VERSION;
	*ddl_version = INVALID_MD_VERSION;

	if (!mdver_enabled())
	{
		/*
		 * MD Versioning feature is turned off. Return (1,0) as a fixed
		 * version so that ORCA can check for equality etc.
		 */
		*ddl_version = 1;
		*dml_version = 0;
		return;
	}

	/*
	 * Basic flow is described below. More details can be found in
	 * the Metadata Versioning design document.
	 *
	 * - Do a look-up in the Local MDVSN. If the object is found there,
	 *   return its version.
	 * - If not found in Local MDVSN, and nuke_happened is not set,
	 *   do a look-up in the Global MDVSN.
	 *    - If the object is found there,
	 *       - Add it to the Local MDVSN and
	 *       - Return its version.
	 *    - If the object is not in Global MDVSN
	 *        - Generate a new version for the object
	 *        - Record the version in Global MDVSN
	 *        - Add new version to Local MDVSN
	 *        - Return new version
	 * - If not found in Local MDVSN and nuke_happened is set, the object
	 *  needs a new version.
	 *    - Generate a new version for the object
	 *    - Read current version from Global MDVSN (if exists)
	 *    - Add a versioning event to the CVQ with the new version
	 *    - Record the new version in the Local MDVSN
	 *    - Return the new version.
	 */

	/* Try Local MDVSN first */
	mdver_local_mdvsn *local_mdvsn = GetCurrentLocalMDVSN();
	Assert(NULL != local_mdvsn);

	mdver_entry *crt_entry = mdver_local_mdvsn_find(local_mdvsn, key);
	if (NULL != crt_entry)
	{

#ifdef MD_VERSIONING_INSTRUMENTATION
		elog(gp_mdversioning_loglevel, "Found version in Local MDVSN: (%d, " UINT64_FORMAT ", " UINT64_FORMAT ")",
				key, crt_entry->ddl_version, crt_entry->dml_version);
#endif

		*ddl_version = crt_entry->ddl_version;
		*dml_version = crt_entry->dml_version;
		return;
	}

	if (!local_mdvsn->nuke_happened)
	{
		/* TODO gcaragea 6/3/2014: Traverse subtransaction contexts during look-up (MPP-22935) */
		mdver_request_from_global(key, ddl_version, dml_version);

	}
	else
	{
		mdver_request_after_nuke(key, ddl_version, dml_version);
	}

	Assert(INVALID_MD_VERSION != *ddl_version ||
			INVALID_MD_VERSION != *dml_version);

	mdver_entry new_entry = { key, *ddl_version, *dml_version};
	mdver_local_mdvsn_add(local_mdvsn, &new_entry, true /* local */);

}
/*
 * 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) */
		}

	}
}