Arcane  v3.14.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
VariableIOWriterMng.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2024 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-2024 */
9/* */
10/* Classe gérant les entrées/sorties pour les 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 // Calcul la liste des variables à sauver
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/*---------------------------------------------------------------------------*/
136void VariableIOWriterMng::
137writeVariables(IDataWriter* writer, const VariableCollection& vars, bool use_hash)
138{
139 if (!writer)
140 return;
141 if (vars.empty()) {
143 for (const auto& i : m_variable_mng->m_full_name_variable_map) {
144 IVariable* var = i.second;
145 var_array.add(var);
146 }
147 _writeVariables(writer, var_array, use_hash);
148 }
149 else
150 _writeVariables(writer, vars, use_hash);
151}
152
153/*---------------------------------------------------------------------------*/
154/*---------------------------------------------------------------------------*/
155
156namespace
157{
158 void _writeAttribute(JSONWriter& json_writer, XmlNode var_node, const String& name, const String& value)
159 {
160 var_node.setAttrValue(name, value);
161 json_writer.write(name, value);
162 }
163 void _writeAttribute(JSONWriter& json_writer, XmlNode var_node, const String& name, Int32 value)
164 {
165 Int64 v = value;
166 var_node.setAttrValue(name, String::fromNumber(v));
167 json_writer.write(name, v);
168 }
169 void _writeAttribute(JSONWriter& json_writer, XmlNode var_node, const String& name, bool value)
170 {
171 var_node.setAttrValue(name, String::fromNumber(value));
172 json_writer.write(name, value);
173 }
174
175} // namespace
176
177/*---------------------------------------------------------------------------*/
178/*---------------------------------------------------------------------------*/
179
180void VariableIOWriterMng::
181_generateVariablesMetaData(JSONWriter& json_writer, XmlNode variables_node,
182 const VariableCollection& vars, IHashAlgorithm* hash_algo)
183{
184 StringBuilder var_full_type_b;
185 ByteUniqueArray hash_values;
186 Ref<IHashAlgorithmContext> hash_context;
187 if (m_use_hash_v2) {
188 SHA1HashAlgorithm sha1_hash_algo;
189 hash_context = sha1_hash_algo.createContext();
190 }
191
192 json_writer.writeKey("variables");
193 json_writer.beginArray();
194
195 for (VariableCollection::Enumerator i(vars); ++i;) {
196 JSONWriter::Object o(json_writer);
197 IVariable* var = *i;
198 Ref<VariableMetaData> vmd(var->createMetaDataRef());
199 String var_full_type = vmd->fullType();
200 String var_family_name = var->itemFamilyName();
201 String var_mesh_name = var->meshName();
202 XmlNode var_node = XmlElement(variables_node, "variable");
203 _writeAttribute(json_writer, var_node, "base-name", var->name());
204 if (!var_family_name.null())
205 _writeAttribute(json_writer, var_node, "item-family-name", var_family_name);
206 if (var->isPartial())
207 _writeAttribute(json_writer, var_node, "item-group-name", var->itemGroupName());
208 if (!var_mesh_name.null())
209 _writeAttribute(json_writer, var_node, "mesh-name", var_mesh_name);
210 _writeAttribute(json_writer, var_node, "full-type", var_full_type);
211 _writeAttribute(json_writer, var_node, "data-type", String(dataTypeName(var->dataType())));
212 _writeAttribute(json_writer, var_node, "dimension", var->dimension());
213 _writeAttribute(json_writer, var_node, "multi-tag", var->multiTag());
214 _writeAttribute(json_writer, var_node, "property", var->property());
215 if (hash_algo) {
216 hash_values.clear();
217 var->data()->computeHash(hash_algo, hash_values);
218 String hash_str = Convert::toHexaString(hash_values);
219 _writeAttribute(json_writer, var_node, "hash", hash_str);
220 if (hash_context.get()) {
221 hash_context->reset();
222 DataHashInfo hash_info(hash_context.get());
223 var->data()->_commonInternal()->computeHash(hash_info);
224 HashAlgorithmValue hash_value;
225 hash_context->computeHashValue(hash_value);
226 String hash2_str = Convert::toHexaString(asBytes(hash_value.bytes()));
227 info(6) << "Hash=" << hash2_str << " old_hash="
228 << hash_str << " name=" << var->name();
229 _writeAttribute(json_writer, var_node, "hash2", hash2_str);
230 _writeAttribute(json_writer, var_node, "hash-version", hash_info.version());
231 }
232 }
233 }
234
235 json_writer.endArray();
236}
237
238/*---------------------------------------------------------------------------*/
239/*---------------------------------------------------------------------------*/
244void VariableIOWriterMng::
245_generateMeshesMetaData(JSONWriter& json_writer, XmlNode meshes_node)
246{
247 // Positionne un numéro de version pour compatibilité avec de futures versions
248 meshes_node.setAttrValue("version", "1");
249
250 json_writer.writeKey("meshes");
251 json_writer.beginArray();
252
253 ISubDomain* sd = m_variable_mng->subDomain();
254 IParallelMng* pm = m_variable_mng->parallelMng();
255 IMesh* default_mesh = sd->defaultMesh();
256 bool is_parallel = pm->isParallel();
258 ConstArrayView<IMesh*> meshes = sd->meshes();
259 for (Integer i = 0, n = meshes.size(); i < n; ++i) {
260 IMesh* mesh = meshes[i];
261 bool do_dump = mesh->properties()->getBool("dump");
262 // Sauve le maillage s'il est marqué dump ou s'il s'agit du maillage par défaut
263 if (do_dump || mesh == default_mesh) {
266 _writeAttribute(json_writer, mesh_node, "name", mesh->name());
267 _writeAttribute(json_writer, mesh_node, "factory-name", mesh->factoryName());
268 // Indique si le maillage utilise le gestionnaire de parallélisme
269 // séquentiel car dans ce cas en reprise il faut le créer avec le
270 // même gestionnaire.
271 // TODO: il faudrait traiter les cas où un maillage est créé
272 // avec un IParallelMng qui n'est ni séquentiel, ni celui du
273 // sous-domaine.
274 if (is_parallel && mesh->parallelMng() == seq_pm)
275 _writeAttribute(json_writer, mesh_node, "sequential", true);
276 }
277 }
278
279 json_writer.endArray();
280}
281
282/*---------------------------------------------------------------------------*/
283/*---------------------------------------------------------------------------*/
284
285String VariableIOWriterMng::
286_generateMetaData(const VariableCollection& vars, IHashAlgorithm* hash_algo)
287{
288 JSONWriter json_writer(JSONWriter::FormatFlags::None);
289
290 ScopedPtrT<IXmlDocumentHolder> doc(domutils::createXmlDocument());
291 XmlNode doc_node = doc->documentNode();
292 XmlElement root_element(doc_node, "arcane-checkpoint-metadata");
294 {
296 JSONWriter::Object o2(json_writer, "arcane-checkpoint-metadata");
297 json_writer.write("version", static_cast<Int64>(1));
298 if (hash_algo)
299 json_writer.write("hash-algorithm-name", hash_algo->name());
300 _generateVariablesMetaData(json_writer, variables_node, vars, hash_algo);
302 _generateMeshesMetaData(json_writer, meshes_node);
303 }
304 {
305 // Sauve la sérialisation JSON dans un élément du fichier XML.
306 XmlElement json_node(root_element, "json", json_writer.getBuffer());
307 }
308 String s = doc->save();
309 info(6) << "META_DATA=" << s;
310 return s;
311}
312
313/*---------------------------------------------------------------------------*/
314/*---------------------------------------------------------------------------*/
315
316void VariableIOWriterMng::
317_writeVariables(IDataWriter* writer, const VariableCollection& vars, bool use_hash)
318{
319 if (!writer)
320 return;
321
322 m_variable_mng->m_write_observable->notifyAllObservers();
323 writer->beginWrite(vars);
324
325 // Appelle la notification de l'écriture des variables
326 // Il faut le faire avant de positionner les méta-données
327 // car cela autorise de changer la valeur de la variable
328 // lors de cet appel.
329 for (VariableCollection::Enumerator i(vars); ++i;) {
330 IVariable* var = *i;
331 if (var->isUsed())
332 var->notifyBeginWrite();
333 }
334
335 MD5HashAlgorithm md5_hash_algo;
336 SHA1HashAlgorithm sha1_hash_algo;
337 IHashAlgorithm* hash_algo = &md5_hash_algo;
338 if (m_use_hash_v2)
339 hash_algo = &sha1_hash_algo;
340 if (!use_hash)
341 hash_algo = nullptr;
342 String meta_data = _generateMetaData(vars, hash_algo);
343 writer->setMetaData(meta_data);
344
345 for (VariableCollection::Enumerator i(vars); ++i;) {
346 IVariable* var = *i;
347 if (!var->isUsed())
348 continue;
349 try {
350 writer->write(var, var->data());
351 }
352 catch (const Exception& ex) {
353 error() << "Exception Arcane while VariableMng::writeVariables()"
354 << " var=" << var->fullName()
355 << " exception=" << ex;
356 throw;
357 }
358 catch (const std::exception& ex) {
359 error() << "Exception while VariableMng::writeVariables()"
360 << " var=" << var->fullName()
361 << " exception=" << ex.what();
362 throw;
363 }
364 }
365 writer->endWrite();
366}
367
368/*---------------------------------------------------------------------------*/
369/*---------------------------------------------------------------------------*/
370
371} // End namespace Arcane
372
373/*---------------------------------------------------------------------------*/
374/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Interface d'écriture des données d'une variable.
Definition IDataWriter.h:49
Interface d'un algorithme de hashage.
virtual String name() const =0
Nom du maillage.
virtual IParallelMng * parallelMng()=0
Gestionnaire de parallèlisme.
virtual String factoryName() const =0
Nom de la fabrique utilisée pour créer le maillage.
virtual Properties * properties()=0
Propriétés associées à ce maillage.
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual IParallelMng * sequentialParallelMng()=0
Retourne un gestionnaire de parallélisme séquentiel.
virtual bool isParallel() const =0
Retourne true si l'exécution est parallèle.
Interface du gestionnaire d'un sous-domaine.
Definition ISubDomain.h:74
Interface d'une variable.
Definition IVariable.h:54
Ecrivain au format JSON.
Definition JSONWriter.h:33
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
Collection de variables.
Elément d'un arbre DOM.
Definition XmlNode.h:396
Noeud d'un arbre DOM.
Definition XmlNode.h:51
Chaîne de caractères unicode.
Positionne une classe de message.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
UniqueArray< Byte > ByteUniqueArray
Tableau dynamique à une dimension de caractères.
Definition UtilsTypes.h:509
const char * dataTypeName(eDataType type)
Nom du type de donnée.
Definition DataTypes.cc:70
detail::SpanTypeFromSize< conststd::byte, SizeType >::SpanType asBytes(const SpanImpl< DataType, SizeType, Extent > &s)
Converti la vue en un tableau d'octets non modifiables.
Definition Span.h:881