Remove _PG_fini Mikhail Litsarev
[online_analyze.git] / online_analyze.c
index 3fe4da5..0021fc3 100644 (file)
@@ -30,6 +30,7 @@
 #include "postgres.h"
 
 #include "pgstat.h"
+#include "miscadmin.h"
 #include "access/transam.h"
 #include "access/xact.h"
 #include "catalog/namespace.h"
@@ -55,6 +56,9 @@
 #if PG_VERSION_NUM >= 100000
 #include "utils/varlena.h"
 #include "utils/regproc.h"
+#if PG_VERSION_NUM >= 130000
+#include "common/hashfn.h"
+#endif
 #endif
 #endif
 #endif
@@ -77,6 +81,10 @@ static ExecutorEnd_hook_type oldExecutorEndHook = NULL;
 static ProcessUtility_hook_type        oldProcessUtilityHook = NULL;
 #endif
 
+#if PG_VERSION_NUM >= 120000
+#define VACOPT_NOWAIT VACOPT_SKIP_LOCKED
+#endif
+
 typedef enum CmdKind
 {
        CK_SELECT = CMD_SELECT,
@@ -114,18 +122,19 @@ typedef struct TableList {
        int             nTables;
        Oid             *tables;
        char    *tableStr;
+       bool    inited;
 } TableList;
 
-static TableList excludeTables = {0, NULL, NULL};
-static TableList includeTables = {0, NULL, NULL};
+static TableList excludeTables = {0, NULL, NULL, false};
+static TableList includeTables = {0, NULL, NULL, false};
 
 typedef struct OnlineAnalyzeTableStat {
        Oid                             tableid;
        bool                    rereadStat;
        PgStat_Counter  n_tuples;
-       PgStat_Counter  changes_since_analyze;
-       TimestampTz             autovac_analyze_timestamp;
-       TimestampTz             analyze_timestamp;
+       PgStat_Counter  mod_since_analyze;
+       TimestampTz             last_autoanalyze_time;
+       TimestampTz             last_analyze_time;
 } OnlineAnalyzeTableStat;
 
 static MemoryContext   onlineAnalyzeMemoryContext = NULL;
@@ -158,6 +167,23 @@ tableListAssign(const char * newval, bool doit, TableList *tbl)
        if (!SplitIdentifierString(rawname, ',', &namelist))
                goto cleanup;
 
+       /*
+       * follow work could be done only in normal processing because of
+       * accsess to system catalog
+       */
+#if PG_VERSION_NUM >= 170000
+       if (MyProcNumber == INVALID_PROC_NUMBER ||
+#else
+       if (MyBackendId == InvalidBackendId ||
+#endif
+               !IsUnderPostmaster ||
+               !IsTransactionState())
+       {
+               includeTables.inited = false;
+               excludeTables.inited = false;
+               return newval;
+       }
+
        if (doit)
        {
                nOids = list_length(namelist);
@@ -170,7 +196,10 @@ tableListAssign(const char * newval, bool doit, TableList *tbl)
        foreach(l, namelist)
        {
                char    *curname = (char *) lfirst(l);
-#if PG_VERSION_NUM >= 90200
+#if PG_VERSION_NUM >= 160000
+               Oid             relOid = RangeVarGetRelid(makeRangeVarFromNameList(
+                                                       stringToQualifiedNameList(curname, NULL)), NoLock, true);
+#elif PG_VERSION_NUM >= 90200
                Oid             relOid = RangeVarGetRelid(makeRangeVarFromNameList(
                                                        stringToQualifiedNameList(curname)), NoLock, true);
 #else
@@ -265,7 +294,7 @@ includeTablesCheck(char **newval, void **extra, GucSource source)
 static void
 includeTablesAssign(const char *newval, void *extra)
 {
-       tableListAssign(newval, true, &excludeTables);
+       tableListAssign(newval, true, &includeTables);
 }
 
 #else /* PG_VERSION_NUM < 90100 */
@@ -284,6 +313,31 @@ includeTablesAssign(const char * newval, bool doit, GucSource source)
 
 #endif
 
+static void
+lateInit()
+{
+       TableList       *tl[] = {&includeTables, &excludeTables};
+       int i;
+
+#if PG_VERSION_NUM >= 170000
+       if (MyProcNumber == INVALID_PROC_NUMBER ||
+#else
+       if (MyBackendId == InvalidBackendId ||
+#endif
+               !IsUnderPostmaster ||
+               !IsTransactionState())
+               return; /* we aren't in connected state */
+
+       for(i=0; i<lengthof(tl); i++)
+       {
+               TableList       *tbl = tl[i];
+
+               if (tbl->inited == false)
+                       tableListAssign(tbl->tableStr, true, tbl);
+               tbl->inited = true;
+       }
+}
+
 static const char*
 tableListShow(TableList *tbl)
 {
@@ -291,6 +345,8 @@ tableListShow(TableList *tbl)
        int             i,
                        len;
 
+       lateInit();
+
        len = 1 /* \0 */ + tbl->nTables * (2 * NAMEDATALEN + 2 /* ', ' */ + 1 /* . */);
        ptr = val = palloc(len);
        *ptr ='\0';
@@ -446,17 +502,20 @@ makeAnalyze(Oid relOid, CmdKind operation, int64 naffected)
                rstat->tableid = relOid;
                newTable = true;
        }
-       else if (operation == CK_VACUUM)
+
+       if (operation == CK_VACUUM)
        {
-               /* force reread becouse vacuum could change n_tuples */
+               /* force reread because vacuum could change n_tuples */
                rstat->rereadStat = true;
                return;
        }
        else if (operation == CK_ANALYZE)
        {
                /* only analyze */
-               rstat->changes_since_analyze = 0;
-               rstat->analyze_timestamp = now;
+               rstat->mod_since_analyze = 0;
+               rstat->last_analyze_time = now;
+               if (newTable)
+                       rstat->rereadStat = true;
                return;
        }
 
@@ -477,17 +536,36 @@ makeAnalyze(Oid relOid, CmdKind operation, int64 naffected)
 
                if (tabentry)
                {
-                       rstat->n_tuples = tabentry->n_dead_tuples + tabentry->n_live_tuples;
-                       rstat->changes_since_analyze =
-#if PG_VERSION_NUM >= 90000
+                       rstat->n_tuples =
+#if PG_VERSION_NUM >= 160000
+                               tabentry->dead_tuples + tabentry->live_tuples;
+#else
+                               tabentry->n_dead_tuples + tabentry->n_live_tuples;
+#endif
+
+                       rstat->mod_since_analyze =
+#if PG_VERSION_NUM >= 160000
+                               tabentry->mod_since_analyze;
+#elif PG_VERSION_NUM >= 90000
                                tabentry->changes_since_analyze;
 #else
                                tabentry->n_live_tuples + tabentry->n_dead_tuples -
                                        tabentry->last_anl_tuples;
 #endif
-                       rstat->autovac_analyze_timestamp =
+
+                       rstat->last_autoanalyze_time =
+#if PG_VERSION_NUM >= 160000
+                               tabentry->last_autoanalyze_time;
+#else
                                tabentry->autovac_analyze_timestamp;
-                       rstat->analyze_timestamp = tabentry->analyze_timestamp;
+#endif
+
+                       rstat->last_analyze_time =
+#if PG_VERSION_NUM >= 160000
+                               tabentry->last_analyze_time;
+#else
+                               tabentry->analyze_timestamp;
+#endif
                }
        }
 
@@ -495,12 +573,12 @@ makeAnalyze(Oid relOid, CmdKind operation, int64 naffected)
                /* force analyze after truncate, fasttruncate already did analyze */
                operation == CK_TRUNCATE || (
                /* do not analyze too often, if both stamps are exceeded the go */
-               TimestampDifferenceExceeds(rstat->analyze_timestamp, now, online_analyze_min_interval) &&
-               TimestampDifferenceExceeds(rstat->autovac_analyze_timestamp, now, online_analyze_min_interval) &&
+               TimestampDifferenceExceeds(rstat->last_analyze_time, now, online_analyze_min_interval) &&
+               TimestampDifferenceExceeds(rstat->last_autoanalyze_time, now, online_analyze_min_interval) &&
                /* do not analyze too small tables */
-               rstat->n_tuples + rstat->changes_since_analyze + naffected > online_analyze_lower_limit &&
+               rstat->n_tuples + rstat->mod_since_analyze + naffected > online_analyze_lower_limit &&
                /* be in sync with relation_needs_vacanalyze */
-               ((double)(rstat->changes_since_analyze + naffected)) >=
+               ((double)(rstat->mod_since_analyze + naffected)) >=
                         online_analyze_scale_factor * ((double)rstat->n_tuples) +
                         (double)online_analyze_threshold))
        {
@@ -510,7 +588,13 @@ makeAnalyze(Oid relOid, CmdKind operation, int64 naffected)
                VacuumParams                    vacstmt;
 #endif
                TimestampTz                             startStamp, endStamp;
+               int                                             flags;
 
+#ifdef PGPRO_EE
+               /* ATX is not compatible with online_analyze */
+               if (getNestLevelATX() != 0)
+                       return;
+#endif
 
                memset(&startStamp, 0, sizeof(startStamp)); /* keep compiler quiet */
 
@@ -538,9 +622,16 @@ makeAnalyze(Oid relOid, CmdKind operation, int64 naffected)
                vacstmt.log_min_duration = -1;
 #endif
 
+
                if (online_analyze_verbose)
                        startStamp = GetCurrentTimestamp();
 
+               flags = VACOPT_ANALYZE | VACOPT_NOWAIT |
+                                       ((online_analyze_verbose) ?  VACOPT_VERBOSE : 0);
+
+#if PG_VERSION_NUM >= 120000
+               vacstmt.options = flags;
+#endif
                analyze_rel(relOid,
 #if PG_VERSION_NUM < 90500
                        &vacstmt
@@ -553,7 +644,9 @@ makeAnalyze(Oid relOid, CmdKind operation, int64 naffected)
 #endif
 #else
                        makeRangeVarFromOid(relOid),
-                       VACOPT_ANALYZE | ((online_analyze_verbose) ? VACOPT_VERBOSE : 0),
+#if PG_VERSION_NUM < 120000
+                       flags,
+#endif
                        &vacstmt, NULL, true, GetAccessStrategy(BAS_VACUUM)
 #endif
                );
@@ -573,8 +666,8 @@ makeAnalyze(Oid relOid, CmdKind operation, int64 naffected)
                                ((double)secs) + ((double)microsecs)/1.0e6);
                }
 
-               rstat->autovac_analyze_timestamp = now;
-               rstat->changes_since_analyze = 0;
+               rstat->last_autoanalyze_time = now;
+               rstat->mod_since_analyze = 0;
 
                switch(operation)
                {
@@ -582,6 +675,7 @@ makeAnalyze(Oid relOid, CmdKind operation, int64 naffected)
                        case CK_INSERT:
                        case CK_UPDATE:
                                rstat->n_tuples += naffected;
+                               /* FALLTHROUGH */
                        case CK_DELETE:
                                rstat->rereadStat = (reltype == OATT_PERSISTENT);
                                break;
@@ -597,8 +691,13 @@ makeAnalyze(Oid relOid, CmdKind operation, int64 naffected)
                /* update last analyze timestamp in local memory of backend */
                if (tabentry)
                {
+#if PG_VERSION_NUM >= 160000
+                       tabentry->last_analyze_time = now;
+                       tabentry->mod_since_analyze = 0;
+#else
                        tabentry->analyze_timestamp = now;
                        tabentry->changes_since_analyze = 0;
+#endif
                }
 #if 0
                /* force reload stat for new table */
@@ -610,24 +709,29 @@ makeAnalyze(Oid relOid, CmdKind operation, int64 naffected)
        {
 #if PG_VERSION_NUM >= 90000
                if (tabentry)
+#if PG_VERSION_NUM >= 160000
+                       tabentry->mod_since_analyze += naffected;
+#else
                        tabentry->changes_since_analyze += naffected;
+#endif
 #endif
                switch(operation)
                {
                        case CK_CREATE:
                        case CK_INSERT:
-                               rstat->changes_since_analyze += naffected;
+                               rstat->mod_since_analyze += naffected;
                                rstat->n_tuples += naffected;
                                break;
                        case CK_UPDATE:
-                               rstat->changes_since_analyze += 2 * naffected;
+                               rstat->mod_since_analyze += 2 * naffected;
                                rstat->n_tuples += naffected;
+                               break;
                        case CK_DELETE:
-                               rstat->changes_since_analyze += naffected;
+                               rstat->mod_since_analyze += naffected;
                                break;
                        case CK_TRUNCATE:
                        case CK_FASTTRUNCATE:
-                               rstat->changes_since_analyze = 0;
+                               rstat->mod_since_analyze = 0;
                                rstat->n_tuples = 0;
                                break;
                        default:
@@ -696,14 +800,21 @@ onlineAnalyzeHooker(QueryDesc *queryDesc)
        if (queryDesc->estate)
                naffected = queryDesc->estate->es_processed;
 
+       lateInit();
+
 #if PG_VERSION_NUM >= 90200
        if (online_analyze_enable &&
                (constval = isFastTruncateCall(queryDesc)) != NULL)
        {
                Datum           tblnamed = constval->constvalue;
                char            *tblname = text_to_cstring(DatumGetTextP(tblnamed));
+#if PG_VERSION_NUM >= 160000
+               RangeVar        *tblvar =
+                       makeRangeVarFromNameList(stringToQualifiedNameList(tblname, NULL));
+#else
                RangeVar        *tblvar =
                        makeRangeVarFromNameList(stringToQualifiedNameList(tblname));
+#endif
 
                makeAnalyze(RangeVarGetRelid(tblvar,
                                                                         NoLock,
@@ -783,6 +894,36 @@ removeTable(XactEvent event, void *arg)
        toremove = NIL;
 }
 
+#if PG_VERSION_NUM >= 120000
+static int
+parse_vacuum_opt(VacuumStmt *vacstmt)
+{
+       int                     options = vacstmt->is_vacuumcmd ? VACOPT_VACUUM : VACOPT_ANALYZE;
+       ListCell        *lc;
+
+       foreach(lc, vacstmt->options)
+       {
+               DefElem *opt = (DefElem *) lfirst(lc);
+
+               /* Parse common options for VACUUM and ANALYZE */
+               if (strcmp(opt->defname, "verbose") == 0)
+                       options |= VACOPT_VERBOSE;
+               else if (strcmp(opt->defname, "skip_locked") == 0)
+                       options |= VACOPT_SKIP_LOCKED;
+               else if (strcmp(opt->defname, "analyze") == 0)
+                       options |= VACOPT_ANALYZE;
+               else if (strcmp(opt->defname, "freeze") == 0)
+                       options |= VACOPT_FREEZE;
+               else if (strcmp(opt->defname, "full") == 0)
+                       options |= VACOPT_FULL;
+               else if (strcmp(opt->defname, "disable_page_skipping") == 0)
+                       options |= VACOPT_DISABLE_PAGE_SKIPPING;
+       }
+
+       return options;
+}
+#endif
+
 
 #if PG_VERSION_NUM >= 90200
 static void
@@ -793,6 +934,9 @@ onlineAnalyzeHookerUtility(
                                                   Node *parsetree,
 #endif
                                                   const char *queryString,
+#if PG_VERSION_NUM >= 140000
+                                                  bool readOnlyTree,
+#endif
 #if PG_VERSION_NUM >= 90300
                                                        ProcessUtilityContext context, ParamListInfo params,
 #if PG_VERSION_NUM >= 100000
@@ -801,7 +945,13 @@ onlineAnalyzeHookerUtility(
 #else
                                                        ParamListInfo params, bool isTopLevel,
 #endif
-                                                       DestReceiver *dest, char *completionTag) {
+                                                       DestReceiver *dest,
+#if  PG_VERSION_NUM >= 130000
+                                                       QueryCompletion *completionTag
+#else
+                                                       char *completionTag
+#endif
+) {
        List            *tblnames = NIL;
        CmdKind         op = CK_INSERT;
 #if PG_VERSION_NUM >= 100000
@@ -811,6 +961,8 @@ onlineAnalyzeHookerUtility(
                parsetree = pstmt->utilityStmt;
 #endif
 
+       lateInit();
+
        if (parsetree && online_analyze_enable)
        {
                if (IsA(parsetree, CreateTableAsStmt) &&
@@ -849,6 +1001,14 @@ onlineAnalyzeHookerUtility(
                else if (IsA(parsetree, VacuumStmt))
                {
                        VacuumStmt      *vac = (VacuumStmt*)parsetree;
+                       int                     options =
+#if PG_VERSION_NUM >= 120000
+                                                       parse_vacuum_opt(vac)
+#else
+                                                       vac->options
+#endif
+                                                       ;
+
 
 #if PG_VERSION_NUM >= 110000
                        tblnames = vac->rels;
@@ -857,7 +1017,7 @@ onlineAnalyzeHookerUtility(
                                tblnames = list_make1(vac->relation);
 #endif
 
-                       if (vac->options & (VACOPT_VACUUM | VACOPT_FULL | VACOPT_FREEZE))
+                       if (options & (VACOPT_VACUUM | VACOPT_FULL | VACOPT_FREEZE))
                        {
                                /* optionally with analyze */
                                op = CK_VACUUM;
@@ -866,7 +1026,7 @@ onlineAnalyzeHookerUtility(
                                if (tblnames == NIL)
                                        relstatsInit();
                        }
-                       else if (vac->options & VACOPT_ANALYZE)
+                       else if (options & VACOPT_ANALYZE)
                        {
                                op = CK_ANALYZE;
 
@@ -881,8 +1041,8 @@ onlineAnalyzeHookerUtility(
 
                                        while((rstat = hash_seq_search(&hs)) != NULL)
                                        {
-                                               rstat->changes_since_analyze = 0;
-                                               rstat->analyze_timestamp = now;
+                                               rstat->mod_since_analyze = 0;
+                                               rstat->last_analyze_time = now;
                                        }
                                }
                        }
@@ -897,6 +1057,9 @@ onlineAnalyzeHookerUtility(
 
        if (oldProcessUtilityHook)
                oldProcessUtilityHook(parsetree, queryString,
+#if PG_VERSION_NUM >= 140000
+                                                         readOnlyTree,
+#endif
 #if PG_VERSION_NUM >= 90300
                                                          context, params,
 #if PG_VERSION_NUM >= 100000
@@ -908,6 +1071,9 @@ onlineAnalyzeHookerUtility(
                                                          dest, completionTag);
        else
                standard_ProcessUtility(parsetree, queryString,
+#if PG_VERSION_NUM >= 140000
+                                                               readOnlyTree,
+#endif
 #if PG_VERSION_NUM >= 90300
                                                                context, params,
 #if PG_VERSION_NUM >= 100000
@@ -944,6 +1110,7 @@ onlineAnalyzeHookerUtility(
 }
 #endif
 
+
 static void
 relstatsInit(void)
 {
@@ -963,17 +1130,20 @@ relstatsInit(void)
        else
        {
                Assert(relstats == NULL);
+
+#if PG_VERSION_NUM < 90600
                onlineAnalyzeMemoryContext =
                        AllocSetContextCreate(CacheMemoryContext,
-                                                                 "online_analyze storage context",
-#if PG_VERSION_NUM < 90600
-                                                                 ALLOCSET_DEFAULT_MINSIZE,
-                                                                 ALLOCSET_DEFAULT_INITSIZE,
-                                                                 ALLOCSET_DEFAULT_MAXSIZE
+                       "online_analyze storage context",
+                       ALLOCSET_DEFAULT_MINSIZE,
+                       ALLOCSET_DEFAULT_INITSIZE,
+                       ALLOCSET_DEFAULT_MAXSIZE
+                       );
 #else
-                                                                 ALLOCSET_DEFAULT_SIZES
+               onlineAnalyzeMemoryContext =
+                       AllocSetContextCreate(CacheMemoryContext,
+                       "online_analyze storage context", ALLOCSET_DEFAULT_SIZES);
 #endif
-                                                                );
        }
 
        hash_ctl.hcxt = onlineAnalyzeMemoryContext;
@@ -1226,21 +1396,3 @@ _PG_init(void)
 
        RegisterXactCallback(removeTable, NULL);
 }
-
-void _PG_fini(void);
-void
-_PG_fini(void)
-{
-       ExecutorEnd_hook = oldExecutorEndHook;
-#if PG_VERSION_NUM >= 90200
-       ProcessUtility_hook = oldProcessUtilityHook;
-#endif
-
-       if (excludeTables.tables)
-               free(excludeTables.tables);
-       if (includeTables.tables)
-               free(includeTables.tables);
-
-       excludeTables.tables = includeTables.tables = NULL;
-       excludeTables.nTables = includeTables.nTables = 0;
-}