On 2016-05-02 22:00:14 +0200, Fabien COELHO wrote:
> I'm wondering that if _mdfd_openseg may return NULL, then ISTM that
> "opened_directly" should logically be false, because it was not opened?
> 
> If so, maybe consider something like:
> 
>       opened_directy = (seg != NULL);

Hm, don't care either way. Seems just as valid to understand it as the
attempt to directly open the segment.


> Also, I do not understand why this issue is raised by the flushing patch, it
> seems rather independent.

It's not the flushing itself, it's 72a98a639574d2e25ed94652848555900c81a799


> >I'm not sure this is the best way to go about this.  I can see valid
> >arguments for *always* using _mdfd_openseg() in mdsync(); and I'm
> >wondering whether we shouldn't make EXTENSION_* into a bitmask
> >(extend,extend_recovery,return_null,open_deleted).
> 
> I thought about that when I looked at the previous fix, but it seemed that
> not all combinations made sense.

Sure, but that's nothing unusual.  Here's an attempt at doing so - not
fully polished, just as a discussion point. I think it looks better.
Fabien, Robert, what do you think?

Greetings,

Andres Freund
diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
index 2981b41..f0c557f 100644
--- a/src/backend/storage/smgr/md.c
+++ b/src/backend/storage/smgr/md.c
@@ -163,23 +163,27 @@ static CycleCtr mdsync_cycle_ctr = 0;
 static CycleCtr mdckpt_cycle_ctr = 0;
 
 
-typedef enum					/* behavior for mdopen & _mdfd_getseg */
-{
-	/* ereport if segment not present, create in recovery */
-	EXTENSION_FAIL,
-	/* return NULL if not present, create in recovery */
-	EXTENSION_RETURN_NULL,
-	/* return NULL if not present */
-	EXTENSION_REALLY_RETURN_NULL,
-	/* create new segments as needed */
-	EXTENSION_CREATE
-} ExtensionBehavior;
+/*** behavior for mdopen & _mdfd_getseg ***/
+/* ereport if segment not present */
+#define EXTENSION_FAIL				(1 << 0)
+/* return NULL if segment not present */
+#define EXTENSION_RETURN_NULL		(1 << 1)
+/* create new segments as needed */
+#define EXTENSION_CREATE			(1 << 2)
+/* create new segments if needed during recovery */
+#define EXTENSION_CREATE_RECOVERY	(1 << 3)
+/*
+ * Allow opening deleted segments. Note that this is breaks mdnblocks() and
+ * related functionality - which currently is ok, because this is only
+ * required in the checkpointer which never uses mdnblocks().
+ */
+#define EXTENSION_OPEN_DELETED		(1 << 4)
+
 
 /* local routines */
 static void mdunlinkfork(RelFileNodeBackend rnode, ForkNumber forkNum,
 			 bool isRedo);
-static MdfdVec *mdopen(SMgrRelation reln, ForkNumber forknum,
-	   ExtensionBehavior behavior);
+static MdfdVec *mdopen(SMgrRelation reln, ForkNumber forknum, int behavior);
 static void register_dirty_segment(SMgrRelation reln, ForkNumber forknum,
 					   MdfdVec *seg);
 static void register_unlink(RelFileNodeBackend rnode);
@@ -189,7 +193,7 @@ static char *_mdfd_segpath(SMgrRelation reln, ForkNumber forknum,
 static MdfdVec *_mdfd_openseg(SMgrRelation reln, ForkNumber forkno,
 			  BlockNumber segno, int oflags);
 static MdfdVec *_mdfd_getseg(SMgrRelation reln, ForkNumber forkno,
-			 BlockNumber blkno, bool skipFsync, ExtensionBehavior behavior);
+			 BlockNumber blkno, bool skipFsync, int behavior);
 static BlockNumber _mdnblocks(SMgrRelation reln, ForkNumber forknum,
 		   MdfdVec *seg);
 
@@ -570,7 +574,7 @@ mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
  * invent one out of whole cloth.
  */
 static MdfdVec *
