@@ -130,16 +130,34 @@ cmp_txid(const void *aa, const void *bb)
130
130
}
131
131
132
132
/*
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.
134
135
*
135
136
* For consistency of on-disk representation, we always sort even if bsearch
136
137
* will not be used.
137
138
*/
138
139
static void
139
140
sort_snapshot (TxidSnapshot * snap )
140
141
{
142
+ txid last = 0 ;
143
+ int nxip , idx1 , idx2 ;
144
+
141
145
if (snap -> nxip > 1 )
146
+ {
142
147
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
+ }
143
161
}
144
162
145
163
/*
@@ -294,10 +312,12 @@ parse_snapshot(const char *str)
294
312
str = endp ;
295
313
296
314
/* 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 )
298
316
goto bad_format ;
299
317
300
- buf_add_txid (buf , val );
318
+ /* skip duplicates */
319
+ if (val != last_val )
320
+ buf_add_txid (buf , val );
301
321
last_val = val ;
302
322
303
323
if (* str == ',' )
@@ -360,8 +380,7 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
360
380
{
361
381
TxidSnapshot * snap ;
362
382
uint32 nxip ,
363
- i ,
364
- size ;
383
+ i ;
365
384
TxidEpoch state ;
366
385
Snapshot cur ;
367
386
@@ -373,9 +392,7 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
373
392
374
393
/* allocate */
375
394
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 ));
379
396
380
397
/* fill */
381
398
snap -> xmin = convert_xid (cur -> xmin , & state );
@@ -384,9 +401,18 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
384
401
for (i = 0 ; i < nxip ; i ++ )
385
402
snap -> xip [i ] = convert_xid (cur -> xip [i ], & state );
386
403
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
+ */
388
411
sort_snapshot (snap );
389
412
413
+ /* set size after sorting, because it may have removed duplicate xips */
414
+ SET_VARSIZE (snap , TXID_SNAPSHOT_SIZE (snap -> nxip ));
415
+
390
416
PG_RETURN_POINTER (snap );
391
417
}
392
418
@@ -464,18 +490,27 @@ txid_snapshot_recv(PG_FUNCTION_ARGS)
464
490
snap = palloc (TXID_SNAPSHOT_SIZE (nxip ));
465
491
snap -> xmin = xmin ;
466
492
snap -> xmax = xmax ;
467
- snap -> nxip = nxip ;
468
- SET_VARSIZE (snap , TXID_SNAPSHOT_SIZE (nxip ));
469
493
470
494
for (i = 0 ; i < nxip ; i ++ )
471
495
{
472
496
txid cur = pq_getmsgint64 (buf );
473
497
474
- if (cur <= last || cur < xmin || cur >= xmax )
498
+ if (cur < last || cur < xmin || cur >= xmax )
475
499
goto bad_format ;
500
+
501
+ /* skip duplicate xips */
502
+ if (cur == last )
503
+ {
504
+ i -- ;
505
+ nxip -- ;
506
+ continue ;
507
+ }
508
+
476
509
snap -> xip [i ] = cur ;
477
510
last = cur ;
478
511
}
512
+ snap -> nxip = nxip ;
513
+ SET_VARSIZE (snap , TXID_SNAPSHOT_SIZE (nxip ));
479
514
PG_RETURN_POINTER (snap );
480
515
481
516
bad_format :
0 commit comments