1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-22 12:22:45 +03:00

Have TRUNCATE update pgstat tuple counters

This works by keeping a per-subtransaction record of the ins/upd/del
counters before the truncate, and then resetting them; this record is
useful to return to the previous state in case the truncate is rolled
back, either in a subtransaction or whole transaction.  The state is
propagated upwards as subtransactions commit.

When the per-table data is sent to the stats collector, a flag indicates
to reset the live/dead counters to zero as well.

Catalog version bumped due to the change in pgstat format.

Author: Alexander Shulgin
Discussion: 1007.1207238291@sss.pgh.pa.us
Discussion: 548F7D38.2000401@BlueTreble.com
Reviewed-by: Álvaro Herrera, Jim Nasby
This commit is contained in:
Alvaro Herrera
2015-02-20 12:10:01 -03:00
parent 5740be6d6e
commit d42358efb1
8 changed files with 374 additions and 3 deletions

View File

@@ -197,8 +197,12 @@ typedef struct TwoPhasePgStatRecord
PgStat_Counter tuples_inserted; /* tuples inserted in xact */
PgStat_Counter tuples_updated; /* tuples updated in xact */
PgStat_Counter tuples_deleted; /* tuples deleted in xact */
PgStat_Counter inserted_pre_trunc; /* tuples inserted prior to truncate */
PgStat_Counter updated_pre_trunc; /* tuples updated prior to truncate */
PgStat_Counter deleted_pre_trunc; /* tuples deleted prior to truncate */
Oid t_id; /* table's OID */
bool t_shared; /* is it a shared catalog? */
bool t_truncated; /* was the relation truncated? */
} TwoPhasePgStatRecord;
/*
@@ -1858,6 +1862,64 @@ pgstat_count_heap_delete(Relation rel)
}
}
/*
* pgstat_truncate_save_counters
*
* Whenever a table is truncated, we save its i/u/d counters so that they can
* be cleared, and if the (sub)xact that executed the truncate later aborts,
* the counters can be restored to the saved (pre-truncate) values. Note we do
* this on the first truncate in any particular subxact level only.
*/
static void
pgstat_truncate_save_counters(PgStat_TableXactStatus *trans)
{
if (!trans->truncated)
{
trans->inserted_pre_trunc = trans->tuples_inserted;
trans->updated_pre_trunc = trans->tuples_updated;
trans->deleted_pre_trunc = trans->tuples_deleted;
trans->truncated = true;
}
}
/*
* pgstat_truncate_restore_counters - restore counters when a truncate aborts
*/
static void
pgstat_truncate_restore_counters(PgStat_TableXactStatus *trans)
{
if (trans->truncated)
{
trans->tuples_inserted = trans->inserted_pre_trunc;
trans->tuples_updated = trans->updated_pre_trunc;
trans->tuples_deleted = trans->deleted_pre_trunc;
}
}
/*
* pgstat_count_truncate - update tuple counters due to truncate
*/
void
pgstat_count_truncate(Relation rel)
{
PgStat_TableStatus *pgstat_info = rel->pgstat_info;
if (pgstat_info != NULL)
{
/* We have to log the effect at the proper transactional level */
int nest_level = GetCurrentTransactionNestLevel();
if (pgstat_info->trans == NULL ||
pgstat_info->trans->nest_level != nest_level)
add_tabstat_xact_level(pgstat_info, nest_level);
pgstat_truncate_save_counters(pgstat_info->trans);
pgstat_info->trans->tuples_inserted = 0;
pgstat_info->trans->tuples_updated = 0;
pgstat_info->trans->tuples_deleted = 0;
}
}
/*
* pgstat_update_heap_dead_tuples - update dead-tuples count
*
@@ -1916,12 +1978,22 @@ AtEOXact_PgStat(bool isCommit)
Assert(trans->upper == NULL);
tabstat = trans->parent;
Assert(tabstat->trans == trans);
/* restore pre-truncate stats (if any) in case of aborted xact */
if (!isCommit)
pgstat_truncate_restore_counters(trans);
/* count attempted actions regardless of commit/abort */
tabstat->t_counts.t_tuples_inserted += trans->tuples_inserted;
tabstat->t_counts.t_tuples_updated += trans->tuples_updated;
tabstat->t_counts.t_tuples_deleted += trans->tuples_deleted;
if (isCommit)
{
tabstat->t_counts.t_truncated = trans->truncated;
if (trans->truncated)
{
/* forget live/dead stats seen by backend thus far */
tabstat->t_counts.t_delta_live_tuples = 0;
tabstat->t_counts.t_delta_dead_tuples = 0;
}
/* insert adds a live tuple, delete removes one */
tabstat->t_counts.t_delta_live_tuples +=
trans->tuples_inserted - trans->tuples_deleted;
@@ -1986,9 +2058,21 @@ AtEOSubXact_PgStat(bool isCommit, int nestDepth)
{
if (trans->upper && trans->upper->nest_level == nestDepth - 1)
{
trans->upper->tuples_inserted += trans->tuples_inserted;
trans->upper->tuples_updated += trans->tuples_updated;
trans->upper->tuples_deleted += trans->tuples_deleted;
if (trans->truncated)
{
/* propagate the truncate status one level up */
pgstat_truncate_save_counters(trans->upper);
/* replace upper xact stats with ours */
trans->upper->tuples_inserted = trans->tuples_inserted;
trans->upper->tuples_updated = trans->tuples_updated;
trans->upper->tuples_deleted = trans->tuples_deleted;
}
else
{
trans->upper->tuples_inserted += trans->tuples_inserted;
trans->upper->tuples_updated += trans->tuples_updated;
trans->upper->tuples_deleted += trans->tuples_deleted;
}
tabstat->trans = trans->upper;
pfree(trans);
}
@@ -2017,6 +2101,8 @@ AtEOSubXact_PgStat(bool isCommit, int nestDepth)
* subtransaction
*/
/* first restore values obliterated by truncate */
pgstat_truncate_restore_counters(trans);
/* count attempted actions regardless of commit/abort */
tabstat->t_counts.t_tuples_inserted += trans->tuples_inserted;
tabstat->t_counts.t_tuples_updated += trans->tuples_updated;
@@ -2065,8 +2151,12 @@ AtPrepare_PgStat(void)
record.tuples_inserted = trans->tuples_inserted;
record.tuples_updated = trans->tuples_updated;
record.tuples_deleted = trans->tuples_deleted;
record.inserted_pre_trunc = trans->inserted_pre_trunc;
record.updated_pre_trunc = trans->updated_pre_trunc;
record.deleted_pre_trunc = trans->deleted_pre_trunc;
record.t_id = tabstat->t_id;
record.t_shared = tabstat->t_shared;
record.t_truncated = trans->truncated;
RegisterTwoPhaseRecord(TWOPHASE_RM_PGSTAT_ID, 0,
&record, sizeof(TwoPhasePgStatRecord));
@@ -2132,6 +2222,8 @@ pgstat_twophase_postcommit(TransactionId xid, uint16 info,
pgstat_info->t_counts.t_tuples_inserted += rec->tuples_inserted;
pgstat_info->t_counts.t_tuples_updated += rec->tuples_updated;
pgstat_info->t_counts.t_tuples_deleted += rec->tuples_deleted;
pgstat_info->t_counts.t_truncated = rec->t_truncated;
pgstat_info->t_counts.t_delta_live_tuples +=
rec->tuples_inserted - rec->tuples_deleted;
pgstat_info->t_counts.t_delta_dead_tuples +=
@@ -2158,6 +2250,12 @@ pgstat_twophase_postabort(TransactionId xid, uint16 info,
pgstat_info = get_tabstat_entry(rec->t_id, rec->t_shared);
/* Same math as in AtEOXact_PgStat, abort case */
if (rec->t_truncated)
{
rec->tuples_inserted = rec->inserted_pre_trunc;
rec->tuples_updated = rec->updated_pre_trunc;
rec->tuples_deleted = rec->deleted_pre_trunc;
}
pgstat_info->t_counts.t_tuples_inserted += rec->tuples_inserted;
pgstat_info->t_counts.t_tuples_updated += rec->tuples_updated;
pgstat_info->t_counts.t_tuples_deleted += rec->tuples_deleted;
@@ -4658,6 +4756,12 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len)
tabentry->tuples_updated += tabmsg->t_counts.t_tuples_updated;
tabentry->tuples_deleted += tabmsg->t_counts.t_tuples_deleted;
tabentry->tuples_hot_updated += tabmsg->t_counts.t_tuples_hot_updated;
/* If table was truncated, first reset the live/dead counters */
if (tabmsg->t_counts.t_truncated)
{
tabentry->n_live_tuples = 0;
tabentry->n_dead_tuples = 0;
}
tabentry->n_live_tuples += tabmsg->t_counts.t_delta_live_tuples;
tabentry->n_dead_tuples += tabmsg->t_counts.t_delta_dead_tuples;
tabentry->changes_since_analyze += tabmsg->t_counts.t_changed_tuples;