]> granicus.if.org Git - postgresql/commitdiff
vacuumlo: Use a cursor to limit client-side memory usage.
authorRobert Haas <rhaas@postgresql.org>
Mon, 15 Jul 2013 14:48:44 +0000 (10:48 -0400)
committerRobert Haas <rhaas@postgresql.org>
Mon, 15 Jul 2013 14:51:27 +0000 (10:51 -0400)
This prevents the client from gobbling up too much memory when the
number of large objects to be removed is very large.

Andrew Dunstan, reviewed by Josh Kupershmidt

contrib/vacuumlo/vacuumlo.c

index 70f7ea70ba08dc11eb1d037aabc2d18f75e49a32..134fd9d9c82d3bbb4663a51cf3b88ea42d765834 100644 (file)
@@ -290,74 +290,101 @@ vacuumlo(const char *database, const struct _param * param)
        PQclear(res);
 
        buf[0] = '\0';
-       strcat(buf, "SELECT lo FROM vacuum_l");
+       strcat(buf,
+                  "DECLARE myportal CURSOR WITH HOLD FOR SELECT lo FROM vacuum_l");
        res = PQexec(conn, buf);
-       if (PQresultStatus(res) != PGRES_TUPLES_OK)
+       if (PQresultStatus(res) != PGRES_COMMAND_OK)
        {
-               fprintf(stderr, "Failed to read temp table:\n");
-               fprintf(stderr, "%s", PQerrorMessage(conn));
+               fprintf(stderr, "DECLARE CURSOR failed: %s", PQerrorMessage(conn));
                PQclear(res);
                PQfinish(conn);
                return -1;
        }
+       PQclear(res);
+
+       snprintf(buf, BUFSIZE, "FETCH FORWARD %ld IN myportal",
+                        param->transaction_limit > 0 ? param->transaction_limit : 1000L);
 
-       matched = PQntuples(res);
        deleted = 0;
-       for (i = 0; i < matched; i++)
+
+       while (1)
        {
-               Oid                     lo = atooid(PQgetvalue(res, i, 0));
+               res = PQexec(conn, buf);
+               if (PQresultStatus(res) != PGRES_TUPLES_OK)
+               {
+                       fprintf(stderr, "FETCH FORWARD failed: %s", PQerrorMessage(conn));
+                       PQclear(res);
+                       PQfinish(conn);
+                       return -1;
+               }
 
-               if (param->verbose)
+               matched = PQntuples(res);
+               if (matched <= 0)
                {
-                       fprintf(stdout, "\rRemoving lo %6u   ", lo);
-                       fflush(stdout);
+                       /* at end of resultset */
+                       PQclear(res);
+                       break;
                }
 
-               if (param->dry_run == 0)
+               for (i = 0; i < matched; i++)
                {
-                       if (lo_unlink(conn, lo) < 0)
+                       Oid                     lo = atooid(PQgetvalue(res, i, 0));
+
+                       if (param->verbose)
+                       {
+                               fprintf(stdout, "\rRemoving lo %6u   ", lo);
+                               fflush(stdout);
+                       }
+
+                       if (param->dry_run == 0)
                        {
-                               fprintf(stderr, "\nFailed to remove lo %u: ", lo);
-                               fprintf(stderr, "%s", PQerrorMessage(conn));
-                               if (PQtransactionStatus(conn) == PQTRANS_INERROR)
+                               if (lo_unlink(conn, lo) < 0)
                                {
-                                       success = false;
-                                       break;
+                                       fprintf(stderr, "\nFailed to remove lo %u: ", lo);
+                                       fprintf(stderr, "%s", PQerrorMessage(conn));
+                                       if (PQtransactionStatus(conn) == PQTRANS_INERROR)
+                                       {
+                                               success = false;
+                                               PQclear(res);
+                                               break;
+                                       }
                                }
+                               else
+                                       deleted++;
                        }
                        else
                                deleted++;
-               }
-               else
-                       deleted++;
-               if (param->transaction_limit > 0 &&
-                       (deleted % param->transaction_limit) == 0)
-               {
-                       res2 = PQexec(conn, "commit");
-                       if (PQresultStatus(res2) != PGRES_COMMAND_OK)
+
+                       if (param->transaction_limit > 0 &&
+                               (deleted % param->transaction_limit) == 0)
                        {
-                               fprintf(stderr, "Failed to commit transaction:\n");
-                               fprintf(stderr, "%s", PQerrorMessage(conn));
+                               res2 = PQexec(conn, "commit");
+                               if (PQresultStatus(res2) != PGRES_COMMAND_OK)
+                               {
+                                       fprintf(stderr, "Failed to commit transaction:\n");
+                                       fprintf(stderr, "%s", PQerrorMessage(conn));
+                                       PQclear(res2);
+                                       PQclear(res);
+                                       PQfinish(conn);
+                                       return -1;
+                               }
                                PQclear(res2);
-                               PQclear(res);
-                               PQfinish(conn);
-                               return -1;
-                       }
-                       PQclear(res2);
-                       res2 = PQexec(conn, "begin");
-                       if (PQresultStatus(res2) != PGRES_COMMAND_OK)
-                       {
-                               fprintf(stderr, "Failed to start transaction:\n");
-                               fprintf(stderr, "%s", PQerrorMessage(conn));
+                               res2 = PQexec(conn, "begin");
+                               if (PQresultStatus(res2) != PGRES_COMMAND_OK)
+                               {
+                                       fprintf(stderr, "Failed to start transaction:\n");
+                                       fprintf(stderr, "%s", PQerrorMessage(conn));
+                                       PQclear(res2);
+                                       PQclear(res);
+                                       PQfinish(conn);
+                                       return -1;
+                               }
                                PQclear(res2);
-                               PQclear(res);
-                               PQfinish(conn);
-                               return -1;
                        }
-                       PQclear(res2);
                }
+
+               PQclear(res);
        }
-       PQclear(res);
 
        /*
         * That's all folks!