Skip to content

Commit 3f2c08b

Browse files
eklitzkeluke-jr
andcommitted
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 <[email protected]>
1 parent c44e734 commit 3f2c08b

File tree

3 files changed

+54
-4
lines changed

3 files changed

+54
-4
lines changed

src/streams.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <span.h>
1111
#include <support/allocators/zeroafterfree.h>
1212
#include <util/overflow.h>
13+
#include <util/system.h>
1314

1415
#include <algorithm>
1516
#include <assert.h>
@@ -616,11 +617,10 @@ class CBufferedFile
616617

617618
public:
618619
CBufferedFile(FILE* fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn)
619-
: nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), m_read_pos(0), nReadLimit(std::numeric_limits<uint64_t>::max()), nRewind(nRewindIn), vchBuf(nBufSize, std::byte{0})
620+
: nType(nTypeIn), nVersion(nVersionIn), src(AdviseSequential(fileIn)), nSrcPos(0), m_read_pos(0), nReadLimit(std::numeric_limits<uint64_t>::max()), nRewind(nRewindIn), vchBuf(nBufSize, std::byte{0})
620621
{
621622
if (nRewindIn >= nBufSize)
622623
throw std::ios_base::failure("Rewind limit must be less than buffer size");
623-
src = fileIn;
624624
}
625625

626626
~CBufferedFile()
@@ -638,7 +638,7 @@ class CBufferedFile
638638
void fclose()
639639
{
640640
if (src) {
641-
::fclose(src);
641+
CloseAndUncache(src);
642642
src = nullptr;
643643
}
644644
}

src/util/system.cpp

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1201,7 +1201,8 @@ void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
12011201
ftruncate(fileno(file), static_cast<off_t>(offset) + length);
12021202
#else
12031203
#if defined(HAVE_POSIX_FALLOCATE)
1204-
// Version using posix_fallocate
1204+
// Use posix_fallocate to advise the kernel how much data we have to write,
1205+
// if this system supports it.
12051206
off_t nEndPos = (off_t)offset + length;
12061207
if (0 == posix_fallocate(fileno(file), 0, nEndPos)) return;
12071208
#endif
@@ -1221,6 +1222,46 @@ void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
12211222
#endif
12221223
}
12231224

1225+
FILE* AdviseSequential(FILE *file) {
1226+
#if _POSIX_C_SOURCE >= 200112L
1227+
// Since this whole thing is advisory anyway, we can ignore any errors
1228+
// encountered up to and including the posix_fadvise call. However, we must
1229+
// rewind the file to the appropriate position if we've changed the seek
1230+
// offset.
1231+
if (file == nullptr) {
1232+
return nullptr;
1233+
}
1234+
const int fd = fileno(file);
1235+
if (fd == -1) {
1236+
return file;
1237+
}
1238+
const off_t start = lseek(fd, 0, SEEK_CUR);
1239+
if (start == -1) {
1240+
return file;
1241+
}
1242+
posix_fadvise(fd, start, 0, POSIX_FADV_WILLNEED);
1243+
posix_fadvise(fd, start, 0, POSIX_FADV_SEQUENTIAL);
1244+
#endif
1245+
return file;
1246+
}
1247+
1248+
int CloseAndUncache(FILE *file) {
1249+
#if _POSIX_C_SOURCE >= 200112L
1250+
// Ignore any errors up to and including the posix_fadvise call since it's
1251+
// advisory.
1252+
if (file != nullptr) {
1253+
const int fd = fileno(file);
1254+
if (fd != -1) {
1255+
const off_t end = lseek(fd, 0, SEEK_END);
1256+
if (end != (off_t)-1) {
1257+
posix_fadvise(fd, 0, end, POSIX_FADV_DONTNEED);
1258+
}
1259+
}
1260+
}
1261+
#endif
1262+
return fclose(file);
1263+
}
1264+
12241265
#ifdef WIN32
12251266
fs::path GetSpecialFolderPath(int nFolder, bool fCreate)
12261267
{

src/util/system.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,15 @@ bool CheckDiskSpace(const fs::path& dir, uint64_t additional_bytes = 0);
8989
*/
9090
std::streampos GetFileSize(const char* path, std::streamsize max = std::numeric_limits<std::streamsize>::max());
9191

92+
//! Return the original FILE* unchanged. On systems that support it,
93+
//! also advise the OS that the file will be accessed sequentially.
94+
FILE* AdviseSequential(FILE*);
95+
96+
//! Close a file and return the result of fclose(). On systems that
97+
//! support it, advise the OS to remove the file contents from the page
98+
//! cache (which can help on memory-constrained systems).
99+
int CloseAndUncache(FILE*);
100+
92101
/** Release all directory locks. This is used for unit testing only, at runtime
93102
* the global destructor will take care of the locks.
94103
*/

0 commit comments

Comments
 (0)