diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c index f4374d077b..f19aedbdd0 100644 --- a/src/backend/storage/smgr/md.c +++ b/src/backend/storage/smgr/md.c @@ -1150,10 +1150,8 @@ mdsync(void) * The bitmap manipulations are slightly tricky, because we can call * AbsorbFsyncRequests() inside the loop and that could result in * bms_add_member() modifying and even re-palloc'ing the bitmapsets. - * This is okay because we unlink each bitmapset from the hashtable - * entry before scanning it. That means that any incoming fsync - * requests will be processed now if they reach the table before we - * begin to scan their fork. + * So we detach it, but if we fail we'll merge it with any new + * requests that have arrived in the meantime. */ for (forknum = 0; forknum <= MAX_FORKNUM; forknum++) { @@ -1163,7 +1161,8 @@ mdsync(void) entry->requests[forknum] = NULL; entry->canceled[forknum] = false; - while ((segno = bms_first_member(requests)) >= 0) + segno = -1; + while ((segno = bms_next_member(requests, segno)) >= 0) { int failures; @@ -1244,6 +1243,7 @@ mdsync(void) longest = elapsed; total_elapsed += elapsed; processed++; + requests = bms_del_member(requests, segno); if (log_checkpoints) elog(DEBUG1, "checkpoint sync: number=%d file=%s time=%.3f msec", processed, @@ -1272,10 +1272,23 @@ mdsync(void) */ if (!FILE_POSSIBLY_DELETED(errno) || failures > 0) + { + Bitmapset *new_requests; + + /* + * We need to merge these unsatisfied requests with + * any others that have arrived since we started. + */ + new_requests = entry->requests[forknum]; + entry->requests[forknum] = + bms_join(new_requests, requests); + + errno = save_errno; ereport(ERROR, (errcode_for_file_access(), errmsg("could not fsync file \"%s\": %m", path))); + } else ereport(DEBUG1, (errcode_for_file_access(),