]> granicus.if.org Git - postgresql/commitdiff
Make autovacuum more aggressive to remove orphaned temp tables
authorMichael Paquier <michael@paquier.xyz>
Mon, 13 Aug 2018 09:49:04 +0000 (11:49 +0200)
committerMichael Paquier <michael@paquier.xyz>
Mon, 13 Aug 2018 09:49:04 +0000 (11:49 +0200)
Commit dafa084, added in 10, made the removal of temporary orphaned
tables more aggressive.  This commit makes an extra step into the
aggressiveness by adding a flag in each backend's MyProc which tracks
down any temporary namespace currently in use.  The flag is set when the
namespace gets created and can be reset if the temporary namespace has
been created in a transaction or sub-transaction which is aborted.  The
flag value assignment is assumed to be atomic, so this can be done in a
lock-less fashion like other flags already present in PGPROC like
databaseId or backendId, still the fact that the temporary namespace and
table created are still locked until the transaction creating those
commits acts as a barrier for other backends.

This new flag gets used by autovacuum to discard more aggressively
orphaned tables by additionally checking for the database a backend is
connected to as well as its temporary namespace in-use, removing
orphaned temporary relations even if a backend reuses the same slot as
one which created temporary relations in a past session.

The base idea of this patch comes from Robert Haas, has been written in
its first version by Tsunakawa Takayuki, then heavily reviewed by me.

Author: Tsunakawa Takayuki
Reviewed-by: Michael Paquier, Kyotaro Horiguchi, Andres Freund
Discussion: https://postgr.es/m/0A3221C70F24FB45833433255569204D1F8A4DC6@G01JPEXMBYT05
Backpatch: 11-, as PGPROC gains a new flag and we don't want silent ABI
breakages on already released versions.

src/backend/access/transam/twophase.c
src/backend/catalog/namespace.c
src/backend/postmaster/autovacuum.c
src/backend/storage/lmgr/proc.c
src/include/catalog/namespace.h
src/include/storage/proc.h

index 0ae0722794147c1909a45bbed8bd2d2999ae5b57..4aff6cf7f278965d73019f7cf9ddb3ea813994ee 100644 (file)
@@ -471,6 +471,7 @@ MarkAsPreparingGuts(GlobalTransaction gxact, TransactionId xid, const char *gid,
        proc->backendId = InvalidBackendId;
        proc->databaseId = databaseid;
        proc->roleId = owner;
+       proc->tempNamespaceId = InvalidOid;
        proc->isBackgroundWorker = false;
        proc->lwWaiting = false;
        proc->lwWaitMode = 0;
index 0f67a122ededddc76d29c8cab7219ac37198182b..3971346e738d1d8e0c0fce89587a4cb51abb598b 100644 (file)
@@ -47,7 +47,7 @@
 #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"
@@ -3204,6 +3204,46 @@ isOtherTempNamespace(Oid namespaceId)
        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
@@ -3893,6 +3933,16 @@ InitTempTableNamespace(void)
        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();
@@ -3923,6 +3973,15 @@ AtEOXact_Namespace(bool isCommit, bool parallel)
                        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;
        }
@@ -3975,6 +4034,15 @@ AtEOSubXact_Namespace(bool isCommit, SubTransactionId mySubid,
                        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;
                }
        }
 
index 1d9cfc63d2211eba8ecb9c3cc746939afc05bc19..978089575b80f315c514bfdf49b808bf4210138a 100644 (file)
@@ -2080,14 +2080,11 @@ do_autovacuum(void)
                 */
                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
@@ -2215,7 +2212,6 @@ do_autovacuum(void)
        {
                Oid                     relid = lfirst_oid(cell);
                Form_pg_class classForm;
-               int                     backendID;
                ObjectAddress object;
 
                /*
@@ -2257,10 +2253,8 @@ do_autovacuum(void)
                        UnlockRelationOid(relid, AccessExclusiveLock);
                        continue;
                }
-               backendID = GetTempNamespaceBackendId(classForm->relnamespace);
-               if (!(backendID != InvalidBackendId &&
-                         (backendID == MyBackendId ||
-                          BackendIdGetProc(backendID) == NULL)))
+
+               if (isTempNamespaceInUse(classForm->relnamespace))
                {
                        UnlockRelationOid(relid, AccessExclusiveLock);
                        continue;
index 6f30e082b26a5bd47ee94e6116e86a3da71db29e..6f9aaa52faf3317f38b1244e24177d9d2d87786e 100644 (file)
@@ -371,6 +371,7 @@ InitProcess(void)
        MyProc->backendId = InvalidBackendId;
        MyProc->databaseId = InvalidOid;
        MyProc->roleId = InvalidOid;
+       MyProc->tempNamespaceId = InvalidOid;
        MyProc->isBackgroundWorker = IsBackgroundWorker;
        MyPgXact->delayChkpt = false;
        MyPgXact->vacuumFlags = 0;
@@ -552,6 +553,7 @@ InitAuxiliaryProcess(void)
        MyProc->backendId = InvalidBackendId;
        MyProc->databaseId = InvalidOid;
        MyProc->roleId = InvalidOid;
+       MyProc->tempNamespaceId = InvalidOid;
        MyProc->isBackgroundWorker = IsBackgroundWorker;
        MyPgXact->delayChkpt = false;
        MyPgXact->vacuumFlags = 0;
index 7991de5e210bb5800fb652d5350b914cecf48f52..0e202372d5aecf4669ca51d421492fe14aad9121 100644 (file)
@@ -137,6 +137,7 @@ extern bool isTempToastNamespace(Oid namespaceId);
 extern bool isTempOrTempToastNamespace(Oid namespaceId);
 extern bool isAnyTempNamespace(Oid namespaceId);
 extern bool isOtherTempNamespace(Oid namespaceId);
+extern bool isTempNamespaceInUse(Oid namespaceId);
 extern int     GetTempNamespaceBackendId(Oid namespaceId);
 extern Oid     GetTempToastNamespace(void);
 extern void GetTempNamespaceState(Oid *tempNamespaceId,
index 5c19a61dcf85a5f8922be0afb67a88d1b9a28b28..cb613c8076ede2b3f71f89cbd719e433b4c53e37 100644 (file)
@@ -114,6 +114,9 @@ struct PGPROC
        Oid                     databaseId;             /* OID of database this backend is using */
        Oid                     roleId;                 /* OID of role using this backend */
 
+       Oid                     tempNamespaceId;        /* OID of temp schema this backend is
+                                                                        * using */
+
        bool            isBackgroundWorker; /* true if background worker. */
 
        /*