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