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);
/*
* 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
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
*/
%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
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
;
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;
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;
}
;
| /*EMPTY*/ { $$ = FALSE; }
;
+opt_oscache:
+ OSCACHE { $$ = TRUE; }
+ | /*EMPTY*/ { $$ = FALSE; }
+ ;
+
opt_name_list:
'(' name_list ')' { $$ = $2; }
| /*EMPTY*/ { $$ = NIL; }
| LIKE
| NATURAL
| NOTNULL
+ | OSCACHE
| OUTER_P
| OVER
| OVERLAPS