summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2021-03-19 01:08:59 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2021-03-19 01:08:59 +0000
commit66a56cd8313b9cf1b17cc80cd5524020e72e8253 (patch)
tree4b7618b104f15680f198aec4fa1ed9124a43b04d
parent1250575b00c158819cdc6d3fe19a2b3dd7ce2102 (diff)
parente22a42fdcc0153b257011f8db7242c13de70e8ea (diff)
downloadincremental_delivery-66a56cd8313b9cf1b17cc80cd5524020e72e8253.tar.gz
Snap for 7219286 from e22a42fdcc0153b257011f8db7242c13de70e8ea to sc-d1-release
Change-Id: Icb1925628f02dea17dc0de06d9f82f8069994798
-rw-r--r--incfs/incfs.cpp105
-rw-r--r--incfs/include/incfs.h1
-rw-r--r--incfs/include/incfs_inline.h14
-rw-r--r--incfs/include/incfs_ndk.h6
-rw-r--r--incfs/path.h5
-rw-r--r--incfs/tests/incfs_test.cpp7
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) {