#include "parser/parse_func.h"
#include "storage/ipc.h"
#include "storage/lmgr.h"
-#include "storage/sinval.h"
+#include "storage/sinvaladt.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/catcache.h"
return isAnyTempNamespace(namespaceId);
}
+/*
+ * isTempNamespaceInUse - is the given namespace owned and actively used
+ * by a backend?
+ *
+ * Note: this can be used while scanning relations in pg_class to detect
+ * orphaned temporary tables or namespaces with a backend connected to a
+ * given database. The result may be out of date quickly, so the caller
+ * must be careful how to handle this information.
+ */
+bool
+isTempNamespaceInUse(Oid namespaceId)
+{
+ PGPROC *proc;
+ int backendId;
+
+ Assert(OidIsValid(MyDatabaseId));
+
+ backendId = GetTempNamespaceBackendId(namespaceId);
+
+ if (backendId == InvalidBackendId ||
+ backendId == MyBackendId)
+ return false;
+
+ /* Is the backend alive? */
+ proc = BackendIdGetProc(backendId);
+ if (proc == NULL)
+ return false;
+
+ /* Is the backend connected to the same database we are looking at? */
+ if (proc->databaseId != MyDatabaseId)
+ return false;
+
+ /* Does the backend own the temporary namespace? */
+ if (proc->tempNamespaceId != namespaceId)
+ return false;
+
+ /* all good to go */
+ return true;
+}
+
/*
* GetTempNamespaceBackendId - if the given namespace is a temporary-table
* namespace (either my own, or another backend's), return the BackendId
myTempNamespace = namespaceId;
myTempToastNamespace = toastspaceId;
+ /*
+ * Mark MyProc as owning this namespace which other processes can use to
+ * decide if a temporary namespace is in use or not. We assume that
+ * assignment of namespaceId is an atomic operation. Even if it is not,
+ * the temporary relation which resulted in the creation of this temporary
+ * namespace is still locked until the current transaction commits, so it
+ * would not be accessible yet, acting as a barrier.
+ */
+ MyProc->tempNamespaceId = namespaceId;
+
/* It should not be done already. */
AssertState(myTempNamespaceSubID == InvalidSubTransactionId);
myTempNamespaceSubID = GetCurrentSubTransactionId();
myTempNamespace = InvalidOid;
myTempToastNamespace = InvalidOid;
baseSearchPathValid = false; /* need to rebuild list */
+
+ /*
+ * Reset the temporary namespace flag in MyProc. We assume that
+ * this operation is atomic. Even if it is not, the temporary
+ * table which created this namespace is still locked until this
+ * transaction aborts so it would not be visible yet, acting as a
+ * barrier.
+ */
+ MyProc->tempNamespaceId = InvalidOid;
}
myTempNamespaceSubID = InvalidSubTransactionId;
}
myTempNamespace = InvalidOid;
myTempToastNamespace = InvalidOid;
baseSearchPathValid = false; /* need to rebuild list */
+
+ /*
+ * Reset the temporary namespace flag in MyProc. We assume that
+ * this operation is atomic. Even if it is not, the temporary
+ * table which created this namespace is still locked until this
+ * transaction aborts so it would not be visible yet, acting as a
+ * barrier.
+ */
+ MyProc->tempNamespaceId = InvalidOid;
}
}
*/
if (classForm->relpersistence == RELPERSISTENCE_TEMP)
{
- int backendID;
-
- backendID = GetTempNamespaceBackendId(classForm->relnamespace);
-
- /* We just ignore it if the owning backend is still active */
- if (backendID != InvalidBackendId &&
- (backendID == MyBackendId ||
- BackendIdGetProc(backendID) == NULL))
+ /*
+ * We just ignore it if the owning backend is still active and
+ * using the temporary schema.
+ */
+ if (!isTempNamespaceInUse(classForm->relnamespace))
{
/*
* The table seems to be orphaned -- although it might be that
{
Oid relid = lfirst_oid(cell);
Form_pg_class classForm;
- int backendID;
ObjectAddress object;
/*
UnlockRelationOid(relid, AccessExclusiveLock);
continue;
}
- backendID = GetTempNamespaceBackendId(classForm->relnamespace);
- if (!(backendID != InvalidBackendId &&
- (backendID == MyBackendId ||
- BackendIdGetProc(backendID) == NULL)))
+
+ if (isTempNamespaceInUse(classForm->relnamespace))
{
UnlockRelationOid(relid, AccessExclusiveLock);
continue;
MyProc->backendId = InvalidBackendId;
MyProc->databaseId = InvalidOid;
MyProc->roleId = InvalidOid;
+ MyProc->tempNamespaceId = InvalidOid;
MyProc->isBackgroundWorker = IsBackgroundWorker;
MyPgXact->delayChkpt = false;
MyPgXact->vacuumFlags = 0;
MyProc->backendId = InvalidBackendId;
MyProc->databaseId = InvalidOid;
MyProc->roleId = InvalidOid;
+ MyProc->tempNamespaceId = InvalidOid;
MyProc->isBackgroundWorker = IsBackgroundWorker;
MyPgXact->delayChkpt = false;
MyPgXact->vacuumFlags = 0;