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

Commit479a36f

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 parentd8dbeb0 commit479a36f

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
@@ -130,16 +130,34 @@ cmp_txid(const void *aa, const void *bb)
130130
}
131131

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

145163
/*
@@ -294,10 +312,12 @@ parse_snapshot(const char *str)
294312
str=endp;
295313

296314
/* require the input to be in order */
297-
if (val<xmin||val >=xmax||val <=last_val)
315+
if (val<xmin||val >=xmax||val<last_val)
298316
gotobad_format;
299317

300-
buf_add_txid(buf,val);
318+
/* skip duplicates */
319+
if (val!=last_val)
320+
buf_add_txid(buf,val);
301321
last_val=val;
302322

303323
if (*str==',')
@@ -360,8 +380,7 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
360380
{
361381
TxidSnapshot*snap;
362382
uint32nxip,
363-
i,
364-
size;
383+
i;
365384
TxidEpochstate;
366385
Snapshotcur;
367386

@@ -373,9 +392,7 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
373392

374393
/* allocate */
375394
nxip=cur->xcnt;
376-
size=TXID_SNAPSHOT_SIZE(nxip);
377-
snap=palloc(size);
378-
SET_VARSIZE(snap,size);
395+
snap=palloc(TXID_SNAPSHOT_SIZE(nxip));
379396

380397
/* fill */
381398
snap->xmin=convert_xid(cur->xmin,&state);
@@ -384,9 +401,18 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
384401
for (i=0;i<nxip;i++)
385402
snap->xip[i]=convert_xid(cur->xip[i],&state);
386403

387-
/* we want them guaranteed to be in ascending order */
404+
/*
405+
* We want them guaranteed to be in ascending order. This also removes
406+
* any duplicate xids. Normally, an XID can only be assigned to one
407+
* backend, but when preparing a transaction for two-phase commit, there
408+
* is a transient state when both the original backend and the dummy
409+
* PGPROC entry reserved for the prepared transaction hold the same XID.
410+
*/
388411
sort_snapshot(snap);
389412

413+
/* set size after sorting, because it may have removed duplicate xips */
414+
SET_VARSIZE(snap,TXID_SNAPSHOT_SIZE(snap->nxip));
415+
390416
PG_RETURN_POINTER(snap);
391417
}
392418

@@ -464,18 +490,27 @@ txid_snapshot_recv(PG_FUNCTION_ARGS)
464490
snap=palloc(TXID_SNAPSHOT_SIZE(nxip));
465491
snap->xmin=xmin;
466492
snap->xmax=xmax;
467-
snap->nxip=nxip;
468-
SET_VARSIZE(snap,TXID_SNAPSHOT_SIZE(nxip));
469493

470494
for (i=0;i<nxip;i++)
471495
{
472496
txidcur=pq_getmsgint64(buf);
473497

474-
if (cur <=last||cur<xmin||cur >=xmax)
498+
if (cur<last||cur<xmin||cur >=xmax)
475499
gotobad_format;
500+
501+
/* skip duplicate xips */
502+
if (cur==last)
503+
{
504+
i--;
505+
nxip--;
506+
continue;
507+
}
508+
476509
snap->xip[i]=cur;
477510
last=cur;
478511
}
512+
snap->nxip=nxip;
513+
SET_VARSIZE(snap,TXID_SNAPSHOT_SIZE(nxip));
479514
PG_RETURN_POINTER(snap);
480515

481516
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