diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index b1df7d19863..7b57796aa55 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -956,7 +956,7 @@ heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap, cleanup_and_next: for (int i = bms_next_member(detoasted, -1); i >= 0; - i = bms_prev_member(detoasted, i)) + i = bms_next_member(detoasted, i)) { pfree(DatumGetPointer(values[i])); } @@ -1072,7 +1072,13 @@ normal_put: /* Write out any remaining tuples, and fsync if needed */ if (rwstate) - end_heap_rewrite(rwstate); + { + double tuples_dropped = end_heap_rewrite(rwstate); + + *tups_vacuumed += tuples_dropped; + *num_tuples -= tuples_dropped; + *tups_recently_dead -= tuples_dropped; + } if (bistate) FreeBulkInsertState(bistate); diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c index 0d57b3f5709..122820fd0d5 100644 --- a/src/backend/access/heap/rewriteheap.c +++ b/src/backend/access/heap/rewriteheap.c @@ -150,6 +150,7 @@ typedef struct RewriteStateData XLogRecPtr rs_begin_lsn; /* XLogInsertLsn when starting the rewrite */ HTAB *rs_unresolved_tups; /* unmatched A tuples */ HTAB *rs_old_new_tid_map; /* unmatched B tuples */ + double rs_tuples_dropped; /* stashed tuples dropped, TOAST gone */ HTAB *rs_logical_mappings; /* logical remapping files */ uint32 rs_num_rewrite_mappings; /* # in memory mappings */ } RewriteStateData; @@ -297,11 +298,12 @@ begin_heap_rewrite(Relation old_heap, Relation new_heap, TransactionId oldest_xm * * state and any other resources are freed. */ -void +double end_heap_rewrite(RewriteState state) { HASH_SEQ_STATUS seq_status; UnresolvedTup unresolved; + double tuples_dropped; /* * Write any remaining tuples in the UnresolvedTups table. If we have any @@ -312,7 +314,8 @@ end_heap_rewrite(RewriteState state) while ((unresolved = hash_seq_search(&seq_status)) != NULL) { ItemPointerSetInvalid(&unresolved->tuple->t_data->t_ctid); - raw_heap_insert(state, unresolved->tuple, unresolved->recently_dead); + if (!raw_heap_insert(state, unresolved->tuple, unresolved->recently_dead)) + state->rs_tuples_dropped += 1; } /* Write the last page, if any */ @@ -326,8 +329,12 @@ end_heap_rewrite(RewriteState state) logical_end_heap_rewrite(state); + tuples_dropped = state->rs_tuples_dropped; + /* Deleting the context frees everything */ MemoryContextDelete(state->rs_cxt); + + return tuples_dropped; } /* @@ -462,10 +469,16 @@ rewrite_heap_tuple(RewriteState state, /* Insert the tuple and find out where it's put in new_heap */ if (!raw_heap_insert(state, new_tuple, recently_dead)) { - if (free_new) - heap_freetuple(new_tuple); + if (!free_new) + { + MemoryContextSwitchTo(old_cxt); + return false; + } + /* stashed prior version; the caller's tuple is already written */ + state->rs_tuples_dropped += 1; + heap_freetuple(new_tuple); MemoryContextSwitchTo(old_cxt); - return false; + return true; } new_tid = new_tuple->t_self; diff --git a/src/include/access/rewriteheap.h b/src/include/access/rewriteheap.h index 67467c2ddbe..ec9d64112ad 100644 --- a/src/include/access/rewriteheap.h +++ b/src/include/access/rewriteheap.h @@ -24,7 +24,7 @@ typedef struct RewriteStateData *RewriteState; extern RewriteState begin_heap_rewrite(Relation old_heap, Relation new_heap, TransactionId oldest_xmin, TransactionId freeze_xid, MultiXactId cutoff_multi); -extern void end_heap_rewrite(RewriteState state); +extern double end_heap_rewrite(RewriteState state); /* See toast_helper.h for the values of "flags" */ extern bool rewrite_heap_tuple(RewriteState state, HeapTuple old_tuple,