Change PosixWritableFile Truncate to reseek to new end of file (#14088)

Summary:
Change PosixWritableFile's Truncate to the new end offset. This ensures that future appends are written with no holes or overwrites. RocksDB doesn't guarantee this in the FileSystem contract, and its left up to the specific implementation.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/14088

Reviewed By: cbi42

Differential Revision: D85786398

Pulled By: anand1976

fbshipit-source-id: 3520d9d6336362f5128a17bbf396297d821a5da3
This commit is contained in:
anand76
2025-10-29 12:58:03 -07:00
committed by meta-codesync[bot]
parent 1bb704b6e0
commit 0eb5b43b4f
4 changed files with 49 additions and 2 deletions
+1
View File
@@ -1406,6 +1406,7 @@ IOStatus PosixWritableFile::Truncate(uint64_t size, const IOOptions& /*opts*/,
filename_, errno);
} else {
filesize_ = size;
lseek(fd_, filesize_, SEEK_SET);
}
return s;
}
+43
View File
@@ -4,6 +4,7 @@
// (found in the LICENSE.Apache file in the root directory).
#include "test_util/testharness.h"
#include "util/random.h"
#ifdef ROCKSDB_LIB_IO_POSIX
#include "env/io_posix.h"
@@ -131,6 +132,48 @@ TEST_F(LogicalBlockSizeCacheTest, Ref) {
}
#endif
class PosixWritableFileTest : public testing::Test {};
TEST_F(PosixWritableFileTest, SeekAfterTruncate) {
std::shared_ptr<FileSystem> fs = FileSystem::Default();
std::string path =
test::PerThreadDBPath("PosixWritableFileTest_SeekAfterTruncate");
Random rnd(300);
std::unique_ptr<FSWritableFile> wfile;
ASSERT_OK(fs->NewWritableFile(path, FileOptions(), &wfile, nullptr));
ASSERT_OK(wfile->Append(rnd.RandomString(16384), IOOptions(), nullptr));
ASSERT_OK(wfile->Truncate(4096, IOOptions(), nullptr));
ASSERT_OK(wfile->Append(rnd.RandomString(4096), IOOptions(), nullptr));
ASSERT_OK(wfile->Close(IOOptions(), nullptr));
wfile.reset();
uint64_t size = 0;
ASSERT_OK(fs->GetFileSize(path, IOOptions(), &size, nullptr));
ASSERT_EQ(size, 8192);
ASSERT_OK(fs->DeleteFile(path, IOOptions(), nullptr));
}
TEST_F(PosixWritableFileTest, SeekAfterExtend) {
std::shared_ptr<FileSystem> fs = FileSystem::Default();
std::string path =
test::PerThreadDBPath("PosixWritableFileTest_SeekAfterTruncate");
Random rnd(300);
std::unique_ptr<FSWritableFile> wfile;
ASSERT_OK(fs->NewWritableFile(path, FileOptions(), &wfile, nullptr));
ASSERT_OK(wfile->Append(rnd.RandomString(4096), IOOptions(), nullptr));
ASSERT_OK(wfile->Truncate(8192, IOOptions(), nullptr));
ASSERT_OK(wfile->Append(rnd.RandomString(8192), IOOptions(), nullptr));
ASSERT_OK(wfile->Close(IOOptions(), nullptr));
wfile.reset();
uint64_t size = 0;
ASSERT_OK(fs->GetFileSize(path, IOOptions(), &size, nullptr));
ASSERT_EQ(size, 16384);
ASSERT_OK(fs->DeleteFile(path, IOOptions(), nullptr));
}
} // namespace ROCKSDB_NAMESPACE
#endif
+4 -2
View File
@@ -1166,8 +1166,10 @@ class FSWritableFile {
// Truncate is necessary to trim the file to the correct size
// before closing. It is not always possible to keep track of the file
// size due to whole pages writes. The behavior is undefined if called
// with other writes to follow.
// size due to whole pages writes. If called with other writes to follow,
// the behavior is file system specific. Posix will reseek to the new EOF.
// Other file systems may behave differently. Its the caller's
// responsibility to check the file system contract.
virtual IOStatus Truncate(uint64_t /*size*/, const IOOptions& /*options*/,
IODebugContext* /*dbg*/) {
return IOStatus::OK();
@@ -0,0 +1 @@
PosixWritableFile now repositions the seek pointer to the new end of file after a call to Truncate.