@@ -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 == ',' )
@@ -359,8 +379,7 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
359
379
{
360
380
TxidSnapshot * snap ;
361
381
uint32 nxip ,
362
- i ,
363
- size ;
382
+ i ;
364
383
TxidEpoch state ;
365
384
Snapshot cur ;
366
385
@@ -372,9 +391,7 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
372
391
373
392
/* allocate */
374
393
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 ));
378
395
379
396
/* fill */
380
397
snap -> xmin = convert_xid (cur -> xmin , & state );
@@ -383,9 +400,18 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
383
400
for (i = 0 ; i < nxip ; i ++ )
384
401
snap -> xip [i ] = convert_xid (cur -> xip [i ], & state );
385
402
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
+ */
387
410
sort_snapshot (snap );
388
411
412
+ /* set size after sorting, because it may have removed duplicate xips */
413
+ SET_VARSIZE (snap , TXID_SNAPSHOT_SIZE (snap -> nxip ));
414
+
389
415
PG_RETURN_POINTER (snap );
390
416
}
391
417
@@ -463,18 +489,27 @@ txid_snapshot_recv(PG_FUNCTION_ARGS)
463
489
snap = palloc (TXID_SNAPSHOT_SIZE (nxip ));
464
490
snap -> xmin = xmin ;
465
491
snap -> xmax = xmax ;
466
- snap -> nxip = nxip ;
467
- SET_VARSIZE (snap , TXID_SNAPSHOT_SIZE (nxip ));
468
492
469
493
for (i = 0 ; i < nxip ; i ++ )
470
494
{
471
495
txid cur = pq_getmsgint64 (buf );
472
496
473
- if (cur <= last || cur < xmin || cur >= xmax )
497
+ if (cur < last || cur < xmin || cur >= xmax )
474
498
goto bad_format ;
499
+
500
+ /* skip duplicate xips */
501
+ if (cur == last )
502
+ {
503
+ i -- ;
504
+ nxip -- ;
505
+ continue ;
506
+ }
507
+
475
508
snap -> xip [i ] = cur ;
476
509
last = cur ;
477
510
}
511
+ snap -> nxip = nxip ;
512
+ SET_VARSIZE (snap , TXID_SNAPSHOT_SIZE (nxip ));
478
513
PG_RETURN_POINTER (snap );
479
514
480
515
bad_format :
0 commit comments