Arcane  4.2.1.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
BasicWriter.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/* BasicWriter.cc (C) 2000-2026 */
9/* */
10/* Ecriture simple pour les protections/reprises. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/std/internal/BasicWriter.h"
15
16#include "arcane/utils/FatalErrorException.h"
17#include "arcane/utils/StringBuilder.h"
18#include "arcane/utils/PlatformUtils.h"
19#include "arcane/utils/JSONWriter.h"
20#include "arcane/utils/IDataCompressor.h"
21#include "arcane/utils/MemoryView.h"
22#include "arcane/utils/Ref.h"
23#include "arcane/utils/IHashAlgorithm.h"
24
25#include "arcane/core/IParallelMng.h"
26#include "arcane/core/ItemGroup.h"
27#include "arcane/core/IVariable.h"
28#include "arcane/core/IItemFamily.h"
29#include "arcane/core/IData.h"
30#include "arcane/core/internal/IVariableInternal.h"
31
32#include "arcane/std/internal/ParallelDataWriter.h"
33
34#include <fstream>
35
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
38
39namespace Arcane::impl
40{
41
42/*---------------------------------------------------------------------------*/
43/*---------------------------------------------------------------------------*/
44
45BasicWriter::
46BasicWriter(IApplication* app, IParallelMng* pm, const String& path,
47 eOpenMode open_mode, Int32 version, bool want_parallel)
48: BasicReaderWriterCommon(app, pm, path, open_mode)
49, m_want_parallel(want_parallel)
50, m_version(version)
51{
52}
53
54/*---------------------------------------------------------------------------*/
55/*---------------------------------------------------------------------------*/
56
57void BasicWriter::
58initialize()
59{
60 _checkNoInit();
61
62 Int32 rank = m_parallel_mng->commRank();
63 if (m_open_mode == OpenModeTruncate && m_parallel_mng->isMasterIO())
64 platform::recursiveCreateDirectory(m_path);
65 m_parallel_mng->barrier();
66 String filename = _getBasicVariableFile(m_version, m_path, rank);
67 m_text_writer = makeRef(new KeyValueTextWriter(traceMng(), filename, m_version));
68 m_text_writer->setDataCompressor(m_data_compressor);
69 m_text_writer->setHashAlgorithm(m_hash_algorithm);
70
71 // Permet de surcharger le service utilisé pour la compression par une
72 // variable d'environnement si aucun n'est positionné
73 if (!m_data_compressor.get()) {
74 String data_compressor_name = platform::getEnvironmentVariable("ARCANE_DEFLATER");
75 if (!data_compressor_name.null()) {
76 data_compressor_name = data_compressor_name + "DataCompressor";
77 auto bc = _createDeflater(m_application, data_compressor_name);
78 info() << "Utilisation du data_compressor de la variable d'environnement ARCANE_DEFLATER nom=" << data_compressor_name;
79 m_data_compressor = bc;
80 m_text_writer->setDataCompressor(bc);
81 }
82 }
83
84 // Idem pour le service de calcul de hash
85 if (!m_hash_algorithm.get()) {
86 String hash_algorithm_name = platform::getEnvironmentVariable("ARCANE_HASHALGORITHM");
87 if (hash_algorithm_name.null())
88 hash_algorithm_name = "SHA3_256";
89 else
90 info() << "Utilisation de l'algorithme de hachage de la variable d'environnement ARCANE_HASHALGORITHM nom=" << hash_algorithm_name;
91 hash_algorithm_name = hash_algorithm_name + "HashAlgorithm";
92 auto v = _createHashAlgorithm(m_application, hash_algorithm_name);
93 m_hash_algorithm = v;
94 m_text_writer->setHashAlgorithm(v);
95 }
96
97 // Pour test, permet de spécifier un service pour le calcul du hash global.
98 if (!m_compare_hash_algorithm.get()) {
99 String algo_name = platform::getEnvironmentVariable("ARCANE_COMPAREHASHALGORITHM");
100 if (!algo_name.empty()) {
101 info() << "Utilisation de l'algorithme de hachage global de la variable d'environnement ARCANE_COMPAREHASHALGORITHM nom=" << algo_name;
102 algo_name = algo_name + "HashAlgorithm";
103 auto v = _createHashAlgorithm(m_application, algo_name);
104 m_compare_hash_algorithm = v;
105 }
106 }
107
108 m_global_writer = new BasicGenericWriter(m_application, m_version, m_text_writer);
109 if (m_verbose_level > 0)
110 info() << "** MODE D'OUVERTURE = " << m_open_mode;
111}
112
113/*---------------------------------------------------------------------------*/
114/*---------------------------------------------------------------------------*/
115
116void BasicWriter::
117_checkNoInit()
118{
119 if (m_is_init)
120 ARCANE_FATAL("initialize() a déjà été appelé");
121}
122
123/*---------------------------------------------------------------------------*/
124/*---------------------------------------------------------------------------*/
125
126Ref<ParallelDataWriter> BasicWriter::
127_getWriter(IVariable* var)
128{
129 return m_parallel_data_writers.getOrCreateWriter(var->itemGroup());
130}
131
132/*---------------------------------------------------------------------------*/
133/*---------------------------------------------------------------------------*/
134
135void BasicWriter::
136_directWriteVal(IVariable* var, IData* data)
137{
138 info(4) << "ÉCRITURE DIRECTE VAL v=" << var->fullName();
139
140 IData* write_data = data;
141 Int64ConstArrayView written_unique_ids;
142 Int64UniqueArray wanted_unique_ids;
143 Int64UniqueArray sequential_written_unique_ids;
144
145 Ref<IData> allocated_write_data;
146 const bool is_mesh_variable = (var->itemKind() != IK_Unknown);
147 if (is_mesh_variable) {
148 ItemGroup group = var->itemGroup();
149 if (m_want_parallel) {
150 Ref<ParallelDataWriter> writer = _getWriter(var);
151 written_unique_ids = writer->sortedUniqueIds();
152 allocated_write_data = writer->getSortedValues(data);
153 write_data = allocated_write_data.get();
154 }
155 else {
156 // TODO vérifier que les uniqueId() sont bien triés.
157 // Normalement c'est toujours le cas.
158 _fillUniqueIds(group, sequential_written_unique_ids);
159 written_unique_ids = sequential_written_unique_ids.view();
160 }
161 // Ecrit les informations du groupe si c'est la première fois qu'on accède à ce groupe.
162 if (m_written_groups.find(group) == m_written_groups.end()) {
163 info(5) << "GROUPE D'ÉCRITURE " << group.name();
164 const IItemFamily* item_family = group.itemFamily();
165 const String& gname = group.name();
166 String group_full_name = item_family->fullName() + "_" + gname;
167 _fillUniqueIds(group, wanted_unique_ids);
168 if (m_is_save_values)
169 m_global_writer->writeItemGroup(group_full_name, written_unique_ids, wanted_unique_ids.view());
170 m_written_groups.insert(group);
171 }
172 }
173
174 Ref<ISerializedData> sdata(write_data->createSerializedDataRef(false));
175 String compare_hash;
176 if (is_mesh_variable) {
177 compare_hash = _computeCompareHash(var, write_data);
178 }
179 m_global_writer->writeData(var->fullName(), sdata.get(), compare_hash, m_is_save_values);
180}
181
182/*---------------------------------------------------------------------------*/
183/*---------------------------------------------------------------------------*/
196String BasicWriter::
197_computeCompareHash(IVariable* var, IData* write_data)
198{
199 IHashAlgorithm* hash_algo = m_compare_hash_algorithm.get();
200 if (!hash_algo)
201 return {};
202 return var->_internalApi()->computeComparisonHashCollective(hash_algo, write_data);
203}
204
205/*---------------------------------------------------------------------------*/
206/*---------------------------------------------------------------------------*/
207
208void BasicWriter::
209write(IVariable* var, IData* data)
210{
211 if (var->isPartial()) {
212 info() << "** AVERTISSEMENT : variable partielle non implémentée dans BasicWriter";
213 return;
214 }
215 _directWriteVal(var, data);
216}
217
218/*---------------------------------------------------------------------------*/
219/*---------------------------------------------------------------------------*/
220
221void BasicWriter::
222setMetaData(const String& meta_data)
223{
224 // Dans la version 3, les méta-données de la protection sont dans la
225 // base de données.
226 if (m_version >= 3) {
227 Span<const Byte> bytes = meta_data.utf8();
228 Int64 length = bytes.length();
229 String key_name = "Global:CheckpointMetadata";
230 m_text_writer->setExtents(key_name, Int64ConstArrayView(1, &length));
231 m_text_writer->write(key_name, asBytes(bytes));
232 }
233 else {
234 Int32 my_rank = m_parallel_mng->commRank();
235 String filename = _getMetaDataFileName(my_rank);
236 std::ofstream ofile(filename.localstr(), ios::binary);
237 meta_data.writeBytes(ofile);
238 }
239}
240
241/*---------------------------------------------------------------------------*/
242/*---------------------------------------------------------------------------*/
243
244void BasicWriter::
245beginWrite(const VariableCollection& vars)
246{
247 ARCANE_UNUSED(vars);
248 Int32 my_rank = m_parallel_mng->commRank();
249 m_global_writer->initialize(m_path, my_rank);
250}
251
252/*---------------------------------------------------------------------------*/
253/*---------------------------------------------------------------------------*/
254
255void BasicWriter::
256_endWriteV3()
257{
258 const Int64 nb_part = m_parallel_mng->commSize();
259
260 // Sauvegarde les informations au format JSON
261 JSONWriter jsw;
262
263 {
264 JSONWriter::Object main_object(jsw);
265 jsw.writeKey(_getArcaneDBTag());
266 {
267 JSONWriter::Object db_object(jsw);
268 jsw.write("Version", (Int64)m_version);
269 jsw.write("NbPart", nb_part);
270 jsw.write("HasValues", m_is_save_values);
271
272 String data_compressor_name;
273 Int64 data_compressor_min_size = 0;
274 if (m_data_compressor.get()) {
275 data_compressor_name = m_data_compressor->name();
276 data_compressor_min_size = m_data_compressor->minCompressSize();
277 }
278 jsw.write("DataCompressor", data_compressor_name);
279 jsw.write("DataCompressorMinSize", String::fromNumber(data_compressor_min_size));
280
281 // Sauve le nom de l'algorithme de hash
282 {
283 String name;
284 if (m_hash_algorithm.get())
285 name = m_hash_algorithm->name();
286 jsw.write("HashAlgorithm", name);
287 }
288
289 // Sauve le nom de l'algorithme de hash pour les comparaisons
290 {
291 String name;
292 if (m_compare_hash_algorithm.get())
293 name = m_compare_hash_algorithm->name();
294 jsw.write("ComparisonHashAlgorithm", name);
295 }
296 }
297 }
298
299 StringBuilder filename = m_path;
300 filename += "/arcane_acr_db.json";
301 String fn = filename.toString();
302 std::ofstream ofile(fn.localstr());
303 ofile << jsw.getBuffer();
304}
305
306/*---------------------------------------------------------------------------*/
307/*---------------------------------------------------------------------------*/
308
309void BasicWriter::
310endWrite()
311{
312 const IParallelMng* pm = m_parallel_mng;
313 if (pm->isMasterIO()) {
314 if (m_version >= 3) {
315 _endWriteV3();
316 }
317 else {
318 Int64 nb_part = pm->commSize();
319 StringBuilder filename = m_path;
320 filename += "/infos.txt";
321 String fn = filename.toString();
322 std::ofstream ofile(fn.localstr());
323 ofile << nb_part << '\n';
324 }
325 }
326 m_global_writer->endWrite();
327}
328
329/*---------------------------------------------------------------------------*/
330/*---------------------------------------------------------------------------*/
331
332} // namespace Arcane::impl
333
334/*---------------------------------------------------------------------------*/
335/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Interface d'une donnée.
Definition IData.h:33
Interface d'un algorithme de hashage.
virtual String computeComparisonHashCollective(IHashAlgorithm *hash_algo, IData *sorted_data)=0
Calcule de Hash de comparaison pour la variable.
Interface d'une variable.
Definition IVariable.h:39
virtual bool isPartial() const =0
Indique si la variable est partielle.
virtual IVariableInternal * _internalApi()=0
API interne à Arcane.
Vue d'un tableau d'éléments de type T.
Definition Span.h:633
Chaîne de caractères unicode.
void writeBytes(std::ostream &o) const
Écrit la chaîne au format UTF-8 sur le flot o.
Definition String.cc:1237
const char * localstr() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Definition String.cc:228
ByteConstArrayView utf8() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Definition String.cc:276
TraceMessage info() const
Flot pour un message d'information.
Collection de variables.
UniqueArray< Int64 > Int64UniqueArray
Tableau dynamique à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:337
std::int64_t Int64
Type entier signé sur 64 bits.
ConstArrayView< Int64 > Int64ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:478
Impl::SpanTypeFromSize< conststd::byte, SizeType >::SpanType asBytes(const SpanImpl< DataType, SizeType, Extent > &s)
Convertit la vue en un tableau d'octets non modifiables.
Definition Span.h:1028
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Créé une référence sur un pointeur.
std::int32_t Int32
Type entier signé sur 32 bits.