#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
+#include "utils/pg_rusage.h"
#include "utils/relcache.h"
#include "utils/relmapper.h"
#include "utils/snapmgr.h"
static void rebuild_relation(Relation OldHeap, Oid indexOid,
- int freeze_min_age, int freeze_table_age);
+ int freeze_min_age, int freeze_table_age, bool verbose);
static void copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex,
- int freeze_min_age, int freeze_table_age,
+ int freeze_min_age, int freeze_table_age, bool verbose,
bool *pSwapToastByContent, TransactionId *pFreezeXid);
static List *get_tables_to_cluster(MemoryContext cluster_context);
static void reform_and_rewrite_tuple(HeapTuple tuple,
if (OidIsValid(indexOid))
check_index_is_clusterable(OldHeap, indexOid, recheck, AccessExclusiveLock);
- /* Log what we're doing (this could use more effort) */
- if (OidIsValid(indexOid))
- ereport(verbose ? INFO : DEBUG2,
- (errmsg("clustering \"%s.%s\"",
- get_namespace_name(RelationGetNamespace(OldHeap)),
- RelationGetRelationName(OldHeap))));
- else
- ereport(verbose ? INFO : DEBUG2,
- (errmsg("vacuuming \"%s.%s\"",
- get_namespace_name(RelationGetNamespace(OldHeap)),
- RelationGetRelationName(OldHeap))));
-
/* rebuild_relation does all the dirty work */
- rebuild_relation(OldHeap, indexOid, freeze_min_age, freeze_table_age);
+ rebuild_relation(OldHeap, indexOid, freeze_min_age, freeze_table_age,
+ verbose);
/* NB: rebuild_relation does heap_close() on OldHeap */
}
*/
static void
rebuild_relation(Relation OldHeap, Oid indexOid,
- int freeze_min_age, int freeze_table_age)
+ int freeze_min_age, int freeze_table_age, bool verbose)
{
Oid tableOid = RelationGetRelid(OldHeap);
Oid tableSpace = OldHeap->rd_rel->reltablespace;
/* Copy the heap data into the new table in the desired order */
copy_heap_data(OIDNewHeap, tableOid, indexOid,
- freeze_min_age, freeze_table_age,
+ freeze_min_age, freeze_table_age, verbose,
&swap_toast_by_content, &frozenXid);
/*
*/
static void
copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex,
- int freeze_min_age, int freeze_table_age,
+ int freeze_min_age, int freeze_table_age, bool verbose,
bool *pSwapToastByContent, TransactionId *pFreezeXid)
{
Relation NewHeap,
RewriteState rwstate;
bool use_sort;
Tuplesortstate *tuplesort;
+ double num_tuples = 0,
+ tups_vacuumed = 0,
+ tups_recently_dead = 0;
+ int elevel = verbose ? INFO : DEBUG2;
+ PGRUsage ru0;
+
+ pg_rusage_init(&ru0);
/*
* Open the relations we need.
indexScan = NULL;
}
+ /* Log what we're doing */
+ if (indexScan != NULL)
+ ereport(elevel,
+ (errmsg("clustering \"%s.%s\" using index scan on \"%s\"",
+ get_namespace_name(RelationGetNamespace(OldHeap)),
+ RelationGetRelationName(OldHeap),
+ RelationGetRelationName(OldIndex))));
+ else if (tuplesort != NULL)
+ ereport(elevel,
+ (errmsg("clustering \"%s.%s\" using sequential scan and sort",
+ get_namespace_name(RelationGetNamespace(OldHeap)),
+ RelationGetRelationName(OldHeap))));
+ else
+ ereport(elevel,
+ (errmsg("vacuuming \"%s.%s\"",
+ get_namespace_name(RelationGetNamespace(OldHeap)),
+ RelationGetRelationName(OldHeap))));
+
/*
* Scan through the OldHeap, either in OldIndex order or sequentially;
* copy each tuple into the NewHeap, or transiently to the tuplesort
/* Definitely dead */
isdead = true;
break;
- case HEAPTUPLE_LIVE:
case HEAPTUPLE_RECENTLY_DEAD:
+ tups_recently_dead += 1;
+ /* fall through */
+ case HEAPTUPLE_LIVE:
/* Live or recently dead, must copy it */
isdead = false;
break;
elog(WARNING, "concurrent delete in progress within table \"%s\"",
RelationGetRelationName(OldHeap));
/* treat as recently dead */
+ tups_recently_dead += 1;
isdead = false;
break;
default:
if (isdead)
{
+ tups_vacuumed += 1;
/* heap rewrite module still needs to see it... */
- rewrite_heap_dead_tuple(rwstate, tuple);
+ if (rewrite_heap_dead_tuple(rwstate, tuple))
+ {
+ /* A previous recently-dead tuple is now known dead */
+ tups_vacuumed += 1;
+ tups_recently_dead -= 1;
+ }
continue;
}
+ num_tuples += 1;
if (tuplesort != NULL)
tuplesort_putheaptuple(tuplesort, tuple);
else
/* Reset rd_toastoid just to be tidy --- it shouldn't be looked at again */
NewHeap->rd_toastoid = InvalidOid;
+ /* Log what we did */
+ ereport(elevel,
+ (errmsg("\"%s\": found %.0f removable, %.0f nonremovable row versions in %u pages",
+ RelationGetRelationName(OldHeap),
+ tups_vacuumed, num_tuples,
+ RelationGetNumberOfBlocks(OldHeap)),
+ errdetail("%.0f dead row versions cannot be removed yet.\n"
+ "%s.",
+ tups_recently_dead,
+ pg_rusage_show(&ru0))));
+
/* Clean up */
pfree(values);
pfree(isnull);