-
Notifications
You must be signed in to change notification settings - Fork 51
ADIOS2 Append Mode #1007
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
ADIOS2 Append Mode #1007
Changes from all commits
41d1fed
0b0524d
d906775
829da9c
e865a03
de98254
a26af87
52176ca
4ef966b
e9caae7
4f2130b
1c25b4f
184f2a6
7afb99d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,39 @@ | ||
.. _workflow: | ||
|
||
Access modes | ||
============ | ||
|
||
The openPMD-api distinguishes between a number of different access modes: | ||
|
||
* **Create mode**: Used for creating a new Series from scratch. | ||
Any file possibly existing in the specified location will be overwritten. | ||
* **Read-only mode**: Used for reading from an existing Series. | ||
No modifications will be made. | ||
* **Read/Write mode**: Creates a new Series if not existing, otherwise opens an existing Series for reading and writing. | ||
New datasets and iterations will be inserted as needed. | ||
Not fully supported by all backends: | ||
|
||
* ADIOS1: Automatically coerced to *Create* mode if the file does not exist yet and to *Read-only* mode if it exists. | ||
franzpoeschel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* ADIOS2: Automatically coerced to *Create* mode if the file does not exist yet and to *Read-only* mode if it exists. | ||
Since this happens on a per-file level, this mode allows to read from existing iterations and write to new iterations at the same time in file-based iteration encoding. | ||
* **Append mode**: Restricted mode for appending new iterations to an existing Series that is supported by all backends at least in file-based iteration encoding, and by all but ADIOS1 in other encodings. | ||
The API is equivalent to that of the *Create* mode, meaning that no reading is supported whatsoever. | ||
If the Series does not exist yet, this behaves equivalently to the *Create* mode. | ||
Existing iterations will not be deleted, newly-written iterations will be inserted. | ||
|
||
**Warning:** When writing an iteration that already exists, the behavior is implementation-defined and depends on the chosen backend and iteration encoding: | ||
|
||
* The new iteration might fully replace the old one. | ||
* The new iteration might be merged into the old one. | ||
* (To be removed in a future update) The old and new iteration might coexist in the resulting dataset. | ||
|
||
We suggest to fully define iterations when using Append mode (i.e. as if using Create mode) to avoid implementation-specific behavior. | ||
Appending to an openPMD Series is only supported on a per-iteration level. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe a bit too strict here to understand what is meant or might be repetitive with what is said above? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In that case, let's maybe restrict the wording to make clear that this refers to the Append mode only:
|
||
|
||
**Warning:** There is no reading involved in using Append mode. | ||
It is a user's responsibility to ensure that the appended dataset and the appended-to dataset are compatible with each other. | ||
The results of using incompatible backend configurations are undefined. | ||
|
||
Workflow | ||
======== | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -121,6 +121,23 @@ namespace internal | |
*/ | ||
class AbstractIOHandler | ||
{ | ||
friend class Series; | ||
|
||
private: | ||
void setIterationEncoding(IterationEncoding encoding) | ||
{ | ||
/* | ||
* In file-based iteration encoding, the APPEND mode is handled entirely | ||
* by the frontend, the backend should just treat it as CREATE mode | ||
*/ | ||
if (encoding == IterationEncoding::fileBased && | ||
m_backendAccess == Access::APPEND) | ||
{ | ||
// do we really want to have those as const members..? | ||
*const_cast<Access *>(&m_backendAccess) = Access::CREATE; | ||
} | ||
} | ||
|
||
public: | ||
#if openPMD_HAVE_MPI | ||
AbstractIOHandler(std::string path, Access at, MPI_Comm) | ||
|
@@ -153,6 +170,7 @@ class AbstractIOHandler | |
virtual std::string backendName() const = 0; | ||
|
||
std::string const directory; | ||
// why do these need to be separate? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we want to answer this question? :) I am not sure we documented this well when this was introduced (also visible in the missing doxygen strings for those two members). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I ran into that a few times. I believe it would be consistent to treat all files in the file mode as they were one file. When its time to overwrite, remove all existing files related to the series. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'd suggest to do it in a separate PR, need to figure out what the answer is at first though
We could think about this for CREATE mode, since its semantics are "overwrite anything that exists". The purpose READ_WRITE and APPEND modes is explicitly not to delete existing data. For APPEND mode, the most sensible solution seems to be truncation (i.e. "delete anything past iteration 500") which would be a follow-up PR. |
||
Access const m_backendAccess; | ||
Access const m_frontendAccess; | ||
std::queue<IOTask> m_work; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -315,9 +315,6 @@ void ADIOS2IOHandlerImpl::createFile( | |
m_iterationEncoding = parameters.encoding; | ||
associateWithFile(writable, shared_name); | ||
this->m_dirty.emplace(shared_name); | ||
getFileData(shared_name, IfFileNotOpen::OpenImplicitly).m_mode = | ||
adios2::Mode::Write; // WORKAROUND | ||
// ADIOS2 does not yet implement ReadWrite Mode | ||
|
||
writable->written = true; | ||
writable->abstractFilePosition = std::make_shared<ADIOS2FilePosition>(); | ||
|
@@ -1074,21 +1071,16 @@ adios2::Mode ADIOS2IOHandlerImpl::adios2AccessMode(std::string const &fullPath) | |
if (auxiliary::directory_exists(fullPath) || | ||
auxiliary::file_exists(fullPath)) | ||
{ | ||
std::cerr << "ADIOS2 does currently not yet implement ReadWrite " | ||
"(Append) mode. " | ||
<< "Replacing with Read mode." << std::endl; | ||
return adios2::Mode::Read; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that the APPEND mode is added. Should READ_WRITE mode be rejected for ADIOS? Might be semantically cleaner. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. READ_WRITE is still useful for file-based iteration encoding since it allows you to read old iterations while at the same time to write new ones. This feature is not found in any other iteration encodings. For the other iteration encodings, there is no use in having READ_WRITE mode for ADIOS2, yeah. |
||
} | ||
else | ||
{ | ||
std::cerr << "ADIOS2 does currently not yet implement ReadWrite " | ||
"(Append) mode. " | ||
<< "Replacing with Write mode." << std::endl; | ||
return adios2::Mode::Write; | ||
} | ||
default: | ||
return adios2::Mode::Undefined; | ||
case Access::APPEND: | ||
return adios2::Mode::Append; | ||
} | ||
throw std::runtime_error("Unreachable!"); | ||
} | ||
|
||
json::TracingJSON ADIOS2IOHandlerImpl::nullvalue = { | ||
|
@@ -2235,6 +2227,7 @@ namespace detail | |
delayOpeningTheFirstStep = true; | ||
break; | ||
case adios2::Mode::Write: | ||
case adios2::Mode::Append: | ||
/* | ||
* File engines, write mode: | ||
* Default for old layout is no steps. | ||
|
@@ -2442,6 +2435,7 @@ namespace detail | |
{ | ||
switch (m_mode) | ||
{ | ||
case adios2::Mode::Append: | ||
case adios2::Mode::Write: { | ||
// usesSteps attribute only written upon ::advance() | ||
// this makes sure that the attribute is only put in case | ||
|
@@ -2686,17 +2680,14 @@ namespace detail | |
switch (ba.m_mode) | ||
{ | ||
case adios2::Mode::Write: | ||
case adios2::Mode::Append: | ||
eng.PerformPuts(); | ||
break; | ||
case adios2::Mode::Read: | ||
eng.PerformGets(); | ||
break; | ||
case adios2::Mode::Append: | ||
// TODO order? | ||
eng.PerformGets(); | ||
eng.PerformPuts(); | ||
break; | ||
default: | ||
throw error::Internal("[ADIOS2] Unexpected access mode."); | ||
break; | ||
} | ||
}, | ||
|
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.
For file-based I/O, I think there might be a potentially confusing corner case:
if one writes the same series again, but with different interval, then some files might be overwritten and others untouched.
I am thinking about this from time to time and see pro and cons for, e.g., actively cleaning/moving out all potential files (even for iterations that are not created again) when opening in truncating create mode.
More of a thing we could discuss next time.
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.
Fair point. I guess the most sensible solution would be within the bounds of a potential truncate option.