Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
When VACUUM or ANALYZE skips a concurrently dropped table, log it.
authorRobert Haas <rhaas@postgresql.org>
Mon, 4 Dec 2017 20:23:36 +0000 (15:23 -0500)
committerRobert Haas <rhaas@postgresql.org>
Mon, 4 Dec 2017 20:25:55 +0000 (15:25 -0500)
Hopefully, the additional logging will help avoid confusion that
could otherwise result.

Nathan Bossart, reviewed by Michael Paquier, Fabrízio Mello, and me

doc/src/sgml/config.sgml
src/backend/commands/analyze.c
src/backend/commands/vacuum.c
src/test/isolation/expected/vacuum-concurrent-drop.out [new file with mode: 0644]
src/test/isolation/isolation_schedule
src/test/isolation/specs/vacuum-concurrent-drop.spec [new file with mode: 0644]

index 3060597011dd720e553b04116d1bc60712039fe7..563ad1fc7f8a1bee1f6059f64fd06f2d5e84b52b 100644 (file)
@@ -5926,8 +5926,8 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
         <literal>250ms</literal> then all automatic vacuums and analyzes that run
         250ms or longer will be logged.  In addition, when this parameter is
         set to any value other than <literal>-1</literal>, a message will be
-        logged if an autovacuum action is skipped due to the existence of a
-        conflicting lock.  Enabling this parameter can be helpful
+        logged if an autovacuum action is skipped due to a conflicting lock or a
+        concurrently dropped relation.  Enabling this parameter can be helpful
         in tracking autovacuum activity.  This parameter can only be set in
         the <filename>postgresql.conf</filename> file or on the server command line;
         but the setting can be overridden for individual tables by
index 760d19142ec5dd79993b72eb97bcc004a47b6b67..f952b3c732834079623edd31d23ecc705c3efa0c 100644 (file)
@@ -120,6 +120,7 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
    int         elevel;
    AcquireSampleRowsFunc acquirefunc = NULL;
    BlockNumber relpages = 0;
+   bool        rel_lock = true;
 
    /* Select logging level */
    if (options & VACOPT_VERBOSE)
