new GUC variables
authorteodor <teodor>
Mon, 3 Oct 2011 14:22:08 +0000 (14:22 +0000)
committerteodor <teodor>
Mon, 3 Oct 2011 14:22:08 +0000 (14:22 +0000)
README.online_analyze
online_analyze.c

index edf5059..eb95307 100644 (file)
@@ -23,4 +23,14 @@ online_analyze.threshold = 50
 online_analyze.min_interval = 10000
     Minimum time interval between analyze call per table (in milliseconds)
 
+online_analyze.table_type = "all"
+       Type(s) of table for onlyne analyze: all, persistent, temporary, none
+
+online_analyze.exclude_tables = ""
+       List of tables which will not online analyze
+
+online_analyze.include_tables = ""
+       List of tables which will online analyze
+       online_analyze.include_tables overwrites online_analyze.exclude_tables.
+
 Author: Teodor Sigaev <teodor@sigaev.ru>
index dc1128b..78077e8 100644 (file)
@@ -36,6 +36,7 @@
 #include "nodes/nodes.h"
 #include "nodes/parsenodes.h"
 #include "storage/bufmgr.h"
+#include "utils/builtins.h"
 #include "utils/lsyscache.h"
 #include "utils/guc.h"
 
@@ -49,6 +50,238 @@ static double online_analyze_scale_factor = 0.1;
 static int online_analyze_threshold = 50;
 static double online_analyze_min_interval = 10000;
 
