From 8fb29d3b96caa6e1e815c181e2a8d84b7e72b65f Mon Sep 17 00:00:00 2001 From: teodor Date: Mon, 3 Oct 2011 14:22:08 +0000 Subject: [PATCH] new GUC variables --- README.online_analyze | 10 ++ online_analyze.c | 337 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 346 insertions(+), 1 deletion(-) diff --git a/README.online_analyze b/README.online_analyze index edf5059..eb95307 100644 --- a/README.online_analyze +++ b/README.online_analyze @@ -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 diff --git a/online_analyze.c b/online_analyze.c index dc1128b..78077e8 100644 --- a/online_analyze.c +++ b/online_analyze.c @@ -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; inTables; 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, µsecs); - 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; } -- 2.46.1