PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
vacuumdb.c File Reference
#include "postgres_fe.h"
#include "catalog/pg_class.h"
#include "common.h"
#include "fe_utils/simple_list.h"
#include "fe_utils/string_utils.h"
Include dependency graph for vacuumdb.c:

Go to the source code of this file.

Data Structures

struct  ParallelSlot
 
struct  vacuumingOptions
 

Macros

#define ERRCODE_UNDEFINED_TABLE   "42P01"
 
#define ANALYZE_NO_STAGE   -1
 
#define ANALYZE_NUM_STAGES   3
 

Typedefs

typedef struct ParallelSlot ParallelSlot
 
typedef struct vacuumingOptions vacuumingOptions
 

Functions

static void vacuum_one_database (const char *dbname, vacuumingOptions *vacopts, int stage, SimpleStringList *tables, const char *host, const char *port, const char *username, enum trivalue prompt_password, int concurrentCons, const char *progname, bool echo, bool quiet)
 
static void vacuum_all_databases (vacuumingOptions *vacopts, bool analyze_in_stages, const char *maintenance_db, const char *host, const char *port, const char *username, enum trivalue prompt_password, int concurrentCons, const char *progname, bool echo, bool quiet)
 
static void prepare_vacuum_command (PQExpBuffer sql, PGconn *conn, vacuumingOptions *vacopts, const char *table)
 
static void run_vacuum_command (PGconn *conn, const char *sql, bool echo, const char *table, const char *progname, bool async)
 
static ParallelSlotGetIdleSlot (ParallelSlot slots[], int numslots, const char *progname)
 
static bool GetQueryResult (PGconn *conn, const char *progname)
 
static void DisconnectDatabase (ParallelSlot *slot)
 
static int select_loop (int maxFd, fd_set *workerset, bool *aborting)
 
static void init_slot (ParallelSlot *slot, PGconn *conn, const char *progname)
 
static void help (const char *progname)
 
int main (int argc, char *argv[])
 

Macro Definition Documentation

#define ANALYZE_NO_STAGE   -1

Definition at line 83 of file vacuumdb.c.

Referenced by main(), vacuum_all_databases(), and vacuum_one_database().

#define ANALYZE_NUM_STAGES   3

Definition at line 84 of file vacuumdb.c.

Referenced by main(), vacuum_all_databases(), and vacuum_one_database().

#define ERRCODE_UNDEFINED_TABLE   "42P01"

Definition at line 26 of file vacuumdb.c.

Referenced by GetQueryResult().

Typedef Documentation

Function Documentation

static void DisconnectDatabase ( ParallelSlot slot)
static

Definition at line 850 of file vacuumdb.c.

References ParallelSlot::connection, PQcancel(), PQfinish(), PQfreeCancel(), PQgetCancel(), PQTRANS_ACTIVE, and PQtransactionStatus().

Referenced by vacuum_one_database().

851 {
852  char errbuf[256];
853 
854  if (!slot->connection)
855  return;
856 
858  {
859  PGcancel *cancel;
860 
861  if ((cancel = PQgetCancel(slot->connection)))
862  {
863  (void) PQcancel(cancel, errbuf, sizeof(errbuf));
864  PQfreeCancel(cancel);
865  }
866  }
867 
868  PQfinish(slot->connection);
869  slot->connection = NULL;
870 }
void PQfreeCancel(PGcancel *cancel)
Definition: fe-connect.c:3774
void PQfinish(PGconn *conn)
Definition: fe-connect.c:3630
PGcancel * PQgetCancel(PGconn *conn)
Definition: fe-connect.c:3751
PGconn * connection
Definition: vacuumdb.c:31
PGTransactionStatusType PQtransactionStatus(const PGconn *conn)
Definition: fe-connect.c:6052
int PQcancel(PGcancel *cancel, char *errbuf, int errbufsize)
Definition: fe-connect.c:3906
static ParallelSlot * GetIdleSlot ( ParallelSlot  slots[],
int  numslots,
const char *  progname 
)
static

Definition at line 738 of file vacuumdb.c.

References Assert, ParallelSlot::connection, GetQueryResult(), i, PQconsumeInput(), PQisBusy(), ResetCancelConn(), select_loop(), SetCancelConn(), and ParallelSlot::sock.

Referenced by vacuum_one_database().

