From 3eb77eba5a51780d5cf52cd66a9844cd4d26feb0 Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Thu, 4 Apr 2019 21:56:03 +1300 Subject: Refactor the fsync queue for wider use. Previously, md.c and checkpointer.c were tightly integrated so that fsync calls could be handed off and processed in the background. Introduce a system of callbacks and file tags, so that other modules can hand off fsync work in the same way. For now only md.c uses the new interface, but other users are being proposed. Since there may be use cases that are not strictly SMGR implementations, use a new function table for sync handlers rather than extending the traditional SMGR one. Instead of using a bitmapset of segment numbers for each RelFileNode in the checkpointer's hash table, make the segment number part of the key. This requires sending explicit "forget" requests for every segment individually when relations are dropped, but suits the file layout schemes of proposed future users better (ie sparse or high segment numbers). Author: Shawn Debnath and Thomas Munro Reviewed-by: Thomas Munro, Andres Freund Discussion: https://postgr.es/m/CAEepm=2gTANm=e3ARnJT=n0h8hf88wqmaZxk0JYkxw+b21fNrw@mail.gmail.com --- src/backend/postmaster/checkpointer.c | 40 ++++++++++++----------------------- 1 file changed, 14 insertions(+), 26 deletions(-) (limited to 'src/backend/postmaster') diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index c2411081a5..d303ce3679 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -108,10 +108,8 @@ */ typedef struct { - RelFileNode rnode; - ForkNumber forknum; - BlockNumber segno; /* see md.c for special values */ - /* might add a real request-type field later; not needed yet */ + SyncRequestType type; /* request type */ + FileTag ftag; /* file identifier */ } CheckpointerRequest; typedef struct @@ -349,7 +347,7 @@ CheckpointerMain(void) /* * Process any requests or signals received recently. */ - AbsorbFsyncRequests(); + AbsorbSyncRequests(); if (got_SIGHUP) { @@ -684,7 +682,7 @@ CheckpointWriteDelay(int flags, double progress) UpdateSharedMemoryConfig(); } - AbsorbFsyncRequests(); + AbsorbSyncRequests(); absorb_counter = WRITES_PER_ABSORB; CheckArchiveTimeout(); @@ -709,7 +707,7 @@ CheckpointWriteDelay(int flags, double progress) * operations even when we don't sleep, to prevent overflow of the * fsync request queue. */ - AbsorbFsyncRequests(); + AbsorbSyncRequests(); absorb_counter = WRITES_PER_ABSORB; } } @@ -1084,7 +1082,7 @@ RequestCheckpoint(int flags) } /* - * ForwardFsyncRequest + * ForwardSyncRequest * Forward a file-fsync request from a backend to the checkpointer * * Whenever a backend is compelled to write directly to a relation @@ -1093,15 +1091,6 @@ RequestCheckpoint(int flags) * is dirty and must be fsync'd before next checkpoint. We also use this * opportunity to count such writes for statistical purposes. * - * This functionality is only supported for regular (not backend-local) - * relations, so the rnode argument is intentionally RelFileNode not - * RelFileNodeBackend. - * - * segno specifies which segment (not block!) of the relation needs to be - * fsync'd. (Since the valid range is much less than BlockNumber, we can - * use high values for special flags; that's all internal to md.c, which - * see for details.) - * * To avoid holding the lock for longer than necessary, we normally write * to the requests[] queue without checking for duplicates. The checkpointer * will have to eliminate dups internally anyway. However, if we discover @@ -1113,7 +1102,7 @@ RequestCheckpoint(int flags) * let the backend know by returning false. */ bool -ForwardFsyncRequest(RelFileNode rnode, ForkNumber forknum, BlockNumber segno) +ForwardSyncRequest(const FileTag *ftag, SyncRequestType type) { CheckpointerRequest *request; bool too_full; @@ -1122,7 +1111,7 @@ ForwardFsyncRequest(RelFileNode rnode, ForkNumber forknum, BlockNumber segno) return false; /* probably shouldn't even get here */ if (AmCheckpointerProcess()) - elog(ERROR, "ForwardFsyncRequest must not be called in checkpointer"); + elog(ERROR, "ForwardSyncRequest must not be called in checkpointer"); LWLockAcquire(CheckpointerCommLock, LW_EXCLUSIVE); @@ -1151,9 +1140,8 @@ ForwardFsyncRequest(RelFileNode rnode, ForkNumber forknum, BlockNumber segno) /* OK, insert request */ request = &CheckpointerShmem->requests[CheckpointerShmem->num_requests++]; - request->rnode = rnode; - request->forknum = forknum; - request->segno = segno; + request->ftag = *ftag; + request->type = type; /* If queue is more than half full, nudge the checkpointer to empty it */ too_full = (CheckpointerShmem->num_requests >= @@ -1284,8 +1272,8 @@ CompactCheckpointerRequestQueue(void) } /* - * AbsorbFsyncRequests - * Retrieve queued fsync requests and pass them to local smgr. + * AbsorbSyncRequests + * Retrieve queued sync requests and pass them to sync mechanism. * * This is exported because it must be called during CreateCheckPoint; * we have to be sure we have accepted all pending requests just before @@ -1293,7 +1281,7 @@ CompactCheckpointerRequestQueue(void) * non-checkpointer processes, do nothing if not checkpointer. */ void -AbsorbFsyncRequests(void) +AbsorbSyncRequests(void) { CheckpointerRequest *requests = NULL; CheckpointerRequest *request; @@ -1335,7 +1323,7 @@ AbsorbFsyncRequests(void) LWLockRelease(CheckpointerCommLock); for (request = requests; n > 0; request++, n--) - RememberFsyncRequest(request->rnode, request->forknum, request->segno); + RememberSyncRequest(&request->ftag, request->type); END_CRIT_SECTION(); -- cgit v1.2.1