+typedef enum 
+{
+       OATT_ALL                = 0x03,
+       OATT_PERSISTENT = 0x01,
+       OATT_TEMPORARY  = 0x02,
+       OATT_NONE               = 0x00
+} OnlyneAnalyzeTableType;
+
+static const struct config_enum_entry online_analyze_table_type_options[] = 
+{
+       {"all", OATT_ALL, false},
+       {"persistent", OATT_PERSISTENT, false},
+       {"temporary", OATT_TEMPORARY, false},
+       {"none", OATT_NONE, false},
+       {NULL, 0, false},
+};
+
+static int online_analyze_table_type = (int)OATT_ALL;
+
+typedef struct TableList {
+       int             nTables;
+       Oid             *tables;
+       char    *tableStr;
+} TableList;
+
+static TableList excludeTables = {0, NULL, NULL};
+static TableList includeTables = {0, NULL, NULL};
+
+static int
+oid_cmp(const void *a, const void *b)
+{
+       if (*(Oid*)a == *(Oid*)b)
+               return 0;
+       return (*(Oid*)a > *(Oid*)b) ? 1 : -1;
+}
+
+static const char *
+tableListAssign(const char * newval, bool doit, TableList *tbl)
+{
+       char       *rawname;
+       List       *namelist;
+       ListCell   *l;
+       Oid         *newOids = NULL;
+       int         nOids = 0,
+                               i = 0;
+
+       rawname = pstrdup(newval);
+
+       if (!SplitIdentifierString(rawname, ',', &namelist))
+               goto cleanup;
+
+       if (doit)
+       {
+               nOids = list_length(namelist);
+               newOids = malloc(sizeof(Oid) * (nOids+1));
+               if (!newOids)
+                       elog(ERROR,"could not allocate %d bytes", (int)(sizeof(Oid) * (nOids+1)));
+       }
+
+       foreach(l, namelist)
+       {
+               char        *curname = (char *) lfirst(l);
+               Oid         relOid = RangeVarGetRelid(makeRangeVarFromNameList(stringToQualifiedNameList(curname)), true);
+
+               if (relOid == InvalidOid)
+               {
+#if PG_VERSION_NUM >= 90100
+                       if (doit == false)
+#endif
+                       elog(WARNING,"'%s' does not exist", curname);
+                       continue;
+               }
+               else if ( get_rel_relkind(relOid) != RELKIND_RELATION )
+               {
+#if PG_VERSION_NUM >= 90100
+                       if (doit == false)
+#endif
+                               elog(WARNING,"'%s' is not an table", curname);
+                       continue;
+               }
+               else if (doit)
+               {
+                       newOids[i++] = relOid;
+               }
+       }
+
+       if (doit)
+       {
+               tbl->nTables = i;
+               if (tbl->tables)
+                       free(tbl->tables);
+               tbl->tables = newOids;
+               if (tbl->nTables > 1)
+                       qsort(tbl->tables, tbl->nTables, sizeof(tbl->tables[0]), oid_cmp);
+       }
+
+       pfree(rawname);
+       list_free(namelist);
+
+       return newval;
+
+cleanup:
+       if (newOids)
+               free(newOids);
+       pfree(rawname);
+       list_free(namelist);
+       return NULL;
+}
+
+#if PG_VERSION_NUM >= 90100
+static bool
+excludeTablesCheck(char **newval, void **extra, GucSource source)
+{
+       char *val;
+
+       val = (char*)tableListAssign(*newval, false, &excludeTables);
+
+       if (val)
+       {
+               *newval = val;
+               return true;
+       }
+
+       return false;
+}
+
+static void
+excludeTablesAssign(const char *newval, void *extra)
+{
+       tableListAssign(newval, true, &excludeTables);
+}
+
+static bool
+includeTablesCheck(char **newval, void **extra, GucSource source)
+{
+       char *val;
+
+       val = (char*)tableListAssign(*newval, false, &includeTables);
+
+       if (val)
+       {
+               *newval = val;
+               return true;
+       }
+
+       return false;
+}
+
+static void
+includeTablesAssign(const char *newval, void *extra)
+{
+       tableListAssign(newval, true, &excludeTables);
+}
+
+#else /* PG_VERSION_NUM < 90100 */ 
+
+static const char *
+excludeTablesAssign(const char * newval, bool doit, GucSource source)
+{
+       return tableListAssign(newval, doit, &excludeTables);
+}
+
+static const char *
+includeTablesAssign(const char * newval, bool doit, GucSource source)
+{
+       return tableListAssign(newval, doit, &includeTables);
+}
+
+#endif
+
+static const char*
+tableListShow(TableList *tbl)
+{
+       char    *val, *ptr;
+       int     i,
+                       len;
+
+       len = 1 /* \0 */ + tbl->nTables * (2 * NAMEDATALEN + 2 /* ', ' */ + 1 /* . */);
+       ptr = val = palloc(len);
+       *ptr ='\0';
+       for(i=0; i<tbl->nTables; i++)
+       {
+               char    *relname = get_rel_name(tbl->tables[i]);
+               Oid     nspOid = get_rel_namespace(tbl->tables[i]);
+               char    *nspname = get_namespace_name(nspOid);
+
+               if ( relname == NULL || nspOid == InvalidOid || nspname == NULL )
+                       continue;
+
+               ptr += snprintf(ptr, len - (ptr - val), "%s%s.%s",
+                                                                                                       (i==0) ? "" : ", ",
+                                                                                                       nspname, relname);
+       }
+
+       return val;
+}
+
+static const char*
+excludeTablesShow(void)
+{
+       return tableListShow(&excludeTables);
+}
+
+static const char*
+includeTablesShow(void)
+{
+       return tableListShow(&includeTables);
+}
+
+static bool
+matchOid(TableList *tbl, Oid oid)
+{
+       Oid     *StopLow = tbl->tables,
+               *StopHigh = tbl->tables + tbl->nTables,
+               *StopMiddle;
+
+       /* Loop invariant: StopLow <= val < StopHigh */
+       while (StopLow < StopHigh)
+       {
+               StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
+
+               if (*StopMiddle == oid)
+                       return true;
+               else  if (*StopMiddle < oid)
+                       StopLow = StopMiddle + 1;
+               else
+                       StopHigh = StopMiddle;
+       }
+
+       return false;
+}
+
 static ExecutorEnd_hook_type oldhook = NULL;
 
 static void
@@ -84,6 +317,42 @@ makeAnalyze(Oid relOid, CmdType operation, uint32 naffected)
                VacuumStmt                              vacstmt;
                TimestampTz                             startStamp, endStamp;
 