740 {
741  int i;
742  int firstFree = -1;
743  fd_set slotset;
744  pgsocket maxFd;
745 
746  for (i = 0; i < numslots; i++)
747  if ((slots + i)->isFree)
748  return slots + i;
749 
750  FD_ZERO(&slotset);
751 
752  maxFd = slots->sock;
753  for (i = 0; i < numslots; i++)
754  {
755  FD_SET((slots + i)->sock, &slotset);
756  if ((slots + i)->sock > maxFd)
757  maxFd = (slots + i)->sock;
758  }
759 
760  /*
761  * No free slot found, so wait until one of the connections has finished
762  * its task and return the available slot.
763  */
764  for (firstFree = -1; firstFree < 0;)
765  {
766  bool aborting;
767 
768  SetCancelConn(slots->connection);
769  i = select_loop(maxFd, &slotset, &aborting);
770  ResetCancelConn();
771 
772  if (aborting)
773  {
774  /*
775  * We set the cancel-receiving connection to the one in the zeroth
776  * slot above, so fetch the error from there.
777  */
779  return NULL;
780  }
781  Assert(i != 0);
782 
783  for (i = 0; i < numslots; i++)
784  {
785  if (!FD_ISSET((slots + i)->sock, &slotset))
786  continue;
787 
788  PQconsumeInput((slots + i)->connection);
789  if (PQisBusy((slots + i)->connection))
790  continue;
791 
792  (slots + i)->isFree = true;
793 
794  if (!GetQueryResult((slots + i)->connection, progname))
795  return NULL;
796 
797  if (firstFree < 0)
798  firstFree = i;
799  }
800  }
801 
802  return slots + firstFree;
803 }
static int select_loop(int maxFd, fd_set *workerset, bool *aborting)
Definition: vacuumdb.c:880
pgsocket sock
Definition: vacuumdb.c:32
const char * progname
Definition: pg_standby.c:37
int pgsocket
Definition: port.h:22
PGconn * connection
Definition: vacuumdb.c:31
void SetCancelConn(void)
Definition: common.c:446
int PQconsumeInput(PGconn *conn)
Definition: fe-exec.c:1682
#define Assert(condition)
Definition: c.h:681
static bool GetQueryResult(PGconn *conn, const char *progname)
Definition: vacuumdb.c:813
int PQisBusy(PGconn *conn)
Definition: fe-exec.c:1732
int i
void ResetCancelConn(void)
Definition: common.c:476
static bool GetQueryResult ( PGconn conn,
const char *  progname 
)
static

Definition at line 813 of file vacuumdb.c.

References _, ERRCODE_UNDEFINED_TABLE, PG_DIAG_SQLSTATE, PGRES_COMMAND_OK, PQclear(), PQdb(), PQerrorMessage(), PQgetResult(), PQresultErrorField(), PQresultStatus(), ResetCancelConn(), and SetCancelConn().

Referenced by GetIdleSlot(), and vacuum_one_database().

814 {
815  PGresult *result;
816 
817  SetCancelConn(conn);
818  while ((result = PQgetResult(conn)) != NULL)
819  {
820  /*
821  * If errors are found, report them. Errors about a missing table are
822  * harmless so we continue processing; but die for other errors.
823  */
824  if (PQresultStatus(result) != PGRES_COMMAND_OK)
825  {
826  char *sqlState = PQresultErrorField(result, PG_DIAG_SQLSTATE);
827 
828  fprintf(stderr, _("%s: vacuuming of database \"%s\" failed: %s"),
829  progname, PQdb(conn), PQerrorMessage(conn));
830 
831  if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) != 0)
832  {
833  PQclear(result);
834  return false;
835  }
836  }
837 
838  PQclear(result);
839  }
840  ResetCancelConn();
841 
842  return true;
843 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6097
const char * progname
Definition: pg_standby.c:37
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:57
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2647
void SetCancelConn(void)
Definition: common.c:446
void PQclear(PGresult *res)
Definition: fe-exec.c:671
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:5965
char * PQresultErrorField(const PGresult *res, int fieldcode)
Definition: fe-exec.c:2709
#define ERRCODE_UNDEFINED_TABLE
Definition: vacuumdb.c:26
void ResetCancelConn(void)
Definition: common.c:476
#define _(x)
Definition: elog.c:84
PGresult * PQgetResult(PGconn *conn)
Definition: fe-exec.c:1753
static void help ( const char *  progname)
static

Definition at line 949 of file vacuumdb.c.

References _.

Referenced by main().

950 {
951  printf(_("%s cleans and analyzes a PostgreSQL database.\n\n"), progname);
952  printf(_("Usage:\n"));
953  printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
954  printf(_("\nOptions:\n"));
955  printf(_(" -a, --all vacuum all databases\n"));
956  printf(_(" -d, --dbname=DBNAME database to vacuum\n"));
957  printf(_(" -e, --echo show the commands being sent to the server\n"));
958  printf(_(" -f, --full do full vacuuming\n"));
959  printf(_(" -F, --freeze freeze row transaction information\n"));
960  printf(_(" -j, --jobs=NUM use this many concurrent connections to vacuum\n"));
961  printf(_(" -q, --quiet don't write any messages\n"));
962  printf(_(" -t, --table='TABLE[(COLUMNS)]' vacuum specific table(s) only\n"));
963  printf(_(" -v, --verbose write a lot of output\n"));
964  printf(_(" -V, --version output version information, then exit\n"));
965  printf(_(" -z, --analyze update optimizer statistics\n"));
966  printf(_(" -Z, --analyze-only only update optimizer statistics; no vacuum\n"));
967  printf(_(" --analyze-in-stages only update optimizer statistics, in multiple\n"
968  " stages for faster results; no vacuum\n"));
969  printf(_(" -?, --help show this help, then exit\n"));
970  printf(_("\nConnection options:\n"));
971  printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
972  printf(_(" -p, --port=PORT database server port\n"));
973  printf(_(" -U, --username=USERNAME user name to connect as\n"));
974  printf(_(" -w, --no-password never prompt for password\n"));
975  printf(_(" -W, --password force password prompt\n"));
976  printf(_(" --maintenance-db=DBNAME alternate maintenance database\n"));
977  printf(_("\nRead the description of the SQL command VACUUM for details.\n"));
978  printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
979 }
const char * progname
Definition: pg_standby.c:37
#define _(x)
Definition: elog.c:84
static void init_slot ( ParallelSlot slot,
PGconn conn,
const char *  progname 
)
static

Definition at line 934 of file vacuumdb.c.

References _, conn, ParallelSlot::connection, ParallelSlot::isFree, PQerrorMessage(), PQsocket(), and ParallelSlot::sock.

Referenced by vacuum_one_database().

935 {
936  slot->connection = conn;
937  slot->isFree = true;
938  slot->sock = PQsocket(conn);
939 
940  if (slot->sock < 0)
941  {
942  fprintf(stderr, _("%s: invalid socket: %s"), progname,
943  PQerrorMessage(conn));
944  exit(1);
945  }
946 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6097
bool isFree
Definition: vacuumdb.c:33
pgsocket sock
Definition: vacuumdb.c:32
const char * progname
Definition: pg_standby.c:37
PGconn * conn
Definition: streamutil.c:46
PGconn * connection
Definition: vacuumdb.c:31
#define _(x)
Definition: elog.c:84
int PQsocket(const PGconn *conn)
Definition: fe-connect.c:6115
int main ( int  argc,
char *  argv[] 
)

Definition at line 88 of file vacuumdb.c.

References _, ANALYZE_NO_STAGE, ANALYZE_NUM_STAGES, vacuumingOptions::analyze_only, vacuumingOptions::and_analyze, dbname, vacuumingOptions::freeze, vacuumingOptions::full, get_progname(), get_user_name_or_exit(), getopt_long(), handle_help_version_opts(), SimpleStringList::head, help(), no_argument, optarg, optind, pg_strdup(), PG_TEXTDOMAIN, port, progname, required_argument, set_pglocale_pgservice(), setup_cancel_handler(), simple_string_list_append(), TRI_DEFAULT, TRI_NO, TRI_YES, username, vacuum_all_databases(), vacuum_one_database(), and vacuumingOptions::verbose.

89 {
90  static struct option long_options[] = {
91  {"host", required_argument, NULL, 'h'},
92  {"port", required_argument, NULL, 'p'},
93  {"username", required_argument, NULL, 'U'},
94  {"no-password", no_argument, NULL, 'w'},
95  {"password", no_argument, NULL, 'W'},
96  {"echo", no_argument, NULL, 'e'},
97  {"quiet", no_argument, NULL, 'q'},
98  {"dbname", required_argument, NULL, 'd'},
99  {"analyze", no_argument, NULL, 'z'},
100  {"analyze-only", no_argument, NULL, 'Z'},
101  {"freeze", no_argument, NULL, 'F'},
102  {"all", no_argument, NULL, 'a'},
103  {"table", required_argument, NULL, 't'},
104  {"full", no_argument, NULL, 'f'},
105  {"verbose", no_argument, NULL, 'v'},
106  {"jobs", required_argument, NULL, 'j'},
107  {"maintenance-db", required_argument, NULL, 2},
108  {"analyze-in-stages", no_argument, NULL, 3},
109  {NULL, 0, NULL, 0}
110  };
111 
112  const char *progname;
113  int optindex;
114  int c;
115  const char *dbname = NULL;
116  const char *maintenance_db = NULL;
117  char *host = NULL;
118  char *port = NULL;
119  char *username = NULL;
120  enum trivalue prompt_password = TRI_DEFAULT;
121  bool echo = false;
122  bool quiet = false;
123  vacuumingOptions vacopts;
124  bool analyze_in_stages = false;
125  bool alldb = false;
126  SimpleStringList tables = {NULL, NULL};
127  int concurrentCons = 1;
128  int tbl_count = 0;
129 
130  /* initialize options to all false */
131  memset(&vacopts, 0, sizeof(vacopts));
132 
133  progname = get_progname(argv[0]);
134 
135  set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
136 
137  handle_help_version_opts(argc, argv, "vacuumdb", help);
138 
139  while ((c = getopt_long(argc, argv, "h:p:U:wWeqd:zZFat:fvj:", long_options, &optindex)) != -1)
140  {
141  switch (c)
142  {
143  case 'h':
144  host = pg_strdup(optarg);
145  break;
146  case 'p':
147  port = pg_strdup(optarg);
148  break;
149  case 'U':
150  username = pg_strdup(optarg);
151  break;
152  case 'w':
153  prompt_password = TRI_NO;
154  break;
155  case 'W':
156  prompt_password = TRI_YES;
157  break;
158  case 'e':
159  echo = true;
160  break;
161  case 'q':
162  quiet = true;
163  break;
164  case 'd':
165  dbname = pg_strdup(optarg);
166  break;
167  case 'z':
168  vacopts.and_analyze = true;
169  break;
170  case 'Z':
171  vacopts.analyze_only = true;
172  break;
173  case 'F':
174  vacopts.freeze = true;
175  break;
176  case 'a':
177  alldb = true;
178  break;
179  case 't':
180  {
182  tbl_count++;
183  break;
184  }
185  case 'f':
186  vacopts.full = true;
187  break;
188  case 'v':
189  vacopts.verbose = true;
190  break;
191  case 'j':
192  concurrentCons = atoi(optarg);
193  if (concurrentCons <= 0)
194  {
195  fprintf(stderr, _("%s: number of parallel jobs must be at least 1\n"),
196  progname);
197  exit(1);
198  }
199  if (concurrentCons > FD_SETSIZE - 1)
200  {
201  fprintf(stderr, _("%s: too many parallel jobs requested (maximum: %d)\n"),
202  progname, FD_SETSIZE - 1);
203  exit(1);
204  }
205  break;
206  case 2:
207  maintenance_db = pg_strdup(optarg);
208  break;
209  case 3:
210  analyze_in_stages = vacopts.analyze_only = true;
211  break;
212  default:
213  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
214  exit(1);
215  }
216  }
217 
218  /*
219  * Non-option argument specifies database name as long as it wasn't
220  * already specified with -d / --dbname
221  */
222  if (optind < argc && dbname == NULL)
223  {
224  dbname = argv[optind];
225  optind++;
226  }
227 
228  if (optind < argc)
229  {
230  fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
231  progname, argv[optind]);
232  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
233  exit(1);
234  }
235 
236  if (vacopts.analyze_only)
237  {
238  if (vacopts.full)
239  {
240  fprintf(stderr, _("%s: cannot use the \"%s\" option when performing only analyze\n"),
241  progname, "full");
242  exit(1);
243  }
244  if (vacopts.freeze)
245  {
246  fprintf(stderr, _("%s: cannot use the \"%s\" option when performing only analyze\n"),
247  progname, "freeze");
248  exit(1);
249  }
250  /* allow 'and_analyze' with 'analyze_only' */
251  }
252 
254 
255  /* Avoid opening extra connections. */
256  if (tbl_count && (concurrentCons > tbl_count))
257  concurrentCons = tbl_count;
258 
259  if (alldb)
260  {
261  if (dbname)
262  {
263  fprintf(stderr, _("%s: cannot vacuum all databases and a specific one at the same time\n"),
264  progname);
265  exit(1);
266  }
267  if (tables.head != NULL)
268  {
269  fprintf(stderr, _("%s: cannot vacuum specific table(s) in all databases\n"),
270  progname);
271  exit(1);
272  }
273 
274  vacuum_all_databases(&vacopts,
275  analyze_in_stages,
276  maintenance_db,
277  host, port, username, prompt_password,
278  concurrentCons,
279  progname, echo, quiet);
280  }
281  else
282  {
283  if (dbname == NULL)
284  {
285  if (getenv("PGDATABASE"))
286  dbname = getenv("PGDATABASE");
287  else if (getenv("PGUSER"))
288  dbname = getenv("PGUSER");
289  else
290  dbname = get_user_name_or_exit(progname);
291  }
292 
293  if (analyze_in_stages)
294  {
295  int stage;
296 
297  for (stage = 0; stage < ANALYZE_NUM_STAGES; stage++)
298  {
299  vacuum_one_database(dbname, &vacopts,
300  stage,
301  &tables,
302  host, port, username, prompt_password,
303  concurrentCons,
304  progname, echo, quiet);
305  }
306  }
307  else
308  vacuum_one_database(dbname, &vacopts,
310  &tables,
311  host, port, username, prompt_password,
312  concurrentCons,
313  progname, echo, quiet);
314  }
315 
316  exit(0);
317 }
const char * get_progname(const char *argv0)
Definition: path.c:453
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:57
static void setup_cancel_handler(void)
Definition: parallel.c:622
#define ANALYZE_NO_STAGE
Definition: vacuumdb.c:83
const char * progname
Definition: pg_standby.c:37
static void vacuum_one_database(const char *dbname, vacuumingOptions *vacopts, int stage, SimpleStringList *tables, const char *host, const char *port, const char *username, enum trivalue prompt_password, int concurrentCons, const char *progname, bool echo, bool quiet)
Definition: vacuumdb.c:333
#define required_argument
Definition: getopt_long.h:25
int optind
Definition: getopt.c:51
char * c
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
bool and_analyze
Definition: vacuumdb.c:41
static int port
Definition: pg_regress.c:90
void handle_help_version_opts(int argc, char *argv[], const char *fixed_progname, help_handler hlp)
Definition: common.c:35
trivalue
Definition: vacuumlo.c:31
static void help(const char *progname)
Definition: vacuumdb.c:949
#define no_argument
Definition: getopt_long.h:24
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1018
static void vacuum_all_databases(vacuumingOptions *vacopts, bool analyze_in_stages, const char *maintenance_db, const char *host, const char *port, const char *username, enum trivalue prompt_password, int concurrentCons, const char *progname, bool echo, bool quiet)
Definition: vacuumdb.c:543
void simple_string_list_append(SimpleStringList *list, const char *val)
Definition: simple_list.c:63
static char * username
Definition: initdb.c:132
SimpleStringListCell * head
Definition: simple_list.h:42
char * dbname
Definition: streamutil.c:42
#define ANALYZE_NUM_STAGES
Definition: vacuumdb.c:84
bool analyze_only
Definition: vacuumdb.c:39
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:550
char * optarg
Definition: getopt.c:53
#define _(x)
Definition: elog.c:84
const char * get_user_name_or_exit(const char *progname)
Definition: username.c:74
static void prepare_vacuum_command ( PQExpBuffer  sql,
PGconn conn,
vacuumingOptions vacopts,
const char *  table 
)
static

