Merge #14501: Fix possible data race when committing block files

ef712298c3 util: Check for file being NULL in DirectoryCommit (Luke Dashjr)
4574904038 Fix possible data race when committing block files (Evan Klitzke)
220bb16cbe util: Introduce DirectoryCommit commit function to sync a directory (Evan Klitzke)
ce5cbaea63 util.h: Document FileCommit function (Evan Klitzke)
844d650eea util: Prefer Mac-specific F_FULLSYNC over fdatasync in FileCommit (Evan Klitzke)
f6cec0bcaf util: Refactor FileCommit from an #if sequence nested in #else, to a sequence of #elif (Evan Klitzke)

Pull request description:

  Reviving #12696

ACKs for top commit:
  laanwj:
    Code review ACK ef712298c3

Tree-SHA512: 07d650990ef4c18d645dee3f9a199a940683ad17557d79d93979a76c4e710d8d70e6eae01d1a5991494a24a7654eb7db868be0c34a31e70b2509945d95bc9cce
pull/826/head
Wladimir J. van der Laan 4 years ago
commit 86a8b35f32
No known key found for this signature in database
GPG Key ID: 1E4AED62986CD25D

@ -92,6 +92,7 @@ bool FlatFileSeq::Flush(const FlatFilePos& pos, bool finalize)
fclose(file); fclose(file);
return error("%s: failed to commit file %d", __func__, pos.nFile); return error("%s: failed to commit file %d", __func__, pos.nFile);
} }
DirectoryCommit(m_dir);
fclose(file); fclose(file);
return true; return true;

@ -1047,27 +1047,36 @@ bool FileCommit(FILE *file)
LogPrintf("%s: FlushFileBuffers failed: %d\n", __func__, GetLastError()); LogPrintf("%s: FlushFileBuffers failed: %d\n", __func__, GetLastError());
return false; return false;
} }
#else
#if HAVE_FDATASYNC
if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync
LogPrintf("%s: fdatasync failed: %d\n", __func__, errno);
return false;
}
#elif defined(MAC_OSX) && defined(F_FULLFSYNC) #elif defined(MAC_OSX) && defined(F_FULLFSYNC)
if (fcntl(fileno(file), F_FULLFSYNC, 0) == -1) { // Manpage says "value other than -1" is returned on success if (fcntl(fileno(file), F_FULLFSYNC, 0) == -1) { // Manpage says "value other than -1" is returned on success
LogPrintf("%s: fcntl F_FULLFSYNC failed: %d\n", __func__, errno); LogPrintf("%s: fcntl F_FULLFSYNC failed: %d\n", __func__, errno);
return false; return false;
} }
#elif HAVE_FDATASYNC
if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync
LogPrintf("%s: fdatasync failed: %d\n", __func__, errno);
return false;
}
#else #else
if (fsync(fileno(file)) != 0 && errno != EINVAL) { if (fsync(fileno(file)) != 0 && errno != EINVAL) {
LogPrintf("%s: fsync failed: %d\n", __func__, errno); LogPrintf("%s: fsync failed: %d\n", __func__, errno);
return false; return false;
} }
#endif #endif
#endif
return true; return true;
} }
void DirectoryCommit(const fs::path &dirname)
{
#ifndef WIN32
FILE* file = fsbridge::fopen(dirname, "r");
if (file) {
fsync(fileno(file));
fclose(file);
}
#endif
}
bool TruncateFile(FILE *file, unsigned int length) { bool TruncateFile(FILE *file, unsigned int length) {
#if defined(WIN32) #if defined(WIN32)
return _chsize(_fileno(file), length) == 0; return _chsize(_fileno(file), length) == 0;

@ -56,7 +56,19 @@ bool error(const char* fmt, const Args&... args)
} }
void PrintExceptionContinue(const std::exception *pex, const char* pszThread); void PrintExceptionContinue(const std::exception *pex, const char* pszThread);
/**
* Ensure file contents are fully committed to disk, using a platform-specific
* feature analogous to fsync().
*/
bool FileCommit(FILE *file); bool FileCommit(FILE *file);
/**
* Sync directory contents. This is required on some environments to ensure that
* newly created files are committed to disk.
*/
void DirectoryCommit(const fs::path &dirname);
bool TruncateFile(FILE *file, unsigned int length); bool TruncateFile(FILE *file, unsigned int length);
int RaiseFileDescriptorLimit(int nMinFD); int RaiseFileDescriptorLimit(int nMinFD);
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length); void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);

Loading…
Cancel
Save