@@ -139,16 +139,34 @@ cmp_txid(const void *aa, const void *bb)
139
139
}
140
140
141
141
/*
142
- * sort a snapshot's txids, so we can use bsearch() later.
142
+ * Sort a snapshot's txids, so we can use bsearch() later. Also remove
143
+ * any duplicates.
143
144
*
144
145
* For consistency of on-disk representation, we always sort even if bsearch
145
146
* will not be used.
146
147
*/
147
148
static void
148
149
sort_snapshot (TxidSnapshot * snap )
149
150
{
151
+ txid last = 0 ;
152
+ int nxip , idx1 , idx2 ;
153
+
150
154
if (snap -> nxip > 1 )
155
+ {
151
156
qsort (snap -> xip , snap -> nxip , sizeof (txid ), cmp_txid );
157
+
158
+ /* remove duplicates */
159
+ nxip = snap -> nxip ;
160
+ idx1 = idx2 = 0 ;
161
+ while (idx1 < nxip )
162
+ {
163
+ if (snap -> xip [idx1 ] != last )
164
+ last = snap -> xip [idx2 ++ ] = snap -> xip [idx1 ];
165
+ else
166
+ snap -> nxip -- ;
167
+ idx1 ++ ;
168
+ }
169
+ }
152
170
}
153
171
154
172
/*
@@ -303,10 +321,12 @@ parse_snapshot(const char *str)
303
321
str = endp ;
304
322
305
323
/* require the input to be in order */
306
- if (val < xmin || val >= xmax || val <= last_val )
324
+ if (val < xmin || val >= xmax || val < last_val )
307
325
goto bad_format ;
308
326
309
- buf_add_txid (buf , val );
327
+ /* skip duplicates */
328
+ if (val != last_val )
329
+ buf_add_txid (buf , val );
310
330
last_val = val ;
311
331
312
332
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