|
17 | 17 |
|
18 | 18 | #include "access/nbtree.h"
|
19 | 19 | #include "access/relscan.h"
|
| 20 | +#include "access/xact.h" |
20 | 21 | #include "miscadmin.h"
|
21 | 22 | #include "pgstat.h"
|
22 | 23 | #include "storage/predicate.h"
|
@@ -1382,22 +1383,34 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
1382 | 1383 | {
|
1383 | 1384 | /*
|
1384 | 1385 | * We only get here if the index is completely empty. Lock relation
|
1385 |
| - * because nothing finer to lock exists. |
| 1386 | + * because nothing finer to lock exists. Without a buffer lock, it's |
| 1387 | + * possible for another transaction to insert data between |
| 1388 | + * _bt_search() and PredicateLockRelation(). We have to try again |
| 1389 | + * after taking the relation-level predicate lock, to close a narrow |
| 1390 | + * window where we wouldn't scan concurrently inserted tuples, but the |
| 1391 | + * writer wouldn't see our predicate lock. |
1386 | 1392 | */
|
1387 |
| - PredicateLockRelation(rel, scan->xs_snapshot); |
1388 |
| - |
1389 |
| - /* |
1390 |
| - * mark parallel scan as done, so that all the workers can finish |
1391 |
| - * their scan |
1392 |
| - */ |
1393 |
| - _bt_parallel_done(scan); |
1394 |
| - BTScanPosInvalidate(so->currPos); |
| 1393 | + if (IsolationIsSerializable()) |
| 1394 | + { |
| 1395 | + PredicateLockRelation(rel, scan->xs_snapshot); |
| 1396 | + stack = _bt_search(rel, NULL, &inskey, &buf, BT_READ, |
| 1397 | + scan->xs_snapshot); |
| 1398 | + _bt_freestack(stack); |
| 1399 | + } |
1395 | 1400 |
|
1396 |
| - return false; |
| 1401 | + if (!BufferIsValid(buf)) |
| 1402 | + { |
| 1403 | + /* |
| 1404 | + * Mark parallel scan as done, so that all the workers can finish |
| 1405 | + * their scan. |
| 1406 | + */ |
| 1407 | + _bt_parallel_done(scan); |
| 1408 | + BTScanPosInvalidate(so->currPos); |
| 1409 | + return false; |
| 1410 | + } |
1397 | 1411 | }
|
1398 |
| - else |
1399 |
| - PredicateLockPage(rel, BufferGetBlockNumber(buf), |
1400 |
| - scan->xs_snapshot); |
| 1412 | + |
| 1413 | + PredicateLockPage(rel, BufferGetBlockNumber(buf), scan->xs_snapshot); |
1401 | 1414 |
|
1402 | 1415 | _bt_initialize_more_data(so, dir);
|
1403 | 1416 |
|
|
0 commit comments