extend_bufmgr_api_for_hash_index_v1.patch

application/octet-stream

Filename: extend_bufmgr_api_for_hash_index_v1.patch
Type: application/octet-stream
Part: 0
Message: Re: Hash Indexes

Patch

Format: unified
Series: patch v1
File+
contrib/bloom/blutils.c 1 1
src/backend/access/gin/ginutil.c 1 1
src/backend/access/gist/gistutil.c 1 1
src/backend/access/nbtree/nbtpage.c 1 1
src/backend/access/spgist/spgdoinsert.c 1 1
src/backend/access/spgist/spgutils.c 3 3
src/backend/storage/buffer/bufmgr.c 58 6
src/include/storage/bufmgr.h 2 1
diff --git a/contrib/bloom/blutils.c b/contrib/bloom/blutils.c
index b68a0d1..bcbf387 100644
--- a/contrib/bloom/blutils.c
+++ b/contrib/bloom/blutils.c
@@ -356,7 +356,7 @@ BloomNewBuffer(Relation index)
 		 * We have to guard against the possibility that someone else already
 		 * recycled this page; the buffer may be locked if so.
 		 */
-		if (ConditionalLockBuffer(buffer))
+		if (ConditionalLockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE))
 		{
 			Page		page = BufferGetPage(buffer);
 
diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c
index f07eedc..75c516a 100644
--- a/src/backend/access/gin/ginutil.c
+++ b/src/backend/access/gin/ginutil.c
@@ -298,7 +298,7 @@ GinNewBuffer(Relation index)
 		 * We have to guard against the possibility that someone else already
 		 * recycled this page; the buffer may be locked if so.
 		 */
-		if (ConditionalLockBuffer(buffer))
+		if (ConditionalLockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE))
 		{
 			Page		page = BufferGetPage(buffer);
 
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 887c58b..607fe34 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -777,7 +777,7 @@ gistNewBuffer(Relation r)
 		 * We have to guard against the possibility that someone else already
 		 * recycled this page; the buffer may be locked if so.
 		 */
-		if (ConditionalLockBuffer(buffer))
+		if (ConditionalLockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE))
 		{
 			Page		page = BufferGetPage(buffer);
 
diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c
index 2001dc1..6434af0 100644
--- a/src/backend/access/nbtree/nbtpage.c
+++ b/src/backend/access/nbtree/nbtpage.c
@@ -614,7 +614,7 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access)
 			if (blkno == InvalidBlockNumber)
 				break;
 			buf = ReadBuffer(rel, blkno);
-			if (ConditionalLockBuffer(buf))
+			if (ConditionalLockBuffer(buf, BUFFER_LOCK_EXCLUSIVE))
 			{
 				page = BufferGetPage(buf);
 				if (_bt_page_recyclable(page))
diff --git a/src/backend/access/spgist/spgdoinsert.c b/src/backend/access/spgist/spgdoinsert.c
index 6fc04b2..2d38cb6 100644
--- a/src/backend/access/spgist/spgdoinsert.c
+++ b/src/backend/access/spgist/spgdoinsert.c
@@ -1997,7 +1997,7 @@ spgdoinsert(Relation index, SpGistState *state,
 			 * held by a reader, or even just background writer/checkpointer
 			 * process.  Perhaps it'd be worth retrying after sleeping a bit?
 			 */
-			if (!ConditionalLockBuffer(current.buffer))
+			if (!ConditionalLockBuffer(current.buffer, BUFFER_LOCK_EXCLUSIVE))
 			{
 				ReleaseBuffer(current.buffer);
 				UnlockReleaseBuffer(parent.buffer);
diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c
index d570ae5..3adfa23 100644
--- a/src/backend/access/spgist/spgutils.c
+++ b/src/backend/access/spgist/spgutils.c
@@ -205,7 +205,7 @@ SpGistNewBuffer(Relation index)
 		 * We have to guard against the possibility that someone else already
 		 * recycled this page; the buffer may be locked if so.
 		 */
-		if (ConditionalLockBuffer(buffer))
+		if (ConditionalLockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE))
 		{
 			Page		page = BufferGetPage(buffer);
 
@@ -255,7 +255,7 @@ SpGistUpdateMetaPage(Relation index)
 
 		metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO);
 
-		if (ConditionalLockBuffer(metabuffer))
+		if (ConditionalLockBuffer(metabuffer, BUFFER_LOCK_EXCLUSIVE))
 		{
 			metadata = SpGistPageGetMeta(BufferGetPage(metabuffer));
 			metadata->lastUsedPages = cache->lastUsedPages;
@@ -392,7 +392,7 @@ SpGistGetBuffer(Relation index, int flags, int needSpace, bool *isNew)
 
 		buffer = ReadBuffer(index, lup->blkno);
 
-		if (!ConditionalLockBuffer(buffer))
+		if (!ConditionalLockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE))
 		{
 			/*
 			 * buffer is locked by another process, so return a new buffer
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index df4c9d7..c1ab893 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -3548,22 +3548,27 @@ LockBuffer(Buffer buffer, int mode)
 
 /*
  * Acquire the content_lock for the buffer, but only if we don't have to wait.
- *
- * This assumes the caller wants BUFFER_LOCK_EXCLUSIVE mode.
  */
 bool
-ConditionalLockBuffer(Buffer buffer)
+ConditionalLockBuffer(Buffer buffer, int mode)
 {
 	BufferDesc *buf;
 
 	Assert(BufferIsValid(buffer));
+	Assert(mode == BUFFER_LOCK_SHARE || mode == BUFFER_LOCK_EXCLUSIVE);
 	if (BufferIsLocal(buffer))
 		return true;			/* act as though we got it */
 
 	buf = GetBufferDescriptor(buffer - 1);
 
-	return LWLockConditionalAcquire(BufferDescriptorGetContentLock(buf),
-									LW_EXCLUSIVE);
+	if (mode == BUFFER_LOCK_SHARE)
+		return LWLockConditionalAcquire(BufferDescriptorGetContentLock(buf),
+										LW_SHARED);
+	else if (mode == BUFFER_LOCK_EXCLUSIVE)
+		return LWLockConditionalAcquire(BufferDescriptorGetContentLock(buf),
+										LW_EXCLUSIVE);
+
+	return false;
 }
 
 /*
@@ -3724,7 +3729,7 @@ ConditionalLockBufferForCleanup(Buffer buffer)
 		return false;
 
 	/* Try to acquire lock */
-	if (!ConditionalLockBuffer(buffer))
+	if (!ConditionalLockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE))
 		return false;
 
 	bufHdr = GetBufferDescriptor(buffer - 1);
@@ -3745,6 +3750,53 @@ ConditionalLockBufferForCleanup(Buffer buffer)
 	return false;
 }
 
+/*
+ * IsBufferCleanupOK - as above, but don't attempt to take lock
+ *
+ * We won't loop, but just check once to see if the pin count is OK.  If
+ * not, return FALSE.
+ */
+bool
+IsBufferCleanupOK(Buffer buffer)
+{
+	BufferDesc *bufHdr;
+	uint32		buf_state;
+
+	Assert(BufferIsValid(buffer));
+
+	if (BufferIsLocal(buffer))
+	{
+		/* There should be exactly one pin */
+		if (LocalRefCount[-buffer - 1] != 1)
+			return false;
+		/* Nobody else to wait for */
+		return true;
+	}
+
+	/* There should be exactly one local pin */
+	if (GetPrivateRefCount(buffer) != 1)
+		return false;
+
+	bufHdr = GetBufferDescriptor(buffer - 1);
+
+	/* caller must hold exclusive lock on buffer */
+	Assert(LWLockHeldByMeInMode(BufferDescriptorGetContentLock(bufHdr),
+								LW_EXCLUSIVE));
+
+	buf_state = LockBufHdr(bufHdr);
+
+	Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0);
+	if (BUF_STATE_GET_REFCOUNT(buf_state) == 1)
+	{
+		/* pincount is OK. */
+		UnlockBufHdr(bufHdr, buf_state);
+		return true;
+	}
+
+	UnlockBufHdr(bufHdr, buf_state);
+	return false;
+}
+
 
 /*
  *	Functions for buffer I/O handling
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index 7b6ba96..fcb2bf2 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -224,9 +224,10 @@ extern void MarkBufferDirtyHint(Buffer buffer, bool buffer_std);
 
 extern void UnlockBuffers(void);
 extern void LockBuffer(Buffer buffer, int mode);
-extern bool ConditionalLockBuffer(Buffer buffer);
+extern bool ConditionalLockBuffer(Buffer buffer, int mode);
 extern void LockBufferForCleanup(Buffer buffer);
 extern bool ConditionalLockBufferForCleanup(Buffer buffer);
+extern bool IsBufferCleanupOK(Buffer buffer);
 extern bool HoldingBufferPinThatDelaysRecovery(void);
 
 extern void AbortBufferIO(void);