@@ -149,15 +150,50 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
    else
    {
        onerel = NULL;
-       if (relation &&
-           IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
-           ereport(LOG,
+       rel_lock = false;
+   }
+
+   /*
+    * If we failed to open or lock the relation, emit a log message before
+    * exiting.
+    */
+   if (!onerel)
+   {
+       /*
+        * If the RangeVar is not defined, we do not have enough information
+        * to provide a meaningful log statement.  Chances are that
+        * analyze_rel's caller has intentionally not provided this
+        * information so that this logging is skipped, anyway.
+        */
+       if (relation == NULL)
+           return;
+
+       /*
+        * Determine the log level.  For autovacuum logs, we emit a LOG if
+        * log_autovacuum_min_duration is not disabled.  For manual ANALYZE,
+        * we emit a WARNING to match the log statements in the permissions
+        * checks.
+        */
+       if (!IsAutoVacuumWorkerProcess())
+           elevel = WARNING;
+       else if (params->log_min_duration >= 0)
+           elevel = LOG;
+       else
+           return;
+
+       if (!rel_lock)
+           ereport(elevel,
                    (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
                     errmsg("skipping analyze of \"%s\" --- lock not available",
                            relation->relname)));
-   }
-   if (!onerel)
+       else
+           ereport(elevel,
+                   (errcode(ERRCODE_UNDEFINED_TABLE),
+                    errmsg("skipping analyze of \"%s\" --- relation no longer exists",
+                           relation->relname)));
+
        return;
+   }
 
    /*
     * Check permissions --- this should match vacuum's check!
index cbd6e9b161698da67ea5808c85c470b7a600ea63..4abe6b15e0dec01034eaea3b7cecc57ee6380d3c 100644 (file)
@@ -1330,6 +1330,7 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
    Oid         save_userid;
    int         save_sec_context;
    int         save_nestlevel;
+   bool        rel_lock = true;
 
    Assert(params != NULL);
 
@@ -1400,16 +1401,52 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
    else
    {
        onerel = NULL;
-       if (relation &&
-           IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
-           ereport(LOG,
-                   (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
-                    errmsg("skipping vacuum of \"%s\" --- lock not available",
-                           relation->relname)));
+       rel_lock = false;
    }
 
+   /*
+    * If we failed to open or lock the relation, emit a log message before
+    * exiting.
+    */
    if (!onerel)
    {
+       int         elevel = 0;
+
+       /*
+        * Determine the log level.
+        *
+        * If the RangeVar is not defined, we do not have enough information
+        * to provide a meaningful log statement.  Chances are that
+        * vacuum_rel's caller has intentionally not provided this information
+        * so that this logging is skipped, anyway.
+        *
+        * Otherwise, for autovacuum logs, we emit a LOG if
+        * log_autovacuum_min_duration is not disabled.  For manual VACUUM, we
+        * emit a WARNING to match the log statements in the permission
+        * checks.
+        */
+       if (relation != NULL)
+       {
+           if (!IsAutoVacuumWorkerProcess())
+               elevel = WARNING;
+           else if (params->log_min_duration >= 0)
+               elevel = LOG;
+       }
+
+       if (elevel != 0)
+       {
+           if (!rel_lock)
+               ereport(elevel,
+                       (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+                        errmsg("skipping vacuum of \"%s\" --- lock not available",
+                               relation->relname)));
+           else
+               ereport(elevel,
+                       (errcode(ERRCODE_UNDEFINED_TABLE),
+                        errmsg("skipping vacuum of \"%s\" --- relation no longer exists",
+                               relation->relname)));
+       }
+
        PopActiveSnapshot();
        CommitTransactionCommand();
        return false;
diff --git a/src/test/isolation/expected/vacuum-concurrent-drop.out b/src/test/isolation/expected/vacuum-concurrent-drop.out
new file mode 100644 (file)
index 0000000..72d80a1
--- /dev/null
@@ -0,0 +1,76 @@
+Parsed test spec with 2 sessions
+
+starting permutation: lock vac_specified drop_and_commit
+step lock: 
+   BEGIN;
+   LOCK test1 IN SHARE MODE;
+
+step vac_specified: VACUUM test1, test2; <waiting ...>
+step drop_and_commit: 
+   DROP TABLE test2;
+   COMMIT;
+
+WARNING:  skipping vacuum of "test2" --- relation no longer exists
+step vac_specified: <... completed>
+
+starting permutation: lock vac_all drop_and_commit
+step lock: 
+   BEGIN;
+   LOCK test1 IN SHARE MODE;
+
+step vac_all: VACUUM; <waiting ...>
+step drop_and_commit: 
+   DROP TABLE test2;
+   COMMIT;
+
+step vac_all: <... completed>
+
+starting permutation: lock analyze_specified drop_and_commit
+step lock: 
+   BEGIN;
+   LOCK test1 IN SHARE MODE;
+
+step analyze_specified: ANALYZE test1, test2; <waiting ...>
+step drop_and_commit: 
+   DROP TABLE test2;
+   COMMIT;
+
+WARNING:  skipping analyze of "test2" --- relation no longer exists
+step analyze_specified: <... completed>
+
+starting permutation: lock analyze_all drop_and_commit
+step lock: 
+   BEGIN;
+   LOCK test1 IN SHARE MODE;
+
+step analyze_all: ANALYZE; <waiting ...>
+step drop_and_commit: 
+   DROP TABLE test2;
+   COMMIT;
+
+step analyze_all: <... completed>
+
+starting permutation: lock vac_analyze_specified drop_and_commit
+step lock: 
+   BEGIN;
+   LOCK test1 IN SHARE MODE;
+
+step vac_analyze_specified: VACUUM ANALYZE test1, test2; <waiting ...>
+step drop_and_commit: 
+   DROP TABLE test2;
+   COMMIT;
+
+WARNING:  skipping vacuum of "test2" --- relation no longer exists
+step vac_analyze_specified: <... completed>
+
+starting permutation: lock vac_analyze_all drop_and_commit
+step lock: 
+   BEGIN;
+   LOCK test1 IN SHARE MODE;
+
+step vac_analyze_all: VACUUM ANALYZE; <waiting ...>
+step drop_and_commit: 
+   DROP TABLE test2;
+   COMMIT;
+
+step vac_analyze_all: <... completed>
index 32c965b2a02a44d6a9daef2e3e1bb8123953ca8f..e41b9164cd0d880afb88ad7372da0e3540a33b0c 100644 (file)
@@ -62,3 +62,4 @@ test: sequence-ddl
 test: async-notify
 test: vacuum-reltuples
 test: timeouts
+test: vacuum-concurrent-drop
diff --git a/src/test/isolation/specs/vacuum-concurrent-drop.spec b/src/test/isolation/specs/vacuum-concurrent-drop.spec
new file mode 100644 (file)
index 0000000..31fc161
--- /dev/null
@@ -0,0 +1,45 @@
+# Test for log messages emitted by VACUUM and ANALYZE when a specified
+# relation is concurrently dropped.
+#
+# This also verifies that log messages are not emitted for concurrently
+# dropped relations that were not specified in the VACUUM or ANALYZE
+# command.
+
+setup
+{
+   CREATE TABLE test1 (a INT);
+   CREATE TABLE test2 (a INT);
+}
+
+teardown
+{
+   DROP TABLE IF EXISTS test1;
+   DROP TABLE IF EXISTS test2;
+}
+
+session "s1"
+step "lock"
+{
+   BEGIN;
+   LOCK test1 IN SHARE MODE;
+}
+step "drop_and_commit"
+{
+   DROP TABLE test2;
+   COMMIT;
+}
+
+session "s2"
+step "vac_specified"       { VACUUM test1, test2; }
+step "vac_all"         { VACUUM; }
+step "analyze_specified"   { ANALYZE test1, test2; }
+step "analyze_all"     { ANALYZE; }
+step "vac_analyze_specified"   { VACUUM ANALYZE test1, test2; }
+step "vac_analyze_all"     { VACUUM ANALYZE; }
+
+permutation "lock" "vac_specified" "drop_and_commit"
+permutation "lock" "vac_all" "drop_and_commit"
+permutation "lock" "analyze_specified" "drop_and_commit"
+permutation "lock" "analyze_all" "drop_and_commit"
+permutation "lock" "vac_analyze_specified" "drop_and_commit"
+permutation "lock" "vac_analyze_all" "drop_and_commit"