diff --git a/src/backend/access/gin/ginfast.c b/src/backend/access/gin/ginfast.c new file mode 100644 index c5732c3..dae860f *** a/src/backend/access/gin/ginfast.c --- b/src/backend/access/gin/ginfast.c *************** processPendingPage(BuildAccumulator *acc *** 713,718 **** --- 713,719 ---- * Move tuples from pending pages into regular GIN structure. * * This can be called concurrently by multiple backends, so it must cope. + * XXX: not any more * On first glance it looks completely not concurrent-safe and not crash-safe * either. The reason it's okay is that multiple insertion of the same entry * is detected and treated as a no-op by gininsert.c. If we crash after *************** ginInsertCleanup(GinState *ginstate, *** 746,751 **** --- 747,770 ---- BlockNumber blkno; metabuffer = ReadBuffer(index, GIN_METAPAGE_BLKNO); + + /* + * A buffer cleanup lock on the metapage represents the exclusive right + * to clean the pending list. Unlike VACUUM's use of cleanup locks, + * this right persists until the pin on the metabuffer is dropped. + */ + if (vac_delay) + { + LockBufferForCleanup(metabuffer); + } + else if (!ConditionalLockBufferForCleanup(metabuffer)) + { + ReleaseBuffer(metabuffer); + return; + } + + /* Exchange the exclusive content lock for a shared one */ + LockBuffer(metabuffer, GIN_UNLOCK); LockBuffer(metabuffer, GIN_SHARE); metapage = BufferGetPage(metabuffer); metadata = GinPageGetMeta(metapage);