Skip to content

Commit d12873d

Browse files
ax3lfranzpoeschel
andcommitted
Test: Interleaved Write & Close (#1073)
* Test: Interleaved Write & Close Add a test that performs writes to interleaved iterations and then closes iterations as they are done writing. * ADIOS2IOHandlerImpl::createFile: Open explicitly * ADIOS2: Only overwrite path from parent in path operations * SerialIOTest: Iteration::close Encoding Cover more iteration encodings with this test. * Doc: tiny update Co-authored-by: Franz Pöschel <[email protected]>
1 parent a1f9257 commit d12873d

File tree

4 files changed

+191
-83
lines changed

4 files changed

+191
-83
lines changed

include/openPMD/IO/AbstractIOHandlerImplCommon.hpp

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,15 @@ class AbstractIOHandlerImplCommon : public AbstractIOHandlerImpl
7878
/**
7979
* Get the writable's containing file.
8080
* @param writable The writable whose containing file to figure out.
81+
* @param preferParentFile If true, the file is set to the parent's file if
82+
* present. Otherwise, the parent file is only considered if no own file
83+
* is defined. This is usually needed when switching between iterations when opening paths.
8184
* @return The containing file of the writable. If its parent is associated
8285
* with another file, update the writable to match its parent and return
8386
* the refreshed file.
8487
*/
85-
InvalidatableFile refreshFileFromParent( Writable * writable );
88+
InvalidatableFile
89+
refreshFileFromParent( Writable * writable, bool preferParentFile );
8690

8791
/**
8892
* Figure out the file position of the writable.
@@ -195,26 +199,40 @@ std::string AbstractIOHandlerImplCommon< FilePositionType >::fullPath(
195199
}
196200
}
197201

198-
199-
template < typename FilePositionType >
202+
template< typename FilePositionType >
200203
InvalidatableFile
201204
AbstractIOHandlerImplCommon< FilePositionType >::refreshFileFromParent(
202-
Writable * writable )
205+
Writable * writable, bool preferParentFile )
203206
{
204-
if ( writable->parent )
205-
{
207+
auto getFileFromParent = [ writable, this ]() {
206208
auto file = m_files.find( writable->parent )->second;
207209
associateWithFile( writable, file );
208210
return file;
211+
};
212+
if( preferParentFile && writable->parent )
213+
{
214+
return getFileFromParent();
209215
}
210216
else
211217
{
212-
return m_files.find( writable )->second;
218+
auto it = m_files.find( writable );
219+
if( it != m_files.end() )
220+
{
221+
return m_files.find( writable )->second;
222+
}
223+
else if( writable->parent )
224+
{
225+
return getFileFromParent();
226+
}
227+
else
228+
{
229+
throw std::runtime_error(
230+
"Internal error: Root object must be opened explicitly." );
231+
}
213232
}
214233
}
215234

216-
217-
template < typename FilePositionType >
235+
template< typename FilePositionType >
218236
std::shared_ptr< FilePositionType >
219237
AbstractIOHandlerImplCommon< FilePositionType >::setAndGetFilePosition(
220238
Writable * writable, bool write )

src/IO/ADIOS/ADIOS2IOHandler.cpp

Lines changed: 47 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,9 @@ void ADIOS2IOHandlerImpl::createFile(
299299
writable->written = true;
300300
writable->abstractFilePosition =
301301
std::make_shared< ADIOS2FilePosition >( );
302+
// enforce opening the file
303+
// lazy opening is deathly in parallel situations
304+
getFileData( shared_name, IfFileNotOpen::OpenImplicitly );
302305
}
303306
}
304307

@@ -307,7 +310,7 @@ void ADIOS2IOHandlerImpl::createPath(
307310
const Parameter< Operation::CREATE_PATH > & parameters )
308311
{
309312
std::string path;
310-
refreshFileFromParent( writable );
313+
refreshFileFromParent( writable, /* preferParentFile = */ true );
311314

312315
/* Sanitize path */
313316
if ( !auxiliary::starts_with( parameters.path, '/' ) )
@@ -342,7 +345,8 @@ void ADIOS2IOHandlerImpl::createDataset(
342345
/* Sanitize name */
343346
std::string name = auxiliary::removeSlashes( parameters.name );
344347

345-
auto const file = refreshFileFromParent( writable );
348+
auto const file =
349+
refreshFileFromParent( writable, /* preferParentFile = */ false );
346350
auto filePos = setAndGetFilePosition( writable, name );
347351
filePos->gd = ADIOS2FilePosition::GD::DATASET;
348352
auto const varName = nameOfVariable( writable );
@@ -439,7 +443,8 @@ ADIOS2IOHandlerImpl::extendDataset(
439443
m_handler->m_backendAccess != Access::READ_ONLY,
440444
"[ADIOS2] Cannot extend datasets in read-only mode." );
441445
setAndGetFilePosition( writable );
442-
auto file = refreshFileFromParent( writable );
446+
auto file =
447+
refreshFileFromParent( writable, /* preferParentFile = */ false );
443448
std::string name = nameOfVariable( writable );
444449
auto & filedata = getFileData( file, IfFileNotOpen::ThrowError );
445450
static detail::DatasetExtender de;
@@ -511,7 +516,7 @@ void ADIOS2IOHandlerImpl::openPath(
511516
Writable * writable, const Parameter< Operation::OPEN_PATH > & parameters )
512517
{
513518
/* Sanitize path */
514-
refreshFileFromParent( writable );
519+
refreshFileFromParent( writable, /* preferParentFile = */ true );
515520
std::string prefix =
516521
filePositionToString( setAndGetFilePosition( writable->parent ) );
517522
std::string suffix = auxiliary::removeSlashes( parameters.path );
@@ -531,10 +536,11 @@ void ADIOS2IOHandlerImpl::openDataset(
531536
Writable * writable, Parameter< Operation::OPEN_DATASET > & parameters )
532537
{
533538
auto name = auxiliary::removeSlashes( parameters.name );
534-
writable->abstractFilePosition.reset( );
539+
writable->abstractFilePosition.reset();
535540
auto pos = setAndGetFilePosition( writable, name );
536541
pos->gd = ADIOS2FilePosition::GD::DATASET;
537-
auto file = refreshFileFromParent( writable );
542+
auto file =
543+
refreshFileFromParent( writable, /* preferParentFile = */ false );
538544
auto varName = nameOfVariable( writable );
539545
*parameters.dtype =
540546
detail::fromADIOS2Type( getFileData( file, IfFileNotOpen::ThrowError )
@@ -580,10 +586,12 @@ void ADIOS2IOHandlerImpl::writeDataset(
580586
Writable * writable,
581587
const Parameter< Operation::WRITE_DATASET > & parameters )
582588
{
583-
VERIFY_ALWAYS( m_handler->m_backendAccess != Access::READ_ONLY,
584-
"[ADIOS2] Cannot write data in read-only mode." );
589+
VERIFY_ALWAYS(
590+
m_handler->m_backendAccess != Access::READ_ONLY,
591+
"[ADIOS2] Cannot write data in read-only mode." );
585592
setAndGetFilePosition( writable );
586-
auto file = refreshFileFromParent( writable );
593+
auto file =
594+
refreshFileFromParent( writable, /* preferParentFile = */ false );
587595
detail::BufferedActions & ba =
588596
getFileData( file, IfFileNotOpen::ThrowError );
589597
detail::BufferedPut bp;
@@ -607,13 +615,13 @@ void ADIOS2IOHandlerImpl::writeAttribute(
607615
writable,
608616
parameters );
609617
break;
610-
case AttributeLayout::ByAdiosVariables:
611-
{
618+
case AttributeLayout::ByAdiosVariables: {
612619
VERIFY_ALWAYS(
613620
m_handler->m_backendAccess != Access::READ_ONLY,
614621
"[ADIOS2] Cannot write attribute in read-only mode." );
615622
auto pos = setAndGetFilePosition( writable );
616-
auto file = refreshFileFromParent( writable );
623+
auto file = refreshFileFromParent(
624+
writable, /* preferParentFile = */ false );
617625
auto fullName = nameOfAttribute( writable, parameters.name );
618626
auto prefix = filePositionToString( pos );
619627

@@ -637,7 +645,8 @@ void ADIOS2IOHandlerImpl::readDataset(
637645
Writable * writable, Parameter< Operation::READ_DATASET > & parameters )
638646
{
639647
setAndGetFilePosition( writable );
640-
auto file = refreshFileFromParent( writable );
648+
auto file =
649+
refreshFileFromParent( writable, /* preferParentFile = */ false );
641650
detail::BufferedActions & ba =
642651
getFileData( file, IfFileNotOpen::ThrowError );
643652
detail::BufferedGet bg;
@@ -709,7 +718,7 @@ ADIOS2IOHandlerImpl::getBufferView(
709718
return;
710719
}
711720
setAndGetFilePosition( writable );
712-
auto file = refreshFileFromParent( writable );
721+
auto file = refreshFileFromParent( writable, /* preferParentFile = */ false );
713722
detail::BufferedActions & ba =
714723
getFileData( file, IfFileNotOpen::ThrowError );
715724
if( parameters.update )
@@ -742,12 +751,10 @@ void *UpdateSpan< T >::update()
742751
}
743752
} // namespace detail
744753

745-
void
746-
ADIOS2IOHandlerImpl::readAttribute(
747-
Writable * writable,
748-
Parameter< Operation::READ_ATT > & parameters )
754+
void ADIOS2IOHandlerImpl::readAttribute(
755+
Writable * writable, Parameter< Operation::READ_ATT > & parameters )
749756
{
750-
auto file = refreshFileFromParent( writable );
757+
auto file = refreshFileFromParent( writable, /* preferParentFile = */ false );
751758
auto pos = setAndGetFilePosition( writable );
752759
detail::BufferedActions & ba =
753760
getFileData( file, IfFileNotOpen::ThrowError );
@@ -781,8 +788,10 @@ void ADIOS2IOHandlerImpl::listPaths(
781788
{
782789
VERIFY_ALWAYS(
783790
writable->written,
784-
"[ADIOS2] Internal error: Writable not marked written during path listing" );
785-
auto file = refreshFileFromParent( writable );
791+
"[ADIOS2] Internal error: Writable not marked written during path "
792+
"listing" );
793+
auto file =
794+
refreshFileFromParent( writable, /* preferParentFile = */ false );
786795
auto pos = setAndGetFilePosition( writable );
787796
std::string myName = filePositionToString( pos );
788797
if ( !auxiliary::ends_with( myName, '/' ) )
@@ -898,8 +907,9 @@ void ADIOS2IOHandlerImpl::listDatasets(
898907
{
899908
VERIFY_ALWAYS(
900909
writable->written,
901-
"[ADIOS2] Internal error: Writable not marked written during path listing" );
902-
auto file = refreshFileFromParent( writable );
910+
"[ADIOS2] Internal error: Writable not marked written during path "
911+
"listing" );
912+
auto file = refreshFileFromParent( writable, /* preferParentFile = */ false );
903913
auto pos = setAndGetFilePosition( writable );
904914
// adios2::Engine & engine = getEngine( file );
905915
std::string myName = filePositionToString( pos );
@@ -949,10 +959,11 @@ void ADIOS2IOHandlerImpl::listDatasets(
949959
void ADIOS2IOHandlerImpl::listAttributes(
950960
Writable * writable, Parameter< Operation::LIST_ATTS > & parameters )
951961
{
952-
VERIFY_ALWAYS( writable->written,
953-
"[ADIOS2] Internal error: Writable not marked "
954-
"written during attribute writing" );
955-
auto file = refreshFileFromParent( writable );
962+
VERIFY_ALWAYS(
963+
writable->written,
964+
"[ADIOS2] Internal error: Writable not marked "
965+
"written during attribute writing" );
966+
auto file = refreshFileFromParent( writable, /* preferParentFile = */ false );
956967
auto pos = setAndGetFilePosition( writable );
957968
auto attributePrefix = filePositionToString( pos );
958969
if ( attributePrefix == "/" )
@@ -1012,7 +1023,7 @@ ADIOS2IOHandlerImpl::closePath(
10121023
// nothing to do
10131024
return;
10141025
}
1015-
auto file = refreshFileFromParent( writable );
1026+
auto file = refreshFileFromParent( writable, /* preferParentFile = */ false );
10161027
auto & fileData = getFileData( file, IfFileNotOpen::ThrowError );
10171028
if( !fileData.optimizeAttributesStreaming )
10181029
{
@@ -1032,13 +1043,11 @@ ADIOS2IOHandlerImpl::closePath(
10321043
}
10331044
}
10341045

1035-
void
1036-
ADIOS2IOHandlerImpl::availableChunks(
1037-
Writable * writable,
1038-
Parameter< Operation::AVAILABLE_CHUNKS > & parameters )
1046+
void ADIOS2IOHandlerImpl::availableChunks(
1047+
Writable * writable, Parameter< Operation::AVAILABLE_CHUNKS > & parameters )
10391048
{
10401049
setAndGetFilePosition( writable );
1041-
auto file = refreshFileFromParent( writable );
1050+
auto file = refreshFileFromParent( writable, /* preferParentFile = */ false );
10421051
detail::BufferedActions & ba =
10431052
getFileData( file, IfFileNotOpen::ThrowError );
10441053
std::string varName = nameOfVariable( writable );
@@ -1399,17 +1408,16 @@ namespace detail
13991408
}
14001409

14011410
template< typename T >
1402-
void
1403-
OldAttributeWriter::operator()(
1411+
void OldAttributeWriter::operator()(
14041412
ADIOS2IOHandlerImpl * impl,
14051413
Writable * writable,
14061414
const Parameter< Operation::WRITE_ATT > & parameters )
14071415
{
1408-
VERIFY_ALWAYS( impl->m_handler->m_backendAccess !=
1409-
Access::READ_ONLY,
1410-
"[ADIOS2] Cannot write attribute in read-only mode." );
1416+
VERIFY_ALWAYS(
1417+
impl->m_handler->m_backendAccess != Access::READ_ONLY,
1418+
"[ADIOS2] Cannot write attribute in read-only mode." );
14111419
auto pos = impl->setAndGetFilePosition( writable );
1412-
auto file = impl->refreshFileFromParent( writable );
1420+
auto file = impl->refreshFileFromParent( writable, /* preferParentFile = */ false );
14131421
auto fullName = impl->nameOfAttribute( writable, parameters.name );
14141422
auto prefix = impl->filePositionToString( pos );
14151423

src/Series.cpp

Lines changed: 29 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,45 +1334,39 @@ void SeriesInterface::openIteration( uint64_t index, Iteration iteration )
13341334
{
13351335
using IE = IterationEncoding;
13361336
case IE::fileBased: {
1337-
switch( IOHandler()->m_frontendAccess )
1337+
/*
1338+
* The iteration is marked written() as soon as its file has been
1339+
* either created or opened.
1340+
* If the iteration has not been created yet, it cannot be opened.
1341+
* In that case, it is not written() and its old close status was
1342+
* not ParseAccessDeferred.
1343+
* Similarly, in Create mode, the iteration must first be created
1344+
* before it is possible to open it.
1345+
*/
1346+
if( !iteration.written() &&
1347+
( IOHandler()->m_frontendAccess == Access::CREATE ||
1348+
oldStatus != Iteration::CloseStatus::ParseAccessDeferred ) )
13381349
{
1339-
case Access::READ_ONLY:
1340-
case Access::READ_WRITE: {
1341-
/*
1342-
* The iteration is marked written() as soon as its file has been
1343-
* either created or opened.
1344-
* If the iteration has not been created yet, it cannot be opened.
1345-
* In that case, it is not written() and its old close status was
1346-
* not ParseAccessDeferred.
1347-
*/
1348-
if( !iteration.written() &&
1349-
oldStatus != Iteration::CloseStatus::ParseAccessDeferred )
1350-
{
1351-
// nothing to do, file will be opened by writing routines
1352-
break;
1353-
}
1354-
auto & series = get();
1355-
// open the iteration's file again
1356-
Parameter< Operation::OPEN_FILE > fOpen;
1357-
fOpen.encoding = iterationEncoding();
1358-
fOpen.name = iterationFilename( index );
1359-
IOHandler()->enqueue( IOTask( this, fOpen ) );
1360-
1361-
/* open base path */
1362-
Parameter< Operation::OPEN_PATH > pOpen;
1363-
pOpen.path = auxiliary::replace_first( basePath(), "%T/", "" );
1364-
IOHandler()->enqueue( IOTask( &series.iterations, pOpen ) );
1365-
/* open iteration path */
1366-
pOpen.path = iterationEncoding() == IterationEncoding::variableBased
1367-
? ""
1368-
: std::to_string( index );
1369-
IOHandler()->enqueue( IOTask( &iteration, pOpen ) );
1370-
break;
1371-
}
1372-
case Access::CREATE:
13731350
// nothing to do, file will be opened by writing routines
13741351
break;
13751352
}
1353+
auto & series = get();
1354+
// open the iteration's file again
1355+
Parameter< Operation::OPEN_FILE > fOpen;
1356+
fOpen.encoding = iterationEncoding();
1357+
fOpen.name = iterationFilename( index );
1358+
IOHandler()->enqueue( IOTask( this, fOpen ) );
1359+
1360+
/* open base path */
1361+
Parameter< Operation::OPEN_PATH > pOpen;
1362+
pOpen.path = auxiliary::replace_first( basePath(), "%T/", "" );
1363+
IOHandler()->enqueue( IOTask( &series.iterations, pOpen ) );
1364+
/* open iteration path */
1365+
pOpen.path = iterationEncoding() == IterationEncoding::variableBased
1366+
? ""
1367+
: std::to_string( index );
1368+
IOHandler()->enqueue( IOTask( &iteration, pOpen ) );
1369+
break;
13761370
}
13771371
case IE::groupBased:
13781372
case IE::variableBased:

0 commit comments

Comments
 (0)