Definition at line 621 of file vacuumdb.c.

References vacuumingOptions::analyze_only, vacuumingOptions::and_analyze, appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), vacuumingOptions::freeze, vacuumingOptions::full, PQserverVersion(), resetPQExpBuffer(), and vacuumingOptions::verbose.

Referenced by vacuum_one_database().

623 {
624  resetPQExpBuffer(sql);
625 
626  if (vacopts->analyze_only)
627  {
628  appendPQExpBufferStr(sql, "ANALYZE");
629  if (vacopts->verbose)
630  appendPQExpBufferStr(sql, " VERBOSE");
631  }
632  else
633  {
634  appendPQExpBufferStr(sql, "VACUUM");
635  if (PQserverVersion(conn) >= 90000)
636  {
637  const char *paren = " (";
638  const char *comma = ", ";
639  const char *sep = paren;
640 
641  if (vacopts->full)
642  {
643  appendPQExpBuffer(sql, "%sFULL", sep);
644  sep = comma;
645  }
646  if (vacopts->freeze)
647  {
648  appendPQExpBuffer(sql, "%sFREEZE", sep);
649  sep = comma;
650  }
651  if (vacopts->verbose)
652  {
653  appendPQExpBuffer(sql, "%sVERBOSE", sep);
654  sep = comma;
655  }
656  if (vacopts->and_analyze)
657  {
658  appendPQExpBuffer(sql, "%sANALYZE", sep);
659  sep = comma;
660  }
661  if (sep != paren)
662  appendPQExpBufferChar(sql, ')');
663  }
664  else
665  {
666  if (vacopts->full)
667  appendPQExpBufferStr(sql, " FULL");
668  if (vacopts->freeze)
669  appendPQExpBufferStr(sql, " FREEZE");
670  if (vacopts->verbose)
671  appendPQExpBufferStr(sql, " VERBOSE");
672  if (vacopts->and_analyze)
673  appendPQExpBufferStr(sql, " ANALYZE");
674  }
675  }
676 
677  if (table)
678  appendPQExpBuffer(sql, " %s", table);
679  appendPQExpBufferChar(sql, ';');
680 }
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:385
int PQserverVersion(const PGconn *conn)
Definition: fe-connect.c:6087
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:262
bool and_analyze
Definition: vacuumdb.c:41
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:396
bool analyze_only
Definition: vacuumdb.c:39
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:145
static void run_vacuum_command ( PGconn conn,
const char *  sql,
bool  echo,
const char *  table,
const char *  progname,
bool  async 
)
static

