diff --git a/src/ivfflat.h b/src/ivfflat.h index ef44a6c..c9ff0f4 100644 --- a/src/ivfflat.h +++ b/src/ivfflat.h @@ -40,6 +40,9 @@ #define IVFFLAT_METAPAGE_BLKNO 0 #define IVFFLAT_HEAD_BLKNO 1 /* first list page */ +/* Must correspond to page numbers since page lock is used */ +#define IVFFLAT_SCAN_LOCK 0 + /* IVFFlat parameters */ #define IVFFLAT_DEFAULT_LISTS 100 #define IVFFLAT_MIN_LISTS 1 @@ -246,6 +249,7 @@ typedef struct IvfflatScanOpaqueData int probes; int dimensions; bool first; + bool hasLock; Buffer buf; ItemPointerData heaptid; diff --git a/src/ivfscan.c b/src/ivfscan.c index 7bd93f0..104e41d 100644 --- a/src/ivfscan.c +++ b/src/ivfscan.c @@ -9,6 +9,7 @@ #include "miscadmin.h" #include "pgstat.h" #include "storage/bufmgr.h" +#include "storage/lmgr.h" /* * Compare list distances @@ -263,6 +264,7 @@ ivfflatbeginscan(Relation index, int nkeys, int norderbys) so = (IvfflatScanOpaque) palloc(offsetof(IvfflatScanOpaqueData, lists) + probes * sizeof(IvfflatScanList)); so->buf = InvalidBuffer; so->first = true; + so->hasLock = false; ItemPointerSetInvalid(&so->heaptid); so->probes = probes; so->dimensions = dimensions; @@ -347,6 +349,13 @@ ivfflatgettuple(IndexScanDesc scan, ScanDirection dir) if (scan->orderByData == NULL) elog(ERROR, "cannot scan ivfflat index without order"); + /* Get a shared lock for non-MVCC snapshots */ + if (!so->hasLock && !IsMVCCSnapshot(scan->xs_snapshot)) + { + so->hasLock = true; + LockPage(scan->indexRelation, IVFFLAT_SCAN_LOCK, ShareLock); + } + if (scan->orderByData->sk_flags & SK_ISNULL) value = PointerGetDatum(InitVector(so->dimensions)); else @@ -422,6 +431,10 @@ ivfflatendscan(IndexScanDesc scan) if (BufferIsValid(so->buf)) ReleaseBuffer(so->buf); + /* Release lock */ + if (so->hasLock) + UnlockPage(scan->indexRelation, IVFFLAT_SCAN_LOCK, ShareLock); + pairingheap_free(so->listQueue); tuplesort_end(so->sortstate); diff --git a/src/ivfvacuum.c b/src/ivfvacuum.c index 435dfe1..52dd5a8 100644 --- a/src/ivfvacuum.c +++ b/src/ivfvacuum.c @@ -3,6 +3,7 @@ #include "commands/vacuum.h" #include "ivfflat.h" #include "storage/bufmgr.h" +#include "storage/lmgr.h" /* * Bulk delete tuples from the index @@ -65,14 +66,10 @@ ivfflatbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, vacuum_delay_point(); - buf = ReadBufferExtended(index, MAIN_FORKNUM, searchPage, RBM_NORMAL, bas); + /* Ensure no in-flight index scans for non-MVCC snapshots */ + LockPage(index, IVFFLAT_SCAN_LOCK, ExclusiveLock); - /* - * ambulkdelete cannot delete entries from pages that are - * pinned by other backends - * - * https://www.postgresql.org/docs/current/index-locking.html - */ + buf = ReadBufferExtended(index, MAIN_FORKNUM, searchPage, RBM_NORMAL, bas); LockBufferForCleanup(buf); state = GenericXLogStart(index); @@ -114,6 +111,8 @@ ivfflatbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, GenericXLogAbort(state); UnlockReleaseBuffer(buf); + + UnlockPage(index, IVFFLAT_SCAN_LOCK, ExclusiveLock); } /*