1
0
Fork 0

Use fallocate() instead of posix_fallocate()

On systems that do not support fallocate() (NFS, BeeGFS),
posix_fallocate() emulates the allocation by writing zeros
which is extremely inefficient.

In these cases we would rather skip-preallocation and
simply use ftruncate() to set the file size without allocating.
This commit is contained in:
Joris van Rantwijk 2022-07-03 10:40:32 +02:00
parent 5c24788b09
commit 35ae98cc65
1 changed files with 59 additions and 28 deletions

View File

@ -391,6 +391,9 @@ protected:
} }
} }
/** Set file size and try to preallocate disk space. */
void preallocate(const std::string& filename, uint64_t new_size);
/** File descriptor. */ /** File descriptor. */
int m_fd; int m_fd;
@ -454,6 +457,60 @@ void BinaryFile::write(
} }
} }
// Set file size and try to preallocate disk space.
void BinaryFile::preallocate(
const std::string& filename,
uint64_t new_size)
{
// Note: posix_fallocate() MUST NOT be used. On systems that do not
// support fallocate(), posix_fallocate() would silently revert
// to writing zeros which is extremely slow.
//
// Instead, we use the Linux-specific call fallocate().
//
int ret = EOPNOTSUPP;
#ifdef __linux__
ret = fallocate(m_fd, 0, 0, new_size);
if (ret != 0) {
if (errno == EOPNOTSUPP) {
fprintf(stderr,
"WARNING: fallocate() not supported for '%s'\n",
filename.c_str());
} else {
int errnum = errno;
// Delete empty output file.
unlink(filename.c_str());
throw std::system_error(
errnum,
std::system_category(),
"Can not allocate space in '" + filename + "'");
}
}
#endif // defined(__linux__)
if (ret != 0) {
// If fallocate() is unavailable or failed, use ftruncate() to
// set the file size.
ret = ftruncate(m_fd, new_size);
if (ret != 0) {
int errnum = errno;
// Delete empty output file.
unlink(filename.c_str());
throw std::system_error(
errnum,
std::system_category(),
"Can not set size of '" + filename + "'");
}
}
m_file_size = new_size;
}
/** Binary input file. */ /** Binary input file. */
class BinaryInputFile : public BinaryFile class BinaryInputFile : public BinaryFile
@ -498,20 +555,7 @@ public:
"Can not create output file"); "Can not create output file");
} }
int ret = posix_fallocate(m_fd, 0, new_size); preallocate(filename, new_size);
if (ret != 0) {
int errnum = errno;
// Delete empty output file.
unlink(filename.c_str());
throw std::system_error(
errnum,
std::system_category(),
"Can not allocate space in output file");
}
m_file_size = new_size;
} }
}; };
@ -546,20 +590,7 @@ public:
"Can not create temporary file"); "Can not create temporary file");
} }
int ret = posix_fallocate(m_fd, 0, new_size); preallocate(filename_buf.data(), new_size);
if (ret != 0) {
int errnum = errno;
// Delete temporary file.
unlink(filename_buf.data());
throw std::system_error(
errnum,
std::system_category(),
"Can not allocate space in temporary file");
}
m_file_size = new_size;
// Delete the temporary file. // Delete the temporary file.
// Since the file is still open, it will continue to exist on disk // Since the file is still open, it will continue to exist on disk