diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2021-03-19 01:08:59 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2021-03-19 01:08:59 +0000 |
commit | 66a56cd8313b9cf1b17cc80cd5524020e72e8253 (patch) | |
tree | 4b7618b104f15680f198aec4fa1ed9124a43b04d | |
parent | 1250575b00c158819cdc6d3fe19a2b3dd7ce2102 (diff) | |
parent | e22a42fdcc0153b257011f8db7242c13de70e8ea (diff) | |
download | incremental_delivery-66a56cd8313b9cf1b17cc80cd5524020e72e8253.tar.gz |
Snap for 7219286 from e22a42fdcc0153b257011f8db7242c13de70e8ea to sc-d1-release
Change-Id: Icb1925628f02dea17dc0de06d9f82f8069994798
-rw-r--r-- | incfs/incfs.cpp | 105 | ||||
-rw-r--r-- | incfs/include/incfs.h | 1 | ||||
-rw-r--r-- | incfs/include/incfs_inline.h | 14 | ||||
-rw-r--r-- | incfs/include/incfs_ndk.h | 6 | ||||
-rw-r--r-- | incfs/path.h | 5 | ||||
-rw-r--r-- | incfs/tests/incfs_test.cpp | 7 |
6 files changed, 126 insertions, 12 deletions
diff --git a/incfs/incfs.cpp b/incfs/incfs.cpp index ced09be..5752d4c 100644 --- a/incfs/incfs.cpp +++ b/incfs/incfs.cpp @@ -50,6 +50,7 @@ #include <mutex> #include <optional> #include <string_view> +#include <unordered_set> #include "MountRegistry.h" #include "path.h" @@ -900,7 +901,7 @@ IncFsErrorCode IncFs_GetMetadataById(const IncFsControl* control, IncFsFileId fi if (root.empty()) { return -EINVAL; } - auto name = path::join(root, kIndexDir, toStringImpl(fileId)); + auto name = path::join(root, INCFS_INDEX_NAME, toStringImpl(fileId)); return getMetadata(details::c_str(name), buffer, bufferSize); } @@ -963,7 +964,7 @@ IncFsErrorCode IncFs_GetSignatureById(const IncFsControl* control, IncFsFileId f if (root.empty()) { return -EINVAL; } - auto file = path::join(root, kIndexDir, toStringImpl(fileId)); + auto file = path::join(root, INCFS_INDEX_NAME, toStringImpl(fileId)); auto fd = openRaw(file); if (fd < 0) { return fd.get(); @@ -1208,7 +1209,7 @@ IncFsFd IncFs_OpenForSpecialOpsById(const IncFsControl* control, IncFsFileId id) if (root.empty()) { return -EINVAL; } - auto name = path::join(root, kIndexDir, toStringImpl(id)); + auto name = path::join(root, INCFS_INDEX_NAME, toStringImpl(id)); return openForSpecialOps(cmd, makeCommandPath(root, name).c_str()); } @@ -1475,6 +1476,98 @@ IncFsErrorCode IncFs_IsFullyLoaded(int fd) { return -ENODATA; } +static IncFsErrorCode isEverythingLoadedV2(const IncFsControl* control) { + const auto root = rootForCmd(control->cmd); + if (root.empty()) { + return -EINVAL; + } + const auto dirPath = path::join(root, INCFS_INCOMPLETE_NAME); + const auto dir = path::openDir(dirPath.c_str()); + if (!dir) { + return -EINVAL; + } + while (const auto entry = ::readdir(dir.get())) { + if (entry->d_type != DT_REG) { + continue; + } + // any file in this directory has to be incomplete + return -ENODATA; + } + return 0; +} + +static bool isInternalEntry(dirent* entry) { + const auto name = std::string_view(entry->d_name); + switch (entry->d_type) { + case DT_REG: + return name == INCFS_PENDING_READS_FILENAME || name == INCFS_LOG_FILENAME || + name == INCFS_BLOCKS_WRITTEN_FILENAME; + case DT_DIR: + return name == INCFS_INDEX_NAME || name == INCFS_INCOMPLETE_NAME; + } + return false; +} + +static IncFsErrorCode isEverythingLoadedSlow(const IncFsControl* control) { + auto root = rootForCmd(control->cmd); + if (root.empty()) { + return -EINVAL; + } + // no special API for this version of the driver, need to recurse and check each file separately + std::vector<std::string> todo{std::move(root)}; + std::unordered_set<ino_t> knownNodes; + do { + const auto dirPath = std::move(todo.back()); + todo.pop_back(); + const auto dir = path::openDir(dirPath.c_str()); + if (!dir) { + return -EINVAL; + } + while (const auto entry = ::readdir(dir.get())) { + if (isInternalEntry(entry)) { + continue; + } + if (knownNodes.find(entry->d_ino) != knownNodes.end()) { + continue; + } + if (entry->d_type == DT_DIR) { + todo.emplace_back(path::join(dirPath, entry->d_name)); + } else if (entry->d_type != DT_REG) { + continue; // no idea what this entry is, but don't care either + } else { + auto name = path::join(dirPath, entry->d_name); + auto fd = ab::unique_fd(openForSpecialOps(control->cmd, name.c_str())); + if (fd.get() < 0) { + PLOG(WARNING) << "Can't open " << entry->d_name << " for special ops"; + return fd.release(); + } + auto checkFullyLoaded = IncFs_IsFullyLoaded(fd.get()); + if (checkFullyLoaded == 0 || checkFullyLoaded == -EOPNOTSUPP || + checkFullyLoaded == -ENOTSUP || checkFullyLoaded == -ENOENT) { + // special kinds of files may return an error here, but it still means + // _this_ file is OK - you simply need to check the rest. E.g. can't query + // a mapped file, instead need to check its parent. + knownNodes.insert(entry->d_ino); + continue; + } + return checkFullyLoaded; + } + } + } while (!todo.empty()); + + return 0; +} + +IncFsErrorCode IncFs_IsEverythingFullyLoaded(const IncFsControl* control) { + if (!control) { + return -EINVAL; + } + if (features() & Features::v2) { + return isEverythingLoadedV2(control); + } + return isEverythingLoadedSlow(control); +} + IncFsErrorCode IncFs_SetUidReadTimeouts(const IncFsControl* control, const IncFsUidReadTimeouts timeouts[], size_t count) { if (!control) { @@ -1561,7 +1654,7 @@ IncFsErrorCode IncFs_GetFileBlockCountById(const IncFsControl* control, IncFsFil if (root.empty()) { return -EINVAL; } - auto name = path::join(root, kIndexDir, toStringImpl(id)); + auto name = path::join(root, INCFS_INDEX_NAME, toStringImpl(id)); auto fd = openRaw(name); if (fd < 0) { return fd.get(); @@ -1601,7 +1694,7 @@ IncFsErrorCode IncFs_ListIncompleteFiles(const IncFsControl* control, IncFsFileI if (root.empty()) { return -EINVAL; } - auto dirPath = path::join(root, kIncompleteDir); + auto dirPath = path::join(root, INCFS_INCOMPLETE_NAME); auto dir = path::openDir(dirPath.c_str()); if (!dir) { return -EINVAL; @@ -1647,7 +1740,7 @@ IncFsErrorCode IncFs_WaitForLoadingComplete(const IncFsControl* control, int32_t } // first create all the watches, and only then list existing files to prevent races - auto dirPath = path::join(root, kIncompleteDir); + auto dirPath = path::join(root, INCFS_INCOMPLETE_NAME); int watchFd = inotify_add_watch(fd.get(), dirPath.c_str(), IN_DELETE); if (watchFd < 0) { return -errno; diff --git a/incfs/include/incfs.h b/incfs/include/incfs.h index c60609b..eb31ec5 100644 --- a/incfs/include/incfs.h +++ b/incfs/include/incfs.h @@ -263,6 +263,7 @@ WaitResult waitForLoadingComplete(const Control& control, std::chrono::milliseco enum class LoadingState { Full, MissingBlocks }; LoadingState isFullyLoaded(int fd); +LoadingState isEverythingFullyLoaded(const Control& control); static const auto kTrimReservedSpace = kIncFsTrimReservedSpace; ErrorCode reserveSpace(const Control& control, std::string_view path, Size size); diff --git a/incfs/include/incfs_inline.h b/incfs/include/incfs_inline.h index a3ac348..7a0f53e 100644 --- a/incfs/include/incfs_inline.h +++ b/incfs/include/incfs_inline.h @@ -28,9 +28,6 @@ constexpr char kIdAttrName[] = INCFS_XATTR_ID_NAME; constexpr char kSizeAttrName[] = INCFS_XATTR_SIZE_NAME; constexpr char kMetadataAttrName[] = INCFS_XATTR_METADATA_NAME; -constexpr char kIndexDir[] = ".index"; -constexpr char kIncompleteDir[] = ".incomplete"; - namespace details { class CStrWrapper { @@ -338,8 +335,7 @@ inline std::pair<ErrorCode, FilledRanges> getFilledRanges(int fd, FilledRanges&& return {res, FilledRanges(std::move(buffer), rawRanges)}; } -inline LoadingState isFullyLoaded(int fd) { - auto res = IncFs_IsFullyLoaded(fd); +inline LoadingState toLoadingState(IncFsErrorCode res) { switch (res) { case 0: return LoadingState::Full; @@ -350,6 +346,14 @@ inline LoadingState isFullyLoaded(int fd) { } } +inline LoadingState isFullyLoaded(int fd) { + return toLoadingState(IncFs_IsFullyLoaded(fd)); +} + +inline LoadingState isEverythingFullyLoaded(const Control& control) { + return toLoadingState(IncFs_IsEverythingFullyLoaded(control)); +} + inline std::optional<std::vector<FileId>> listIncompleteFiles(const Control& control) { std::vector<FileId> ids(32); size_t count = ids.size(); diff --git a/incfs/include/incfs_ndk.h b/incfs/include/incfs_ndk.h index 46e3caa..2bc3c84 100644 --- a/incfs/include/incfs_ndk.h +++ b/incfs/include/incfs_ndk.h @@ -276,6 +276,12 @@ IncFsErrorCode IncFs_GetFilledRangesStartingFrom(int fd, int startBlockIndex, In // <0 - error from the syscall. IncFsErrorCode IncFs_IsFullyLoaded(int fd); +// Check if all files on the mount are fully loaded. Return codes: +// 0 - fully loaded, +// -ENODATA - some blocks are missing, +// <0 - error from the syscall. +IncFsErrorCode IncFs_IsEverythingFullyLoaded(const IncFsControl* control); + // Reserve |size| bytes for the file. Trims reserved space to the current file size when |size = -1| static const IncFsSize kIncFsTrimReservedSpace = -1; IncFsErrorCode IncFs_ReserveSpace(const IncFsControl* control, const char* path, IncFsSize size); diff --git a/incfs/path.h b/incfs/path.h index f312d17..46e9041 100644 --- a/incfs/path.h +++ b/incfs/path.h @@ -60,7 +60,10 @@ bool startsWith(std::string_view path, std::string_view prefix); bool endsWith(std::string_view path, std::string_view prefix); inline auto openDir(const char* path) { - auto dir = std::unique_ptr<DIR, decltype(&closedir)>(::opendir(path), &::closedir); + struct closer { + void operator()(DIR* d) const { ::closedir(d); } + }; + auto dir = std::unique_ptr<DIR, closer>(::opendir(path)); return dir; } diff --git a/incfs/tests/incfs_test.cpp b/incfs/tests/incfs_test.cpp index d758a63..7b197ff 100644 --- a/incfs/tests/incfs_test.cpp +++ b/incfs/tests/incfs_test.cpp @@ -497,6 +497,7 @@ TEST_F(IncFsTest, GetFilledRanges) { EXPECT_EQ(0, filledRanges.hashRangesCount); EXPECT_EQ(-ENODATA, IncFs_IsFullyLoaded(fd.get())); + EXPECT_EQ(-ENODATA, IncFs_IsEverythingFullyLoaded(control_)); // write one block std::vector<char> data(INCFS_DATA_FILE_BLOCK_SIZE); @@ -530,6 +531,7 @@ TEST_F(IncFsTest, GetFilledRanges) { EXPECT_EQ(0, filledRanges.hashRangesCount); EXPECT_EQ(-ENODATA, IncFs_IsFullyLoaded(fd.get())); + EXPECT_EQ(-ENODATA, IncFs_IsEverythingFullyLoaded(control_)); // append one more block next to the first one block.pageIndex = 1; @@ -558,6 +560,7 @@ TEST_F(IncFsTest, GetFilledRanges) { EXPECT_EQ(0, filledRanges.hashRangesCount); EXPECT_EQ(-ENODATA, IncFs_IsFullyLoaded(fd.get())); + EXPECT_EQ(-ENODATA, IncFs_IsEverythingFullyLoaded(control_)); // now create a gap between filled blocks block.pageIndex = 3; @@ -598,6 +601,7 @@ TEST_F(IncFsTest, GetFilledRanges) { EXPECT_EQ(0, filledRanges.hashRangesCount); EXPECT_EQ(-ENODATA, IncFs_IsFullyLoaded(fd.get())); + EXPECT_EQ(-ENODATA, IncFs_IsEverythingFullyLoaded(control_)); // at last fill the whole file and make sure we report it as having a single range block.pageIndex = 2; @@ -625,6 +629,7 @@ TEST_F(IncFsTest, GetFilledRanges) { EXPECT_EQ(0, filledRanges.hashRangesCount); EXPECT_EQ(0, IncFs_IsFullyLoaded(fd.get())); + EXPECT_EQ(0, IncFs_IsEverythingFullyLoaded(control_)); } TEST_F(IncFsTest, GetFilledRangesSmallBuffer) { @@ -756,6 +761,7 @@ TEST_F(IncFsTest, GetFilledRangesCpp) { EXPECT_EQ(size_t(1), ranges3.hashRanges()[1].size()); EXPECT_EQ(LoadingState::MissingBlocks, isFullyLoaded(fd.get())); + EXPECT_EQ(LoadingState::MissingBlocks, isEverythingFullyLoaded(control_)); { std::vector<char> data(INCFS_DATA_FILE_BLOCK_SIZE); @@ -775,6 +781,7 @@ TEST_F(IncFsTest, GetFilledRangesCpp) { } } EXPECT_EQ(LoadingState::Full, isFullyLoaded(fd.get())); + EXPECT_EQ(LoadingState::Full, isEverythingFullyLoaded(control_)); } TEST_F(IncFsTest, BlocksWritten) { |