Truncate unused space on PosixWritableFile::Close()
Summary: Blocks allocated with fallocate will take extra space on disk even if they are unused and the file is close. Now we remove the extra blocks at the end of the file by calling `ftruncate`. Test Plan: added a test to env_test Reviewers: dhruba Reviewed By: dhruba CC: leveldb Differential Revision: https://reviews.facebook.net/D16647
This commit is contained in:
parent
9c8ad62691
commit
26ac5603f4
@ -678,10 +678,19 @@ class PosixWritableFile : public WritableFile {
|
||||
Status s;
|
||||
s = Flush(); // flush cache to OS
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
|
||||
TEST_KILL_RANDOM(rocksdb_kill_odds);
|
||||
|
||||
size_t block_size;
|
||||
size_t last_allocated_block;
|
||||
GetPreallocationStatus(&block_size, &last_allocated_block);
|
||||
if (last_allocated_block > 0) {
|
||||
// trim the extra space preallocated at the end of the file
|
||||
ftruncate(fd_, filesize_); // ignore errors
|
||||
}
|
||||
|
||||
if (close(fd_) < 0) {
|
||||
if (s.ok()) {
|
||||
s = IOError(filename_, errno);
|
||||
|
@ -12,6 +12,11 @@
|
||||
#include <iostream>
|
||||
#include <unordered_set>
|
||||
|
||||
#ifdef OS_LINUX
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "rocksdb/env.h"
|
||||
#include "port/port.h"
|
||||
#include "util/coding.h"
|
||||
@ -258,6 +263,41 @@ TEST(EnvPosixTest, RandomAccessUniqueID) {
|
||||
env_->DeleteFile(fname);
|
||||
}
|
||||
|
||||
// only works in linux platforms
|
||||
#ifdef ROCKSDB_FALLOCATE_PRESENT
|
||||
TEST(EnvPosixTest, AllocateTest) {
|
||||
std::string fname = GetOnDiskTestDir() + "/preallocate_testfile";
|
||||
EnvOptions soptions;
|
||||
soptions.use_mmap_writes = false;
|
||||
unique_ptr<WritableFile> wfile;
|
||||
ASSERT_OK(env_->NewWritableFile(fname, &wfile, soptions));
|
||||
|
||||
// allocate 100 MB
|
||||
size_t kPreallocateSize = 100 * 1024 * 1024;
|
||||
size_t kBlockSize = 512;
|
||||
size_t kPageSize = 4096;
|
||||
std::string data = "test";
|
||||
wfile->SetPreallocationBlockSize(kPreallocateSize);
|
||||
ASSERT_OK(wfile->Append(Slice(data)));
|
||||
ASSERT_OK(wfile->Flush());
|
||||
|
||||
struct stat f_stat;
|
||||
stat(fname.c_str(), &f_stat);
|
||||
ASSERT_EQ(data.size(), f_stat.st_size);
|
||||
// verify that blocks are preallocated
|
||||
ASSERT_EQ(kPreallocateSize / kBlockSize, f_stat.st_blocks);
|
||||
|
||||
// close the file, should deallocate the blocks
|
||||
wfile.reset();
|
||||
|
||||
stat(fname.c_str(), &f_stat);
|
||||
ASSERT_EQ(data.size(), f_stat.st_size);
|
||||
// verify that preallocated blocks were deallocated on file close
|
||||
size_t data_blocks_pages = ((data.size() + kPageSize - 1) / kPageSize);
|
||||
ASSERT_EQ(data_blocks_pages * kPageSize / kBlockSize, f_stat.st_blocks);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Returns true if any of the strings in ss are the prefix of another string.
|
||||
bool HasPrefix(const std::unordered_set<std::string>& ss) {
|
||||
for (const std::string& s: ss) {
|
||||
|
Loading…
Reference in New Issue
Block a user