-mdopen(SMgrRelation reln, ForkNumber forknum, ExtensionBehavior behavior)
+mdopen(SMgrRelation reln, ForkNumber forknum, int behavior)
 {
 	MdfdVec    *mdfd;
 	char	   *path;
@@ -596,8 +600,7 @@ mdopen(SMgrRelation reln, ForkNumber forknum, ExtensionBehavior behavior)
 			fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, 0600);
 		if (fd < 0)
 		{
-			if ((behavior == EXTENSION_RETURN_NULL ||
-				 behavior == EXTENSION_REALLY_RETURN_NULL) &&
+			if ((behavior & EXTENSION_RETURN_NULL) &&
 				FILE_POSSIBLY_DELETED(errno))
 			{
 				pfree(path);
@@ -691,7 +694,7 @@ mdwriteback(SMgrRelation reln, ForkNumber forknum,
 					segnum_end;
 
 		v = _mdfd_getseg(reln, forknum, blocknum, false,
-						 EXTENSION_REALLY_RETURN_NULL);
+						 EXTENSION_RETURN_NULL);
 
 		/*
 		 * We might be flushing buffers of already removed relations, that's
@@ -737,7 +740,8 @@ mdread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
 										reln->smgr_rnode.node.relNode,
 										reln->smgr_rnode.backend);
 
-	v = _mdfd_getseg(reln, forknum, blocknum, false, EXTENSION_FAIL);
+	v = _mdfd_getseg(reln, forknum, blocknum, false,
+					 EXTENSION_FAIL | EXTENSION_CREATE_RECOVERY);
 
 	seekpos = (off_t) BLCKSZ *(blocknum % ((BlockNumber) RELSEG_SIZE));
 
@@ -812,7 +816,8 @@ mdwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
 										 reln->smgr_rnode.node.relNode,
 										 reln->smgr_rnode.backend);
 
-	v = _mdfd_getseg(reln, forknum, blocknum, skipFsync, EXTENSION_FAIL);
+	v = _mdfd_getseg(reln, forknum, blocknum, skipFsync,
+					 EXTENSION_FAIL | EXTENSION_CREATE_RECOVERY);
 
 	seekpos = (off_t) BLCKSZ *(blocknum % ((BlockNumber) RELSEG_SIZE));
 
@@ -1219,7 +1224,9 @@ mdsync(void)
 					/* Attempt to open and fsync the target segment */
 					seg = _mdfd_getseg(reln, forknum,
 							 (BlockNumber) segno * (BlockNumber) RELSEG_SIZE,
-									   false, EXTENSION_RETURN_NULL);
+									   false,
+									   EXTENSION_RETURN_NULL
+									   | EXTENSION_OPEN_DELETED);
 
 					INSTR_TIME_SET_CURRENT(sync_start);
 
@@ -1773,14 +1780,18 @@ _mdfd_openseg(SMgrRelation reln, ForkNumber forknum, BlockNumber segno,
  */
 static MdfdVec *
 _mdfd_getseg(SMgrRelation reln, ForkNumber forknum, BlockNumber blkno,
-			 bool skipFsync, ExtensionBehavior behavior)
+			 bool skipFsync, int behavior)
 {
 	MdfdVec    *v = mdopen(reln, forknum, behavior);
 	BlockNumber targetseg;
 	BlockNumber nextsegno;
 
+	/* some way to handle non-existant segments needs to be specified */
+	Assert(behavior &
+		   (EXTENSION_FAIL | EXTENSION_CREATE | EXTENSION_RETURN_NULL));
+
 	if (!v)
-		return NULL;			/* if EXTENSION_(REALLY_)RETURN_NULL */
+		return NULL;			/* if behavior & EXTENSION_RETURN_NULL */
 
 	targetseg = blkno / ((BlockNumber) RELSEG_SIZE);
 	for (nextsegno = 1; nextsegno <= targetseg; nextsegno++)
@@ -1795,8 +1806,8 @@ _mdfd_getseg(SMgrRelation reln, ForkNumber forknum, BlockNumber blkno,
 			if (nblocks > ((BlockNumber) RELSEG_SIZE))
 				elog(FATAL, "segment too big");
 
-			if (behavior == EXTENSION_CREATE ||
-				(InRecovery && behavior != EXTENSION_REALLY_RETURN_NULL))
+			if ((behavior & EXTENSION_CREATE) ||
+				(InRecovery && (behavior & EXTENSION_CREATE_RECOVERY)))
 			{
 				/*
 				 * Normally we will create new segments only if authorized by
@@ -1827,15 +1838,16 @@ _mdfd_getseg(SMgrRelation reln, ForkNumber forknum, BlockNumber blkno,
 				}
 				flags = O_CREAT;
 			}
-			else if (nblocks < ((BlockNumber) RELSEG_SIZE))
+			else if (!(behavior & EXTENSION_OPEN_DELETED) &&
+					 nblocks < ((BlockNumber) RELSEG_SIZE))
 			{
 				/*
-				 * When not extending, only open the next segment if the
-				 * current one is exactly RELSEG_SIZE.  If not (this branch),
-				 * either return NULL or fail.
+				 * When not extending or explicitly opening deleted segments,
+				 * only open the next segment if the current one is exactly
+				 * RELSEG_SIZE.  If not (this branch), either return NULL or
+				 * fail.
 				 */
-				if (behavior == EXTENSION_RETURN_NULL ||
-					behavior == EXTENSION_REALLY_RETURN_NULL)
+				if (behavior & EXTENSION_RETURN_NULL)
 				{
 					/*
 					 * Some callers discern between reasons for _mdfd_getseg()
@@ -1858,8 +1870,7 @@ _mdfd_getseg(SMgrRelation reln, ForkNumber forknum, BlockNumber blkno,
 
 			if (v->mdfd_chain == NULL)
 			{
-				if ((behavior == EXTENSION_RETURN_NULL ||
-					 behavior == EXTENSION_REALLY_RETURN_NULL) &&
+				if ((behavior & EXTENSION_RETURN_NULL) &&
 					FILE_POSSIBLY_DELETED(errno))
 					return NULL;
 				ereport(ERROR,
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to