+               /*
+                * includeTables overwrites excludeTables
+                */
+               switch(online_analyze_table_type)
+               {
+                       case OATT_ALL:
+                               if (matchOid(&excludeTables, relOid) == true && matchOid(&includeTables, relOid) == false)
+                                       return;
+                               break;
+                       case OATT_NONE:
+                               if (matchOid(&includeTables, relOid) == false)
+                                       return;
+                               break;
+                       case OATT_TEMPORARY:
+                       case OATT_PERSISTENT:
+                       default:
+                               {
+                                       Relation                                rel;
+                                       OnlyneAnalyzeTableType  reltype;
+
+                                       rel = RelationIdGetRelation(relOid);
+                                       reltype = (rel->rd_istemp || rel->rd_islocaltemp) ? OATT_TEMPORARY : OATT_PERSISTENT;
+                                       RelationClose(rel);
+
+                                       /*
+                                        * skip analyze if relation's type doesn't not match online_analyze_table_type
+                                        */
+                                       if ((online_analyze_table_type & reltype) == 0 || matchOid(&excludeTables, relOid) == true)
+                                       {
+                                               if (matchOid(&includeTables, relOid) == false)
+                                                       return;
+                                       }
+                               }
+                               break;
+               }
+
                vacstmt.type = T_VacuumStmt;
                vacstmt.freeze_min_age = -1;
                vacstmt.freeze_table_age = -1; /* ??? */
@@ -116,7 +385,8 @@ makeAnalyze(Oid relOid, CmdType operation, uint32 naffected)
 
                        endStamp = GetCurrentTimestamp();
                        TimestampDifference(startStamp, endStamp, &secs, &microsecs);
-                       elog(INFO, "analyze \"%s\" took %.02f seconds", get_rel_name(relOid), ((double)secs) + ((double)microsecs)/1.0e6);
+                       elog(INFO, "analyze \"%s\" took %.02f seconds", 
+                               get_rel_name(relOid), ((double)secs) + ((double)microsecs)/1.0e6);
                }
 
 
@@ -291,6 +561,63 @@ _PG_init(void)
                NULL
        );
 
+DefineCustomEnumVariable(
+               "online_analyze.table_type",
+               "Type(s) of table for onlyne analyze: all(default), persistent, temporary, none",
+               NULL,
+               &online_analyze_table_type,
+#if PG_VERSION_NUM >= 80400
+               online_analyze_table_type,
+#endif
+               online_analyze_table_type_options,
+               PGC_USERSET,
+#if PG_VERSION_NUM >= 80400
+        GUC_NOT_IN_SAMPLE,
+#if PG_VERSION_NUM >= 90100
+               NULL,
+#endif
+#endif
+               NULL,
+               NULL
+       );
+
+    DefineCustomStringVariable(
+               "online_analyze.exclude_tables",
+               "List of tables which will not online analyze",
+               NULL,
+               &excludeTables.tableStr,
+#if PG_VERSION_NUM >= 80400
+               "",
+#endif
+               PGC_USERSET,
+               0,
+#if PG_VERSION_NUM >= 90100
+               excludeTablesCheck,
+               excludeTablesAssign,
+#else
+               excludeTablesAssign,
+#endif
+               excludeTablesShow
+       );
+
+    DefineCustomStringVariable(
+               "online_analyze.include_tables",
+               "List of tables which will online analyze",
+               NULL,
+               &includeTables.tableStr,
+#if PG_VERSION_NUM >= 80400
+               "",
+#endif
+               PGC_USERSET,
+               0,
+#if PG_VERSION_NUM >= 90100
+               includeTablesCheck,
+               includeTablesAssign,
+#else
+               includeTablesAssign,
+#endif
+               includeTablesShow
+       );
 }
 
 void _PG_fini(void);
@@ -298,4 +625,12 @@ void
 _PG_fini(void)
 {
        ExecutorEnd_hook = oldhook;
+
+       if (excludeTables.tables)
+               free(excludeTables.tables);
+       if (includeTables.tables)
+               free(includeTables.tables);
+
+       excludeTables.tables = includeTables.tables = NULL;
+       excludeTables.nTables = includeTables.nTables = 0;
 }