Merge "fiemap_writer: Add a progress notification."
am: dec436438a
Change-Id: I580c5f8efd0e3fe8147f782fa0bfdc5c895153bb
This commit is contained in:
commit
3b7f64d323
3 changed files with 44 additions and 5 deletions
|
|
@ -220,7 +220,7 @@ static bool PerformFileChecks(const std::string& file_path, uint64_t file_size,
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool AllocateFile(int file_fd, const std::string& file_path, uint64_t blocksz,
|
static bool AllocateFile(int file_fd, const std::string& file_path, uint64_t blocksz,
|
||||||
uint64_t file_size) {
|
uint64_t file_size, std::function<bool(uint64_t, uint64_t)> on_progress) {
|
||||||
// Reserve space for the file on the file system and write it out to make sure the extents
|
// Reserve space for the file on the file system and write it out to make sure the extents
|
||||||
// don't come back unwritten. Return from this function with the kernel file offset set to 0.
|
// don't come back unwritten. Return from this function with the kernel file offset set to 0.
|
||||||
// If the filesystem is f2fs, then we also PIN the file on disk to make sure the blocks
|
// If the filesystem is f2fs, then we also PIN the file on disk to make sure the blocks
|
||||||
|
|
@ -245,12 +245,22 @@ static bool AllocateFile(int file_fd, const std::string& file_path, uint64_t blo
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int permille = -1;
|
||||||
for (; offset < file_size; offset += blocksz) {
|
for (; offset < file_size; offset += blocksz) {
|
||||||
if (!::android::base::WriteFully(file_fd, buffer.get(), blocksz)) {
|
if (!::android::base::WriteFully(file_fd, buffer.get(), blocksz)) {
|
||||||
PLOG(ERROR) << "Failed to write" << blocksz << " bytes at offset" << offset
|
PLOG(ERROR) << "Failed to write" << blocksz << " bytes at offset" << offset
|
||||||
<< " in file " << file_path;
|
<< " in file " << file_path;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// Don't invoke the callback every iteration - wait until a significant
|
||||||
|
// chunk (here, 1/1000th) of the data has been processed.
|
||||||
|
int new_permille = (static_cast<uint64_t>(offset) * 1000) / file_size;
|
||||||
|
if (new_permille != permille) {
|
||||||
|
if (on_progress && !on_progress(offset, file_size)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
permille = new_permille;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lseek64(file_fd, 0, SEEK_SET) < 0) {
|
if (lseek64(file_fd, 0, SEEK_SET) < 0) {
|
||||||
|
|
@ -264,6 +274,10 @@ static bool AllocateFile(int file_fd, const std::string& file_path, uint64_t blo
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send one last progress notification.
|
||||||
|
if (on_progress && !on_progress(file_size, file_size)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -412,7 +426,8 @@ static bool ReadFiemap(int file_fd, const std::string& file_path,
|
||||||
return last_extent_seen;
|
return last_extent_seen;
|
||||||
}
|
}
|
||||||
|
|
||||||
FiemapUniquePtr FiemapWriter::Open(const std::string& file_path, uint64_t file_size, bool create) {
|
FiemapUniquePtr FiemapWriter::Open(const std::string& file_path, uint64_t file_size, bool create,
|
||||||
|
std::function<bool(uint64_t, uint64_t)> progress) {
|
||||||
// if 'create' is false, open an existing file and do not truncate.
|
// if 'create' is false, open an existing file and do not truncate.
|
||||||
int open_flags = O_RDWR | O_CLOEXEC;
|
int open_flags = O_RDWR | O_CLOEXEC;
|
||||||
if (create) {
|
if (create) {
|
||||||
|
|
@ -474,7 +489,7 @@ FiemapUniquePtr FiemapWriter::Open(const std::string& file_path, uint64_t file_s
|
||||||
}
|
}
|
||||||
|
|
||||||
if (create) {
|
if (create) {
|
||||||
if (!AllocateFile(file_fd, abs_path, blocksz, file_size)) {
|
if (!AllocateFile(file_fd, abs_path, blocksz, file_size, std::move(progress))) {
|
||||||
LOG(ERROR) << "Failed to allocate file: " << abs_path << " of size: " << file_size
|
LOG(ERROR) << "Failed to allocate file: " << abs_path << " of size: " << file_size
|
||||||
<< " bytes";
|
<< " bytes";
|
||||||
cleanup(abs_path, create);
|
cleanup(abs_path, create);
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,25 @@ TEST_F(FiemapWriterTest, CheckFilePath) {
|
||||||
EXPECT_EQ(access(testfile.c_str(), F_OK), 0);
|
EXPECT_EQ(access(testfile.c_str(), F_OK), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(FiemapWriterTest, CheckProgress) {
|
||||||
|
std::vector<uint64_t> expected{
|
||||||
|
0,
|
||||||
|
4096,
|
||||||
|
};
|
||||||
|
size_t invocations = 0;
|
||||||
|
auto callback = [&](uint64_t done, uint64_t total) -> bool {
|
||||||
|
EXPECT_LT(invocations, expected.size());
|
||||||
|
EXPECT_EQ(done, expected[invocations]);
|
||||||
|
EXPECT_EQ(total, 4096);
|
||||||
|
invocations++;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto ptr = FiemapWriter::Open(testfile, 4096, true, std::move(callback));
|
||||||
|
EXPECT_NE(ptr, nullptr);
|
||||||
|
EXPECT_EQ(invocations, 2);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(FiemapWriterTest, CheckBlockDevicePath) {
|
TEST_F(FiemapWriterTest, CheckBlockDevicePath) {
|
||||||
FiemapUniquePtr fptr = FiemapWriter::Open(testfile, 4096);
|
FiemapUniquePtr fptr = FiemapWriter::Open(testfile, 4096);
|
||||||
EXPECT_EQ(fptr->size(), 4096);
|
EXPECT_EQ(fptr->size(), 4096);
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
@ -36,9 +37,13 @@ class FiemapWriter final {
|
||||||
public:
|
public:
|
||||||
// Factory method for FiemapWriter.
|
// Factory method for FiemapWriter.
|
||||||
// The method returns FiemapUniquePtr that contains all the data necessary to be able to write
|
// The method returns FiemapUniquePtr that contains all the data necessary to be able to write
|
||||||
// to the given file directly using raw block i/o.
|
// to the given file directly using raw block i/o. The optional progress callback will be
|
||||||
|
// invoked, if create is true, while the file is being initialized. It receives the bytes
|
||||||
|
// written and the number of total bytes. If the callback returns false, the operation will
|
||||||
|
// fail.
|
||||||
static FiemapUniquePtr Open(const std::string& file_path, uint64_t file_size,
|
static FiemapUniquePtr Open(const std::string& file_path, uint64_t file_size,
|
||||||
bool create = true);
|
bool create = true,
|
||||||
|
std::function<bool(uint64_t, uint64_t)> progress = {});
|
||||||
|
|
||||||
// Syncs block device writes.
|
// Syncs block device writes.
|
||||||
bool Flush() const;
|
bool Flush() const;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue