Try to use posix_fadvise with CBufferedFile

This primarily affects blocks when bitcoin is launched with -reindex, as
that causes the block files to be loaded as CBufferedFile objects one at
a time as the reindex progresses.

Co-Authored-By: Luke Dashjr <luke-jr+git@utopios.org>

Github-Pull: #14485
Rebased-From: 289e88b3133107f8a54184d8316559c7cf8ddb12
This commit is contained in:
Evan Klitzke 2018-02-20 11:46:52 -05:00 committed by Luke Dashjr
parent 1ad1438d91
commit 2bc60a4acb
3 changed files with 64 additions and 2 deletions

View File

@ -9,6 +9,7 @@
#include <serialize.h> #include <serialize.h>
#include <span.h> #include <span.h>
#include <support/allocators/zeroafterfree.h> #include <support/allocators/zeroafterfree.h>
#include <util/fs_helpers.h>
#include <util/overflow.h> #include <util/overflow.h>
#include <algorithm> #include <algorithm>
@ -457,6 +458,10 @@ public:
bool Commit(); bool Commit();
bool IsError(); bool IsError();
bool Truncate(unsigned size); bool Truncate(unsigned size);
void AdviseSequential()
{
::AdviseSequential(m_file);
}
}; };
/** Wrapper around an AutoFile& that implements a ring buffer to /** Wrapper around an AutoFile& that implements a ring buffer to
@ -520,11 +525,18 @@ public:
{ {
if (nRewindIn >= nBufSize) if (nRewindIn >= nBufSize)
throw std::ios_base::failure("Rewind limit must be less than buffer size"); throw std::ios_base::failure("Rewind limit must be less than buffer size");
m_src.AdviseSequential();
} }
~BufferedFile() { fclose(); } ~BufferedFile() { fclose(); }
int fclose() { return m_src.fclose(); } int fclose()
{
if (auto rel{m_src.release()}) {
return CloseAndUncache(rel);
}
return m_src.fclose();
}
//! check whether we're at the end of the source file //! check whether we're at the end of the source file
bool eof() const { bool eof() const {

View File

@ -212,7 +212,8 @@ void AllocateFileRange(FILE* file, unsigned int offset, unsigned int length)
ftruncate(fileno(file), static_cast<off_t>(offset) + length); ftruncate(fileno(file), static_cast<off_t>(offset) + length);
#else #else
#if defined(HAVE_POSIX_FALLOCATE) #if defined(HAVE_POSIX_FALLOCATE)
// Version using posix_fallocate // Use posix_fallocate to advise the kernel how much data we have to write,
// if this system supports it.
off_t nEndPos = (off_t)offset + length; off_t nEndPos = (off_t)offset + length;
if (0 == posix_fallocate(fileno(file), 0, nEndPos)) return; if (0 == posix_fallocate(fileno(file), 0, nEndPos)) return;
#endif #endif
@ -232,6 +233,46 @@ void AllocateFileRange(FILE* file, unsigned int offset, unsigned int length)
#endif #endif
} }
FILE* AdviseSequential(FILE *file) {
#if _POSIX_C_SOURCE >= 200112L
// Since this whole thing is advisory anyway, we can ignore any errors
// encountered up to and including the posix_fadvise call. However, we must
// rewind the file to the appropriate position if we've changed the seek
// offset.
if (file == nullptr) {
return nullptr;
}
const int fd = fileno(file);
if (fd == -1) {
return file;
}
const off_t start = lseek(fd, 0, SEEK_CUR);
if (start == -1) {
return file;
}
posix_fadvise(fd, start, 0, POSIX_FADV_WILLNEED);
posix_fadvise(fd, start, 0, POSIX_FADV_SEQUENTIAL);
#endif
return file;
}
int CloseAndUncache(FILE *file) {
#if _POSIX_C_SOURCE >= 200112L
// Ignore any errors up to and including the posix_fadvise call since it's
// advisory.
if (file != nullptr) {
const int fd = fileno(file);
if (fd != -1) {
const off_t end = lseek(fd, 0, SEEK_END);
if (end != (off_t)-1) {
posix_fadvise(fd, 0, end, POSIX_FADV_DONTNEED);
}
}
}
#endif
return std::fclose(file);
}
#ifdef WIN32 #ifdef WIN32
fs::path GetSpecialFolderPath(int nFolder, bool fCreate) fs::path GetSpecialFolderPath(int nFolder, bool fCreate)
{ {

View File

@ -55,6 +55,15 @@ bool CheckDiskSpace(const fs::path& dir, uint64_t additional_bytes = 0);
*/ */
std::streampos GetFileSize(const char* path, std::streamsize max = std::numeric_limits<std::streamsize>::max()); std::streampos GetFileSize(const char* path, std::streamsize max = std::numeric_limits<std::streamsize>::max());
//! Return the original FILE* unchanged. On systems that support it,
//! also advise the OS that the file will be accessed sequentially.
FILE* AdviseSequential(FILE*);
//! Close a file and return the result of fclose(). On systems that
//! support it, advise the OS to remove the file contents from the page
//! cache (which can help on memory-constrained systems).
int CloseAndUncache(FILE*);
/** Release all directory locks. This is used for unit testing only, at runtime /** Release all directory locks. This is used for unit testing only, at runtime
* the global destructor will take care of the locks. * the global destructor will take care of the locks.
*/ */