Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd42358e

Browse files
committed
Have TRUNCATE update pgstat tuple counters
This works by keeping a per-subtransaction record of the ins/upd/delcounters before the truncate, and then resetting them; this record isuseful to return to the previous state in case the truncate is rolledback, either in a subtransaction or whole transaction. The state ispropagated upwards as subtransactions commit.When the per-table data is sent to the stats collector, a flag indicatesto reset the live/dead counters to zero as well.Catalog version bumped due to the change in pgstat format.Author: Alexander ShulginDiscussion: 1007.1207238291@sss.pgh.pa.usDiscussion: 548F7D38.2000401@BlueTreble.comReviewed-by: Álvaro Herrera, Jim Nasby
1 parent5740be6 commitd42358e

File tree

8 files changed

+374
-3
lines changed

8 files changed

+374
-3
lines changed

‎src/backend/commands/tablecmds.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
#include"parser/parse_type.h"
7272
#include"parser/parse_utilcmd.h"
7373
#include"parser/parser.h"
74+
#include"pgstat.h"
7475
#include"rewrite/rewriteDefine.h"
7576
#include"rewrite/rewriteHandler.h"
7677
#include"rewrite/rewriteManip.h"
@@ -1220,6 +1221,8 @@ ExecuteTruncate(TruncateStmt *stmt)
12201221
*/
12211222
reindex_relation(heap_relid,REINDEX_REL_PROCESS_TOAST);
12221223
}
1224+
1225+
pgstat_count_truncate(rel);
12231226
}
12241227

12251228
/*

‎src/backend/postmaster/pgstat.c

Lines changed: 107 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,12 @@ typedef struct TwoPhasePgStatRecord
197197
PgStat_Countertuples_inserted;/* tuples inserted in xact */
198198
PgStat_Countertuples_updated;/* tuples updated in xact */
199199
PgStat_Countertuples_deleted;/* tuples deleted in xact */
200+
PgStat_Counterinserted_pre_trunc;/* tuples inserted prior to truncate */
201+
PgStat_Counterupdated_pre_trunc;/* tuples updated prior to truncate */
202+
PgStat_Counterdeleted_pre_trunc;/* tuples deleted prior to truncate */
200203
Oidt_id;/* table's OID */
201204
boolt_shared;/* is it a shared catalog? */
205+
boolt_truncated;/* was the relation truncated? */
202206
}TwoPhasePgStatRecord;
203207

