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

Commitf1f3bcb

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 parent82a83ec commitf1f3bcb

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==',')
@@ -359,8 +379,7 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
359379
{
360380
TxidSnapshot*snap;
361381
uint32nxip,
362-
i,
363-
size;
382+
i;
364383
TxidEpochstate;
365384
Snapshotcur;
366385

@@ -372,9 +391,7 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
372391

373392
/* allocate */
374393
nxip=cur->xcnt;
375-
size=TXID_SNAPSHOT_SIZE(nxip);
376-
snap=palloc(size);
377-
SET_VARSIZE(snap,size);
394+
snap=palloc(TXID_SNAPSHOT_SIZE(nxip));
378395

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

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

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

@@ -463,18 +489,27 @@ txid_snapshot_recv(PG_FUNCTION_ARGS)
463489
snap=palloc(TXID_SNAPSHOT_SIZE(nxip));
464490
snap->xmin=xmin;
465491
snap->xmax=xmax;
466-
snap->nxip=nxip;
467-
SET_VARSIZE(snap,TXID_SNAPSHOT_SIZE(nxip));
468492

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

473-
if (cur <=last||cur<xmin||cur >=xmax)
497+
if (cur<last||cur<xmin||cur >=xmax)
474498
gotobad_format;
499+
500+
/* skip duplicate xips */
501+
if (cur==last)
502+
{
503+
i--;
504+
nxip--;
505+
continue;
506+
}
507+
475508
snap->xip[i]=cur;
476509
last=cur;
477510
}
511+
snap->nxip=nxip;
512+
SET_VARSIZE(snap,TXID_SNAPSHOT_SIZE(nxip));
478513
PG_RETURN_POINTER(snap);
479514

480515
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