diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c index 99235da..e110a66 100644 *** a/src/backend/access/heap/rewriteheap.c --- b/src/backend/access/heap/rewriteheap.c *************** rewrite_heap_tuple(RewriteState state, *** 501,509 **** /* * Register a dead tuple with an ongoing rewrite. Dead tuples are not * copied to the new table, but we still make note of them so that we ! * can release some resources earlier. */ ! void rewrite_heap_dead_tuple(RewriteState state, HeapTuple old_tuple) { /* --- 501,509 ---- /* * Register a dead tuple with an ongoing rewrite. Dead tuples are not * copied to the new table, but we still make note of them so that we ! * can release some resources earlier. Returns true if actually registered. */ ! bool rewrite_heap_dead_tuple(RewriteState state, HeapTuple old_tuple) { /* *************** rewrite_heap_dead_tuple(RewriteState sta *** 539,545 **** --- 539,549 ---- hash_search(state->rs_unresolved_tups, &hashkey, HASH_REMOVE, &found); Assert(found); + + return true; } + + return false; } /* diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index 383d7cf..2041a85 100644 *** a/src/backend/commands/cluster.c --- b/src/backend/commands/cluster.c *************** *** 45,50 **** --- 45,51 ---- #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" *************** typedef struct *** 66,75 **** static void rebuild_relation(Relation OldHeap, Oid indexOid, ! int freeze_min_age, int freeze_table_age); static void copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, int freeze_min_age, int freeze_table_age, ! bool *pSwapToastByContent, TransactionId *pFreezeXid); static List *get_tables_to_cluster(MemoryContext cluster_context); static void deform_and_rewrite_tuple(HeapTuple tuple, TupleDesc oldTupDesc, TupleDesc newTupDesc, Datum *values, bool *isnull, --- 67,77 ---- static void rebuild_relation(Relation OldHeap, Oid indexOid, ! 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, ! bool *pSwapToastByContent, TransactionId *pFreezeXid, ! bool verbose); static List *get_tables_to_cluster(MemoryContext cluster_context); static void deform_and_rewrite_tuple(HeapTuple tuple, TupleDesc oldTupDesc, TupleDesc newTupDesc, Datum *values, bool *isnull, *************** cluster_rel(Oid tableOid, Oid indexOid, *** 383,402 **** 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); /* NB: rebuild_relation does heap_close() on OldHeap */ } --- 385,392 ---- if (OidIsValid(indexOid)) check_index_is_clusterable(OldHeap, indexOid, recheck, AccessExclusiveLock); /* rebuild_relation does all the dirty work */ ! rebuild_relation(OldHeap, indexOid, freeze_min_age, freeze_table_age, verbose); /* NB: rebuild_relation does heap_close() on OldHeap */ } *************** mark_index_clustered(Relation rel, Oid i *** 580,586 **** */ static void rebuild_relation(Relation OldHeap, Oid indexOid, ! int freeze_min_age, int freeze_table_age) { Oid tableOid = RelationGetRelid(OldHeap); Oid tableSpace = OldHeap->rd_rel->reltablespace; --- 570,576 ---- */ static void rebuild_relation(Relation OldHeap, Oid indexOid, ! int freeze_min_age, int freeze_table_age, bool verbose) { Oid tableOid = RelationGetRelid(OldHeap); Oid tableSpace = OldHeap->rd_rel->reltablespace; *************** rebuild_relation(Relation OldHeap, Oid i *** 605,611 **** /* Copy the heap data into the new table in the desired order */ copy_heap_data(OIDNewHeap, tableOid, indexOid, freeze_min_age, freeze_table_age, ! &swap_toast_by_content, &frozenXid); /* * Swap the physical files of the target and transient tables, then --- 595,601 ---- /* Copy the heap data into the new table in the desired order */ copy_heap_data(OIDNewHeap, tableOid, indexOid, freeze_min_age, freeze_table_age, ! &swap_toast_by_content, &frozenXid, verbose); /* * Swap the physical files of the target and transient tables, then *************** make_new_heap(Oid OIDOldHeap, Oid NewTab *** 747,753 **** static void copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, int freeze_min_age, int freeze_table_age, ! bool *pSwapToastByContent, TransactionId *pFreezeXid) { Relation NewHeap, OldHeap, --- 737,744 ---- static void copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, int freeze_min_age, int freeze_table_age, ! bool *pSwapToastByContent, TransactionId *pFreezeXid, ! bool verbose) { Relation NewHeap, OldHeap, *************** copy_heap_data(Oid OIDNewHeap, Oid OIDOl *** 766,771 **** --- 757,769 ---- RewriteState rwstate; bool use_sort; Tuplesortstate *tuplesort; + PGRUsage ru0; + double num_tuples = 0, + tups_vacuumed = 0, + nkeep = 0; + int elevel = verbose ? INFO : DEBUG2; + + pg_rusage_init(&ru0); /* * Open the relations we need. *************** copy_heap_data(Oid OIDNewHeap, Oid OIDOl *** 891,896 **** --- 889,912 ---- tuplesort = NULL; } + /* Log what we're doing */ + if (indexScan != NULL) + ereport(elevel, + (errmsg("clustering \"%s.%s\" by index scan on \"%s\"", + get_namespace_name(RelationGetNamespace(OldHeap)), + RelationGetRelationName(OldHeap), + RelationGetRelationName(OldIndex)))); + else if (tuplesort != NULL) + ereport(elevel, + (errmsg("clustering \"%s.%s\" by 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)))); + for (;;) { HeapTuple tuple; *************** copy_heap_data(Oid OIDNewHeap, Oid OIDOl *** 928,935 **** /* Definitely dead */ isdead = true; break; - case HEAPTUPLE_LIVE: case HEAPTUPLE_RECENTLY_DEAD: /* Live or recently dead, must copy it */ isdead = false; break; --- 944,953 ---- /* Definitely dead */ isdead = true; break; case HEAPTUPLE_RECENTLY_DEAD: + nkeep += 1; + /* fall through */ + case HEAPTUPLE_LIVE: /* Live or recently dead, must copy it */ isdead = false; break; *************** copy_heap_data(Oid OIDNewHeap, Oid OIDOl *** 973,983 **** if (isdead) { /* heap rewrite module still needs to see it... */ ! rewrite_heap_dead_tuple(rwstate, tuple); continue; } if (tuplesort != NULL) tuplesort_putrawtuple(tuplesort, tuple); else --- 991,1004 ---- if (isdead) { + tups_vacuumed += 1; /* heap rewrite module still needs to see it... */ ! if (rewrite_heap_dead_tuple(rwstate, tuple)) ! nkeep += 1; continue; } + num_tuples += 1; if (tuplesort != NULL) tuplesort_putrawtuple(tuplesort, tuple); else *************** copy_heap_data(Oid OIDNewHeap, Oid OIDOl *** 1030,1035 **** --- 1051,1065 ---- pfree(values); pfree(isnull); + 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.", + nkeep, + pg_rusage_show(&ru0)))); + if (OldIndex != NULL) index_close(OldIndex, NoLock); heap_close(OldHeap, NoLock); diff --git a/src/include/access/rewriteheap.h b/src/include/access/rewriteheap.h index 8ede6be..53a9ded 100644 *** a/src/include/access/rewriteheap.h --- b/src/include/access/rewriteheap.h *************** extern RewriteState begin_heap_rewrite(R *** 25,30 **** extern void end_heap_rewrite(RewriteState state); extern void rewrite_heap_tuple(RewriteState state, HeapTuple oldTuple, HeapTuple newTuple); ! extern void rewrite_heap_dead_tuple(RewriteState state, HeapTuple oldTuple); #endif /* REWRITE_HEAP_H */ --- 25,30 ---- extern void end_heap_rewrite(RewriteState state); extern void rewrite_heap_tuple(RewriteState state, HeapTuple oldTuple, HeapTuple newTuple); ! extern bool rewrite_heap_dead_tuple(RewriteState state, HeapTuple oldTuple); #endif /* REWRITE_HEAP_H */