Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
VariableIOWriterMng.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* VariableIOWriterMng.cc (C) 2000-2026 */
9/* */
10/* Class managing input/output for variables. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/impl/internal/VariableMng.h"
15
16#include "arcane/utils/FatalErrorException.h"
17#include "arcane/utils/IObservable.h"
18#include "arcane/utils/ScopedPtr.h"
19#include "arcane/utils/StringBuilder.h"
20#include "arcane/utils/MD5HashAlgorithm.h"
21#include "arcane/utils/SHA1HashAlgorithm.h"
22#include "arcane/utils/JSONWriter.h"
23#include "arcane/utils/ValueConvert.h"
24
25#include "arcane/core/IDataWriter.h"
26#include "arcane/core/IXmlDocumentHolder.h"
27#include "arcane/core/DomUtils.h"
28#include "arcane/core/XmlNode.h"
29#include "arcane/core/VariableMetaData.h"
30#include "arcane/core/IData.h"
31#include "arcane/core/IMesh.h"
32#include "arcane/core/Properties.h"
33#include "arcane/core/Timer.h"
34#include "arcane/core/ICheckpointWriter.h"
35#include "arcane/core/IPostProcessorWriter.h"
36#include "arcane/core/internal/IDataInternal.h"
37
38#include "arcane/core/ISubDomain.h"
39#include "arcane/core/IParallelMng.h"
40
41/*---------------------------------------------------------------------------*/
42/*---------------------------------------------------------------------------*/
43
44namespace Arcane
45{
46
47/*---------------------------------------------------------------------------*/
48/*---------------------------------------------------------------------------*/
49
50VariableIOWriterMng::
51VariableIOWriterMng(VariableMng* vm)
52: TraceAccessor(vm->traceMng())
53, m_variable_mng(vm)
54{
55 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_VARIABLEMNG_HASHV2", true))
56 m_use_hash_v2 = (v.value() != 0);
57}
58
59/*---------------------------------------------------------------------------*/
60/*---------------------------------------------------------------------------*/
61
62/*---------------------------------------------------------------------------*/
63/*---------------------------------------------------------------------------*/
64
65void VariableIOWriterMng::
66writeCheckpoint(ICheckpointWriter* service)
67{
68 if (!service)
69 ARCANE_FATAL("No protection service specified");
70
71 Trace::Setter mci(traceMng(), _msgClassName());
72
73 Timer::Phase tp(m_variable_mng->m_time_stats, TP_InputOutput);
74
75 CheckpointSaveFilter save_filter;
76
77 service->notifyBeginWrite();
78 IDataWriter* data_writer = service->dataWriter();
79 if (!data_writer)
80 ARCANE_FATAL("no writer() nor dataWriter()");
81 writeVariables(data_writer, &save_filter, true);
82 service->notifyEndWrite();
83}
84
85/*---------------------------------------------------------------------------*/
86/*---------------------------------------------------------------------------*/
87
88void VariableIOWriterMng::
89writePostProcessing(IPostProcessorWriter* post_processor)
90{
91 Trace::Setter mci(traceMng(), _msgClassName());
92
93 if (!post_processor)
94 ARCANE_FATAL("No post-processing service specified");
95
96 Timer::Phase tp(m_variable_mng->m_time_stats, TP_InputOutput);
97
98 post_processor->notifyBeginWrite();
99 VariableCollection variables(post_processor->variables());
100 IDataWriter* data_writer = post_processor->dataWriter();
101 if (!data_writer)
102 ARCANE_FATAL("no writer() nor dataWriter()");
103 writeVariables(data_writer, variables, false);
104 post_processor->notifyEndWrite();
105}
106
107/*---------------------------------------------------------------------------*/
108/*---------------------------------------------------------------------------*/
109
110void VariableIOWriterMng::
111writeVariables(IDataWriter* writer, IVariableFilter* filter, bool use_hash)
112{
113 Trace::Setter mci(traceMng(), _msgClassName());
114
115 if (!writer)
116 ARCANE_FATAL("No writer available for protection");
117
118 // Calculate the list of variables to save
119 VariableList vars;
120 for (const auto& i : m_variable_mng->m_full_name_variable_map) {
121 IVariable* var = i.second;
122 bool apply_var = true;
123 if (filter)
124 apply_var = filter->applyFilter(*var);
125 if (apply_var)
126 vars.add(var);
127 }
128 _writeVariables(writer, vars, use_hash);
129}
130
131/*---------------------------------------------------------------------------*/
132/*---------------------------------------------------------------------------*/
133
137void VariableIOWriterMng::
138writeVariables(IDataWriter* writer, const VariableCollection& vars, bool use_hash)
139{
140 if (!writer)
141 return;
142 if (vars.empty()) {
143 VariableList var_array;
144 for (const auto& i : m_variable_mng->m_full_name_variable_map) {
145 IVariable* var = i.second;
146 var_array.add(var);
147 }
148 _writeVariables(writer, var_array, use_hash);
149 }
150 else
151 _writeVariables(writer, vars, use_hash);
152}
153
154/*---------------------------------------------------------------------------*/
155/*---------------------------------------------------------------------------*/
156
157namespace
158{
159 void _writeAttribute(JSONWriter& json_writer, XmlNode var_node, const String& name, const String& value)
160 {
161 var_node.setAttrValue(name, value);
162 json_writer.write(name, value);
163 }
164 void _writeAttribute(JSONWriter& json_writer, XmlNode var_node, const String& name, Int32 value)
165 {
166 Int64 v = value;
167 var_node.setAttrValue(name, String::fromNumber(v));
168 json_writer.write(name, v);
169 }
170 void _writeAttribute(JSONWriter& json_writer, XmlNode var_node, const String& name, bool value)
171 {
172 var_node.setAttrValue(name, String::fromNumber(value));
173 json_writer.write(name, value);
174 }
175
176} // namespace
177
178/*---------------------------------------------------------------------------*/
179/*---------------------------------------------------------------------------*/
180
181void VariableIOWriterMng::
182_generateVariablesMetaData(JSONWriter& json_writer, XmlNode variables_node,
183 const VariableCollection& vars, IHashAlgorithm* hash_algo)
184{
185 StringBuilder var_full_type_b;
186 ByteUniqueArray hash_values;
187 Ref<IHashAlgorithmContext> hash_context;
188 if (m_use_hash_v2) {
189 SHA1HashAlgorithm sha1_hash_algo;
190 hash_context = sha1_hash_algo.createContext();
191 }
192
193 json_writer.writeKey("variables");
194 json_writer.beginArray();
195
196 for (VariableCollection::Enumerator i(vars); ++i;) {
197 JSONWriter::Object o(json_writer);
198 IVariable* var = *i;
199 Ref<VariableMetaData> vmd(var->createMetaDataRef());
200 String var_full_type = vmd->fullType();
201 String var_family_name = var->itemFamilyName();
202 String var_mesh_name = var->meshName();
203 XmlNode var_node = XmlElement(variables_node, "variable");
204 _writeAttribute(json_writer, var_node, "base-name", var->name());
205 if (!var_family_name.null())
206 _writeAttribute(json_writer, var_node, "item-family-name", var_family_name);
207 if (var->isPartial())
208 _writeAttribute(json_writer, var_node, "item-group-name", var->itemGroupName());
209 if (!var_mesh_name.null())
210 _writeAttribute(json_writer, var_node, "mesh-name", var_mesh_name);
211 _writeAttribute(json_writer, var_node, "full-type", var_full_type);
212 _writeAttribute(json_writer, var_node, "data-type", String(dataTypeName(var->dataType())));
213 _writeAttribute(json_writer, var_node, "dimension", var->dimension());
214 _writeAttribute(json_writer, var_node, "multi-tag", var->multiTag());
215 _writeAttribute(json_writer, var_node, "property", var->property());
216 if (hash_algo) {
217 hash_values.clear();
218 if (var->property() & IVariable::PDumpNull)
219 var->data()->cloneEmptyRef()->computeHash(hash_algo, hash_values);
220 else
221 var->data()->computeHash(hash_algo, hash_values);
222 String hash_str = Convert::toHexaString(hash_values);
223 _writeAttribute(json_writer, var_node, "hash", hash_str);
224 if (hash_context.get()) {
225 hash_context->reset();
226 DataHashInfo hash_info(hash_context.get());
227 if (var->property() & IVariable::PDumpNull)
228 var->data()->cloneEmptyRef()->_commonInternal()->computeHash(hash_info);
229 else
230 var->data()->_commonInternal()->computeHash(hash_info);
231 HashAlgorithmValue hash_value;
232 hash_context->computeHashValue(hash_value);
233 String hash2_str = Convert::toHexaString(asBytes(hash_value.bytes()));
234 info(6) << "Hash=" << hash2_str << " old_hash="
235 << hash_str << " name=" << var->name();
236 _writeAttribute(json_writer, var_node, "hash2", hash2_str);
237 _writeAttribute(json_writer, var_node, "hash-version", hash_info.version());
238 }
239 }
240 }
241
242 json_writer.endArray();
243}
244
245/*---------------------------------------------------------------------------*/
246/*---------------------------------------------------------------------------*/
247
252void VariableIOWriterMng::
253_generateMeshesMetaData(JSONWriter& json_writer, XmlNode meshes_node)
254{
255 // Positionne un numéro de version pour compatibilité avec de futures versions
256 meshes_node.setAttrValue("version", "1");
257
258 json_writer.writeKey("meshes");
259 json_writer.beginArray();
260
261 ISubDomain* sd = m_variable_mng->subDomain();
262 IParallelMng* pm = m_variable_mng->parallelMng();
263 IMesh* default_mesh = sd->defaultMesh();
264 bool is_parallel = pm->isParallel();
265 IParallelMng* seq_pm = pm->sequentialParallelMng();
266 ConstArrayView<IMesh*> meshes = sd->meshes();
267 for (Integer i = 0, n = meshes.size(); i < n; ++i) {
268 IMesh* mesh = meshes[i];
269 bool do_dump = mesh->properties()->getBool("dump");
270 // Save the mesh if it is marked dump or if it is the default mesh
271 if (do_dump || mesh == default_mesh) {
272 JSONWriter::Object o(json_writer);
273 XmlNode mesh_node = XmlElement(meshes_node, "mesh");
274 _writeAttribute(json_writer, mesh_node, "name", mesh->name());
275 _writeAttribute(json_writer, mesh_node, "factory-name", mesh->factoryName());
276 // Indicates if the mesh uses the parallelism manager
277 // sequential because in this case, during restart, it must be created with the
278 // same manager.
279 // TODO: cases where a mesh is created
280 // with an IParallelMng that is neither sequential nor the one of the
281 // subdomain.
282 if (is_parallel && mesh->parallelMng() == seq_pm)
283 _writeAttribute(json_writer, mesh_node, "sequential", true);
284 }
285 }
286
287 json_writer.endArray();
288}
289
290/*---------------------------------------------------------------------------*/
291/*---------------------------------------------------------------------------*/
292
293String VariableIOWriterMng::
294_generateMetaData(const VariableCollection& vars, IHashAlgorithm* hash_algo)
295{
296 JSONWriter json_writer(JSONWriter::FormatFlags::None);
297
298 ScopedPtrT<IXmlDocumentHolder> doc(domutils::createXmlDocument());
299 XmlNode doc_node = doc->documentNode();
300 XmlElement root_element(doc_node, "arcane-checkpoint-metadata");
301 XmlElement variables_node(root_element, "variables");
302 {
303 JSONWriter::Object o(json_writer);
304 JSONWriter::Object o2(json_writer, "arcane-checkpoint-metadata");
305 json_writer.write("version", static_cast<Int64>(1));
306 if (hash_algo)
307 json_writer.write("hash-algorithm-name", hash_algo->name());
308 _generateVariablesMetaData(json_writer, variables_node, vars, hash_algo);
309 XmlElement meshes_node(root_element, "meshes");
310 _generateMeshesMetaData(json_writer, meshes_node);
311 }
312 {
313 // Saves the JSON serialization into an XML file element.
314 XmlElement json_node(root_element, "json", json_writer.getBuffer());
315 }
316 String s = doc->save();
317 info(6) << "META_DATA=" << s;
318 return s;
319}
320
321/*---------------------------------------------------------------------------*/
322/*---------------------------------------------------------------------------*/
323
324void VariableIOWriterMng::
325_writeVariables(IDataWriter* writer, const VariableCollection& vars, bool use_hash)
326{
327 if (!writer)
328 return;
329
330 m_variable_mng->m_write_observable->notifyAllObservers();
331 writer->beginWrite(vars);
332
333 // Calls the notification of variable writing
334 // It must be done before positioning the metadata
335 // because this allows changing the variable value
336 // during this call.
337 for (VariableCollection::Enumerator i(vars); ++i;) {
338 IVariable* var = *i;
339 if (var->isUsed())
340 var->notifyBeginWrite();
341 }
342
343 MD5HashAlgorithm md5_hash_algo;
344 SHA1HashAlgorithm sha1_hash_algo;
345 IHashAlgorithm* hash_algo = &md5_hash_algo;
346 if (m_use_hash_v2)
347 hash_algo = &sha1_hash_algo;
348 if (!use_hash)
349 hash_algo = nullptr;
350 String meta_data = _generateMetaData(vars, hash_algo);
351 writer->setMetaData(meta_data);
352
353 for (VariableCollection::Enumerator i(vars); ++i;) {
354 IVariable* var = *i;
355 if (!var->isUsed())
356 continue;
357 try {
358 if (var->property() & (IVariable::PDumpNull))
359 writer->write(var, var->data()->cloneEmptyRef().get());
360 else
361 writer->write(var, var->data());
362 }
363 catch (const Exception& ex) {
364 error() << "Exception Arcane while VariableMng::writeVariables()"
365 << " var=" << var->fullName()
366 << " exception=" << ex;
367 throw;
368 }
369 catch (const std::exception& ex) {
370 error() << "Exception while VariableMng::writeVariables()"
371 << " var=" << var->fullName()
372 << " exception=" << ex.what();
373 throw;
374 }
375 }
376 writer->endWrite();
377}
378
379/*---------------------------------------------------------------------------*/
380/*---------------------------------------------------------------------------*/
381
382} // End namespace Arcane
383
384/*---------------------------------------------------------------------------*/
385/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
Constant view of an array of type T.
constexpr Integer size() const noexcept
Number of elements in the array.
Interface for writing variable data.
Definition IDataWriter.h:45
Interface of a hashing algorithm.
virtual String name() const
Name of the algorithm.
Interface of the parallelism manager for a subdomain.
virtual IParallelMng * sequentialParallelMng()=0
Returns a sequential parallelism manager.
virtual bool isParallel() const =0
Returns true if the execution is parallel.
Interface of the subdomain manager.
Definition ISubDomain.h:75
virtual IMesh * defaultMesh()=0
Default mesh.
virtual ConstArrayView< IMesh * > meshes() const =0
List of meshes in the subdomain.
Interface of a variable.
Definition IVariable.h:40
Encapsulation of an automatically destructing pointer.
Definition ScopedPtr.h:44
Variable manager.
Definition VariableMng.h:57
Element of a DOM tree.
Definition XmlNode.h:406
Node of a DOM tree.
Definition XmlNode.h:51
void setAttrValue(const String &name, const String &value)
Sets the attribute name to the value value.
Definition XmlNode.cc:248
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
UniqueArray< Byte > ByteUniqueArray
Dynamic 1D array of characters.
Definition UtilsTypes.h:335
Impl::SpanTypeFromSize< conststd::byte, SizeType >::SpanType asBytes(const SpanImpl< DataType, SizeType, Extent > &s)
Converts the view into an array of non-modifiable bytes.
Definition Span.h:1032
const char * dataTypeName(eDataType type)
Data type name.
Definition DataTypes.cc:72