mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: add support for OFstream atomic file creation (#2631)
- with ATOMIC, an intermediary file is created - eg, (fileAbc~tmp~) where all of the output is written to. When the stream goes out of scope, this intermediary file is moved/renamed to the actually output name - eg, (fileAbc~tmp~) -> (fileAbc). This adds some safety if the simulation crashes while writing the file, since it will the partial (corrupt) file will be left behind as (fileAbc~tmp~) and not as (fileAbc), which means it will will be treated as a backup file and not loaded again on restart. ENH: provided enumeration for APPEND/NON_APPEND - clearer than using bool (with comments). Since append mode is primarily only used by masterOFstream etc this change is unlikely to affect user coding. ENH: use file atomic for ensight file creation - avoids corrupt (truncated) files being referenced by the ensight case file if the simulation crashes while writing the ensight file.
This commit is contained in:
3
applications/test/OFstream/Make/files
Normal file
3
applications/test/OFstream/Make/files
Normal file
@ -0,0 +1,3 @@
|
||||
Test-OFstream.C
|
||||
|
||||
EXE = $(FOAM_USER_APPBIN)/Test-OFstream
|
||||
2
applications/test/OFstream/Make/options
Normal file
2
applications/test/OFstream/Make/options
Normal file
@ -0,0 +1,2 @@
|
||||
/* EXE_INC = */
|
||||
/* EXE_LIBS = */
|
||||
228
applications/test/OFstream/Test-OFstream.C
Normal file
228
applications/test/OFstream/Test-OFstream.C
Normal file
@ -0,0 +1,228 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2022 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Description
|
||||
Test OFstream. Primarily atomic operations
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "Fstream.H"
|
||||
#include "IOstreams.H"
|
||||
#include "OSspecific.H"
|
||||
#include "argList.H"
|
||||
#include "ListOps.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
void listFiles(const fileName& dir)
|
||||
{
|
||||
wordList files = ListOps::create<word>
|
||||
(
|
||||
readDir(dir, fileName::FILE),
|
||||
nameOp<fileName>()
|
||||
);
|
||||
|
||||
Info
|
||||
<< nl
|
||||
<< "files:" << nl
|
||||
<< files << nl
|
||||
<< "ls" << nl
|
||||
<< "============" << endl;
|
||||
Foam::system("ls -al " + dir);
|
||||
Info<< "============" << endl;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
// Main program:
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addBoolOption("gz", "Use compression");
|
||||
argList::addBoolOption("append", "Use append mode");
|
||||
argList::addBoolOption("atomic", "Use atomic");
|
||||
argList::addBoolOption("keep", "Do not remove test directory");
|
||||
argList::addOption("write", "file", "test writing to file");
|
||||
|
||||
#include "setRootCase.H"
|
||||
|
||||
const fileName baseDir("Test-OFstream-directory");
|
||||
|
||||
Foam::mkDir(baseDir);
|
||||
|
||||
InfoErr<< "mkdir: " << baseDir << endl;
|
||||
|
||||
IOstreamOption streamOpt;
|
||||
|
||||
if (args.found("gz"))
|
||||
{
|
||||
streamOpt.compression(IOstreamOption::COMPRESSED);
|
||||
}
|
||||
|
||||
IOstreamOption::appendType append =
|
||||
(
|
||||
args.found("append")
|
||||
? IOstreamOption::APPEND
|
||||
: IOstreamOption::NON_APPEND
|
||||
);
|
||||
IOstreamOption::atomicType atomic =
|
||||
(
|
||||
args.found("atomic")
|
||||
? IOstreamOption::ATOMIC
|
||||
: IOstreamOption::NON_ATOMIC
|
||||
);
|
||||
|
||||
{
|
||||
OFstream(baseDir/"dummy")() << "Some file content" << endl;
|
||||
|
||||
Foam::ln("dummy", baseDir/"Test2.txt");
|
||||
Foam::ln("dummy", baseDir/"Test3.txt");
|
||||
Foam::ln("dummy", baseDir/"Test4.txt");
|
||||
Foam::ln("dummy", baseDir/"Test4.txt.gz");
|
||||
Foam::ln("dummy", baseDir/"Test5.txt");
|
||||
Foam::ln("dummy", baseDir/"Test5.txt.gz");
|
||||
}
|
||||
|
||||
{
|
||||
OFstream os
|
||||
(
|
||||
atomic,
|
||||
baseDir/"Test1.txt",
|
||||
streamOpt,
|
||||
append
|
||||
);
|
||||
|
||||
os << "=========================" << endl;
|
||||
|
||||
InfoErr<< "open: " << os.name() << endl;
|
||||
InfoErr<< "... sleep" << endl;
|
||||
|
||||
listFiles(baseDir);
|
||||
|
||||
sleep(2);
|
||||
|
||||
os << "+++++++++++++++++++++++++++++++++++" << endl;
|
||||
}
|
||||
|
||||
{
|
||||
OFstream os
|
||||
(
|
||||
atomic,
|
||||
baseDir/"Test2.txt",
|
||||
streamOpt
|
||||
// NON_APPEND
|
||||
);
|
||||
|
||||
os << "=========================" << endl;
|
||||
|
||||
InfoErr<< "open: " << os.name() << endl;
|
||||
InfoErr<< "... sleep" << endl;
|
||||
|
||||
listFiles(baseDir);
|
||||
|
||||
sleep(2);
|
||||
|
||||
os << "+++++++++++++++++++++++++++++++++++" << endl;
|
||||
}
|
||||
{
|
||||
OFstream os
|
||||
(
|
||||
atomic,
|
||||
baseDir/"Test3.txt",
|
||||
streamOpt,
|
||||
IOstreamOption::APPEND
|
||||
);
|
||||
|
||||
os << "=========================" << endl;
|
||||
|
||||
InfoErr<< "open: " << os.name() << endl;
|
||||
InfoErr<< "... sleep" << endl;
|
||||
|
||||
listFiles(baseDir);
|
||||
|
||||
sleep(2);
|
||||
|
||||
os << "+++++++++++++++++++++++++++++++++++" << endl;
|
||||
}
|
||||
{
|
||||
OFstream os
|
||||
(
|
||||
baseDir/"Test4.txt",
|
||||
IOstreamOption::ASCII,
|
||||
IOstreamOption::COMPRESSED
|
||||
);
|
||||
|
||||
os << "=========================" << endl;
|
||||
|
||||
InfoErr<< "open: " << os.name() << endl;
|
||||
InfoErr<< "... sleep" << endl;
|
||||
|
||||
listFiles(baseDir);
|
||||
|
||||
sleep(2);
|
||||
|
||||
os << "+++++++++++++++++++++++++++++++++++" << endl;
|
||||
}
|
||||
{
|
||||
OFstream os
|
||||
(
|
||||
IOstreamOption::ATOMIC,
|
||||
baseDir/"Test5.txt"
|
||||
// ASCII UNCOMPRESSED NON_APPEND
|
||||
);
|
||||
|
||||
os << "=========================" << endl;
|
||||
|
||||
InfoErr<< "open: " << os.name() << endl;
|
||||
InfoErr<< "... sleep" << endl;
|
||||
|
||||
listFiles(baseDir);
|
||||
|
||||
sleep(2);
|
||||
|
||||
os << "+++++++++++++++++++++++++++++++++++" << endl;
|
||||
}
|
||||
|
||||
Info<< nl << "done:" << endl;
|
||||
|
||||
listFiles(baseDir);
|
||||
|
||||
if (args.found("keep"))
|
||||
{
|
||||
InfoErr<< "keep: " << baseDir << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
InfoErr<< "rmdir: " << baseDir << endl;
|
||||
Foam::rmDir(baseDir);
|
||||
}
|
||||
|
||||
Info<< "\nEnd\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -126,7 +126,7 @@ void Foam::IFstream::rewind()
|
||||
if (IOstreamOption::COMPRESSED == ifstreamPointer::whichCompression())
|
||||
{
|
||||
lineNumber_ = 1; // Reset line number
|
||||
ifstreamPointer::reopen_gz(this->name() + ".gz");
|
||||
ifstreamPointer::reopen_gz(this->name());
|
||||
setState(ifstreamPointer::get()->rdstate());
|
||||
}
|
||||
else
|
||||
@ -150,7 +150,7 @@ Foam::IFstream& Foam::IFstream::operator()() const
|
||||
if (!good())
|
||||
{
|
||||
// Also checks .gz file
|
||||
if (isFile(this->name(), true))
|
||||
if (Foam::isFile(this->name(), true))
|
||||
{
|
||||
check(FUNCTION_NAME);
|
||||
FatalIOError.exit();
|
||||
|
||||
@ -64,14 +64,14 @@ public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct from pathname
|
||||
//- Construct from pathname, default or specified stream options
|
||||
explicit IFstream
|
||||
(
|
||||
const fileName& pathname,
|
||||
IOstreamOption streamOpt = IOstreamOption()
|
||||
);
|
||||
|
||||
//- Construct from pathname, format (version)
|
||||
//- Construct from pathname and format
|
||||
IFstream
|
||||
(
|
||||
const fileName& pathname,
|
||||
|
||||
@ -56,12 +56,19 @@ Foam::OFstream::OFstream
|
||||
|
||||
Foam::OFstream::OFstream
|
||||
(
|
||||
IOstreamOption::atomicType atomic,
|
||||
const fileName& pathname,
|
||||
IOstreamOption streamOpt,
|
||||
const bool append
|
||||
IOstreamOption::appendType append
|
||||
)
|
||||
:
|
||||
Foam::ofstreamPointer(pathname, streamOpt.compression(), append),
|
||||
Foam::ofstreamPointer
|
||||
(
|
||||
pathname,
|
||||
streamOpt.compression(),
|
||||
(IOstreamOption::appendType::APPEND == append),
|
||||
(IOstreamOption::atomicType::ATOMIC == atomic)
|
||||
),
|
||||
OSstream(*(ofstreamPointer::get()), pathname, streamOpt)
|
||||
{
|
||||
setClosed();
|
||||
@ -100,7 +107,9 @@ Foam::OFstream::OFstream
|
||||
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::OFstream::~OFstream()
|
||||
{}
|
||||
{
|
||||
ofstreamPointer::close(this->name());
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
@ -137,15 +146,8 @@ const std::ostream& Foam::OFstream::stdStream() const
|
||||
|
||||
void Foam::OFstream::rewind()
|
||||
{
|
||||
if (IOstreamOption::COMPRESSED == ofstreamPointer::whichCompression())
|
||||
{
|
||||
ofstreamPointer::reopen_gz(this->name() + ".gz");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reopen (truncate)
|
||||
ofstreamPointer::reopen(this->name());
|
||||
}
|
||||
// Reopen (truncate) std::ostream
|
||||
ofstreamPointer::reopen(this->name());
|
||||
|
||||
// As per OSstream::rewind()
|
||||
|
||||
|
||||
@ -68,28 +68,57 @@ public:
|
||||
// Behaves like \c /dev/null and is named accordingly
|
||||
explicit OFstream(std::nullptr_t);
|
||||
|
||||
//- Construct from pathname
|
||||
//- Construct with specified atomic behaviour
|
||||
//- from pathname, stream option, optional append
|
||||
OFstream
|
||||
(
|
||||
IOstreamOption::atomicType atomic,
|
||||
const fileName& pathname,
|
||||
IOstreamOption streamOpt = IOstreamOption(),
|
||||
IOstreamOption::appendType append = IOstreamOption::NON_APPEND
|
||||
);
|
||||
|
||||
//- Construct from pathname and other specifications
|
||||
explicit OFstream
|
||||
(
|
||||
const fileName& pathname,
|
||||
IOstreamOption streamOpt = IOstreamOption(),
|
||||
const bool append = false
|
||||
);
|
||||
IOstreamOption::appendType append = IOstreamOption::NON_APPEND
|
||||
)
|
||||
:
|
||||
OFstream(IOstreamOption::NON_ATOMIC, pathname, streamOpt, append)
|
||||
{}
|
||||
|
||||
//- Construct from pathname, format (uncompressed), optional append
|
||||
//- Construct from pathname, format (uncompressed), optional append,
|
||||
//- atomic behaviour as per system default
|
||||
OFstream
|
||||
(
|
||||
const fileName& pathname,
|
||||
IOstreamOption::streamFormat fmt,
|
||||
IOstreamOption::compressionType cmp = IOstreamOption::UNCOMPRESSED,
|
||||
const bool append = false
|
||||
IOstreamOption::appendType append = IOstreamOption::NON_APPEND
|
||||
)
|
||||
:
|
||||
OFstream(pathname, IOstreamOption(fmt, cmp), append)
|
||||
{}
|
||||
|
||||
//- Construct with specified atomic behaviour
|
||||
//- from pathname, format (uncompressed), optional append
|
||||
OFstream
|
||||
(
|
||||
IOstreamOption::atomicType atomic,
|
||||
const fileName& pathname,
|
||||
IOstreamOption::streamFormat fmt,
|
||||
IOstreamOption::compressionType cmp = IOstreamOption::UNCOMPRESSED,
|
||||
IOstreamOption::appendType append = IOstreamOption::NON_APPEND
|
||||
)
|
||||
:
|
||||
OFstream(atomic, pathname, IOstreamOption(fmt, cmp), append)
|
||||
{}
|
||||
|
||||
//- Destructor
|
||||
|
||||
//- Destructor. Possibly invokes an atomic rename
|
||||
//- (preference defined during construction)
|
||||
~OFstream();
|
||||
|
||||
|
||||
@ -122,13 +151,14 @@ public:
|
||||
#ifdef Foam_IOstream_extras
|
||||
|
||||
//- Construct from pathname, format (version, compression)
|
||||
FOAM_DEPRECATED_FOR(2022-09, "Construct without specifying version")
|
||||
OFstream
|
||||
(
|
||||
const fileName& pathname,
|
||||
IOstreamOption::streamFormat fmt,
|
||||
IOstreamOption::versionNumber ver,
|
||||
IOstreamOption::compressionType cmp = IOstreamOption::UNCOMPRESSED,
|
||||
const bool append = false
|
||||
IOstreamOption::appendType append = IOstreamOption::NON_APPEND
|
||||
)
|
||||
:
|
||||
OFstream(pathname, IOstreamOption(fmt, ver, cmp), append)
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2020 OpenCFD Ltd.
|
||||
Copyright (C) 2020-2022 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -77,12 +77,14 @@ class ifstreamPointer
|
||||
//- The stream pointer (ifstream or igzstream)
|
||||
std::unique_ptr<std::istream> ptr_;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Protected Member Functions
|
||||
|
||||
//- Special 'rewind' method for compressed stream
|
||||
void reopen_gz(const std::string& pathname_gz);
|
||||
void reopen_gz(const std::string& pathname);
|
||||
|
||||
|
||||
public:
|
||||
|
||||
@ -109,7 +111,9 @@ public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct from pathname
|
||||
//- Construct from pathname.
|
||||
// Attempts to read the specified file.
|
||||
// If that fails, try as a compressed file (.gz ending).
|
||||
explicit ifstreamPointer(const fileName& pathname);
|
||||
|
||||
|
||||
@ -167,23 +171,25 @@ class ofstreamPointer
|
||||
//- The stream pointer (ofstream | ogzstream | ocountstream)
|
||||
std::unique_ptr<std::ostream> ptr_;
|
||||
|
||||
//- Atomic file creation
|
||||
bool atomic_;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Protected Member Functions
|
||||
|
||||
//- Special 'rewind' method for compressed stream
|
||||
void reopen_gz(const std::string& pathname_gz);
|
||||
|
||||
//- General 'rewind' method (non-compressed)
|
||||
//- Reopen for compressed/non-compressed
|
||||
void reopen(const std::string& pathname);
|
||||
|
||||
//- Close stream and rename file
|
||||
void close(const std::string& pathname);
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// Generated Methods
|
||||
|
||||
//- Default construct (empty)
|
||||
ofstreamPointer() noexcept = default;
|
||||
|
||||
//- No copy construct
|
||||
ofstreamPointer(const ofstreamPointer&) = delete;
|
||||
|
||||
@ -202,22 +208,25 @@ public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Default construct (empty)
|
||||
ofstreamPointer() noexcept;
|
||||
|
||||
//- Construct as null output stream using Foam::ocountstream
|
||||
explicit ofstreamPointer(std::nullptr_t);
|
||||
|
||||
//- Construct from pathname, with specified append option
|
||||
ofstreamPointer(const fileName& pathname, const bool append)
|
||||
:
|
||||
ofstreamPointer(pathname, IOstreamOption::UNCOMPRESSED, append)
|
||||
{}
|
||||
|
||||
//- Construct from pathname,
|
||||
//- with preferred compression and specified append option
|
||||
//- Construct from pathname, compression, append, file handling atomic
|
||||
// \param pathname The file name to open for writing
|
||||
// \param comp UNCOMPRESSED | COMPRESSED
|
||||
// \param append Open in append mode
|
||||
// \param atomic Write into temporary file (not target file).
|
||||
// This option should only be used with a stream wrapper
|
||||
// (eg, OFstream) that handles the final renaming.
|
||||
explicit ofstreamPointer
|
||||
(
|
||||
const fileName& pathname,
|
||||
IOstreamOption::compressionType comp = IOstreamOption::UNCOMPRESSED,
|
||||
const bool append = false
|
||||
const bool append = false,
|
||||
const bool atomic = false
|
||||
);
|
||||
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011 OpenFOAM Foundation
|
||||
Copyright (C) 2018-2021 OpenCFD Ltd.
|
||||
Copyright (C) 2018-2022 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -29,6 +29,7 @@ License
|
||||
#include "fstreamPointer.H"
|
||||
#include "OCountStream.H"
|
||||
#include "OSspecific.H"
|
||||
#include <cstdio>
|
||||
|
||||
// HAVE_LIBZ defined externally
|
||||
// #define HAVE_LIBZ
|
||||
@ -37,37 +38,6 @@ License
|
||||
#include "gzstream.h"
|
||||
#endif /* HAVE_LIBZ */
|
||||
|
||||
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
static inline void removeConflictingFiles
|
||||
(
|
||||
const fileName& otherName,
|
||||
const bool append,
|
||||
const fileName& targetName
|
||||
)
|
||||
{
|
||||
// Remove other (compressed/uncompressed) version
|
||||
|
||||
const fileName::Type pathType = Foam::type(otherName, false);
|
||||
|
||||
if (pathType == fileName::FILE || pathType == fileName::SYMLINK)
|
||||
{
|
||||
Foam::rm(otherName);
|
||||
}
|
||||
|
||||
// Disallow writing into symlinked files.
|
||||
// Eg, avoid problems with symlinked initial fields
|
||||
|
||||
if (!append && Foam::type(targetName, false) == fileName::SYMLINK)
|
||||
{
|
||||
Foam::rm(targetName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
|
||||
|
||||
bool Foam::ifstreamPointer::supports_gz()
|
||||
@ -112,7 +82,7 @@ Foam::ifstreamPointer::ifstreamPointer
|
||||
|
||||
const fileName pathname_gz(pathname + ".gz");
|
||||
|
||||
if (isFile(pathname_gz, false))
|
||||
if (Foam::isFile(pathname_gz, false))
|
||||
{
|
||||
#ifdef HAVE_LIBZ
|
||||
|
||||
@ -128,13 +98,29 @@ Foam::ifstreamPointer::ifstreamPointer
|
||||
|
||||
#endif /* HAVE_LIBZ */
|
||||
}
|
||||
else
|
||||
{
|
||||
// TBD:
|
||||
// Can also fallback and open .orig files too
|
||||
//
|
||||
// auto* file = dynamic_cast<std::ifstream*>(ptr_.get());
|
||||
// file->open(pathname + ".orig", mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Foam::ofstreamPointer::ofstreamPointer() noexcept
|
||||
:
|
||||
ptr_(),
|
||||
atomic_(false)
|
||||
{}
|
||||
|
||||
|
||||
Foam::ofstreamPointer::ofstreamPointer(std::nullptr_t)
|
||||
:
|
||||
ptr_(new Foam::ocountstream)
|
||||
ptr_(new Foam::ocountstream),
|
||||
atomic_(false)
|
||||
{}
|
||||
|
||||
|
||||
@ -142,10 +128,12 @@ Foam::ofstreamPointer::ofstreamPointer
|
||||
(
|
||||
const fileName& pathname,
|
||||
IOstreamOption::compressionType comp,
|
||||
const bool append
|
||||
const bool append,
|
||||
const bool atomic
|
||||
)
|
||||
:
|
||||
ptr_(nullptr)
|
||||
ptr_(nullptr),
|
||||
atomic_(atomic)
|
||||
{
|
||||
std::ios_base::openmode mode
|
||||
(
|
||||
@ -155,18 +143,56 @@ Foam::ofstreamPointer::ofstreamPointer
|
||||
if (append)
|
||||
{
|
||||
mode |= std::ios_base::app;
|
||||
|
||||
// Cannot append to gzstream
|
||||
comp = IOstreamOption::UNCOMPRESSED;
|
||||
|
||||
// Cannot use append + atomic operation, without lots of extra work
|
||||
atomic_ = false;
|
||||
}
|
||||
|
||||
|
||||
// When opening new files, remove file variants out of the way.
|
||||
// Eg, opening "file1"
|
||||
// - remove old "file1.gz" (compressed)
|
||||
// - also remove old "file1" if it is a symlink and we are not appending
|
||||
//
|
||||
// Not writing into symlinked files avoids problems with symlinked
|
||||
// initial fields (eg, 0/U -> ../0.orig/U)
|
||||
|
||||
const fileName pathname_gz(pathname + ".gz");
|
||||
const fileName pathname_tmp(pathname + "~tmp~");
|
||||
|
||||
fileName::Type fType = fileName::Type::UNDEFINED;
|
||||
|
||||
if (IOstreamOption::COMPRESSED == comp)
|
||||
{
|
||||
// Output compression requested
|
||||
// Output compression requested.
|
||||
|
||||
#ifdef HAVE_LIBZ
|
||||
// TBD:
|
||||
// atomic_ = true; // Always treat COMPRESSED like an atomic
|
||||
|
||||
removeConflictingFiles(pathname, append, pathname_gz);
|
||||
ptr_.reset(new ogzstream(pathname_gz, mode));
|
||||
const fileName& target = (atomic_ ? pathname_tmp : pathname_gz);
|
||||
|
||||
// Remove old uncompressed version (if any)
|
||||
fType = Foam::type(pathname, false);
|
||||
if (fType == fileName::SYMLINK || fType == fileName::FILE)
|
||||
{
|
||||
Foam::rm(pathname);
|
||||
}
|
||||
|
||||
// Avoid writing into symlinked files (non-append mode)
|
||||
if (!append || atomic_)
|
||||
{
|
||||
fType = Foam::type(target, false);
|
||||
if (fType == fileName::SYMLINK)
|
||||
{
|
||||
Foam::rm(target);
|
||||
}
|
||||
}
|
||||
|
||||
ptr_.reset(new ogzstream(target, mode));
|
||||
|
||||
#else /* HAVE_LIBZ */
|
||||
|
||||
@ -181,43 +207,51 @@ Foam::ofstreamPointer::ofstreamPointer
|
||||
#endif /* HAVE_LIBZ */
|
||||
}
|
||||
|
||||
if (IOstreamOption::UNCOMPRESSED == comp)
|
||||
if (IOstreamOption::COMPRESSED != comp)
|
||||
{
|
||||
removeConflictingFiles(pathname_gz, append, pathname);
|
||||
ptr_.reset(new std::ofstream(pathname, mode));
|
||||
const fileName& target = (atomic_ ? pathname_tmp : pathname);
|
||||
|
||||
// Remove old compressed version (if any)
|
||||
fType = Foam::type(pathname_gz, false);
|
||||
if (fType == fileName::SYMLINK || fType == fileName::FILE)
|
||||
{
|
||||
Foam::rm(pathname_gz);
|
||||
}
|
||||
|
||||
// Avoid writing into symlinked files (non-append mode)
|
||||
if (!append || atomic_)
|
||||
{
|
||||
fType = Foam::type(target, false);
|
||||
if (fType == fileName::SYMLINK)
|
||||
{
|
||||
Foam::rm(target);
|
||||
}
|
||||
}
|
||||
|
||||
ptr_.reset(new std::ofstream(target, mode));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
void Foam::ifstreamPointer::reopen_gz(const std::string& pathname_gz)
|
||||
void Foam::ifstreamPointer::reopen_gz(const std::string& pathname)
|
||||
{
|
||||
#ifdef HAVE_LIBZ
|
||||
igzstream* gz = dynamic_cast<igzstream*>(ptr_.get());
|
||||
auto* gz = dynamic_cast<igzstream*>(ptr_.get());
|
||||
|
||||
if (gz)
|
||||
{
|
||||
// Special treatment for gzstream
|
||||
gz->close();
|
||||
gz->clear();
|
||||
gz->open(pathname_gz);
|
||||
}
|
||||
#endif /* HAVE_LIBZ */
|
||||
}
|
||||
|
||||
|
||||
void Foam::ofstreamPointer::reopen_gz(const std::string& pathname_gz)
|
||||
{
|
||||
#ifdef HAVE_LIBZ
|
||||
ogzstream* gz = dynamic_cast<ogzstream*>(ptr_.get());
|
||||
|
||||
if (gz)
|
||||
{
|
||||
// Special treatment for gzstream
|
||||
gz->close();
|
||||
gz->clear();
|
||||
gz->open(pathname_gz);
|
||||
gz->open
|
||||
(
|
||||
pathname + ".gz",
|
||||
(std::ios_base::in | std::ios_base::binary)
|
||||
);
|
||||
return;
|
||||
}
|
||||
#endif /* HAVE_LIBZ */
|
||||
}
|
||||
@ -225,7 +259,36 @@ void Foam::ofstreamPointer::reopen_gz(const std::string& pathname_gz)
|
||||
|
||||
void Foam::ofstreamPointer::reopen(const std::string& pathname)
|
||||
{
|
||||
std::ofstream* file = dynamic_cast<std::ofstream*>(ptr_.get());
|
||||
#ifdef HAVE_LIBZ
|
||||
auto* gz = dynamic_cast<ogzstream*>(ptr_.get());
|
||||
|
||||
if (gz)
|
||||
{
|
||||
// Special treatment for gzstream
|
||||
gz->close();
|
||||
gz->clear();
|
||||
|
||||
if (atomic_)
|
||||
{
|
||||
gz->open
|
||||
(
|
||||
pathname + "~tmp~",
|
||||
(std::ios_base::out | std::ios_base::binary)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
gz->open
|
||||
(
|
||||
pathname + ".gz",
|
||||
(std::ios_base::out | std::ios_base::binary)
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif /* HAVE_LIBZ */
|
||||
|
||||
auto* file = dynamic_cast<std::ofstream*>(ptr_.get());
|
||||
|
||||
if (file)
|
||||
{
|
||||
@ -234,7 +297,69 @@ void Foam::ofstreamPointer::reopen(const std::string& pathname)
|
||||
file->close();
|
||||
}
|
||||
file->clear();
|
||||
file->open(pathname);
|
||||
|
||||
// Don't need original request to append since rewind implies
|
||||
// trashing that anyhow.
|
||||
|
||||
if (atomic_)
|
||||
{
|
||||
file->open
|
||||
(
|
||||
pathname + "~tmp~",
|
||||
(std::ios_base::out | std::ios_base::binary)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
file->open
|
||||
(
|
||||
pathname,
|
||||
(std::ios_base::out | std::ios_base::binary)
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::ofstreamPointer::close(const std::string& pathname)
|
||||
{
|
||||
if (!atomic_ || pathname.empty()) return;
|
||||
|
||||
#ifdef HAVE_LIBZ
|
||||
auto* gz = dynamic_cast<ogzstream*>(ptr_.get());
|
||||
|
||||
if (gz)
|
||||
{
|
||||
// Special treatment for gzstream
|
||||
gz->close();
|
||||
gz->clear();
|
||||
|
||||
std::rename
|
||||
(
|
||||
(pathname + "~tmp~").c_str(),
|
||||
(pathname + ".gz").c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
#endif /* HAVE_LIBZ */
|
||||
|
||||
auto* file = dynamic_cast<std::ofstream*>(ptr_.get());
|
||||
|
||||
if (file)
|
||||
{
|
||||
if (file->is_open())
|
||||
{
|
||||
file->close();
|
||||
}
|
||||
file->clear();
|
||||
|
||||
std::rename
|
||||
(
|
||||
(pathname + "~tmp~").c_str(),
|
||||
pathname.c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -83,7 +83,7 @@ void Foam::masterOFstream::checkWrite
|
||||
const std::string& s
|
||||
)
|
||||
{
|
||||
checkWrite(fName, &s[0], s.length());
|
||||
checkWrite(fName, s.data(), s.length());
|
||||
}
|
||||
|
||||
|
||||
@ -126,7 +126,7 @@ void Foam::masterOFstream::commit()
|
||||
string s(this->str());
|
||||
this->reset();
|
||||
|
||||
os.write(&s[0], s.length());
|
||||
os.write(s.data(), s.length());
|
||||
}
|
||||
|
||||
labelList recvSizes;
|
||||
@ -179,7 +179,7 @@ Foam::masterOFstream::masterOFstream
|
||||
(
|
||||
const fileName& pathName,
|
||||
IOstreamOption streamOpt,
|
||||
const bool append,
|
||||
IOstreamOption::appendType append,
|
||||
const bool valid
|
||||
)
|
||||
:
|
||||
|
||||
@ -55,11 +55,14 @@ class masterOFstream
|
||||
{
|
||||
// Private Data
|
||||
|
||||
//- The backend file name
|
||||
const fileName pathName_;
|
||||
|
||||
//- Output file compression
|
||||
const IOstreamOption::compressionType compression_;
|
||||
|
||||
const bool append_;
|
||||
//- Open file in append mode
|
||||
const IOstreamOption::appendType append_;
|
||||
|
||||
//- Should file be written
|
||||
const bool valid_;
|
||||
@ -91,7 +94,7 @@ public:
|
||||
(
|
||||
const fileName& pathname,
|
||||
IOstreamOption streamOpt = IOstreamOption(),
|
||||
const bool append = false,
|
||||
IOstreamOption::appendType append = IOstreamOption::NON_APPEND,
|
||||
const bool valid = true
|
||||
);
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2015 OpenFOAM Foundation
|
||||
Copyright (C) 2018-2021 OpenCFD Ltd.
|
||||
Copyright (C) 2018-2022 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
@ -26,7 +26,7 @@ License
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "IOstreamOption.H"
|
||||
#include "error.H"
|
||||
#include "debug.H"
|
||||
#include "dictionary.H"
|
||||
#include "Enum.H"
|
||||
#include "Switch.H"
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2015 OpenFOAM Foundation
|
||||
Copyright (C) 2018-2021 OpenCFD Ltd.
|
||||
Copyright (C) 2018-2022 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -36,6 +36,9 @@ Description
|
||||
The compression (UNCOMPRESSED | COMPRESSED) is typically controlled
|
||||
by switch values (true/false, on/off, ...).
|
||||
|
||||
Additionally, some enumerations are defined (APPEND, NON_APPEND, ...)
|
||||
that are useful, verbose alternatives to bool values.
|
||||
|
||||
SourceFiles
|
||||
IOstreamOption.C
|
||||
|
||||
@ -80,6 +83,20 @@ public:
|
||||
COMPRESSED //!< compression = true
|
||||
};
|
||||
|
||||
//- File appending (NON_APPEND | APPEND)
|
||||
enum appendType : char
|
||||
{
|
||||
NON_APPEND = 0, //!< append = false
|
||||
APPEND //!< append = true
|
||||
};
|
||||
|
||||
//- Atomic operations (output)
|
||||
enum atomicType : char
|
||||
{
|
||||
NON_ATOMIC = 0, //!< atomic = false
|
||||
ATOMIC //!< atomic = true
|
||||
};
|
||||
|
||||
|
||||
//- Representation of a major/minor version number
|
||||
class versionNumber
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2017-2018 OpenFOAM Foundation
|
||||
Copyright (C) 2019-2021 OpenCFD Ltd.
|
||||
Copyright (C) 2019-2022 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -51,7 +51,7 @@ bool Foam::OFstreamCollator::writeFile
|
||||
const labelUList& recvSizes,
|
||||
const PtrList<SubList<char>>& slaveData, // optional slave data
|
||||
IOstreamOption streamOpt,
|
||||
const bool append,
|
||||
IOstreamOption::appendType append,
|
||||
const dictionary& headerEntries
|
||||
)
|
||||
{
|
||||
@ -79,7 +79,7 @@ bool Foam::OFstreamCollator::writeFile
|
||||
osPtr.reset(new OFstream(fName, streamOpt, append));
|
||||
auto& os = *osPtr;
|
||||
|
||||
if (!append)
|
||||
if (append == IOstreamOption::NON_APPEND)
|
||||
{
|
||||
// No IOobject so cannot use IOobject::writeHeader
|
||||
|
||||
@ -348,7 +348,7 @@ bool Foam::OFstreamCollator::write
|
||||
const fileName& fName,
|
||||
const string& data,
|
||||
IOstreamOption streamOpt,
|
||||
const bool append,
|
||||
IOstreamOption::appendType append,
|
||||
const bool useThread,
|
||||
const dictionary& headerEntries
|
||||
)
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2017-2018 OpenFOAM Foundation
|
||||
Copyright (C) 2021 OpenCFD Ltd.
|
||||
Copyright (C) 2021-2022 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -48,8 +48,8 @@ SourceFiles
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef OFstreamCollator_H
|
||||
#define OFstreamCollator_H
|
||||
#ifndef Foam_OFstreamCollator_H
|
||||
#define Foam_OFstreamCollator_H
|
||||
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
@ -81,7 +81,7 @@ class OFstreamCollator
|
||||
const labelList sizes_;
|
||||
PtrList<List<char>> slaveData_;
|
||||
const IOstreamOption streamOpt_;
|
||||
const bool append_;
|
||||
IOstreamOption::appendType append_;
|
||||
const dictionary headerEntries_;
|
||||
|
||||
writeData
|
||||
@ -92,7 +92,7 @@ class OFstreamCollator
|
||||
const string& data,
|
||||
const labelList& sizes,
|
||||
IOstreamOption streamOpt,
|
||||
const bool append,
|
||||
IOstreamOption::appendType append,
|
||||
const dictionary& headerEntries
|
||||
)
|
||||
:
|
||||
@ -157,7 +157,7 @@ class OFstreamCollator
|
||||
const labelUList& recvSizes,
|
||||
const PtrList<SubList<char>>& slaveData,
|
||||
IOstreamOption streamOpt,
|
||||
const bool append,
|
||||
IOstreamOption::appendType append,
|
||||
const dictionary& headerEntries
|
||||
);
|
||||
|
||||
@ -200,7 +200,7 @@ public:
|
||||
const fileName&,
|
||||
const string& data,
|
||||
IOstreamOption streamOpt,
|
||||
const bool append,
|
||||
IOstreamOption::appendType append,
|
||||
const bool useThread = true,
|
||||
const dictionary& headerEntries = dictionary::null
|
||||
);
|
||||
|
||||
@ -217,13 +217,17 @@ bool Foam::fileOperations::collatedFileOperation::appendObject
|
||||
|
||||
// Note: cannot do append + compression. This is a limitation
|
||||
// of ogzstream (or rather most compressed formats)
|
||||
//
|
||||
// File should always be created as non-atomic
|
||||
// (consistency between append/non-append)
|
||||
|
||||
OFstream os
|
||||
(
|
||||
pathName,
|
||||
// UNCOMPRESSED
|
||||
// UNCOMPRESSED (binary only)
|
||||
IOstreamOption(IOstreamOption::BINARY, streamOpt.version()),
|
||||
!isMaster // append slaves
|
||||
// Append on sub-ranks
|
||||
(isMaster ? IOstreamOption::NON_APPEND : IOstreamOption::APPEND)
|
||||
);
|
||||
|
||||
if (!os.good())
|
||||
@ -381,7 +385,7 @@ bool Foam::fileOperations::collatedFileOperation::writeObject
|
||||
(
|
||||
pathName,
|
||||
streamOpt,
|
||||
false, // append=false
|
||||
IOstreamOption::NON_APPEND,
|
||||
valid
|
||||
);
|
||||
|
||||
@ -424,7 +428,7 @@ bool Foam::fileOperations::collatedFileOperation::writeObject
|
||||
(
|
||||
pathName,
|
||||
streamOpt,
|
||||
false, // append=false
|
||||
IOstreamOption::NON_APPEND,
|
||||
valid
|
||||
);
|
||||
|
||||
|
||||
@ -59,7 +59,7 @@ Foam::threadedCollatedOFstream::~threadedCollatedOFstream()
|
||||
pathName_,
|
||||
str(),
|
||||
IOstreamOption(IOstreamOption::BINARY, version(), compression_),
|
||||
false, // append=false
|
||||
IOstreamOption::NON_APPEND,
|
||||
useThread_,
|
||||
headerEntries_
|
||||
);
|
||||
|
||||
@ -2455,7 +2455,7 @@ Foam::fileOperations::masterUncollatedFileOperation::NewOFstream
|
||||
(
|
||||
pathName,
|
||||
streamOpt,
|
||||
false, // append=false
|
||||
IOstreamOption::NON_APPEND,
|
||||
valid
|
||||
)
|
||||
);
|
||||
|
||||
@ -79,7 +79,7 @@ Foam::ensightFile::ensightFile
|
||||
IOstreamOption::streamFormat fmt
|
||||
)
|
||||
:
|
||||
OFstream(ensight::FileName(pathname), fmt)
|
||||
OFstream(IOstreamOption::ATOMIC, ensight::FileName(pathname), fmt)
|
||||
{
|
||||
init();
|
||||
}
|
||||
@ -92,7 +92,7 @@ Foam::ensightFile::ensightFile
|
||||
IOstreamOption::streamFormat fmt
|
||||
)
|
||||
:
|
||||
OFstream(path/ensight::FileName(name), fmt)
|
||||
OFstream(IOstreamOption::ATOMIC, path/ensight::FileName(name), fmt)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ public:
|
||||
// Static Functions
|
||||
|
||||
//- Return a null ensightFile
|
||||
inline static const ensightFile& null()
|
||||
static const ensightFile& null()
|
||||
{
|
||||
return NullObjectRef<ensightFile>();
|
||||
}
|
||||
@ -102,6 +102,7 @@ public:
|
||||
|
||||
//- Construct from path-name.
|
||||
// The path-name is adjusted for valid ensight file naming.
|
||||
// Always created as an atomic
|
||||
explicit ensightFile
|
||||
(
|
||||
const fileName& pathname,
|
||||
@ -110,6 +111,7 @@ public:
|
||||
|
||||
//- Construct from path and name.
|
||||
// Only the name portion is adjusted for valid ensight file naming.
|
||||
// Always created as an atomic
|
||||
ensightFile
|
||||
(
|
||||
const fileName& path,
|
||||
|
||||
@ -67,7 +67,7 @@ public:
|
||||
// Static Functions
|
||||
|
||||
//- Return a null ensightGeoFile
|
||||
inline static const ensightGeoFile& null()
|
||||
static const ensightGeoFile& null()
|
||||
{
|
||||
return NullObjectRef<ensightGeoFile>();
|
||||
}
|
||||
|
||||
@ -1314,7 +1314,7 @@ bool Foam::lumpedPointMovement::writeData
|
||||
(
|
||||
coupler().resolveFile(logName_),
|
||||
IOstreamOption(),
|
||||
true // append
|
||||
IOstreamOption::APPEND
|
||||
);
|
||||
|
||||
writeData(os, forces, moments, outputFormatType::PLAIN, timesWritten);
|
||||
|
||||
Reference in New Issue
Block a user