Definition at line 689 of file vacuumdb.c.

References _, executeMaintenanceCommand(), PQdb(), PQerrorMessage(), PQfinish(), PQsendQuery(), and status().

Referenced by vacuum_one_database().

691 {
692  bool status;
693 
694  if (async)
695  {
696  if (echo)
697  printf("%s\n", sql);
698 
699  status = PQsendQuery(conn, sql) == 1;
700  }
701  else
702  status = executeMaintenanceCommand(conn, sql, echo);
703 
704  if (!status)
705  {
706  if (table)
707  fprintf(stderr,
708  _("%s: vacuuming of table \"%s\" in database \"%s\" failed: %s"),
709  progname, table, PQdb(conn), PQerrorMessage(conn));
710  else
711  fprintf(stderr, _("%s: vacuuming of database \"%s\" failed: %s"),
712  progname, PQdb(conn), PQerrorMessage(conn));
713 
714  if (!async)
715  {
716  PQfinish(conn);
717  exit(1);
718  }
719  }
720 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6097
void PQfinish(PGconn *conn)
Definition: fe-connect.c:3630
const char * progname
Definition: pg_standby.c:37
int PQsendQuery(PGconn *conn, const char *query)
Definition: fe-exec.c:1183
bool executeMaintenanceCommand(PGconn *conn, const char *query, bool echo)
Definition: common.c:235
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:5965
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
#define _(x)
Definition: elog.c:84
static int select_loop ( int  maxFd,
fd_set *  workerset,
bool aborting 
)
static

Definition at line 880 of file vacuumdb.c.

References CancelRequested, EINTR, i, and select.

Referenced by GetIdleSlot().

881 {
882  int i;
883  fd_set saveSet = *workerset;
884 
885  if (CancelRequested)
886  {
887  *aborting = true;
888  return -1;
889  }
890  else
891  *aborting = false;
892 
893  for (;;)
894  {
895  /*
896  * On Windows, we need to check once in a while for cancel requests;
897  * on other platforms we rely on select() returning when interrupted.
898  */
899  struct timeval *tvp;
900 #ifdef WIN32
901  struct timeval tv = {0, 1000000};
902 
903  tvp = &tv;
904 #else
905  tvp = NULL;
906 #endif
907 
908  *workerset = saveSet;
909  i = select(maxFd + 1, workerset, NULL, NULL, tvp);
910 
911 #ifdef WIN32
912  if (i == SOCKET_ERROR)
913  {
914  i = -1;
915 
916  if (WSAGetLastError() == WSAEINTR)
917  errno = EINTR;
918  }
919 #endif
920 
921  if (i < 0 && errno == EINTR)
922  continue; /* ignore this */
923  if (i < 0 || CancelRequested)
924  *aborting = true; /* but not this */
925  if (i == 0)
926  continue; /* timeout (Win32 only) */
927  break;
928  }
929 
930  return i;
931 }
#define select(n, r, w, e, timeout)
Definition: win32.h:374
#define EINTR
Definition: win32.h:285
bool CancelRequested
Definition: common.c:24
int i
static void vacuum_all_databases ( vacuumingOptions vacopts,
bool  analyze_in_stages,
const char *  maintenance_db,
const char *  host,
const char *  port,
const char *  username,
enum trivalue  prompt_password,
int  concurrentCons,
const char *  progname,
bool  echo,
bool  quiet 
)
static

Definition at line 543 of file vacuumdb.c.

References ANALYZE_NO_STAGE, ANALYZE_NUM_STAGES, appendConnStrVal(), appendPQExpBuffer(), conn, connectMaintenanceDatabase(), connstr, PQExpBufferData::data, executeQuery(), i, initPQExpBuffer(), PQclear(), PQfinish(), PQgetvalue(), PQntuples(), resetPQExpBuffer(), termPQExpBuffer(), and vacuum_one_database().

Referenced by main().

550 {
551  PGconn *conn;
552  PGresult *result;
554  int stage;
555  int i;
556 
557  conn = connectMaintenanceDatabase(maintenance_db, host, port,
558  username, prompt_password, progname);
559  result = executeQuery(conn,
560  "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;",
561  progname, echo);
562  PQfinish(conn);
563 
564  initPQExpBuffer(&connstr);
565  if (analyze_in_stages)
566  {
567  /*
568  * When analyzing all databases in stages, we analyze them all in the
569  * fastest stage first, so that initial statistics become available
570  * for all of them as soon as possible.
571  *
572  * This means we establish several times as many connections, but
573  * that's a secondary consideration.
574  */
575  for (stage = 0; stage < ANALYZE_NUM_STAGES; stage++)
576  {
577  for (i = 0; i < PQntuples(result); i++)
578  {
579  resetPQExpBuffer(&connstr);
580  appendPQExpBuffer(&connstr, "dbname=");
581  appendConnStrVal(&connstr, PQgetvalue(result, i, 0));
582 
583  vacuum_one_database(connstr.data, vacopts,
584  stage,
585  NULL,
586  host, port, username, prompt_password,
587  concurrentCons,
588  progname, echo, quiet);
589  }
590  }
591  }
592  else
593  {
594  for (i = 0; i < PQntuples(result); i++)
595  {
596  resetPQExpBuffer(&connstr);
597  appendPQExpBuffer(&connstr, "dbname=");
598  appendConnStrVal(&connstr, PQgetvalue(result, i, 0));
599 
600  vacuum_one_database(connstr.data, vacopts,
602  NULL,
603  host, port, username, prompt_password,
604  concurrentCons,
605  progname, echo, quiet);
606  }
607  }
608  termPQExpBuffer(&connstr);
609 
610  PQclear(result);
611 }
static PGresult * executeQuery(PGconn *conn, const char *query)
Definition: pg_dumpall.c:2140
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3118
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:128
void appendConnStrVal(PQExpBuffer buf, const char *str)
Definition: string_utils.c:551
void PQfinish(PGconn *conn)
Definition: fe-connect.c:3630
#define ANALYZE_NO_STAGE
Definition: vacuumdb.c:83
const char * progname
Definition: pg_standby.c:37
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2724
static void vacuum_one_database(const char *dbname, vacuumingOptions *vacopts, int stage, SimpleStringList *tables, const char *host, const char *port, const char *username, enum trivalue prompt_password, int concurrentCons, const char *progname, bool echo, bool quiet)
Definition: vacuumdb.c:333
PGconn * conn
Definition: streamutil.c:46
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:262
static int port
Definition: pg_regress.c:90
PGconn * connectMaintenanceDatabase(const char *maintenance_db, const char *pghost, const char *pgport, const char *pguser, enum trivalue prompt_password, const char *progname)
Definition: common.c:152
static char * username
Definition: initdb.c:132
void PQclear(PGresult *res)
Definition: fe-exec.c:671
#define ANALYZE_NUM_STAGES
Definition: vacuumdb.c:84
int i
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:145
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:89
static char * connstr
Definition: pg_dumpall.c:64
static void vacuum_one_database ( const char *  dbname,
vacuumingOptions vacopts,
int  stage,
SimpleStringList tables,
const char *  host,
const char *  port,
const char *  username,
enum trivalue  prompt_password,
int  concurrentCons,
const char *  progname,
bool  echo,
bool  quiet 
)
static

Definition at line 333 of file vacuumdb.c.

References _, ANALYZE_NO_STAGE, ANALYZE_NUM_STAGES, appendPQExpBufferStr(), Assert, buf, CancelRequested, conn, connectDatabase(), ParallelSlot::connection, CppAsString2, PQExpBufferData::data, DisconnectDatabase(), executeCommand(), executeQuery(), fmtQualifiedId(), GetIdleSlot(), GetQueryResult(), gettext_noop, SimpleStringList::head, i, init_slot(), initPQExpBuffer(), ParallelSlot::isFree, SimpleStringListCell::next, pfree(), pg_malloc(), PQclear(), PQdb(), PQgetvalue(), PQntuples(), PQserverVersion(), prepare_vacuum_command(), RELKIND_MATVIEW, RELKIND_RELATION, resetPQExpBuffer(), run_vacuum_command(), simple_string_list_append(), termPQExpBuffer(), and SimpleStringListCell::val.

Referenced by main(), and vacuum_all_databases().

340 {
341  PQExpBufferData sql;
342  PGconn *conn;
343  SimpleStringListCell *cell;
344  ParallelSlot *slots = NULL;
345  SimpleStringList dbtables = {NULL, NULL};
346  int i;
347  bool failed = false;
348  bool parallel = concurrentCons > 1;
349  const char *stage_commands[] = {
350  "SET default_statistics_target=1; SET vacuum_cost_delay=0;",
351  "SET default_statistics_target=10; RESET vacuum_cost_delay;",
352  "RESET default_statistics_target;"
353  };
354  const char *stage_messages[] = {
355  gettext_noop("Generating minimal optimizer statistics (1 target)"),
356  gettext_noop("Generating medium optimizer statistics (10 targets)"),
357  gettext_noop("Generating default (full) optimizer statistics")
358  };
359 
360  Assert(stage == ANALYZE_NO_STAGE ||
361  (stage >= 0 && stage < ANALYZE_NUM_STAGES));
362 
363  conn = connectDatabase(dbname, host, port, username, prompt_password,
364  progname, false, true);
365 
366  if (!quiet)
367  {
368  if (stage != ANALYZE_NO_STAGE)
369  printf(_("%s: processing database \"%s\": %s\n"),
370  progname, PQdb(conn), stage_messages[stage]);
371  else
372  printf(_("%s: vacuuming database \"%s\"\n"),
373  progname, PQdb(conn));
374  fflush(stdout);
375  }
376 
377  initPQExpBuffer(&sql);
378 
379  /*
380  * If a table list is not provided and we're using multiple connections,
381  * prepare the list of tables by querying the catalogs.
382  */
383  if (parallel && (!tables || !tables->head))
384  {
386  PGresult *res;
387  int ntups;
388  int i;
389 
390  initPQExpBuffer(&buf);
391 
392  res = executeQuery(conn,
393  "SELECT c.relname, ns.nspname"
394  " FROM pg_class c, pg_namespace ns\n"
395  " WHERE relkind IN ("
398  " AND c.relnamespace = ns.oid\n"
399  " ORDER BY c.relpages DESC;",
400  progname, echo);
401 
402  ntups = PQntuples(res);
403  for (i = 0; i < ntups; i++)
404  {
407  PQgetvalue(res, i, 1),
408  PQgetvalue(res, i, 0)));
409 
410  simple_string_list_append(&dbtables, buf.data);
411  resetPQExpBuffer(&buf);
412  }
413 
414  termPQExpBuffer(&buf);
415  tables = &dbtables;
416 
417  /*
418  * If there are more connections than vacuumable relations, we don't
419  * need to use them all.
420  */
421  if (concurrentCons > ntups)
422  concurrentCons = ntups;
423  if (concurrentCons <= 1)
424  parallel = false;
425  PQclear(res);
426  }
427 
428  /*
429  * Setup the database connections. We reuse the connection we already have
430  * for the first slot. If not in parallel mode, the first slot in the
431  * array contains the connection.
432  */
433  slots = (ParallelSlot *) pg_malloc(sizeof(ParallelSlot) * concurrentCons);
434  init_slot(slots, conn, progname);
435  if (parallel)
436  {
437  for (i = 1; i < concurrentCons; i++)
438  {
439  conn = connectDatabase(dbname, host, port, username, prompt_password,
440  progname, false, true);
441  init_slot(slots + i, conn, progname);
442  }
443  }
444 
445  /*
446  * Prepare all the connections to run the appropriate analyze stage, if
447  * caller requested that mode.
448  */
449  if (stage != ANALYZE_NO_STAGE)
450  {
451  int j;
452 
453  /* We already emitted the message above */
454 
455  for (j = 0; j < concurrentCons; j++)
456  executeCommand((slots + j)->connection,
457  stage_commands[stage], progname, echo);
458  }
459 
460  cell = tables ? tables->head : NULL;
461  do
462  {
463  ParallelSlot *free_slot;
464  const char *tabname = cell ? cell->val : NULL;
465 
466  prepare_vacuum_command(&sql, conn, vacopts, tabname);
467 
468  if (CancelRequested)
469  {
470  failed = true;
471  goto finish;
472  }
473 
474  /*
475  * Get the connection slot to use. If in parallel mode, here we wait
476  * for one connection to become available if none already is. In
477  * non-parallel mode we simply use the only slot we have, which we
478  * know to be free.
479  */
480  if (parallel)
481  {
482  /*
483  * Get a free slot, waiting until one becomes free if none
484  * currently is.
485  */
486  free_slot = GetIdleSlot(slots, concurrentCons, progname);
487  if (!free_slot)
488  {
489  failed = true;
490  goto finish;
491  }
492 
493  free_slot->isFree = false;
494  }
495  else
496  free_slot = slots;
497 
498  /*
499  * Execute the vacuum. If not in parallel mode, this terminates the
500  * program in case of an error. (The parallel case handles query
501  * errors in GetQueryResult through GetIdleSlot.)
502  */
503  run_vacuum_command(free_slot->connection, sql.data,
504  echo, tabname, progname, parallel);
505 
506  if (cell)
507  cell = cell->next;
508  } while (cell != NULL);
509 
510  if (parallel)
511  {
512  int j;
513 
514  for (j = 0; j < concurrentCons; j++)
515  {
516  /* wait for all connection to return the results */
517  if (!GetQueryResult((slots + j)->connection, progname))
518  goto finish;
519 
520  (slots + j)->isFree = true;
521  }
522  }
523 
524 finish:
525  for (i = 0; i < concurrentCons; i++)
526  DisconnectDatabase(slots + i);
527  pfree(slots);
528 
529  termPQExpBuffer(&sql);
530 
531  if (failed)
532  exit(1);
533 }
static PGresult * executeQuery(PGconn *conn, const char *query)
Definition: pg_dumpall.c:2140
bool isFree
Definition: vacuumdb.c:33
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3118
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:128
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:385
static ParallelSlot * GetIdleSlot(ParallelSlot slots[], int numslots, const char *progname)
Definition: vacuumdb.c:738
#define RELKIND_MATVIEW
Definition: pg_class.h:165
#define gettext_noop(x)
Definition: c.h:139
#define ANALYZE_NO_STAGE
Definition: vacuumdb.c:83
int PQserverVersion(const PGconn *conn)
Definition: fe-connect.c:6087
const char * progname
Definition: pg_standby.c:37
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2724
void pfree(void *pointer)
Definition: mcxt.c:949
PGconn * conn
Definition: streamutil.c:46
static void executeCommand(PGconn *conn, const char *query)
Definition: pg_dumpall.c:2166
static char * buf
Definition: pg_test_fsync.c:67
struct SimpleStringListCell * next
Definition: simple_list.h:34
PGconn * connection
Definition: vacuumdb.c:31
static void init_slot(ParallelSlot *slot, PGconn *conn, const char *progname)
Definition: vacuumdb.c:934
static int port
Definition: pg_regress.c:90
static void DisconnectDatabase(ParallelSlot *slot)
Definition: vacuumdb.c:850
#define CppAsString2(x)
Definition: c.h:162
static void run_vacuum_command(PGconn *conn, const char *sql, bool echo, const char *table, const char *progname, bool async)
Definition: vacuumdb.c:689
void simple_string_list_append(SimpleStringList *list, const char *val)
Definition: simple_list.c:63
static char * username
Definition: initdb.c:132
void PQclear(PGresult *res)
Definition: fe-exec.c:671
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:5965
#define Assert(condition)
Definition: c.h:681
static void prepare_vacuum_command(PQExpBuffer sql, PGconn *conn, vacuumingOptions *vacopts, const char *table)
Definition: vacuumdb.c:621
static PGconn * connectDatabase(const char *dbname, const char *connstr, const char *pghost, const char *pgport, const char *pguser, trivalue prompt_password, bool fail_on_error)
Definition: pg_dumpall.c:1891
static bool GetQueryResult(PGconn *conn, const char *progname)
Definition: vacuumdb.c:813
SimpleStringListCell * head
Definition: simple_list.h:42
char * dbname
Definition: streamutil.c:42
#define ANALYZE_NUM_STAGES
Definition: vacuumdb.c:84
bool CancelRequested
Definition: common.c:24
int i
char val[FLEXIBLE_ARRAY_MEMBER]
Definition: simple_list.h:37
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:145
#define RELKIND_RELATION
Definition: pg_class.h:160
#define _(x)
Definition: elog.c:84
const char * fmtQualifiedId(int remoteVersion, const char *schema, const char *id)
Definition: string_utils.c:150
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:89