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

Commit8f9b959

Browse files
committed
Handle duplicate XIDs in txid_snapshot.
The proc array can contain duplicate XIDs, when a transaction is just beingprepared for two-phase commit. To cope, remove any duplicates intxid_current_snapshot(). Also ignore duplicates in the input functions, sothat if e.g. you have an old pg_dump file that already contains duplicates,it will be accepted.Report and fix by Jan Wieck. Backpatch to all supported versions.
1 parentbb38fb0 commit8f9b959

File tree

3 files changed

+54
-17
lines changed

3 files changed

+54
-17
lines changed

‎src/backend/utils/adt/txid.c

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -131,16 +131,34 @@ cmp_txid(const void *aa, const void *bb)
131131
}
132132

133133
/*
134-
* sort a snapshot's txids, so we can use bsearch() later.
134+
* Sort a snapshot's txids, so we can use bsearch() later. Also remove
135+
* any duplicates.
135136
*
136137
* For consistency of on-disk representation, we always sort even if bsearch
137138
* will not be used.
138139
*/
139140
staticvoid
140141
sort_snapshot(TxidSnapshot*snap)
141142
{
143+
txidlast=0;
144+
intnxip,idx1,idx2;
145+
142146
if (snap->nxip>1)
147+
{
143148
qsort(snap->xip,snap->nxip,sizeof(txid),cmp_txid);
149+
150+
/* remove duplicates */
151+
nxip=snap->nxip;
152+
idx1=idx2=0;
153+
while (idx1<nxip)
154+
{
155+
if (snap->xip[idx1]!=last)
156+
last=snap->xip[idx2++]=snap->xip[idx1];
157+
else
158+
snap->nxip--;
159+
idx1++;
160+
}
161+
}
144162
}
145163

146164
/*
@@ -295,10 +313,12 @@ parse_snapshot(const char *str)
295313
str=endp;
296314

297315
/* require the input to be in order */
298-
if (val<xmin||val >=xmax||val <=last_val)
316+
if (val<xmin||val >=xmax||val<last_val)
299317
gotobad_format;
300318

301-
buf_add_txid(buf,val);
319+
/* skip duplicates */
320+
if (val!=last_val)
321+
buf_add_txid(buf,val);
302322
last_val=val;
303323

304324
if (*str==',')
@@ -361,8 +381,7 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
361381
{
362382
TxidSnapshot*snap;
363383
uint32nxip,
364-
i,
365-
size;
384+
i;
366385
TxidEpochstate;
367386
Snapshotcur;
368387

@@ -381,9 +400,7 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
381400

382401
/* allocate */
383402
nxip=cur->xcnt;
384-
size=TXID_SNAPSHOT_SIZE(nxip);
385-
snap=palloc(size);
386-
SET_VARSIZE(snap,size);
403+
snap=palloc(TXID_SNAPSHOT_SIZE(nxip));
387404

388405
/* fill */
389406
snap->xmin=convert_xid(cur->xmin,&state);
@@ -392,9 +409,18 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
392409
for (i=0;i<nxip;i++)
393410
snap->xip[i]=convert_xid(cur->xip[i],&state);
394411

395-
/* we want them guaranteed to be in ascending order */
412+
/*
413+
* We want them guaranteed to be in ascending order. This also removes
414+
* any duplicate xids. Normally, an XID can only be assigned to one
415+
* backend, but when preparing a transaction for two-phase commit, there
416+
* is a transient state when both the original backend and the dummy
417+
* PGPROC entry reserved for the prepared transaction hold the same XID.
418+
*/
396419
sort_snapshot(snap);
397420

421+
/* set size after sorting, because it may have removed duplicate xips */
422+
SET_VARSIZE(snap,TXID_SNAPSHOT_SIZE(snap->nxip));
423+
398424
PG_RETURN_POINTER(snap);
399425
}
400426

@@ -472,18 +498,27 @@ txid_snapshot_recv(PG_FUNCTION_ARGS)
472498
snap=palloc(TXID_SNAPSHOT_SIZE(nxip));
473499
snap->xmin=xmin;
474500
snap->xmax=xmax;
475-
snap->nxip=nxip;
476-
SET_VARSIZE(snap,TXID_SNAPSHOT_SIZE(nxip));
477501

478502
for (i=0;i<nxip;i++)
479503
{
480504
txidcur=pq_getmsgint64(buf);
481505

482-
if (cur <=last||cur<xmin||cur >=xmax)
506+
if (cur<last||cur<xmin||cur >=xmax)
483507
gotobad_format;
508+
509+
/* skip duplicate xips */
510+
if (cur==last)
511+
{
512+
i--;
513+
nxip--;
514+
continue;
515+
}
516+
484517
snap->xip[i]=cur;
485518
last=cur;
486519
}
520+
snap->nxip=nxip;
521+
SET_VARSIZE(snap,TXID_SNAPSHOT_SIZE(nxip));
487522
PG_RETURN_POINTER(snap);
488523

489524
bad_format:

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ select '12:18:14,16'::txid_snapshot;
1212
12:18:14,16
1313
(1 row)
1414

15+
select '12:16:14,14'::txid_snapshot;
16+
txid_snapshot
17+
---------------
18+
12:16:14
19+
(1 row)
20+
1521
-- errors
1622
select '31:12:'::txid_snapshot;
1723
ERROR: invalid input for txid_snapshot: "31:12:"
@@ -29,10 +35,6 @@ select '12:16:14,13'::txid_snapshot;
2935
ERROR: invalid input for txid_snapshot: "12:16:14,13"
3036
LINE 1: select '12:16:14,13'::txid_snapshot;
3137
^
32-
select '12:16:14,14'::txid_snapshot;
33-
ERROR: invalid input for txid_snapshot: "12:16:14,14"
34-
LINE 1: select '12:16:14,14'::txid_snapshot;
35-
^
3638
create temp table snapshot_test (
3739
nrinteger,
3840
snaptxid_snapshot

‎src/test/regress/sql/txid.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
-- i/o
44
select'12:13:'::txid_snapshot;
55
select'12:18:14,16'::txid_snapshot;
6+
select'12:16:14,14'::txid_snapshot;
67

78
-- errors
89
select'31:12:'::txid_snapshot;
910
select'0:1:'::txid_snapshot;
1011
select'12:13:0'::txid_snapshot;
1112
select'12:16:14,13'::txid_snapshot;
12-
select'12:16:14,14'::txid_snapshot;
1313

1414
create temp table snapshot_test (
1515
nrinteger,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp