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