-
Notifications
You must be signed in to change notification settings - Fork 146
BP5Reader: close metadata FDs when writer is inactive #4846
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+318
−15
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,191 @@ | ||
| /* | ||
| * Distributed under the OSI-approved Apache License, Version 2.0. See | ||
| * accompanying file Copyright.txt for details. | ||
| * | ||
| * Test that BP5Reader closes metadata file descriptors (md.idx, md.0, mmd.0) | ||
| * after opening a completed file in ReadRandomAccess mode. | ||
| * | ||
| * Uses /proc/self/fd on Linux and fcntl(F_GETPATH) on macOS to inspect | ||
| * which files the process has open. | ||
| */ | ||
|
|
||
| #include <cstdint> | ||
| #include <cstring> | ||
| #include <iostream> | ||
| #include <string> | ||
| #include <vector> | ||
|
|
||
| #include <adios2.h> | ||
|
|
||
| #include <gtest/gtest.h> | ||
|
|
||
| #include "../TestHelpers.h" | ||
|
|
||
| #if defined(__linux__) | ||
| #include <dirent.h> | ||
| #include <unistd.h> | ||
| #define HAS_FD_INSPECTION 1 | ||
| #elif defined(__APPLE__) | ||
| #include <fcntl.h> | ||
| #include <sys/param.h> | ||
| #include <sys/resource.h> | ||
| #include <unistd.h> | ||
| #define HAS_FD_INSPECTION 1 | ||
| #else | ||
| #define HAS_FD_INSPECTION 0 | ||
| #endif | ||
|
|
||
| std::string engineName; // comes from command line | ||
| std::string engineParameters; // comes from command line | ||
|
|
||
| #if HAS_FD_INSPECTION | ||
| /* Return the number of open file descriptors whose path contains `substr`. */ | ||
| static int CountOpenFDs(const std::string &substr) | ||
| { | ||
| int count = 0; | ||
|
|
||
| #if defined(__linux__) | ||
| DIR *dir = opendir("/proc/self/fd"); | ||
| if (!dir) | ||
| { | ||
| return -1; | ||
| } | ||
| struct dirent *entry; | ||
| while ((entry = readdir(dir)) != nullptr) | ||
| { | ||
| if (entry->d_name[0] == '.') | ||
| { | ||
| continue; | ||
| } | ||
| char linkTarget[PATH_MAX]; | ||
| std::string fdPath = std::string("/proc/self/fd/") + entry->d_name; | ||
| ssize_t len = readlink(fdPath.c_str(), linkTarget, sizeof(linkTarget) - 1); | ||
| if (len > 0) | ||
| { | ||
| linkTarget[len] = '\0'; | ||
| if (std::string(linkTarget).find(substr) != std::string::npos) | ||
| { | ||
| ++count; | ||
| } | ||
| } | ||
| } | ||
| closedir(dir); | ||
|
|
||
| #elif defined(__APPLE__) | ||
| /* On macOS, iterate FD numbers and use fcntl(F_GETPATH) to get the path. */ | ||
| struct rlimit rl; | ||
| rlim_t maxfd = 256; | ||
| if (getrlimit(RLIMIT_NOFILE, &rl) == 0 && rl.rlim_cur < 4096) | ||
| { | ||
| maxfd = rl.rlim_cur; | ||
| } | ||
| char pathbuf[MAXPATHLEN]; | ||
| for (int fd = 0; fd < (int)maxfd; ++fd) | ||
| { | ||
| if (fcntl(fd, F_GETPATH, pathbuf) != -1) | ||
| { | ||
| if (std::string(pathbuf).find(substr) != std::string::npos) | ||
| { | ||
| ++count; | ||
| } | ||
| } | ||
| } | ||
| #endif | ||
|
|
||
| return count; | ||
| } | ||
| #endif /* HAS_FD_INSPECTION */ | ||
|
|
||
| TEST(BPMetadataFDClose, ReadRandomAccessClosesFDs) | ||
| { | ||
| const std::string fname("BPMetadataFDCloseTest.bp"); | ||
| const size_t Nx = 10; | ||
| const size_t NSteps = 3; | ||
|
|
||
| adios2::ADIOS adios; | ||
|
|
||
| /* Write a small file */ | ||
| { | ||
| adios2::IO io = adios.DeclareIO("WriteIO"); | ||
| if (!engineName.empty()) | ||
| { | ||
| io.SetEngine(engineName); | ||
| } | ||
| if (!engineParameters.empty()) | ||
| { | ||
| io.SetParameters(engineParameters); | ||
| } | ||
| auto var = io.DefineVariable<double>("data", {Nx}, {0}, {Nx}); | ||
| adios2::Engine writer = io.Open(fname, adios2::Mode::Write); | ||
| std::vector<double> buf(Nx); | ||
| for (size_t step = 0; step < NSteps; ++step) | ||
| { | ||
| for (size_t i = 0; i < Nx; ++i) | ||
| { | ||
| buf[i] = static_cast<double>(step * Nx + i); | ||
| } | ||
| writer.BeginStep(); | ||
| writer.Put(var, buf.data()); | ||
| writer.EndStep(); | ||
| } | ||
| writer.Close(); | ||
| } | ||
|
|
||
| /* Open in ReadRandomAccess and verify metadata FDs are closed */ | ||
| { | ||
| adios2::IO io = adios.DeclareIO("ReadIO"); | ||
| if (!engineName.empty()) | ||
| { | ||
| io.SetEngine(engineName); | ||
| } | ||
| if (!engineParameters.empty()) | ||
| { | ||
| io.SetParameters(engineParameters); | ||
| } | ||
|
|
||
| adios2::Engine reader = io.Open(fname, adios2::Mode::ReadRandomAccess); | ||
| ASSERT_EQ(reader.Steps(), NSteps); | ||
|
|
||
| /* Verify we can still read data (FD closing must not break reads) */ | ||
| auto var = io.InquireVariable<double>("data"); | ||
| ASSERT_TRUE(var); | ||
| std::vector<double> buf(Nx); | ||
| var.SetStepSelection({0, 1}); | ||
| reader.Get(var, buf.data(), adios2::Mode::Sync); | ||
| EXPECT_EQ(buf[0], 0.0); | ||
| EXPECT_EQ(buf[Nx - 1], static_cast<double>(Nx - 1)); | ||
|
|
||
| #if HAS_FD_INSPECTION | ||
| /* After Open in ReadRandomAccess on a completed file, the three | ||
| metadata files (md.idx, md.0, mmd.0) should be closed. */ | ||
| int mdIdxFDs = CountOpenFDs("/md.idx"); | ||
| int md0FDs = CountOpenFDs("/md.0"); | ||
| int mmd0FDs = CountOpenFDs("/mmd.0"); | ||
|
|
||
| EXPECT_EQ(mdIdxFDs, 0) << "md.idx should be closed after ReadRandomAccess Open"; | ||
| EXPECT_EQ(md0FDs, 0) << "md.0 should be closed after ReadRandomAccess Open"; | ||
| EXPECT_EQ(mmd0FDs, 0) << "mmd.0 should be closed after ReadRandomAccess Open"; | ||
| #endif | ||
|
|
||
| reader.Close(); | ||
| } | ||
|
|
||
| CleanupTestFiles(fname); | ||
| } | ||
|
|
||
| int main(int argc, char **argv) | ||
| { | ||
| int result; | ||
| ::testing::InitGoogleTest(&argc, argv); | ||
|
|
||
| if (argc > 1) | ||
| { | ||
| engineName = std::string(argv[1]); | ||
| } | ||
| if (argc > 2) | ||
| { | ||
| engineParameters = std::string(argv[2]); | ||
| } | ||
| result = RUN_ALL_TESTS(); | ||
| return result; | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you do a reset of the metadata index without resizing the buffer to 0? In no, I would put the resize inside the reset function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of the time we call Reset and want the buffer to survive. Here, the next bit of code needs to see the buffer as size zero, so we can't really move it inside (without adding something like a parameter to say we wanted the buffer to go away or something).