@@ -131,16 +131,34 @@ cmp_txid(const void *aa, const void *bb)
131
131
}
132
132
133
133
/*
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.
135
136
*
136
137
* For consistency of on-disk representation, we always sort even if bsearch
137
138
* will not be used.
138
139
*/
139
140
static void
140
141
sort_snapshot (TxidSnapshot * snap )
141
142
{
143
+ txid last = 0 ;
144
+ int nxip , idx1 , idx2 ;
145
+
142
146
if (snap -> nxip > 1 )
147
+ {
143
148
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
+ }
144
162
}
145
163
146
164
/*
@@ -295,10 +313,12 @@ parse_snapshot(const char *str)
295
313
str = endp ;
296
314
297
315
/* 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 )
299
317
goto bad_format ;
300
318
301
- buf_add_txid (buf , val );
319
+ /* skip duplicates */
320
+ if (val != last_val )
321
+ buf_add_txid (buf , val );
302
322
last_val = val ;
303
323
304
324
if (* str == ',' )
@@ -361,8 +381,7 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
361
381
{
362
382
TxidSnapshot * snap ;
363
383
uint32 nxip ,
364
- i ,
365
- size ;
384
+ i ;
366
385
TxidEpoch state ;
367
386
Snapshot cur ;
368
387
@@ -381,9 +400,7 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
381
400
382
401
/* allocate */
383
402
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 ));
387
404
388
405
/* fill */
389
406
snap -> xmin = convert_xid (cur -> xmin , & state );
@@ -392,9 +409,18 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
392
409
for (i = 0 ; i < nxip ; i ++ )
393
410
snap -> xip [i ] = convert_xid (cur -> xip [i ], & state );
394
411
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
+ */
396
419
sort_snapshot (snap );
397
420
421
+ /* set size after sorting, because it may have removed duplicate xips */
422
+ SET_VARSIZE (snap , TXID_SNAPSHOT_SIZE (snap -> nxip ));
423
+
398
424
PG_RETURN_POINTER (snap );
399
425
}
400
426
@@ -472,18 +498,27 @@ txid_snapshot_recv(PG_FUNCTION_ARGS)
472
498
snap = palloc (TXID_SNAPSHOT_SIZE (nxip ));
473
499
snap -> xmin = xmin ;
474
500
snap -> xmax = xmax ;
475
- snap -> nxip = nxip ;
476
- SET_VARSIZE (snap , TXID_SNAPSHOT_SIZE (nxip ));
477
501
478
502
for (i = 0 ; i < nxip ; i ++ )
479
503
{
480
504
txid cur = pq_getmsgint64 (buf );
481
505
482
- if (cur <= last || cur < xmin || cur >= xmax )
506
+ if (cur < last || cur < xmin || cur >= xmax )
483
507
goto bad_format ;
508
+
509
+ /* skip duplicate xips */
510
+ if (cur == last )
511
+ {
512
+ i -- ;
513
+ nxip -- ;
514
+ continue ;
515
+ }
516
+
484
517
snap -> xip [i ] = cur ;
485
518
last = cur ;
486
519
}
520
+ snap -> nxip = nxip ;
521
+ SET_VARSIZE (snap , TXID_SNAPSHOT_SIZE (nxip ));
487
522
PG_RETURN_POINTER (snap );
488
523
489
524
bad_format :
0 commit comments