Skip to content
Snippets Groups Projects
Commit 67ccbb08 authored by Robert Haas's avatar Robert Haas
Browse files

vacuumlo: Use a cursor to limit client-side memory usage.

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
parent 03010366
No related branches found
No related tags found
No related merge requests found
...@@ -290,74 +290,101 @@ vacuumlo(const char *database, const struct _param * param) ...@@ -290,74 +290,101 @@ vacuumlo(const char *database, const struct _param * param)
PQclear(res); PQclear(res);
buf[0] = '\0'; 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); 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, "DECLARE CURSOR failed: %s", PQerrorMessage(conn));
fprintf(stderr, "%s", PQerrorMessage(conn));
PQclear(res); PQclear(res);
PQfinish(conn); PQfinish(conn);
return -1; 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; 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); /* at end of resultset */
fflush(stdout); 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); if (lo_unlink(conn, lo) < 0)
fprintf(stderr, "%s", PQerrorMessage(conn));
if (PQtransactionStatus(conn) == PQTRANS_INERROR)
{ {
success = false; fprintf(stderr, "\nFailed to remove lo %u: ", lo);
break; fprintf(stderr, "%s", PQerrorMessage(conn));
if (PQtransactionStatus(conn) == PQTRANS_INERROR)
{
success = false;
PQclear(res);
break;
}
} }
else
deleted++;
} }
else else
deleted++; deleted++;
}
else if (param->transaction_limit > 0 &&
deleted++; (deleted % param->transaction_limit) == 0)
if (param->transaction_limit > 0 &&
(deleted % param->transaction_limit) == 0)
{
res2 = PQexec(conn, "commit");
if (PQresultStatus(res2) != PGRES_COMMAND_OK)
{ {
fprintf(stderr, "Failed to commit transaction:\n"); res2 = PQexec(conn, "commit");
fprintf(stderr, "%s", PQerrorMessage(conn)); 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(res2);
PQclear(res); res2 = PQexec(conn, "begin");
PQfinish(conn); if (PQresultStatus(res2) != PGRES_COMMAND_OK)
return -1; {
} fprintf(stderr, "Failed to start transaction:\n");
PQclear(res2); fprintf(stderr, "%s", PQerrorMessage(conn));
res2 = PQexec(conn, "begin"); PQclear(res2);
if (PQresultStatus(res2) != PGRES_COMMAND_OK) PQclear(res);
{ PQfinish(conn);
fprintf(stderr, "Failed to start transaction:\n"); return -1;
fprintf(stderr, "%s", PQerrorMessage(conn)); }
PQclear(res2); PQclear(res2);
PQclear(res);
PQfinish(conn);
return -1;
} }
PQclear(res2);
} }
PQclear(res);
} }
PQclear(res);
/* /*
* That's all folks! * That's all folks!
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment