]> granicus.if.org Git - postgresql/commitdiff
Teach vacuumlo to limit number of removals, via new -l option.
authorRobert Haas <rhaas@postgresql.org>
Mon, 8 Aug 2011 13:12:16 +0000 (09:12 -0400)
committerRobert Haas <rhaas@postgresql.org>
Mon, 8 Aug 2011 13:16:45 +0000 (09:16 -0400)
Also, handle failure better: don't just blindly keep trying to delete
stuff after the transaction has already failed.

Tim Lewis, reviewed by Josh Kupershmidt, with further hacking by me.

contrib/vacuumlo/vacuumlo.c
doc/src/sgml/vacuumlo.sgml

index f6e2a28cf38cc5645c83a6eb0b73aebe87bdb2cc..6818d4ac43628d7b225f4a0651364566dc9ba9e2 100644 (file)
@@ -48,6 +48,7 @@ struct _param
        char       *pg_host;
        int                     verbose;
        int                     dry_run;
+       long            transaction_limit;
 };
 
 int                    vacuumlo(char *, struct _param *);
@@ -65,11 +66,12 @@ vacuumlo(char *database, struct _param * param)
        PGresult   *res,
                           *res2;
        char            buf[BUFSIZE];
-       int                     matched;
-       int                     deleted;
+       long            matched;
+       long            deleted;
        int                     i;
        static char *password = NULL;
        bool            new_pass;
+       bool        success = true;
 
        if (param->pg_prompt == TRI_YES && password == NULL)
                password = simple_prompt("Password: ", 100, false);
@@ -280,12 +282,19 @@ vacuumlo(char *database, struct _param * param)
                        {
                                fprintf(stderr, "\nFailed to remove lo %u: ", lo);
                                fprintf(stderr, "%s", PQerrorMessage(conn));
+                               if (PQtransactionStatus(conn) == PQTRANS_INERROR)
+                               {
+                                       success = false;
+                                       break;
+                               }
                        }
                        else
                                deleted++;
                }
                else
                        deleted++;
+               if (param->transaction_limit != 0 && deleted >= param->transaction_limit)
+                       break;
        }
        PQclear(res);
 
@@ -298,10 +307,20 @@ vacuumlo(char *database, struct _param * param)
        PQfinish(conn);
 
        if (param->verbose)
-               fprintf(stdout, "\r%s %d large objects from %s.\n",
-                  (param->dry_run ? "Would remove" : "Removed"), deleted, database);
+       {
+               if (param->dry_run)
+                       fprintf(stdout, "\rWould remove %ld large objects from %s.\n",
+                                       deleted, database);
+               else if (success)
+                       fprintf(stdout,
+                                       "\rSuccessfully removed %ld large objects from %s.\n",
+                                       deleted, database);
+               else
+                       fprintf(stdout, "\rRemoval from %s failed at object %ld of %ld.\n",
+                                       database, deleted, matched);
+       }
 
-       return 0;
+       return ((param->dry_run || success) ? 0 : -1);
 }
 
 void
@@ -311,6 +330,7 @@ usage(const char *progname)
        printf("Usage:\n  %s [OPTION]... DBNAME...\n\n", progname);
        printf("Options:\n");
        printf("  -h HOSTNAME  database server host or socket directory\n");
+       printf("  -l LIMIT     stop after removing LIMIT large objects\n");
        printf("  -n           don't remove large objects, just show what would be done\n");
        printf("  -p PORT      database server port\n");
        printf("  -U USERNAME  user name to connect as\n");
@@ -342,6 +362,7 @@ main(int argc, char **argv)
        param.pg_port = NULL;
        param.verbose = 0;
        param.dry_run = 0;
+       param.transaction_limit = 0;
 
        if (argc > 1)
        {
@@ -359,7 +380,7 @@ main(int argc, char **argv)
 
        while (1)
        {
-               c = getopt(argc, argv, "h:U:p:vnwW");
+               c = getopt(argc, argv, "h:l:U:p:vnwW");
                if (c == -1)
                        break;
 
@@ -395,6 +416,16 @@ main(int argc, char **argv)
                                }
                                param.pg_port = strdup(optarg);
                                break;
+                       case 'l':
+                               param.transaction_limit = strtol(optarg, NULL, 10);
+                               if (param.transaction_limit < 0)
+                               {
+                                       fprintf(stderr,
+                               "%s: transaction limit must not be negative (0 disables)\n",
+                                               progname);
+                                       exit(1);
+                               }
+                               break;
                        case 'h':
                                param.pg_host = strdup(optarg);
                                break;
index 471a6ca32be9e75e7a38b3fe51891373ce02e357..0ae39c71d2c00c5c9f27e195bbf5ad1423a945cb 100644 (file)
@@ -56,6 +56,16 @@ vacuumlo [options] database [database2 ... databaseN]
     </listitem>
    </varlistentry>
 
+   <varlistentry>
+    <term><option>-l</option> <replaceable>limit</></term>
+    <listitem>
+     <para>
+      Stop after removing LIMIT large objects.  Useful to avoid 
+      exceeding <xref linkend="guc-max-locks-per-transaction">.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry>
     <term><option>-w</></term>
     <term><option>--no-password</></term>