Merge "fiemap_writer: Add a progress notification."

am: dec436438a

Change-Id: I580c5f8efd0e3fe8147f782fa0bfdc5c895153bb
This commit is contained in:
David Anderson 2019-01-22 12:52:16 -08:00 committed by android-build-merger
commit 3b7f64d323
3 changed files with 44 additions and 5 deletions

View File

@ -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,
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
// 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
@ -245,12 +245,22 @@ static bool AllocateFile(int file_fd, const std::string& file_path, uint64_t blo
return false;
}
int permille = -1;
for (; offset < file_size; offset += blocksz) {
if (!::android::base::WriteFully(file_fd, buffer.get(), blocksz)) {
PLOG(ERROR) << "Failed to write" << blocksz << " bytes at offset" << offset
<< " in file " << file_path;
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) {
@ -264,6 +274,10 @@ static bool AllocateFile(int file_fd, const std::string& file_path, uint64_t blo
return false;
}
// Send one last progress notification.
if (on_progress && !on_progress(file_size, file_size)) {
return false;
}
return true;
}
@ -412,7 +426,8 @@ static bool ReadFiemap(int file_fd, const std::string& file_path,
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.
int open_flags = O_RDWR | O_CLOEXEC;
if (create) {
@ -474,7 +489,7 @@ FiemapUniquePtr FiemapWriter::Open(const std::string& file_path, uint64_t file_s
}
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
<< " bytes";
cleanup(abs_path, create);

View File

@ -83,6 +83,25 @@ TEST_F(FiemapWriterTest, CheckFilePath) {
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) {
FiemapUniquePtr fptr = FiemapWriter::Open(testfile, 4096);
EXPECT_EQ(fptr->size(), 4096);

View File

@ -21,6 +21,7 @@
#include <sys/types.h>
#include <unistd.h>
#include <functional>
#include <string>
#include <vector>
@ -36,9 +37,13 @@ class FiemapWriter final {
public:
// Factory method for FiemapWriter.
// 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,
bool create = true);
bool create = true,
std::function<bool(uint64_t, uint64_t)> progress = {});
// Syncs block device writes.
bool Flush() const;