Add "ANALYZE OSCACHE [VERBOSE] [relation];"
authorCédric Villemain <[email protected]>
Thu, 28 Apr 2011 03:16:01 +0000 (05:16 +0200)
committerCédric Villemain <[email protected]>
Sun, 1 May 2011 14:29:06 +0000 (16:29 +0200)
it updates the relative columns in pg_class
with currently dummy functions

src/backend/commands/analyze.c
src/backend/parser/gram.y
src/backend/storage/buffer/bufmgr.c
src/include/nodes/parsenodes.h
src/include/parser/kwlist.h
src/include/storage/bufmgr.h

index 0568a1bcf86281a9b1086d343e7027557295065c..284ab5db06181db8974b61c79e6038d0fe51eaa1 100644 (file)
@@ -86,6 +86,8 @@ static BufferAccessStrategy vac_strategy;
 
 static void do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
                           bool update_reltuples, bool inh);
+static void do_cache_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
+                          bool update_reltuples, bool inh);
 static void BlockSampler_Init(BlockSampler bs, BlockNumber nblocks,
                                  int samplesize);
 static bool BlockSampler_HasMore(BlockSampler bs);
@@ -238,13 +240,21 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt,
        /*
         * Do the normal non-recursive ANALYZE.
         */
-       do_analyze_rel(onerel, vacstmt, update_reltuples, false);
+       if (vacstmt->options & (VACOPT_CACHE))
+               do_cache_analyze_rel(onerel, vacstmt, update_reltuples, false);
+       else
+               do_analyze_rel(onerel, vacstmt, update_reltuples, false);
 
        /*
         * If there are child tables, do recursive ANALYZE.
         */
        if (onerel->rd_rel->relhassubclass)
-               do_analyze_rel(onerel, vacstmt, false, true);
+       {
+               if (vacstmt->options & (VACOPT_CACHE))
+                       do_cache_analyze_rel(onerel, vacstmt, false, true);
+               else
+                       do_analyze_rel(onerel, vacstmt, false, true);
+       }
 
        /*
         * Close source relation now, but keep lock so that no one deletes it
@@ -639,6 +649,120 @@ cleanup:
        anl_context = NULL;
 }
 
+/*
+ *     do_analyze_rel() -- analyze one relation, recursively or not
+ */
+static void
+do_cache_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
+                                        bool update_relcache, bool inh)
+{
+       int                     ind;
+       Relation   *Irel;
+       int                     nindexes;
+       bool            hasindex;
+       AnlIndexData *indexdata;
+       PGRUsage        ru0;
+       TimestampTz starttime = 0;
+       MemoryContext caller_context;
+       int                     save_nestlevel;
+
+       if (inh)
+               ereport(elevel,
+                               (errmsg("cache analyzing \"%s.%s\" inheritance tree",
+                                               get_namespace_name(RelationGetNamespace(onerel)),
+                                               RelationGetRelationName(onerel))));
+       else
+               ereport(elevel,
+                               (errmsg("cache analyzing \"%s.%s\"",
+                                               get_namespace_name(RelationGetNamespace(onerel)),
+                                               RelationGetRelationName(onerel))));
+
+       /*
+        * Set up a working context so that we can easily free whatever junk gets
+        * created.
+        */
+       anl_context = AllocSetContextCreate(CurrentMemoryContext,
+                                                                               "Analyze",
+                                                                               ALLOCSET_DEFAULT_MINSIZE,
+                                                                               ALLOCSET_DEFAULT_INITSIZE,
+                                                                               ALLOCSET_DEFAULT_MAXSIZE);
+       caller_context = MemoryContextSwitchTo(anl_context);
+
+       /*
+        * Arrange to make GUC variable changes local to this command.
+        */
+       save_nestlevel = NewGUCNestLevel();
+
+       /* measure elapsed time iff autovacuum logging requires it */
+       if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0)
+       {
+               pg_rusage_init(&ru0);
+               if (Log_autovacuum_min_duration > 0)
+                       starttime = GetCurrentTimestamp();
+       }
+
+       /*
+        * Open all indexes of the relation, and see if there are any analyzable
+        * columns in the indexes.      We do not analyze index columns if there was
+        * an explicit column list in the ANALYZE command, however.  If we are
+        * doing a recursive scan, we don't want to touch the parent's indexes at
+        * all.
+        */
+       if (!inh)
+               vac_open_indexes(onerel, AccessShareLock, &nindexes, &Irel);
+       else
+       {
+               Irel = NULL;
+               nindexes = 0;
+       }
+       hasindex = (nindexes > 0);
+       indexdata = NULL;
+
+       /*
+        * Update cache stats in pg_class.
+        */
+       cache_update_relstats(onerel,
+                                                 RelationGetRelationOSCacheInFork(onerel, MAIN_FORKNUM),
+                                                 RelationGetRelationPGCacheInFork(onerel, MAIN_FORKNUM),
+                                                 InvalidTransactionId);
+
+       /*
+        * Same for indexes.
+        */
+       for (ind = 0; ind < nindexes; ind++)
+       {
+               cache_update_relstats(Irel[ind],
+                                                         RelationGetRelationOSCacheInFork(Irel[ind], MAIN_FORKNUM),
+                                                         RelationGetRelationPGCacheInFork(Irel[ind], MAIN_FORKNUM),
+                                                         InvalidTransactionId);
+       }
+
+       /* Done with indexes */
+       vac_close_indexes(nindexes, Irel, NoLock);
+
+       /* Log the action if appropriate */
+       if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0)
+       {
+               if (Log_autovacuum_min_duration == 0 ||
+                       TimestampDifferenceExceeds(starttime, GetCurrentTimestamp(),
+                                                                          Log_autovacuum_min_duration))
+                       ereport(LOG,
+                                       (errmsg("automatic cache analyze of table \"%s.%s.%s\" system usage: %s",
+                                                       get_database_name(MyDatabaseId),
+                                                       get_namespace_name(RelationGetNamespace(onerel)),
+                                                       RelationGetRelationName(onerel),
+                                                       pg_rusage_show(&ru0))));
+       }
+
+       /* Roll back any GUC changes executed by index functions */
+       AtEOXact_GUC(false, save_nestlevel);
+
+       /* Restore current context and release memory */
+       MemoryContextSwitchTo(caller_context);
+       MemoryContextDelete(anl_context);
+       anl_context = NULL;
+}
+
 /*
  * Compute statistics about indexes of a relation
  */
index 933a1a2ff9f3739529154e6e07aca4f1a06b95ab..34ecd292cb6d6a4607e4e0d7973fc87c9f24d444 100644 (file)
@@ -342,7 +342,7 @@ static void SplitColQualList(List *qualList,
 
 %type <boolean> opt_instead
 %type <boolean> opt_unique opt_concurrently opt_verbose opt_full
-%type <boolean> opt_freeze opt_default opt_recheck
+%type <boolean> opt_freeze opt_oscache opt_default opt_recheck
 %type <defelt> opt_binary opt_oids copy_delimiter
 
 %type <boolean> copy_from
@@ -529,7 +529,7 @@ static void SplitColQualList(List *qualList,
        NULLS_P NUMERIC
 
        OBJECT_P OF OFF OFFSET OIDS ON ONLY OPERATOR OPTION OPTIONS OR
-       ORDER OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER
+       ORDER OSCACHE OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER
 
        PARSER PARTIAL PARTITION PASSING PASSWORD PLACING PLANS POSITION
        PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
@@ -7802,11 +7802,13 @@ vacuum_option_elem:
                ;
 
 AnalyzeStmt:
-                       analyze_keyword opt_verbose
+                       analyze_keyword opt_oscache opt_verbose
                                {
                                        VacuumStmt *n = makeNode(VacuumStmt);
                                        n->options = VACOPT_ANALYZE;
                                        if ($2)
+                                               n->options |= VACOPT_CACHE;
+                                       if ($3)
                                                n->options |= VACOPT_VERBOSE;
                                        n->freeze_min_age = -1;
                                        n->freeze_table_age = -1;
@@ -7814,16 +7816,18 @@ AnalyzeStmt:
                                        n->va_cols = NIL;
                                        $$ = (Node *)n;
                                }
-                       | analyze_keyword opt_verbose qualified_name opt_name_list
+                       | analyze_keyword opt_oscache opt_verbose qualified_name opt_name_list
                                {
                                        VacuumStmt *n = makeNode(VacuumStmt);
                                        n->options = VACOPT_ANALYZE;
                                        if ($2)
+                                               n->options |= VACOPT_CACHE;
+                                       if ($3)
                                                n->options |= VACOPT_VERBOSE;
                                        n->freeze_min_age = -1;
                                        n->freeze_table_age = -1;
-                                       n->relation = $3;
-                                       n->va_cols = $4;
+                                       n->relation = $4;
+                                       n->va_cols = $5;
                                        $$ = (Node *)n;
                                }
                ;
@@ -7846,6 +7850,11 @@ opt_freeze: FREEZE                                                                       { $$ = TRUE; }
                        | /*EMPTY*/                                                             { $$ = FALSE; }
                ;
 
+opt_oscache:
+                       OSCACHE                                                                 { $$ = TRUE; }
+                       | /*EMPTY*/                             { $$ = FALSE; }
+               ;
+
 opt_name_list:
                        '(' name_list ')'                                               { $$ = $2; }
                        | /*EMPTY*/                                                             { $$ = NIL; }
@@ -12159,6 +12168,7 @@ type_func_name_keyword:
                        | LIKE
                        | NATURAL
                        | NOTNULL
+                       | OSCACHE
                        | OUTER_P
                        | OVER
                        | OVERLAPS
index f96685db50b70144ffc6193f941ba4d7b60e6f21..301b368d37fc8d5c532d2b4d394d958c4b3cbfef 100644 (file)
@@ -1922,6 +1922,32 @@ RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum)
        return smgrnblocks(relation->rd_smgr, forkNum);
 }
 
+/*
+ * RelationGetRelationOSCacheInFork
+ *             Determines the current percentage of pages in OS cache for the
+ *             relation.
+ */
+float4
+RelationGetRelationOSCacheInFork(Relation relation, ForkNumber forkNum)
+{
+       float4 percent = 0;
+
+       return percent;
+}
+
+/*
+ * RelationGetRelationPGCacheInFork
+ *             Determines the current percentage of pages in PostgreSQL cache
+ *             for the relation.
+ */
+float4
+RelationGetRelationPGCacheInFork(Relation relation, ForkNumber forkNum)
+{
+       float4 percent = 0;
+
+       return percent;
+}
+
 /* ---------------------------------------------------------------------
  *             DropRelFileNodeBuffers
  *
index ee1881b630fbe5f60dd1dbd0ee16d42af71ec7b5..bc7a3010da6129cb2579c3e6978e0a5997296f0b 100644 (file)
@@ -2417,7 +2417,8 @@ typedef enum VacuumOption
        VACOPT_VERBOSE = 1 << 2,        /* print progress info */
        VACOPT_FREEZE = 1 << 3,         /* FREEZE option */
        VACOPT_FULL = 1 << 4,           /* FULL (non-concurrent) vacuum */
-       VACOPT_NOWAIT = 1 << 5
+       VACOPT_NOWAIT = 1 << 5,
+       VACOPT_CACHE = 1 << 6           /* do CACHE stats analyze */
 } VacuumOption;
 
 typedef struct VacuumStmt
index 12c2faf3de8fbfb3169c99a360cc15465e425d79..95a7e3d32009ce50deaf70099ee7831790ac1e6c 100644 (file)
@@ -264,6 +264,7 @@ PG_KEYWORD("option", OPTION, UNRESERVED_KEYWORD)
 PG_KEYWORD("options", OPTIONS, UNRESERVED_KEYWORD)
 PG_KEYWORD("or", OR, RESERVED_KEYWORD)
 PG_KEYWORD("order", ORDER, RESERVED_KEYWORD)
+PG_KEYWORD("oscache", OSCACHE, TYPE_FUNC_NAME_KEYWORD)
 PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD)
 PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD)
 PG_KEYWORD("over", OVER, TYPE_FUNC_NAME_KEYWORD)
index b8fc87ec57f9a8da601a7ef88f04d86f01adb79d..5bcc911b2248f4bda0eaeb1515f0d98fd192b4c2 100644 (file)
@@ -179,6 +179,10 @@ extern void CheckPointBuffers(int flags);
 extern BlockNumber BufferGetBlockNumber(Buffer buffer);
 extern BlockNumber RelationGetNumberOfBlocksInFork(Relation relation,
                                                                ForkNumber forkNum);
+extern float4 RelationGetRelationOSCacheInFork(Relation relation,
+                                                               ForkNumber forkNum);
+extern float4 RelationGetRelationPGCacheInFork(Relation relation,
+                                                               ForkNumber forkNum);
 extern void FlushRelationBuffers(Relation rel);
 extern void FlushDatabaseBuffers(Oid dbid);
 extern void DropRelFileNodeBuffers(RelFileNodeBackend rnode,