204208
/*
@@ -1858,6 +1862,64 @@ pgstat_count_heap_delete(Relation rel)
18581862
}
18591863
}
18601864

1865+
/*
1866+
* pgstat_truncate_save_counters
1867+
*
1868+
* Whenever a table is truncated, we save its i/u/d counters so that they can
1869+
* be cleared, and if the (sub)xact that executed the truncate later aborts,
1870+
* the counters can be restored to the saved (pre-truncate) values. Note we do
1871+
* this on the first truncate in any particular subxact level only.
1872+
*/
1873+
staticvoid
1874+
pgstat_truncate_save_counters(PgStat_TableXactStatus*trans)
1875+
{
1876+
if (!trans->truncated)
1877+
{
1878+
trans->inserted_pre_trunc=trans->tuples_inserted;
1879+
trans->updated_pre_trunc=trans->tuples_updated;
1880+
trans->deleted_pre_trunc=trans->tuples_deleted;
1881+
trans->truncated= true;
1882+
}
1883+
}
1884+
1885+
/*
1886+
* pgstat_truncate_restore_counters - restore counters when a truncate aborts
1887+
*/
1888+
staticvoid
1889+
pgstat_truncate_restore_counters(PgStat_TableXactStatus*trans)
1890+
{
1891+
if (trans->truncated)
1892+
{
1893+
trans->tuples_inserted=trans->inserted_pre_trunc;
1894+
trans->tuples_updated=trans->updated_pre_trunc;
1895+
trans->tuples_deleted=trans->deleted_pre_trunc;
1896+
}
1897+
}
1898+
1899+
/*
1900+
* pgstat_count_truncate - update tuple counters due to truncate
1901+
*/
1902+
void
1903+
pgstat_count_truncate(Relationrel)
1904+
{
1905+
PgStat_TableStatus*pgstat_info=rel->pgstat_info;
1906+
1907+
if (pgstat_info!=NULL)
1908+
{
1909+
/* We have to log the effect at the proper transactional level */
1910+
intnest_level=GetCurrentTransactionNestLevel();
1911+
1912+
if (pgstat_info->trans==NULL||
1913+
pgstat_info->trans->nest_level!=nest_level)
1914+
add_tabstat_xact_level(pgstat_info,nest_level);
1915+
1916+
pgstat_truncate_save_counters(pgstat_info->trans);
1917+
pgstat_info->trans->tuples_inserted=0;
1918+
pgstat_info->trans->tuples_updated=0;
1919+
pgstat_info->trans->tuples_deleted=0;
1920+
}
1921+
}
1922+
18611923
/*
18621924
* pgstat_update_heap_dead_tuples - update dead-tuples count
18631925
*
@@ -1916,12 +1978,22 @@ AtEOXact_PgStat(bool isCommit)
19161978
Assert(trans->upper==NULL);
19171979
tabstat=trans->parent;
19181980
Assert(tabstat->trans==trans);
1981+
/* restore pre-truncate stats (if any) in case of aborted xact */
1982+
if (!isCommit)
1983+
pgstat_truncate_restore_counters(trans);
19191984
/* count attempted actions regardless of commit/abort */
19201985
tabstat->t_counts.t_tuples_inserted+=trans->tuples_inserted;
19211986
tabstat->t_counts.t_tuples_updated+=trans->tuples_updated;
19221987
tabstat->t_counts.t_tuples_deleted+=trans->tuples_deleted;
19231988
if (isCommit)
19241989
{
1990+
tabstat->t_counts.t_truncated=trans->truncated;
1991+
if (trans->truncated)
1992+
{
1993+
/* forget live/dead stats seen by backend thus far */
1994+
tabstat->t_counts.t_delta_live_tuples=0;
1995+
tabstat->t_counts.t_delta_dead_tuples=0;
1996+
}
19251997
/* insert adds a live tuple, delete removes one */
19261998
tabstat->t_counts.t_delta_live_tuples+=
19271999
trans->tuples_inserted-trans->tuples_deleted;
@@ -1986,9 +2058,21 @@ AtEOSubXact_PgStat(bool isCommit, int nestDepth)
19862058
{
19872059
if (trans->upper&&trans->upper->nest_level==nestDepth-1)
19882060
{
1989-
trans->upper->tuples_inserted+=trans->tuples_inserted;
1990-
trans->upper->tuples_updated+=trans->tuples_updated;
1991-
trans->upper->tuples_deleted+=trans->tuples_deleted;
2061+
if (trans->truncated)
2062+
{
2063+
/* propagate the truncate status one level up */
2064+
pgstat_truncate_save_counters(trans->upper);
2065+
/* replace upper xact stats with ours */
2066+
trans->upper->tuples_inserted=trans->tuples_inserted;
2067+
trans->upper->tuples_updated=trans->tuples_updated;
2068+
trans->upper->tuples_deleted=trans->tuples_deleted;
2069+
}
2070+
else
2071+
{
2072+
trans->upper->tuples_inserted+=trans->tuples_inserted;
2073+
trans->upper->tuples_updated+=trans->tuples_updated;
2074+
trans->upper->tuples_deleted+=trans->tuples_deleted;
2075+
}
19922076
tabstat->trans=trans->upper;
19932077
pfree(trans);
19942078
}
@@ -2017,6 +2101,8 @@ AtEOSubXact_PgStat(bool isCommit, int nestDepth)
20172101
* subtransaction
20182102
*/
20192103

2104+
/* first restore values obliterated by truncate */
2105+
pgstat_truncate_restore_counters(trans);
20202106
/* count attempted actions regardless of commit/abort */
20212107
tabstat->t_counts.t_tuples_inserted+=trans->tuples_inserted;
20222108
tabstat->t_counts.t_tuples_updated+=trans->tuples_updated;
@@ -2065,8 +2151,12 @@ AtPrepare_PgStat(void)
20652151
record.tuples_inserted=trans->tuples_inserted;
20662152
record.tuples_updated=trans->tuples_updated;
20672153
record.tuples_deleted=trans->tuples_deleted;
2154+
record.inserted_pre_trunc=trans->inserted_pre_trunc;
2155+
record.updated_pre_trunc=trans->updated_pre_trunc;
2156+
record.deleted_pre_trunc=trans->deleted_pre_trunc;
20682157
record.t_id=tabstat->t_id;
20692158
record.t_shared=tabstat->t_shared;
2159+
record.t_truncated=trans->truncated;
20702160

20712161
RegisterTwoPhaseRecord(TWOPHASE_RM_PGSTAT_ID,0,
20722162
&record,sizeof(TwoPhasePgStatRecord));
@@ -2132,6 +2222,8 @@ pgstat_twophase_postcommit(TransactionId xid, uint16 info,
21322222
pgstat_info->t_counts.t_tuples_inserted+=rec->tuples_inserted;
21332223
pgstat_info->t_counts.t_tuples_updated+=rec->tuples_updated;
21342224
pgstat_info->t_counts.t_tuples_deleted+=rec->tuples_deleted;
2225+
pgstat_info->t_counts.t_truncated=rec->t_truncated;
2226+
21352227
pgstat_info->t_counts.t_delta_live_tuples+=
21362228
rec->tuples_inserted-rec->tuples_deleted;
21372229
pgstat_info->t_counts.t_delta_dead_tuples+=
@@ -2158,6 +2250,12 @@ pgstat_twophase_postabort(TransactionId xid, uint16 info,
21582250
pgstat_info=get_tabstat_entry(rec->t_id,rec->t_shared);
21592251

21602252
/* Same math as in AtEOXact_PgStat, abort case */
2253+
if (rec->t_truncated)
2254+
{
2255+
rec->tuples_inserted=rec->inserted_pre_trunc;
2256+
rec->tuples_updated=rec->updated_pre_trunc;
2257+
rec->tuples_deleted=rec->deleted_pre_trunc;
2258+
}
21612259
pgstat_info->t_counts.t_tuples_inserted+=rec->tuples_inserted;
21622260
pgstat_info->t_counts.t_tuples_updated+=rec->tuples_updated;
21632261
pgstat_info->t_counts.t_tuples_deleted+=rec->tuples_deleted;
@@ -4658,6 +4756,12 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len)
46584756
tabentry->tuples_updated+=tabmsg->t_counts.t_tuples_updated;
46594757
tabentry->tuples_deleted+=tabmsg->t_counts.t_tuples_deleted;
46604758
tabentry->tuples_hot_updated+=tabmsg->t_counts.t_tuples_hot_updated;
4759+
/* If table was truncated, first reset the live/dead counters */
4760+
if (tabmsg->t_counts.t_truncated)
4761+
{
4762+
tabentry->n_live_tuples=0;
4763+
tabentry->n_dead_tuples=0;
4764+
}
46614765
tabentry->n_live_tuples+=tabmsg->t_counts.t_delta_live_tuples;
46624766
tabentry->n_dead_tuples+=tabmsg->t_counts.t_delta_dead_tuples;
46634767
tabentry->changes_since_analyze+=tabmsg->t_counts.t_changed_tuples;

‎src/include/pgstat.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ typedef struct PgStat_TableCounts
104104
PgStat_Countert_tuples_updated;
105105
PgStat_Countert_tuples_deleted;
106106
PgStat_Countert_tuples_hot_updated;
107+
boolt_truncated;
107108

108109
PgStat_Countert_delta_live_tuples;
109110
PgStat_Countert_delta_dead_tuples;
@@ -165,6 +166,10 @@ typedef struct PgStat_TableXactStatus
165166
PgStat_Countertuples_inserted;/* tuples inserted in (sub)xact */
166167
PgStat_Countertuples_updated;/* tuples updated in (sub)xact */
167168
PgStat_Countertuples_deleted;/* tuples deleted in (sub)xact */
169+
booltruncated;/* relation truncated in this (sub)xact */
170+
PgStat_Counterinserted_pre_trunc;/* tuples inserted prior to truncate */
171+
PgStat_Counterupdated_pre_trunc;/* tuples updated prior to truncate */
172+
PgStat_Counterdeleted_pre_trunc;/* tuples deleted prior to truncate */
168173
intnest_level;/* subtransaction nest level */
169174
/* links to other structs for same relation: */
170175
structPgStat_TableXactStatus*upper;/* next higher subxact if any */
@@ -960,6 +965,7 @@ extern void pgstat_initstats(Relation rel);
960965
externvoidpgstat_count_heap_insert(Relationrel,intn);
961966
externvoidpgstat_count_heap_update(Relationrel,boolhot);
962967
externvoidpgstat_count_heap_delete(Relationrel);
968+
externvoidpgstat_count_truncate(Relationrel);
963969
externvoidpgstat_update_heap_dead_tuples(Relationrel,intdelta);
964970

965971
externvoidpgstat_init_function_usage(FunctionCallInfoData*fcinfo,

‎src/test/regress/expected/prepared_xacts.out

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,58 @@ SELECT gid FROM pg_prepared_xacts;
247247
-----
248248
(0 rows)
249249

250+
CREATE TABLE pxtest5 (a SERIAL);
251+
INSERT INTO pxtest5 DEFAULT VALUES;
252+
SELECT * FROM pxtest5;
253+
a
254+
---
255+
1
256+
(1 row)
257+
258+
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
259+
INSERT INTO pxtest5 DEFAULT VALUES;
260+
INSERT INTO pxtest5 DEFAULT VALUES;
261+
TRUNCATE pxtest5;
262+
INSERT INTO pxtest5 DEFAULT VALUES;
263+
PREPARE TRANSACTION 'trunc-and-pgstat';
264+
SELECT pg_sleep(0.5);
265+
pg_sleep
266+
----------
267+
268+
(1 row)
269+
270+
SELECT n_tup_ins, n_tup_upd, n_tup_del, n_live_tup, n_dead_tup
271+
FROM pg_stat_user_tables
272+
WHERE relname='pxtest5';
273+
n_tup_ins | n_tup_upd | n_tup_del | n_live_tup | n_dead_tup
274+
-----------+-----------+-----------+------------+------------
275+
1 | 0 | 0 | 1 | 0
276+
(1 row)
277+
278+
COMMIT PREPARED 'trunc-and-pgstat';
279+
SELECT pg_sleep(0.5);
280+
pg_sleep
281+
----------
282+
283+
(1 row)
284+
285+
SELECT n_tup_ins, n_tup_upd, n_tup_del, n_live_tup, n_dead_tup
286+
FROM pg_stat_user_tables
287+
WHERE relname='pxtest5';
288+
n_tup_ins | n_tup_upd | n_tup_del | n_live_tup | n_dead_tup
289+
-----------+-----------+-----------+------------+------------
290+
2 | 0 | 0 | 1 | 0
291+
(1 row)
292+
293+
SELECT * FROM pxtest5;
294+
a
295+
---
296+
4
297+
(1 row)
298+
250299
-- Clean up
251300
DROP TABLE pxtest2;
252301
DROP TABLE pxtest3; -- will still be there if prepared xacts are disabled
253302
ERROR: table "pxtest3" does not exist
254303
DROP TABLE pxtest4;
304+
DROP TABLE pxtest5;

‎src/test/regress/expected/prepared_xacts_1.out

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,62 @@ SELECT gid FROM pg_prepared_xacts;
249249
-----
250250
(0 rows)
251251

252+
CREATE TABLE pxtest5 (a SERIAL);
253+
INSERT INTO pxtest5 DEFAULT VALUES;
254+
SELECT * FROM pxtest5;
255+
a
256+
---
257+
1
258+
(1 row)
259+
260+
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
261+
INSERT INTO pxtest5 DEFAULT VALUES;
262+
INSERT INTO pxtest5 DEFAULT VALUES;
263+
TRUNCATE pxtest5;
264+
INSERT INTO pxtest5 DEFAULT VALUES;
265+
PREPARE TRANSACTION 'trunc-and-pgstat';
266+
ERROR: prepared transactions are disabled
267+
HINT: Set max_prepared_transactions to a nonzero value.
268+
SELECT pg_sleep(0.5);
269+
pg_sleep
270+
----------
271+
272+
(1 row)
273+
274+
SELECT n_tup_ins, n_tup_upd, n_tup_del, n_live_tup, n_dead_tup
275+
FROM pg_stat_user_tables
276+
WHERE relname='pxtest5';
277+
n_tup_ins | n_tup_upd | n_tup_del | n_live_tup | n_dead_tup
278+
-----------+-----------+-----------+------------+------------
279+
3 | 0 | 0 | 1 | 2
280+
(1 row)
281+
282+
COMMIT PREPARED 'trunc-and-pgstat';
283+
ERROR: prepared transaction with identifier "trunc-and-pgstat" does not exist
284+
SELECT pg_sleep(0.5);
285+
pg_sleep
286+
----------
287+
288+
(1 row)
289+
290+
SELECT n_tup_ins, n_tup_upd, n_tup_del, n_live_tup, n_dead_tup
291+
FROM pg_stat_user_tables
292+
WHERE relname='pxtest5';
293+
n_tup_ins | n_tup_upd | n_tup_del | n_live_tup | n_dead_tup
294+
-----------+-----------+-----------+------------+------------
295+
3 | 0 | 0 | 1 | 2
296+
(1 row)
297+
298+
SELECT * FROM pxtest5;
299+
a
300+
---
301+
1
302+
(1 row)
303+
252304
-- Clean up
253305
DROP TABLE pxtest2;
254306
ERROR: table "pxtest2" does not exist
255307
DROP TABLE pxtest3; -- will still be there if prepared xacts are disabled
256308
DROP TABLE pxtest4;
257309
ERROR: table "pxtest4" does not exist
310+
DROP TABLE pxtest5;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp