From c17bcea12ea0ffc94b65dd837db0e664743ff4de Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@enterprisedb.com>
Date: Wed, 27 Jun 2018 11:18:01 +1200
Subject: [PATCH] Use a dlist for unowned relations.

Previously we used an open-coded singly-linked list, which required
remove_from_unowned_list() to perform an O(n) search.  Make it O(1).

Author: Thomas Munro
Discussion: https://postgr.es/m/CAHGQGwHVQkdfDqtvGVkty+19cQakAydXn1etGND3X0PHbZ3+6w@mail.gmail.com
---
 src/backend/storage/smgr/smgr.c | 44 +++++++++------------------------
 src/include/storage/smgr.h      |  3 ++-
 2 files changed, 14 insertions(+), 33 deletions(-)

diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c
index 08f06bade25..1388557c1ba 100644
--- a/src/backend/storage/smgr/smgr.c
+++ b/src/backend/storage/smgr/smgr.c
@@ -18,6 +18,7 @@
 #include "postgres.h"
 
 #include "commands/tablespace.h"
+#include "lib/ilist.h"
 #include "storage/bufmgr.h"
 #include "storage/ipc.h"
 #include "storage/smgr.h"
@@ -82,7 +83,7 @@ static const int NSmgr = lengthof(smgrsw);
  */
 static HTAB *SMgrRelationHash = NULL;
 
-static SMgrRelation first_unowned_reln = NULL;
+static dlist_head unowned_relns;
 
 /* local function prototypes */
 static void smgrshutdown(int code, Datum arg);
@@ -150,7 +151,7 @@ smgropen(RelFileNode rnode, BackendId backend)
 		ctl.entrysize = sizeof(SMgrRelationData);
 		SMgrRelationHash = hash_create("smgr relation table", 400,
 									   &ctl, HASH_ELEM | HASH_BLOBS);
-		first_unowned_reln = NULL;
+		dlist_init(&unowned_relns);
 	}
 
 	/* Look up or create an entry */
@@ -236,16 +237,11 @@ smgrclearowner(SMgrRelation *owner, SMgrRelation reln)
 
 /*
  * add_to_unowned_list -- link an SMgrRelation onto the unowned list
- *
- * Check remove_from_unowned_list()'s comments for performance
- * considerations.
  */
 static void
 add_to_unowned_list(SMgrRelation reln)
 {
-	/* place it at head of the list (to make smgrsetowner cheap) */
-	reln->next_unowned_reln = first_unowned_reln;
-	first_unowned_reln = reln;
+	dlist_push_head(&unowned_relns, &reln->unowned_node);
 }
 
 /*
@@ -253,31 +249,11 @@ add_to_unowned_list(SMgrRelation reln)
  *
  * If the reln is not present in the list, nothing happens.  Typically this
  * would be caller error, but there seems no reason to throw an error.
- *
- * In the worst case this could be rather slow; but in all the cases that seem
- * likely to be performance-critical, the reln being sought will actually be
- * first in the list.  Furthermore, the number of unowned relns touched in any
- * one transaction shouldn't be all that high typically.  So it doesn't seem
- * worth expending the additional space and management logic needed for a
- * doubly-linked list.
  */
 static void
 remove_from_unowned_list(SMgrRelation reln)
 {
-	SMgrRelation *link;
-	SMgrRelation cur;
-
-	for (link = &first_unowned_reln, cur = *link;
-		 cur != NULL;
-		 link = &cur->next_unowned_reln, cur = *link)
-	{
-		if (cur == reln)
-		{
-			*link = cur->next_unowned_reln;
-			cur->next_unowned_reln = NULL;
-			break;
-		}
-	}
+	dlist_delete(&reln->unowned_node);
 }
 
 /*
@@ -797,13 +773,17 @@ smgrpostckpt(void)
 void
 AtEOXact_SMgr(void)
 {
+	SMgrRelation reln;
+	dlist_mutable_iter iter;
+
 	/*
 	 * Zap all unowned SMgrRelations.  We rely on smgrclose() to remove each
 	 * one from the list.
 	 */
-	while (first_unowned_reln != NULL)
+	dlist_foreach_modify(iter, &unowned_relns)
 	{
-		Assert(first_unowned_reln->smgr_owner == NULL);
-		smgrclose(first_unowned_reln);
+		reln = dlist_container(SMgrRelationData, unowned_node, iter.cur);
+		Assert(reln->smgr_owner == NULL);
+		smgrclose(reln);
 	}
 }
diff --git a/src/include/storage/smgr.h b/src/include/storage/smgr.h
index 558e4d8518b..275fc6ce419 100644
--- a/src/include/storage/smgr.h
+++ b/src/include/storage/smgr.h
@@ -15,6 +15,7 @@
 #define SMGR_H
 
 #include "fmgr.h"
+#include "lib/ilist.h"
 #include "storage/block.h"
 #include "storage/relfilenode.h"
 
@@ -72,7 +73,7 @@ typedef struct SMgrRelationData
 	struct _MdfdVec *md_seg_fds[MAX_FORKNUM + 1];
 
 	/* if unowned, list link in list of all unowned SMgrRelations */
-	struct SMgrRelationData *next_unowned_reln;
+	dlist_node	unowned_node;
 } SMgrRelationData;
 
 typedef SMgrRelationData *SMgrRelation;
-- 
2.17.0

