Arcane  4.2.1.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
BasicReader.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/* BasicReader.cc (C) 2000-2026 */
9/* */
10/* Lecture simple pour les protections/reprises. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/std/internal/BasicReader.h"
15
16#include "arcane/utils/PlatformUtils.h"
17#include "arcane/utils/JSONReader.h"
18#include "arcane/utils/Ref.h"
19
20#include "arcane/core/IParallelMng.h"
21#include "arcane/core/IIOMng.h"
22#include "arcane/core/IData.h"
23#include "arcane/core/ItemGroup.h"
24#include "arcane/core/IVariable.h"
25#include "arcane/core/SerializeBuffer.h"
26
27#include "arcane/std/internal/ParallelDataReader.h"
28
29#include <fstream>
30
31/*---------------------------------------------------------------------------*/
32/*---------------------------------------------------------------------------*/
33
34namespace Arcane::impl
35{
36
37/*---------------------------------------------------------------------------*/
38/*---------------------------------------------------------------------------*/
39
40BasicReader::
41BasicReader(IApplication* app, IParallelMng* pm, Int32 forced_rank_to_read,
42 const String& path, bool want_parallel)
43: BasicReaderWriterCommon(app, pm, path, BasicReaderWriterCommon::OpenModeRead)
44, m_want_parallel(want_parallel)
45, m_nb_written_part(0)
46, m_version(-1)
47, m_first_rank_to_read(0)
48, m_nb_rank_to_read(0)
49, m_forced_rank_to_read(forced_rank_to_read)
50, m_item_group_finder(nullptr)
51{
52}
53
54/*---------------------------------------------------------------------------*/
55/*---------------------------------------------------------------------------*/
56
57void BasicReader::
58initialize()
59{
60 info() << "BasicReader::initialize()";
61
62 IParallelMng* pm = m_parallel_mng;
63 // Si un fichier 'arcane_acr_db.json' existe alors on lit les informations
64 // de ce fichier pour détecter entre autre le numéro de version. Il faut
65 // le faire avant de lire les informations telles que les méta-données
66 // de la protection car l'emplacement des ces dernières dépend de la version
67 String db_filename = String::concat(m_path, "/arcane_acr_db.json");
68 Int32 has_db_file = 0;
69 {
70 if (pm->isMasterIO())
71 has_db_file = platform::isFileReadable(db_filename) ? 1 : 0;
72 pm->broadcast(Int32ArrayView(1, &has_db_file), pm->masterIORank());
73 }
74 String data_compressor_name;
75 String hash_algorithm_name;
76 String comparison_hash_algorithm_name;
77 if (has_db_file) {
78 UniqueArray<Byte> bytes;
79 pm->ioMng()->collectiveRead(db_filename, bytes, false);
80 JSONDocument json_doc;
81 json_doc.parse(bytes, db_filename);
82 JSONValue root = json_doc.root();
83 JSONValue jv_arcane_db = root.expectedChild(_getArcaneDBTag());
84 m_version = jv_arcane_db.expectedChild("Version").valueAsInt32();
85 m_nb_written_part = jv_arcane_db.expectedChild("NbPart").valueAsInt32();
86 data_compressor_name = jv_arcane_db.child("DataCompressor").value();
87 hash_algorithm_name = jv_arcane_db.child("HashAlgorithm").value();
88 comparison_hash_algorithm_name = jv_arcane_db.child("ComparisonHashAlgorithm").value();
89 info() << "**--** Début de la lecture en utilisant la version de la base de données=" << m_version
90 << " nb_part=" << m_nb_written_part
91 << " compresseur=" << data_compressor_name
92 << " hash_algorithm=" << hash_algorithm_name
93 << " comparison_hash_algorithm=" << comparison_hash_algorithm_name;
94 }
95 else {
96 // Ancien format
97 // Le proc maitre lit le fichier 'infos.txt' et envoie les informations
98 // aux autres. Ce format ne permet d'avoir que le nombre de parties
99 // comme information.
100 if (pm->isMasterIO()) {
101 Integer nb_part = 0;
102 String filename = String::concat(m_path, "/infos.txt");
103 std::ifstream ifile(filename.localstr());
104 ifile >> nb_part;
105 info(4) << "** NB PART=" << nb_part;
106 m_nb_written_part = nb_part;
107 }
108 pm->broadcast(Int32ArrayView(1, &m_nb_written_part), pm->masterIORank());
109 }
110 if (m_version >= 3) {
111 Int32 rank_to_read = m_forced_rank_to_read;
112 if (rank_to_read < 0) {
113 if (m_nb_written_part > 1)
114 rank_to_read = pm->commRank();
115 else
116 rank_to_read = 0;
117 }
118 String main_filename = _getBasicVariableFile(m_version, m_path, rank_to_read);
119 m_forced_rank_to_read_text_reader = makeRef(new KeyValueTextReader(traceMng(), main_filename, m_version));
120 if (!data_compressor_name.empty()) {
121 Ref<IDataCompressor> dc = _createDeflater(m_application, data_compressor_name);
122 m_forced_rank_to_read_text_reader->setDataCompressor(dc);
123 }
124 if (!hash_algorithm_name.empty()) {
125 Ref<IHashAlgorithm> v = _createHashAlgorithm(m_application, hash_algorithm_name);
126 m_forced_rank_to_read_text_reader->setHashAlgorithm(v);
127 }
128 if (!comparison_hash_algorithm_name.empty()) {
129 Ref<IHashAlgorithm> v = _createHashAlgorithm(m_application, comparison_hash_algorithm_name);
130 m_comparison_hash_algorithm = v;
131 }
132 }
133}
134
135/*---------------------------------------------------------------------------*/
136/*---------------------------------------------------------------------------*/
137
138void BasicReader::
139_directReadVal(VariableMetaData* varmd, IData* data)
140{
141 info(4) << "LECTURE DIRECT VAL v=" << varmd->fullName();
142
143 bool is_item_variable = !varmd->itemFamilyName().null();
144 Int32 nb_rank_to_read = m_nb_rank_to_read;
145 // S'il s'agit d'une variable qui n'est pas sur le maillage,
146 // il ne faut lire qu'un seul rang car il n'est pas
147 // certain que cette variable soit definie partout
148 if (!is_item_variable)
149 if (nb_rank_to_read > 1)
150 nb_rank_to_read = 1;
151
152 UniqueArray<Ref<IData>> allocated_data;
153 UniqueArray<IData*> written_data(nb_rank_to_read);
154
155 for (Integer i = 0; i < nb_rank_to_read; ++i) {
156 written_data[i] = data;
157 if ((nb_rank_to_read > 1 || m_want_parallel) && is_item_variable) {
158 Ref<IData> new_data = data->cloneEmptyRef();
159 written_data[i] = new_data.get();
160 allocated_data.add(new_data);
161 }
162 String vname = varmd->fullName();
163 info(4) << " ESSAI DE LECTURE var_full_name=" << vname;
164 m_global_readers[i]->readData(vname, written_data[i]);
165 if (i == 0 && m_comparison_hash_algorithm.get())
166 info(5) << "COMPARISON_HASH =" << m_global_readers[i]->comparisonHashValue(vname);
167 }
168
169 if (is_item_variable) {
170 Ref<ParallelDataReader> parallel_data_reader = _getReader(varmd);
171
172 Int64UniqueArray full_written_unique_ids;
173 IData* full_written_data = nullptr;
174
175 if (nb_rank_to_read == 0) {
176 // Rien à lire
177 // Il faut tout de même passer dans le reader parallèle
178 // pour assurer les opérations collectives
179 full_written_data = nullptr;
180 }
181 else if (nb_rank_to_read == 1) {
182 //full_written_unique_ids = written_unique_ids[0];
183 full_written_data = written_data[0];
184 }
185 else {
186 // Il faut créer une donnée qui contient l'union des written_data
187 Ref<IData> allocated_written_data = data->cloneEmptyRef();
188 allocated_data.add(allocated_written_data);
189 full_written_data = allocated_written_data.get();
190 SerializeBuffer sbuf;
191 sbuf.setMode(ISerializer::ModeReserve);
192 for (Int32 i = 0; i < nb_rank_to_read; ++i)
193 written_data[i]->serialize(&sbuf, nullptr);
194 sbuf.allocateBuffer();
195 sbuf.setMode(ISerializer::ModePut);
196 for (Int32 i = 0; i < nb_rank_to_read; ++i)
197 written_data[i]->serialize(&sbuf, nullptr);
198 sbuf.setMode(ISerializer::ModeGet);
199 sbuf.setReadMode(ISerializer::ReadAdd);
200 for (Int32 i = 0; i < nb_rank_to_read; ++i)
201 full_written_data->serialize(&sbuf, nullptr);
202 }
203 if (data != full_written_data) {
204 info(5) << "LECTURE PARALLÈLE";
205 parallel_data_reader->getSortedValues(full_written_data, data);
206 }
207 }
208}
209
210/*---------------------------------------------------------------------------*/
211/*---------------------------------------------------------------------------*/
212
213Ref<ParallelDataReader> BasicReader::
214_getReader(VariableMetaData* varmd)
215{
216 Int32 nb_to_read = m_nb_rank_to_read;
217
218 // Pour la lecture, lors d'une reprise, le groupe (var->itemGroup())
219 // associé à la variable ainsi que la famille (var->itemFamily())
220 // n'existe pas encore. Il ne faut donc pas l'utiliser
221 const String& var_group_name = varmd->itemGroupName();
222 String group_full_name = varmd->meshName() + "_" + varmd->itemFamilyName() + "_" + var_group_name;
223 auto ix = m_parallel_data_readers.find(group_full_name);
224 if (ix != m_parallel_data_readers.end())
225 return ix->second;
226
227 IParallelMng* pm = m_parallel_mng;
228 Ref<ParallelDataReader> reader = makeRef(new ParallelDataReader(pm));
229 {
230 UniqueArray<SharedArray<Int64>> written_unique_ids(nb_to_read);
231 Int64Array& wanted_unique_ids = reader->wantedUniqueIds();
232 for (Integer i = 0; i < nb_to_read; ++i) {
233 m_global_readers[i]->readItemGroup(group_full_name, written_unique_ids[i], wanted_unique_ids);
234 }
235 // Cela ne doit être actif que pour les comparaisons (pas en reprise car les groupes
236 // ne sont pas valides)
237 if (m_item_group_finder) {
238 ItemGroup ig = m_item_group_finder->getWantedGroup(varmd);
239 _fillUniqueIds(ig, wanted_unique_ids);
240 }
241 for (Integer i = 0; i < nb_to_read; ++i) {
242 Integer nb_uid = written_unique_ids[i].size();
243 if (nb_uid >= 1)
244 info(5) << "PART I=" << i
245 << " nb_uid=" << nb_uid
246 << " min_uid=" << written_unique_ids[i][0]
247 << " max_uid=" << written_unique_ids[i][nb_uid - 1];
248 }
249 Int64Array& full_written_unique_ids = reader->writtenUniqueIds();
250 for (Integer i = 0; i < nb_to_read; ++i)
251 full_written_unique_ids.addRange(written_unique_ids[i]);
252 info(5) << "TAILLE TOTALE DES UID=" << full_written_unique_ids.size();
253 if (m_want_parallel)
254 reader->sort();
255 }
256 m_parallel_data_readers.insert(std::make_pair(group_full_name, reader));
257 return reader;
258}
259
260/*---------------------------------------------------------------------------*/
261/*---------------------------------------------------------------------------*/
262
268void BasicReader::
269fillComparisonHash(std::map<String, String>& comparison_hash_map)
270{
271 comparison_hash_map.clear();
272 if (m_nb_rank_to_read == 0)
273 return;
274 if (m_parallel_mng->commRank() != m_parallel_mng->masterIORank())
275 return;
276 const VariableDataInfoMap& var_map = m_global_readers[0]->variablesDataInfoMap();
277 for (auto v : var_map) {
278 VariableDataInfo* vd = v.second.get();
279 comparison_hash_map.try_emplace(vd->fullName(), vd->comparisonHashValue());
280 }
281}
282
283/*---------------------------------------------------------------------------*/
284/*---------------------------------------------------------------------------*/
285
286void BasicReader::
287read(IVariable* var, IData* data)
288{
289 info(4) << "LECTURE MAÎTRE var=" << var->fullName() << " data=" << data;
290 if (var->isPartial()) {
291 info() << "** AVERTISSEMENT: variable partielle non implémentée dans BasicReaderWriter";
292 return;
293 }
295 _directReadVal(vmd.get(), data);
296}
297
298/*---------------------------------------------------------------------------*/
299/*---------------------------------------------------------------------------*/
300
301void BasicReader::
302read(const VariableDataReadInfo& infos)
303{
304 VariableMetaData* vmd = infos.variableMetaData();
305 IData* data = infos.data();
306 info(4) << "LECTURE MAÎTRE2 var=" << vmd->fullName() << " data=" << data;
307 if (vmd->isPartial()) {
308 info() << "** AVERTISSEMENT: variable partielle non implémentée dans BasicReaderWriter";
309 return;
310 }
311 _directReadVal(vmd, data);
312}
313
314/*---------------------------------------------------------------------------*/
315/*---------------------------------------------------------------------------*/
316
317String BasicReader::
318metaData()
319{
320 ByteUniqueArray bytes;
321 fillMetaData(bytes);
322 String s(bytes);
323 info(5) << " S=" << s << '\n';
324 return s;
325}
326
327/*---------------------------------------------------------------------------*/
328/*---------------------------------------------------------------------------*/
329
330void BasicReader::
331fillMetaData(ByteArray& bytes)
332{
333 Int32 rank = m_parallel_mng->commRank();
334 if (m_forced_rank_to_read >= 0)
335 rank = m_forced_rank_to_read;
336 if (m_version >= 3) {
337 Int64 meta_data_size = 0;
338 String key_name = "Global:CheckpointMetadata";
339 info(4) << "Lecture des métadonnées du point de contrôle depuis la base de données";
340 m_forced_rank_to_read_text_reader->getExtents(key_name, Int64ArrayView(1, &meta_data_size));
341 bytes.resize(meta_data_size);
342 m_forced_rank_to_read_text_reader->read(key_name, asWritableBytes(bytes.span()));
343 }
344 else {
345 String filename = _getMetaDataFileName(rank);
346 info(4) << "Lecture du fichier de métadonnées du point de contrôle=" << filename;
347 platform::readAllFile(filename, false, bytes);
348 }
349}
350
351/*---------------------------------------------------------------------------*/
352/*---------------------------------------------------------------------------*/
353
354void BasicReader::
355_setRanksToRead()
356{
357 IParallelMng* pm = m_parallel_mng;
358 Int32 my_rank = pm->commRank();
359 Int32 nb_rank = pm->commSize();
360 Int32 first_to_read = my_rank;
361 Int32 nb_to_read = 1;
362
363 if (m_forced_rank_to_read >= 0) {
364 m_first_rank_to_read = m_forced_rank_to_read;
365 m_nb_rank_to_read = 1;
366 return;
367 }
368 if (nb_rank == 1) {
369 nb_to_read = m_nb_written_part;
370 }
371 else if (nb_rank < m_nb_written_part) {
372 // Il y a plus de fichiers que de processeurs.
373 // Un des processeurs doit donc lire au moins deux fichiers.
374 // Pour ceux dont c'est le cas, il faut que ces fichiers
375 // soient consécutifs pour que l'intervalle des uniqueId()
376 // des entités du processeur soient consécutifs
377 Int32 nb_part_per_rank = m_nb_written_part / nb_rank;
378 Int32 remaining_nb_part = m_nb_written_part - (nb_part_per_rank * nb_rank);
379 first_to_read = nb_part_per_rank * my_rank;
380 nb_to_read = nb_part_per_rank;
381 info(4) << "NB_PART_PER_RANK = " << nb_part_per_rank
382 << " RESTANT=" << remaining_nb_part;
383 if (my_rank >= remaining_nb_part) {
384 first_to_read += remaining_nb_part;
385 }
386 else {
387 first_to_read += my_rank;
388 ++nb_to_read;
389 }
390 }
391 else {
392 if (my_rank >= m_nb_written_part) {
393 // Aucune partie à lire
394 nb_to_read = 0;
395 }
396 }
397
398 m_first_rank_to_read = first_to_read;
399 m_nb_rank_to_read = nb_to_read;
400}
401
402/*---------------------------------------------------------------------------*/
403/*---------------------------------------------------------------------------*/
404
405Ref<IGenericReader> BasicReader::
406_readOwnMetaDataAndCreateReader(Int32 rank)
407{
408 String main_filename = _getBasicVariableFile(m_version, m_path, rank);
409 Ref<KeyValueTextReader> text_reader;
410 if (m_version >= 3) {
411 // Si le rang est le même que m_forced_rank_to_read, alors on peut réutiliser
412 // le lecteur déjà créé.
413 if (rank == m_forced_rank_to_read)
414 text_reader = m_forced_rank_to_read_text_reader;
415 else {
416 text_reader = makeRef(new KeyValueTextReader(traceMng(), main_filename, m_version));
417 // Il faut que ce lecteur ait le même gestionnaire de compression
418 // que celui déjà créé
419 text_reader->setDataCompressor(m_forced_rank_to_read_text_reader->dataCompressor());
420 text_reader->setHashAlgorithm(m_forced_rank_to_read_text_reader->hashAlgorithm());
421 }
422 }
423
424 auto r = makeRef<IGenericReader>(new BasicGenericReader(m_application, m_version, text_reader));
425 r->initialize(m_path, rank);
426 return r;
427}
428
429/*---------------------------------------------------------------------------*/
430/*---------------------------------------------------------------------------*/
431
432void BasicReader::
433beginRead(const VariableCollection& vars)
434{
435 ARCANE_UNUSED(vars);
436 beginRead(DataReaderInfo());
437}
438
439/*---------------------------------------------------------------------------*/
440/*---------------------------------------------------------------------------*/
441
442void BasicReader::
443beginRead(const DataReaderInfo& infos)
444{
445 ARCANE_UNUSED(infos);
446 info(4) << "** ** DÉBUT DE LA LECTURE";
447
448 _setRanksToRead();
449 info(4) << "RangsÀLire: PREMIER À LIRE =" << m_first_rank_to_read
450 << " nb=" << m_nb_rank_to_read << " version=" << m_version;
451 m_global_readers.resize(m_nb_rank_to_read);
452 for (Integer i = 0; i < m_nb_rank_to_read; ++i)
453 m_global_readers[i] = _readOwnMetaDataAndCreateReader(i + m_first_rank_to_read);
454}
455
456/*---------------------------------------------------------------------------*/
457/*---------------------------------------------------------------------------*/
458
459} // namespace Arcane::impl
460
461/*---------------------------------------------------------------------------*/
462/*---------------------------------------------------------------------------*/
void addRange(ConstReferenceType val, Int64 n)
Ajoute n élément de valeur val à la fin du tableau.
Informations de relecture des données.
Interface d'une donnée.
Definition IData.h:33
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual Int32 commRank() const =0
Rang de cette instance dans le communicateur.
virtual Int32 commSize() const =0
Nombre d'instance dans le communicateur.
Interface d'une variable.
Definition IVariable.h:39
virtual String fullName() const =0
Nom complet de la variable (avec le préfixe de la famille).
virtual Ref< VariableMetaData > createMetaDataRef() const =0
Créé une instance contenant les meta-données de la variable.
virtual bool isPartial() const =0
Indique si la variable est partielle.
InstanceType * get() const
Instance associée ou nullptr si aucune.
Référence à une instance.
Chaîne de caractères unicode.
TraceMessage info() const
Flot pour un message d'information.
Informations de relecture des données d'une variable.
Meta-données sur une variable.
String fullName() const
Nom complet de la variable.
Ref< KeyValueTextReader > m_forced_rank_to_read_text_reader
Lecteur pour le premier rang à lire.
Definition BasicReader.h:91
void fillMetaData(ByteArray &bytes) override
Remplit bytes avec le contenu des méta-données.
Tableau associatif des données des variables.
Informations sur les données d'une variable.
bool readAllFile(StringView filename, bool is_binary, ByteArray &out_bytes)
Lit le contenu d'un fichier et le conserve dans out_bytes.
Array< Int64 > Int64Array
Tableau dynamique à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:119
ArrayView< Int64 > Int64ArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:449
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.
Int32 Integer
Type représentant un entier.
Array< Byte > ByteArray
Tableau dynamique à une dimension de caractères.
Definition UtilsTypes.h:115
UniqueArray< Byte > ByteUniqueArray
Tableau dynamique à une dimension de caractères.
Definition UtilsTypes.h:333
ArrayView< Int32 > Int32ArrayView
Equivalent C d'un tableau à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:451
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Créé une référence sur un pointeur.
Impl::SpanTypeFromSize< std::byte, SizeType >::SpanType asWritableBytes(const SpanImpl< DataType, SizeType, Extent > &s)
Convertit la vue en un tableau d'octets modifiables.
Definition Span.h:1064
std::int32_t Int32
Type entier signé sur 32 bits.