- {
- db_elem=DLGetHead(db_list);
- found_match=0;
- while(NULL != db_elem)
- {
- dbi=((db_info *)DLE_VAL(db_elem));
- if(dbi->oid==atoi(PQgetvalue(res,i,PQfnumber(res,"oid"))))
- {
- found_match=1;
- break;
- }
- db_elem=DLGetSucc(db_elem);
- }
- if(0==found_match) /*then we didn't find this result now in the tbl_list */
- {
- DLAddTail(db_list,DLNewElem(init_dbinfo(PQgetvalue(res,i,PQfnumber(res,"datname")),
- atoi(PQgetvalue(res,i,PQfnumber(res,"oid"))),atoi(PQgetvalue(res,i,PQfnumber(res,"age"))))));
- if(args->debug >= 1) {printf("added database: %s\n",((db_info *)DLE_VAL(DLGetTail(db_list)))->dbname);}
- }
- } /* end of for loop that adds tables */
- PQclear(res); res=NULL;
- if(args->debug >= 3) {print_db_list(db_list,0);}
- if(disconnect) db_disconnect(dbi_template1);
- }
+ if (NULL != dbi_template1->conn) {
+ /* Get a result set that has all the information
+ we will need to both remove databasews from the list
+ that no longer exist and add databases to the list
+ that are new */
+ res = send_query (FROZENOID_QUERY2, dbi_template1);
+ t = PQntuples (res);
+
+ /* First: use the db_list as the outer loop and
+ the result set as the inner loop, this will
+ determine what databases should be removed */
+ while (NULL != db_elem) {
+ dbi = ((db_info *) DLE_VAL (db_elem));
+ found_match = 0;
+
+ for (i = 0; i < t; i++) { /* loop through result set looking for a match */
+ if (dbi->oid == atoi (PQgetvalue (res, i, PQfnumber (res, "oid")))) {
+ found_match = 1;
+ /* update the dbi->age so that we ensure xid_wraparound won't happen */
+ dbi->age = atoi (PQgetvalue (res, i, PQfnumber (res, "age")));
+ break;
+ }
+ }
+ if (0 == found_match) { /*then we didn't find this db_elem in the result set */
+ Dlelem *elem_to_remove = db_elem;
+ db_elem = DLGetSucc (db_elem);
+ remove_db_from_list (elem_to_remove);
+ }
+ else
+ db_elem = DLGetSucc (db_elem);
+ } /* Done removing dropped databases from the table_list */
+
+ /* Then loop use result set as outer loop and
+ db_list as the inner loop to determine
+ what databases are new */
+ for (i = 0; i < t; i++)
+ {
+ db_elem = DLGetHead (db_list);
+ found_match = 0;
+ while (NULL != db_elem)
+ {
+ dbi = ((db_info *) DLE_VAL (db_elem));
+ if (dbi->oid == atoi (PQgetvalue (res, i, PQfnumber (res, "oid"))))
+ {
+ found_match = 1;
+ break;
+ }
+ db_elem = DLGetSucc (db_elem);
+ }
+ if (0 == found_match) /*then we didn't find this result now in the tbl_list */
+ {
+ DLAddTail (db_list, DLNewElem (init_dbinfo
+ (PQgetvalue(res, i, PQfnumber (res, "datname")),
+ atoi (PQgetvalue(res, i, PQfnumber (res, "oid"))),
+ atoi (PQgetvalue(res, i, PQfnumber (res, "age"))))));
+ if (args->debug >= 1)
+ {
+ sprintf (logbuffer, "added database: %s",((db_info *) DLE_VAL (DLGetTail (db_list)))->dbname);
+ log_entry (logbuffer);
+ }
+ }
+ } /* end of for loop that adds tables */
+ fflush (LOGOUTPUT);
+ PQclear (res);
+ res = NULL;
+ if (args->debug >= 3) {
+ print_db_list (db_list, 0);
+ }
+ if (disconnect)
+ db_disconnect (dbi_template1);
+ }
}
/* xid_wraparound_check
return 0 if nothing happened,
return 1 if the database needed a database wide vacuum
*/
-int xid_wraparound_check(db_info *dbi)
+int
+xid_wraparound_check (db_info * dbi)
{
/* FIXME: should probably do something better here so that we don't vacuum all the
- databases on the server at the same time. We have 500million xacts to work with so
- we should be able to spread the load of full database vacuums a bit */
- if(1500000000 < dbi->age)
- {
- PGresult *res=NULL;
- res=send_query("vacuum",dbi);
- /* FIXME: Perhaps should add a check for PQ_COMMAND_OK */
- PQclear(res);
- return 1;
- }
- return 0;
+ databases on the server at the same time. We have 500million xacts to work with so
+ we should be able to spread the load of full database vacuums a bit */
+ if (1500000000 < dbi->age) {
+ PGresult *res = NULL;
+ res = send_query ("vacuum", dbi);
+ /* FIXME: Perhaps should add a check for PQ_COMMAND_OK */
+ PQclear (res);
+ return 1;
+ }
+ return 0;
}
/* Close DB connection, free memory, and remove the node from the list */
-void remove_db_from_list(Dlelem *db_to_remove)
+void
+remove_db_from_list (Dlelem * db_to_remove)
{
- db_info *dbi=((db_info *)DLE_VAL(db_to_remove));
-
- if(args->debug >= 1) {printf("Removing db: %s from list.\n",dbi->dbname);}
- DLRemove(db_to_remove);
- if(dbi->conn)
- db_disconnect(dbi);
- if(dbi->dbname)
- { free(dbi->dbname); dbi->dbname=NULL;}
- if(dbi->username)
- { free(dbi->username); dbi->username=NULL;}
- if(dbi->password)
- { free(dbi->password); dbi->password=NULL;}
- if(dbi->table_list)
- { free_tbl_list(dbi->table_list); dbi->table_list=NULL;}
- if(dbi)
- { free(dbi); dbi=NULL;}
- DLFreeElem(db_to_remove);
+ db_info *dbi = ((db_info *) DLE_VAL (db_to_remove));
+
+ if (args->debug >= 1) {
+ sprintf (logbuffer, "Removing db: %s from list.", dbi->dbname);
+ log_entry (logbuffer);
+ fflush (LOGOUTPUT);
+ }
+ DLRemove (db_to_remove);
+ if (dbi->conn)
+ db_disconnect (dbi);
+ if (dbi->dbname) {
+ free (dbi->dbname);
+ dbi->dbname = NULL;
+ }
+ if (dbi->username) {
+ free (dbi->username);
+ dbi->username = NULL;
+ }
+ if (dbi->password) {
+ free (dbi->password);
+ dbi->password = NULL;
+ }
+ if (dbi->table_list) {
+ free_tbl_list (dbi->table_list);
+ dbi->table_list = NULL;
+ }
+ if (dbi) {
+ free (dbi);
+ dbi = NULL;
+ }
+ DLFreeElem (db_to_remove);
}
/* Function is called before program exit to free all memory
mostly it's just to keep valgrind happy */
-void free_db_list(Dllist *db_list)
+void
+free_db_list (Dllist * db_list)
{
- Dlelem *db_elem=DLGetHead(db_list);
- Dlelem *db_elem_to_remove=NULL;
- while(NULL != db_elem)
- {
- db_elem_to_remove=db_elem;
- db_elem=DLGetSucc(db_elem);
- remove_db_from_list(db_elem_to_remove);
- db_elem_to_remove=NULL;
- }
- DLFreeList(db_list);
+ Dlelem *db_elem = DLGetHead (db_list);
+ Dlelem *db_elem_to_remove = NULL;
+ while (NULL != db_elem) {
+ db_elem_to_remove = db_elem;
+ db_elem = DLGetSucc (db_elem);
+ remove_db_from_list (db_elem_to_remove);
+ db_elem_to_remove = NULL;
+ }
+ DLFreeList (db_list);
}
-void print_db_list(Dllist *db_list, int print_table_lists)
+void
+print_db_list (Dllist * db_list, int print_table_lists)
{
- Dlelem *db_elem=DLGetHead(db_list);
- while(NULL != db_elem)
- {
- print_db_info(((db_info *)DLE_VAL(db_elem)),print_table_lists);
- db_elem=DLGetSucc(db_elem);
+ Dlelem *db_elem = DLGetHead (db_list);
+ while (NULL != db_elem) {
+ print_db_info (((db_info *) DLE_VAL (db_elem)), print_table_lists);
+ db_elem = DLGetSucc (db_elem);
}
}
-void print_db_info(db_info *dbi, int print_tbl_list)
+void
+print_db_info (db_info * dbi, int print_tbl_list)
{
- printf("dbname: %s\n Username %s\n Passwd %s\n",dbi->dbname,dbi->username,dbi->password);
- printf(" oid %i\n InsertThresh: %i\n DeleteThresh: %i\n",dbi->oid,dbi->insertThreshold,dbi->deleteThreshold);
- if(NULL!=dbi->conn)
- printf(" conn is valid, we are connected\n");
+ sprintf (logbuffer, "dbname: %s Username %s Passwd %s", dbi->dbname,
+ dbi->username, dbi->password);
+ log_entry (logbuffer);
+ sprintf (logbuffer, " oid %i InsertThresh: %i DeleteThresh: %i", dbi->oid,
+ dbi->analyze_threshold, dbi->vacuum_threshold);
+ log_entry (logbuffer);
+ if (NULL != dbi->conn)
+ log_entry (" conn is valid, we are connected");
else
- printf(" conn is null, we are not connected.\n");
+ log_entry (" conn is null, we are not connected.");
- if(0 < print_tbl_list)
- print_table_list(dbi->table_list);
+ fflush (LOGOUTPUT);
+ if (0 < print_tbl_list)
+ print_table_list (dbi->table_list);
}
/* End of DB List Management Function */
/* Begninning of misc Functions */
-char *query_table_stats(db_info *dbi)
+char *
+query_table_stats (db_info * dbi)
{
- if(!strcmp(dbi->dbname,"template1")) /* Use template1 to monitor the system tables */
- return (char*)TABLE_STATS_ALL;
+ if (!strcmp (dbi->dbname, "template1")) /* Use template1 to monitor the system tables */
+ return (char *) TABLE_STATS_ALL;
else
- return (char*)TABLE_STATS_USER;
+ return (char *) TABLE_STATS_USER;
}
-/* Perhaps add some test to this function to make sure that the stats we need are availalble */
-PGconn *db_connect(db_info *dbi)
+/* Perhaps add some test to this function to make sure that the stats we need are available */
+PGconn *
+db_connect (db_info * dbi)
{
- PGconn *db_conn=PQsetdbLogin(args->host, args->port, NULL, NULL, dbi->dbname, dbi->username, dbi->password);
-
- if(CONNECTION_OK != PQstatus(db_conn))
- {
- fprintf(stderr,"Failed connection to database %s with error: %s.\n",dbi->dbname,PQerrorMessage(db_conn));
- PQfinish(db_conn);
- db_conn=NULL;
+ PGconn *db_conn =
+ PQsetdbLogin (args->host, args->port, NULL, NULL, dbi->dbname,
+ dbi->username, dbi->password);
+
+ if (CONNECTION_OK != PQstatus (db_conn)) {
+ sprintf (logbuffer, "Failed connection to database %s with error: %s.",
+ dbi->dbname, PQerrorMessage (db_conn));
+ log_entry (logbuffer);
+ fflush (LOGOUTPUT);
+ PQfinish (db_conn);
+ db_conn = NULL;
}
return db_conn;
-} /* end of db_connect() */
+} /* end of db_connect() */
-void db_disconnect(db_info *dbi)
+void
+db_disconnect (db_info * dbi)
{
- if(NULL != dbi->conn)
- {
- PQfinish(dbi->conn);
- dbi->conn=NULL;
+ if (NULL != dbi->conn) {
+ PQfinish (dbi->conn);
+ dbi->conn = NULL;
}
}
-int check_stats_enabled(db_info *dbi)
+int
+check_stats_enabled (db_info * dbi)
{
- PGresult *res=NULL;
- int ret=0;
- res=send_query("show stats_row_level",dbi);
- ret = strcmp("on",PQgetvalue(res,0,PQfnumber(res,"stats_row_level")));
- PQclear(res);
- return ret;
+ PGresult *res = NULL;
+ int ret = 0;
+ res = send_query ("show stats_row_level", dbi);
+ ret =
+ strcmp ("on", PQgetvalue (res, 0, PQfnumber (res, "stats_row_level")));
+ PQclear (res);
+ return ret;
}
-PGresult *send_query(const char *query,db_info *dbi)
+PGresult *
+send_query (const char *query, db_info * dbi)
{
PGresult *res;
- if(NULL==dbi->conn)
+ if (NULL == dbi->conn)
return NULL;
- res=PQexec(dbi->conn,query);
+ res = PQexec (dbi->conn, query);
- if(!res)
- {
- fprintf(stderr,"Fatal error occured while sending query (%s) to database %s\n",query,dbi->dbname);
- fprintf(stderr,"The error is \n%s\n",PQresultErrorMessage(res));
+ if (!res) {
+ sprintf (logbuffer,
+ "Fatal error occured while sending query (%s) to database %s",
+ query, dbi->dbname);
+ log_entry (logbuffer);
+ sprintf (logbuffer, "The error is [%s]", PQresultErrorMessage (res));
+ log_entry (logbuffer);
+ fflush (LOGOUTPUT);
return NULL;
}
- if(PQresultStatus(res)!=PGRES_TUPLES_OK && PQresultStatus(res)!=PGRES_COMMAND_OK)
- {
- fprintf(stderr,"Can not refresh statistics information from the database %s.\n",dbi->dbname);
- fprintf(stderr,"The error is \n%s\n",PQresultErrorMessage(res));
- PQclear(res);
+ if (PQresultStatus (res) != PGRES_TUPLES_OK
+ && PQresultStatus (res) != PGRES_COMMAND_OK) {
+ sprintf (logbuffer,
+ "Can not refresh statistics information from the database %s.",
+ dbi->dbname);
+ log_entry (logbuffer);
+ sprintf (logbuffer, "The error is [%s]", PQresultErrorMessage (res));
+ log_entry (logbuffer);
+ fflush (LOGOUTPUT);
+ PQclear (res);
return NULL;
}
return res;
-} /* End of send_query() */
+} /* End of send_query() */
-void free_cmd_args()
+void
+free_cmd_args ()
{
- if(NULL!=args)
- {
- if(NULL!=args->user)
- free(args->user);
- if(NULL!=args->user)
- free(args->password);
- free(args);
+ if (NULL != args) {
+ if (NULL != args->user)
+ free (args->user);
+ if (NULL != args->user)
+ free (args->password);
+ free (args);
}
}
-cmd_args *get_cmd_args(int argc,char *argv[])
+cmd_args *
+get_cmd_args (int argc, char *argv[])
{
int c;
-
- args=(cmd_args *)malloc(sizeof(cmd_args));
- args->sleep_base_value=SLEEPVALUE;
- args->sleep_scaling_factor=SLEEPSCALINGFACTOR;
- args->tuple_base_threshold=BASETHRESHOLD;
- args->tuple_scaling_factor=SCALINGFACTOR;
- args->debug=AUTOVACUUM_DEBUG;
- args->user=NULL;
- args->password=NULL;
- args->host=NULL;
- args->port=NULL;
- while (-1 != (c = getopt(argc, argv, "s:S:t:T:d:U:P:H:p:h")))
- {
- switch (c)
- {
- case 's':
- args->sleep_base_value=atoi(optarg);
- break;
- case 'S':
- args->sleep_scaling_factor = atof(optarg);
- break;
- case 't':
- args->tuple_base_threshold = atoi(optarg);
- break;
- case 'T':
- args->tuple_scaling_factor = atof(optarg);
- break;
- case 'd':
- args->debug = atoi(optarg);
- break;
- case 'U':
- args->user=optarg;
- break;
- case 'P':
- args->password=optarg;
- break;
- case 'H':
- args->host=optarg;
- break;
- case 'p':
- args->port=optarg;
- break;
- case 'h':
- default:
- fprintf(stderr, "usage: pg_autovacuum [-d debug][-s sleep base value][-S sleep scaling factor]\n[-t tuple base threshold][-T tulple scaling factor]\n[-U username][-P password][-H host][-p port][-h help]\n");
- exit(1);
- break;
- }
+ args = (cmd_args *) malloc (sizeof (cmd_args));
+ args->sleep_base_value = SLEEPBASEVALUE;
+ args->sleep_scaling_factor = SLEEPSCALINGFACTOR;
+ args->vacuum_base_threshold = VACBASETHRESHOLD;
+ args->vacuum_scaling_factor = VACSCALINGFACTOR;
+ args->analyze_base_threshold = -1;
+ args->analyze_scaling_factor = -1;
+ args->debug = AUTOVACUUM_DEBUG;
+ args->daemonize = 0;
+
+ /* Fixme: Should add some sanity checking such as positive integer values etc */
+ while (-1 != (c = getopt (argc, argv, "s:S:v:V:a:A:d:U:P:H:L:p:hD"))) {
+ switch (c) {
+ case 's':
+ args->sleep_base_value = atoi (optarg);
+ break;
+ case 'S':
+ args->sleep_scaling_factor = atof (optarg);
+ break;
+ case 'v':
+ args->vacuum_base_threshold = atoi (optarg);
+ break;
+ case 'V':
+ args->vacuum_scaling_factor = atof (optarg);
+ break;
+ case 'a':
+ args->analyze_base_threshold = atoi (optarg);
+ break;
+ case 'A':
+ args->analyze_scaling_factor = atof (optarg);
+ break;
+ case 'D':
+ args->daemonize++;
+ break;
+ case 'd':
+ args->debug = atoi (optarg);
+ break;
+ case 'U':
+ args->user = optarg;
+ break;
+ case 'P':
+ args->password = optarg;
+ break;
+ case 'H':
+ args->host = optarg;
+ break;
+ case 'L':
+ args->logfile = optarg;
+ break;
+ case 'p':
+ args->port = optarg;
+ break;
+ case 'h':
+ usage();
+ exit (0);
+ default:
+ /* It's here that we know that things are invalid...
+ It is not forcibly an error to call usage */
+ fprintf (stderr, "Error: Invalid Command Line Options.\n");
+ usage();
+ exit (1);
+ break;
+ }
+ /* if values for insert thresholds are not specified,
+ then they default to 1/2 of the delete values */
+ if(-1 == args->analyze_base_threshold)
+ args->analyze_base_threshold = args->vacuum_base_threshold / 2;
+ if(-1 == args->analyze_scaling_factor)
+ args->analyze_scaling_factor = args->vacuum_scaling_factor / 2;
}
-
return args;
}
-void print_cmd_args()
+void usage()
+{
+ int i=0;
+ float f=0;
+ fprintf (stderr, "usage: pg_autovacuum \n");
+ fprintf (stderr, " [-D] Daemonize (Detach from tty and run in the background)\n");
+ i=AUTOVACUUM_DEBUG;
+ fprintf (stderr, " [-d] debug (debug level=0,1,2,3; default=%i)\n",i);
+
+ i=SLEEPBASEVALUE;
+ fprintf (stderr, " [-s] sleep base value (default=%i)\n",i);
+ f=SLEEPSCALINGFACTOR;
+ fprintf (stderr, " [-S] sleep scaling factor (default=%f)\n",f);
+
+ i=VACBASETHRESHOLD;
+ fprintf (stderr, " [-v] vacuum base threshold (default=%i)\n",i);
+ f=VACSCALINGFACTOR;
+ fprintf (stderr, " [-V] vacuum scaling factor (default=%f)\n",f);
+ i=i/2;
+ fprintf (stderr, " [-a] analyze base threshold (default=%i)\n",i);
+ f=f/2;
+ fprintf (stderr, " [-A] analyze scaling factor (default=%f)\n",f);
+
+ fprintf (stderr, " [-L] logfile (default=none)\n");
+
+ fprintf (stderr, " [-U] username (libpq default)\n");
+ fprintf (stderr, " [-P] password (libpq default)\n");
+ fprintf (stderr, " [-H] host (libpq default)\n");
+ fprintf (stderr, " [-p] port (libpq default)\n");
+
+ fprintf (stderr, " [-h] help (Show this output)\n");
+}
+
+void
+print_cmd_args ()
{
- printf("Printing command_args\n");
- printf(" args->host=%s\n",args->host);
- printf(" args->port=%s\n",args->port);
- printf(" args->user=%s\n",args->user);
- printf(" args->password=%s\n",args->password);
- printf(" args->sleep_base_value=%i\n",args->sleep_base_value);
- printf(" args->sleep_scaling_factor=%f\n",args->sleep_scaling_factor);
- printf(" args->tuple_base_threshold=%i\n",args->tuple_base_threshold);
- printf(" args->tuple_scaling_factor=%f\n",args->tuple_scaling_factor);
- printf(" args->debug=%i\n",args->debug);
+ sprintf (logbuffer, "Printing command_args");
+ log_entry (logbuffer);
+ sprintf (logbuffer, " args->host=%s", (args->host) ? args->host : "(null)");
+ log_entry (logbuffer);
+ sprintf (logbuffer, " args->port=%s", (args->port) ? args->port : "(null)");
+ log_entry (logbuffer);
+ sprintf (logbuffer, " args->user=%s", (args->user) ? args->user : "(null)");
+ log_entry (logbuffer);
+ sprintf (logbuffer, " args->password=%s",(args->password) ? args->password : "(null)");
+ log_entry (logbuffer);
+ sprintf (logbuffer, " args->logfile=%s",(args->logfile) ? args->logfile : "(null)");
+ log_entry (logbuffer);
+ sprintf (logbuffer, " args->daemonize=%i",args->daemonize);
+ log_entry (logbuffer);
+
+ sprintf (logbuffer, " args->sleep_base_value=%i", args->sleep_base_value);
+ log_entry (logbuffer);
+ sprintf (logbuffer, " args->sleep_scaling_factor=%f",args->sleep_scaling_factor);
+ log_entry (logbuffer);
+ sprintf (logbuffer, " args->vacuum_base_threshold=%i",args->vacuum_base_threshold);
+ log_entry (logbuffer);
+ sprintf (logbuffer, " args->vacuum_scaling_factor=%f",args->vacuum_scaling_factor);
+ log_entry (logbuffer);
+ sprintf (logbuffer, " args->analyze_base_threshold=%i",args->analyze_base_threshold);
+ log_entry (logbuffer);
+ sprintf (logbuffer, " args->analyze_scaling_factor=%f",args->analyze_scaling_factor);
+ log_entry (logbuffer);
+ sprintf (logbuffer, " args->debug=%i", args->debug);
+ log_entry (logbuffer);
+
+ fflush (LOGOUTPUT);
}
/* Beginning of AutoVacuum Main Program */
-int main(int argc, char *argv[])
+int
+main (int argc, char *argv[])
{
char buf[256];
- int j=0, loops=0;
- int numInserts, numDeletes, sleep_secs;
- Dllist *db_list;
- Dlelem *db_elem,*tbl_elem;
- db_info *dbs;
- tbl_info *tbl;
- PGresult *res;
- long long diff=0;
- struct timeval now,then;
-
- args=get_cmd_args(argc,argv); /* Get Command Line Args and put them in the args struct */
-
- if(args->debug >= 2) {print_cmd_args();}
-
- db_list=init_db_list(); /* Init the db list with template1 */
- if(NULL == db_list)
+ int j = 0, loops = 0;
+/* int numInserts, numDeletes, */
+ int sleep_secs;
+ Dllist *db_list;
+ Dlelem *db_elem, *tbl_elem;
+ db_info *dbs;
+ tbl_info *tbl;
+ PGresult *res=NULL;
+ long long diff = 0;
+ struct timeval now, then;
+
+ args = get_cmd_args (argc, argv); /* Get Command Line Args and put them in the args struct */
+
+ /* Dameonize if requested */
+ if (1 == args->daemonize){ daemonize(); }
+
+ if (args->logfile) {
+ LOGOUTPUT = fopen (args->logfile, "a");
+ if (!LOGOUTPUT) {
+ fprintf (stderr, "Could not open log file - [%s]\n", args->logfile);
+ exit(-1);
+ }
+ }
+ else {
+ LOGOUTPUT = stderr;
+ }
+ if (args->debug >= 2) {
+ print_cmd_args ();
+ }
+
+ /* Init the db list with template1 */
+ db_list = init_db_list ();
+ if (NULL == db_list)
return 1;
- if(0!=check_stats_enabled(((db_info*)DLE_VAL(DLGetHead(db_list)))))
- {
- printf("Error: GUC variable stats_row_level must be enabled.\n Please fix the problems and try again.\n");
- exit(1);
- }
+ if (0 != check_stats_enabled (((db_info *) DLE_VAL (DLGetHead (db_list))))) {
+ log_entry ("Error: GUC variable stats_row_level must be enabled.");
+ log_entry (" Please fix the problems and try again.");
+ fflush (LOGOUTPUT);
+
+ exit (1);
+ }
+
+ gettimeofday (&then, 0); /* for use later to caluculate sleep time */
+
+ while (1) { /* Main Loop */
+ db_elem = DLGetHead (db_list); /* Reset cur_db_node to the beginning of the db_list */
- gettimeofday(&then, 0); /* for use later to caluculate sleep time */
+ dbs = ((db_info *) DLE_VAL (db_elem)); /* get pointer to cur_db's db_info struct */
+ if (NULL == dbs->conn) {
+ dbs->conn = db_connect (dbs);
+ if (NULL == dbs->conn) { /* Serious problem: We can't connect to template1 */
+ log_entry ("Error: Cannot connect to template1, exiting.");
+ fflush (LOGOUTPUT);
+ fclose (LOGOUTPUT);
+ exit (1);
+ }
+ }
+
+ if (0 == (loops % UPDATE_INTERVAL)) /* Update the list if it's time */
+ update_db_list (db_list); /* Add and remove databases from the list */
+
+ while (NULL != db_elem) { /* Loop through databases in list */
+ dbs = ((db_info *) DLE_VAL (db_elem)); /* get pointer to cur_db's db_info struct */
+ if (NULL == dbs->conn)
+ dbs->conn = db_connect (dbs);
+
+ if (NULL != dbs->conn) {
+ if (0 == (loops % UPDATE_INTERVAL)) /* Update the list if it's time */
+ update_table_list (dbs); /* Add and remove tables from the list */
- while(1) /* Main Loop */
+ if (0 == xid_wraparound_check (dbs));
{
- db_elem=DLGetHead(db_list); /* Reset cur_db_node to the beginning of the db_list */
-
- dbs=((db_info *)DLE_VAL(db_elem)); /* get pointer to cur_db's db_info struct */
- if(NULL==dbs->conn)
- {
- dbs->conn=db_connect(dbs);
- if(NULL==dbs->conn) /* Serious problem: We can't connect to template1 */
- {
- printf("Error: Cannot connect to template1, exiting.\n");
- exit(1);
- }
- }
-
- if(0==(loops % UPDATE_INTERVAL)) /* Update the list if it's time */
- update_db_list(db_list); /* Add new databases to the list to be checked, and remove databases that no longer exist */
-
- while(NULL != db_elem) /* Loop through databases in list */
- {
- dbs=((db_info *)DLE_VAL(db_elem)); /* get pointer to cur_db's db_info struct */
- if(NULL==dbs->conn)
- dbs->conn=db_connect(dbs);
-
- if(NULL!=dbs->conn)
- {
- if(0==(loops % UPDATE_INTERVAL)) /* Update the list if it's time */
- update_table_list(dbs); /* Add new databases to the list to be checked, and remove databases that no longer exist */
-
- if(0==xid_wraparound_check(dbs));
- {
- res=send_query(query_table_stats(dbs),dbs); /* Get an updated snapshot of this dbs table stats */
- for(j=0;j < PQntuples(res);j++) /* loop through result set */
- {
- tbl_elem = DLGetHead(dbs->table_list); /* Reset tbl_elem to top of dbs->table_list */
- while(NULL!=tbl_elem) /* Loop through tables in list */
- {
- tbl=((tbl_info *)DLE_VAL(tbl_elem)); /* set tbl_info = current_table */
- if(tbl->relfilenode == atoi(PQgetvalue(res,j,PQfnumber(res,"relfilenode"))))
+ res = send_query (query_table_stats (dbs), dbs); /* Get an updated snapshot of this dbs table stats */
+ for (j = 0; j < PQntuples (res); j++) { /* loop through result set */
+ tbl_elem = DLGetHead (dbs->table_list); /* Reset tbl_elem to top of dbs->table_list */
+ while (NULL != tbl_elem) { /* Loop through tables in list */
+ tbl = ((tbl_info *) DLE_VAL (tbl_elem)); /* set tbl_info = current_table */
+ if (tbl->relfilenode == atoi (PQgetvalue(res, j, PQfnumber (res, "relfilenode")))) {
+ tbl->curr_analyze_count =
+ (atol (PQgetvalue (res, j, PQfnumber (res, "n_tup_ins"))) +
+ atol (PQgetvalue (res, j, PQfnumber (res, "n_tup_upd"))) +
+ atol (PQgetvalue (res, j, PQfnumber (res, "n_tup_del"))));
+ tbl->curr_vacuum_count =
+ (atol (PQgetvalue (res, j, PQfnumber (res, "n_tup_del"))) +
+ atol (PQgetvalue (res, j, PQfnumber (res, "n_tup_upd"))));
+
+ /* Check numDeletes to see if we need to vacuum, if so:
+ Run vacuum analyze (adding analyze is small so we might as well)
+ Update table thresholds and related information
+ if numDeletes is not big enough for vacuum then check numInserts for analyze */
+ if ((tbl->curr_vacuum_count - tbl->CountAtLastVacuum) >= tbl->vacuum_threshold)
+ {
+ snprintf (buf, sizeof (buf), "vacuum analyze %s", tbl->table_name);
+ if (args->debug >= 1) {
+ sprintf (logbuffer, "Performing: %s", buf);
+ log_entry (logbuffer);
+ fflush (LOGOUTPUT);
+ }
+ send_query (buf, dbs);
+ update_table_thresholds (dbs, tbl, VACUUM_ANALYZE);
+ if (args->debug >= 2) {print_table_info (tbl);}
+ }
+ else if ((tbl->curr_analyze_count - tbl->CountAtLastAnalyze) >= tbl->analyze_threshold)
{
- numInserts=(atol(PQgetvalue(res,j,PQfnumber(res,"n_tup_ins"))) + atol(PQgetvalue(res,j,PQfnumber(res,"n_tup_upd"))));
- numDeletes=(atol(PQgetvalue(res,j,PQfnumber(res,"n_tup_del"))) + atol(PQgetvalue(res,j,PQfnumber(res,"n_tup_upd"))));
-
- /* Check numDeletes to see if we need to vacuum, if so:
- Run vacuum analyze (adding analyze is small so we might as well)
- Update table thresholds and related information
- if numDeletes is not big enough for vacuum then check numInserts for analyze */
- if((numDeletes - tbl->DeletesAtLastVacuum) >= tbl->deleteThreshold)
- {
- snprintf(buf,sizeof(buf),"vacuum %s",tbl->table_name);
- if(args->debug >= 1) {printf("Performing: %s\n",buf);}
- send_query(buf,dbs);
- tbl->DeletesAtLastVacuum=numDeletes;
- update_table_thresholds(dbs,tbl);
- if(args->debug >= 2) {print_table_info(tbl);}
- }
- else if((numInserts - tbl->InsertsAtLastAnalyze) >= tbl->insertThreshold)
- {
- snprintf(buf,sizeof(buf),"analyze %s",tbl->table_name);
- if(args->debug >= 1) {printf("Performing: %s\n",buf);}
- send_query(buf,dbs);
- tbl->InsertsAtLastAnalyze=numInserts;
- tbl->reltuples=atoi(PQgetvalue(res,j,PQfnumber(res,"reltuples")));
- tbl->insertThreshold = (args->tuple_base_threshold + args->tuple_scaling_factor*tbl->reltuples);
- if(args->debug >= 2) {print_table_info(tbl);}
- }
-
- /* If the stats collector is reporting fewer updates then we have on record
- then the stats were probably reset, so we need to reset also */
- if((numInserts < tbl->InsertsAtLastAnalyze)||(numDeletes < tbl->DeletesAtLastVacuum))
- {
- tbl->InsertsAtLastAnalyze=numInserts;
- tbl->DeletesAtLastVacuum=numDeletes;
- }
- break; /* once we have found a match, no need to keep checking. */
- }
- /* Advance the table pointers for the next loop */
- tbl_elem=DLGetSucc(tbl_elem);
-
- } /* end for table while loop */
- } /* end for j loop (tuples in PGresult) */
- } /* close of if(xid_wraparound_check()) */
- /* Done working on this db, Clean up, then advance cur_db */
- PQclear(res); res=NULL;
- db_disconnect(dbs);
- }
- db_elem=DLGetSucc(db_elem); /* move on to next DB regardless */
- } /* end of db_list while loop */
+ snprintf (buf, sizeof (buf), "analyze %s", tbl->table_name);
+ if (args->debug >= 1) {
+ sprintf (logbuffer, "Performing: %s", buf);
+ log_entry (logbuffer);
+ fflush (LOGOUTPUT);
+ }
+ send_query (buf, dbs);
+ update_table_thresholds (dbs, tbl, ANALYZE_ONLY);
+ if (args->debug >= 2) { print_table_info (tbl); }
+ }
+
+ break; /* once we have found a match, no need to keep checking. */
+ }
+ /* Advance the table pointers for the next loop */
+ tbl_elem = DLGetSucc (tbl_elem);
+
+ } /* end for table while loop */
+ } /* end for j loop (tuples in PGresult) */
+ } /* close of if(xid_wraparound_check()) */
+ /* Done working on this db, Clean up, then advance cur_db */
+ PQclear (res);
+ res = NULL;
+ db_disconnect (dbs);
+ }
+ db_elem = DLGetSucc (db_elem); /* move on to next DB regardless */
+ } /* end of db_list while loop */
/* Figure out how long to sleep etc ... */
- gettimeofday(&now, 0);
+ gettimeofday (&now, 0);
diff = (now.tv_sec - then.tv_sec) * 1000000 + (now.tv_usec - then.tv_usec);
- sleep_secs = args->sleep_base_value + args->sleep_scaling_factor*diff/1000000;
+ sleep_secs = args->sleep_base_value + args->sleep_scaling_factor * diff / 1000000;
loops++;
- if(args->debug >= 2)
- { printf("%i All DBs checked in: %lld usec, will sleep for %i secs.\n",loops,diff,sleep_secs);}
+ if (args->debug >= 2) {
+ sprintf (logbuffer,
+ "%i All DBs checked in: %lld usec, will sleep for %i secs.",
+ loops, diff, sleep_secs);
+ log_entry (logbuffer);
+ }
- sleep(sleep_secs); /* Larger Pause between outer loops */
+ sleep (sleep_secs); /* Larger Pause between outer loops */
- gettimeofday(&then, 0); /* Reset time counter */
+ gettimeofday (&then, 0); /* Reset time counter */
} /* end of while loop */
- /* program is exiting, this should never run, but is here to make compiler / valgrind happy */
- free_db_list(db_list);
- free_cmd_args();
+ /* program is exiting, this should never run, but is here to make compiler / valgrind happy */
+ free_db_list (db_list);
+ free_cmd_args ();
return EXIT_SUCCESS;
}