14#include "arcane/std/internal/BasicReaderWriterDatabase.h"
16#include "arcane/utils/Array.h"
17#include "arcane/utils/PlatformUtils.h"
18#include "arcane/utils/Ref.h"
19#include "arcane/utils/FatalErrorException.h"
20#include "arcane/utils/JSONReader.h"
21#include "arcane/utils/JSONWriter.h"
22#include "arcane/utils/CheckedConvert.h"
23#include "arcane/utils/IDataCompressor.h"
24#include "arcane/utils/SmallArray.h"
25#include "arcane/utils/IHashAlgorithm.h"
26#include "arcane/utils/ITraceMng.h"
28#include "arcane/core/ArcaneException.h"
30#include "arcane/std/internal/TextReader2.h"
31#include "arcane/std/internal/TextWriter2.h"
32#include "arcane/std/internal/IHashDatabase.h"
56 m_nb_processed_bytes += bytes.size();
57 m_hash_algorithm->computeHash64(bytes, hash_result);
59 m_hash_time += (t2 - t1);
65 m_hash_algorithm = algo;
70 if (m_nb_processed_bytes == 0)
72 Real nb_byte_per_second =
static_cast<Real>(m_nb_processed_bytes) / (m_hash_time + 1.0e-9);
74 nb_byte_per_second /= 1.0e6;
75 tm->
info() <<
"Hasher:nb_processed=" << m_nb_processed_bytes
76 <<
" hash_time=" << m_hash_time
77 <<
" rate=" <<
static_cast<Int64>(nb_byte_per_second) <<
" MB/s"
84 Int64 m_nb_processed_bytes = 0;
85 Real m_hash_time = 0.0;
92class BasicReaderWriterDatabaseEpilogFormat
99 static constexpr Int64 STRUCT_SIZE = 128;
103 BasicReaderWriterDatabaseEpilogFormat()
105 checkStructureSize();
106 for (
int i = 0; i < 10; ++i)
107 m_remaining_padding[i] = i;
112 void setJSONDataInfoOffsetAndSize(
Int64 file_offset,
Int64 data_size)
114 m_json_data_info_file_offset = file_offset;
115 m_json_data_info_size = data_size;
117 Int32 version()
const {
return m_version; }
118 Int64 jsonDataInfoFileOffset()
const {
return m_json_data_info_file_offset; }
119 Int64 jsonDataInfoSize()
const {
return m_json_data_info_size; }
122 return {
reinterpret_cast<std::byte*
>(
this), STRUCT_SIZE };
130 Int32 m_padding0 = 0;
131 Int64 m_padding1 = 0;
132 Int64 m_padding2 = 0;
133 Int64 m_padding3 = 0;
134 Int64 m_json_data_info_file_offset = -1;
135 Int64 m_json_data_info_size = 0;
136 Int64 m_remaining_padding[10];
140 static void checkStructureSize()
142 Int64 s =
sizeof(BasicReaderWriterDatabaseEpilogFormat);
143 if (s != STRUCT_SIZE)
144 ARCANE_FATAL(
"Invalid size for epilog format size={0} expected={1}", s, STRUCT_SIZE);
152class BasicReaderWriterDatabaseHeaderFormat
159 static constexpr Int64 STRUCT_SIZE = 128;
163 BasicReaderWriterDatabaseHeaderFormat()
165 checkStructureSize();
166 for (
int i = 0; i < 12; ++i)
167 m_remaining_padding[i] = i;
174 return {
reinterpret_cast<std::byte*
>(
this), STRUCT_SIZE };
176 void setVersion(
Int32 version) { m_version = version; }
177 Int32 version()
const {
return m_version; }
181 if (m_header_begin[0] !=
'A' || m_header_begin[1] !=
'C' || m_header_begin[2] !=
'R' || m_header_begin[3] != (
Byte)39)
189 std::array<Byte, 4> m_header_begin = {
'A',
'C',
'R', 39 };
191 Int32 m_endian_int = 0x01020304;
194 Int32 m_padding0 = 0;
195 Int64 m_padding1 = 0;
196 Int64 m_padding2 = 0;
197 Int64 m_remaining_padding[12];
201 static void checkStructureSize()
203 Int64 s =
sizeof(BasicReaderWriterDatabaseHeaderFormat);
204 if (s != STRUCT_SIZE)
205 ARCANE_FATAL(
"Invalid size for header format size={0} expected={1}", s, STRUCT_SIZE);
212class BasicReaderWriterDatabaseCommon
219 static constexpr int MAX_SIZE = 8;
227 for (
Int32 i = 0; i < nb; ++i)
234 return m_large_extents.view();
236 Int32 size()
const {
return nb; }
244 Int64 sizes[MAX_SIZE];
250 Int64 m_file_offset = 0;
261 if (!hash_directory.
null()) {
262 info() <<
"Using Hash database at location '" << hash_directory <<
"'";
263 m_hash_database = createFileHashDatabase(tm, hash_directory);
267 if (!redis_machine.
null()) {
268 info() <<
"Using Redis database at location '" << redis_machine <<
"'";
269 m_hash_database = createRedisHashDatabase(tm, redis_machine, 6379);
277 DataInfo& findData(
const String& key_name)
279 auto x = m_data_infos.find(key_name);
280 if (x == m_data_infos.end())
281 ARCANE_FATAL(
"Can not find key '{0}' in database", key_name);
287 std::map<String, DataInfo> m_data_infos;
288 Ref<IDataCompressor> m_data_compressor;
289 Ref<IHashAlgorithm> m_hash_algorithm;
290 Ref<IHashDatabase> m_hash_database;
300:
public BasicReaderWriterDatabaseCommon
305 : BasicReaderWriterDatabaseCommon(tm, version)
322 Int64 fileOffset() {
return m_writer.fileOffset(); }
329 void _writeKey(
const String& key);
350, m_p(new
Impl(tm, filename, version))
382 header.setVersion(m_version);
389void KeyValueTextWriter::Impl::
396 jsw.writeKey(
"Data");
398 for (
auto& x : m_data_infos) {
400 jsw.write(
"Name", x.first);
401 jsw.write(
"FileOffset", x.second.m_file_offset);
402 jsw.write(
"Extents", x.second.m_extents.view());
407 std::ostream& stream = m_writer.stream();
411 Int64 file_offset = m_writer.fileOffset();
419 epilog.setJSONDataInfoOffsetAndSize(file_offset, meta_data_size);
428void KeyValueTextWriter::Impl::
429setExtents(
const String& key_name, SmallSpan<const Int64> extents)
431 if (m_version >= 3) {
432 _addKey(key_name, extents);
439 Integer dimension_array_size = extents.size();
440 if (dimension_array_size != 0) {
441 String true_key_name =
"Extents:" + key_name;
442 String comment = String::format(
"Writing Dim1Size for '{0}'", key_name);
443 if (m_version == 1) {
445 UniqueArray<Integer> dims(dimension_array_size);
446 for (
Integer i = 0; i < dimension_array_size; ++i)
447 dims[i] = CheckedConvert::toInteger(extents[i]);
452 m_writer.write(
asBytes(extents));
460void KeyValueTextWriter::Impl::
461write(
const String& key, Span<const std::byte> values)
465 IDataCompressor* d = m_data_compressor.get();
467 if (d && len > d->minCompressSize()) {
468 UniqueArray<std::byte> compressed_values;
469 m_data_compressor->compress(values, compressed_values);
470 Int64 compressed_size = compressed_values.largeSize();
471 m_writer.write(
asBytes(Span<const Int64>(&compressed_size, 1)));
472 _write2(key, compressed_values);
475 _write2(key, values);
481void KeyValueTextWriter::Impl::
482_write2(
const String& key, Span<const std::byte> values)
484 if (m_hash_database.get()) {
485 IHashAlgorithm* hash_algo = m_hash_algorithm.get();
487 ARCANE_FATAL(
"Can not use hash database without hash algorithm");
489 SmallArray<Byte, 1024> hash_result;
490 m_hasher.computeHash(values, hash_result);
493 HashDatabaseWriteResult result;
494 HashDatabaseWriteArgs args(values, hash_value);
497 m_hash_database->writeValues(args, result);
498 info(5) <<
"WRITE_KW_HASH key=" << key <<
" hash=" << hash_value <<
" len=" << values.size();
499 m_writer.write(
asBytes(hash_result));
502 m_writer.write(values);
508String KeyValueTextWriter::
511 return m_p->m_writer.fileName();
517void KeyValueTextWriter::
518setDataCompressor(Ref<IDataCompressor> ds)
520 m_p->m_data_compressor = ds;
526Ref<IDataCompressor> KeyValueTextWriter::
527dataCompressor()
const
529 return m_p->m_data_compressor;
535void KeyValueTextWriter::
536setHashAlgorithm(Ref<IHashAlgorithm> v)
538 m_p->m_hash_algorithm = v;
539 m_p->m_hasher.setHashAlgorithm(v.get());
545Ref<IHashAlgorithm> KeyValueTextWriter::
548 return m_p->m_hash_algorithm;
554Int64 KeyValueTextWriter::
557 return m_p->m_writer.fileOffset();
563void KeyValueTextWriter::Impl::
564_addKey(
const String& key, SmallSpan<const Int64> extents)
567 d.m_extents.fill(extents);
568 m_data_infos.insert(std::make_pair(key, d));
574void KeyValueTextWriter::Impl::
575_writeKey(
const String& key)
577 if (m_version >= 3) {
578 auto x = m_data_infos.find(key);
579 if (x == m_data_infos.end())
580 ARCANE_FATAL(
"Key '{0}' is not in map. You should call setExtents() before", key);
581 x->second.m_file_offset = fileOffset();
591void KeyValueTextWriter::
592setExtents(
const String& key_name, SmallSpan<const Int64> extents)
594 m_p->setExtents(key_name, extents);
600void KeyValueTextWriter::
601write(
const String& key, Span<const std::byte> values)
603 m_p->write(key, values);
613:
public BasicReaderWriterDatabaseCommon
618 : BasicReaderWriterDatabaseCommon(tm, version)
622 if (m_version >= 3) {
638 void _setFileOffset(
const String& key_name);
653, m_p(new
Impl(tm, filename, version))
669void KeyValueTextReader::Impl::
672 m_reader.setFileOffset(offset);
673 std::istream& s = m_reader.stream();
676 ARCANE_FATAL(
"Can not read file part offset={0} length={1}", offset, bytes.length());
693 _readDirect(0, bytes);
694 header.checkHeader();
695 Int32 version = header.version();
696 if (version != m_version)
697 ARCANE_FATAL(
"Invalid version for ACR file version={0} expected={1}", version, m_version);
703void KeyValueTextReader::Impl::
708 Int64 file_length = m_reader.fileLength();
710 Int64 struct_size = BasicReaderWriterDatabaseEpilogFormat::STRUCT_SIZE;
711 if (file_length < struct_size)
712 ARCANE_FATAL(
"File is too short length={0} minimum={1}", file_length, struct_size);
718 _readDirect(file_length - struct_size, epilog.bytes());
719 const int expected_version = 1;
720 if (epilog.version() != expected_version)
721 ARCANE_FATAL(
"Bad version for epilog version={0} expected={1}",
722 epilog.version(), expected_version);
729 Int64 file_offset = epilog.jsonDataInfoFileOffset();
730 Int64 meta_data_size = epilog.jsonDataInfoSize();
732 json_bytes.
resize(meta_data_size);
733 _readDirect(file_offset, json_bytes);
739 json_doc.
parse(json_bytes);
744 for (
JSONValue v : data.valueAsArray()) {
745 String name = v.child(
"Name").value();
746 Int64 file_offset = v.child(
"FileOffset").valueAsInt64();
749 JSONValueList extents_info = v.child(
"Extents").valueAsArray();
752 extents.
add(v2.valueAsInt64());
755 x.m_file_offset = file_offset;
756 x.m_extents.fill(extents.
view());
757 m_data_infos.insert(std::make_pair(name, x));
765void KeyValueTextReader::
766getExtents(
const String& key_name, SmallSpan<Int64> extents)
769 if (m_p->m_version >= 3) {
772 if (extents.size() != exi.size())
773 ARCANE_FATAL(
"Bad size for extents size={0} expected={1}", extents.size(), exi.size());
774 extents.copy(exi.view());
777 if (m_p->m_version == 1) {
780 if (dimension_array_size > 0) {
781 dims.resize(dimension_array_size);
784 for (
Integer i = 0; i < dimension_array_size; ++i)
785 extents[i] = dims[i];
788 if (dimension_array_size > 0) {
798void KeyValueTextReader::Impl::
799readIntegers(
const String& key, Span<Integer> values)
802 m_reader.readIntegers(values);
808void KeyValueTextReader::Impl::
809read(
const String& key, Span<std::byte> values)
813 IDataCompressor* d = m_data_compressor.get();
815 if (d && len > d->minCompressSize()) {
816 UniqueArray<std::byte> compressed_values;
817 Int64 compressed_size = 0;
819 compressed_values.resize(compressed_size);
820 _read2(key, compressed_values);
821 m_data_compressor->decompress(compressed_values, values);
831void KeyValueTextReader::Impl::
832_read2(
const String& key, Span<std::byte> values)
834 if (m_hash_database.get()) {
835 IHashAlgorithm* hash_algo = m_hash_algorithm.get();
837 ARCANE_FATAL(
"Can not use hash database without hash algorithm");
838 Int32 hash_size = hash_algo->hashSize();
839 SmallArray<Byte, 1024> hash_as_bytes;
840 hash_as_bytes.resize(hash_size);
843 info(5) <<
"READ_KW_HASH key=" << key <<
" hash=" << hash_value <<
" expected_len=" << values.size();
844 HashDatabaseReadArgs args(hash_value, values);
845 m_hash_database->readValues(args);
850 hasher.setHashAlgorithm(hash_algo);
851 SmallArray<Byte, 1024> hash_result;
852 hasher.computeHash(values, hash_result);
854 if (check_hash_value != hash_value)
855 ARCANE_FATAL(
"Invalid hash expected={0} read={1} key={2}", hash_value, check_hash_value, key);
859 m_reader.read(values);
865void KeyValueTextReader::Impl::
866_setFileOffset(
const String& key_name)
870 if (m_version >= 3) {
872 m_reader.setFileOffset(data.m_file_offset);
882String KeyValueTextReader::
885 return m_p->m_reader.fileName();
891void KeyValueTextReader::
892setFileOffset(
Int64 v)
894 m_p->m_reader.setFileOffset(v);
900void KeyValueTextReader::
901setDataCompressor(Ref<IDataCompressor> ds)
903 m_p->m_data_compressor = ds;
909Ref<IDataCompressor> KeyValueTextReader::
910dataCompressor()
const
912 return m_p->m_data_compressor;
918void KeyValueTextReader::
919setHashAlgorithm(Ref<IHashAlgorithm> v)
921 m_p->m_hash_algorithm = v;
927Ref<IHashAlgorithm> KeyValueTextReader::
930 return m_p->m_hash_algorithm;
936void KeyValueTextReader::
937readIntegers(
const String& key, Span<Integer> values)
939 m_p->readIntegers(key, values);
945void KeyValueTextReader::
946read(
const String& key, Span<std::byte> values)
948 m_p->read(key, values);
#define ARCANE_CHECK_POINTER(ptr)
Macro returning the pointer ptr if it is not null or throwing an exception if it is null.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
Integer size() const
Number of elements in the vector.
Base class for 1D data vectors.
void resize(Int64 s)
Changes the number of elements in the array to s.
void clear()
Removes the elements from the array.
void add(ConstReferenceType val)
Adds element val to the end of the array.
void reserve(Int64 new_capacity)
Reserves memory for new_capacity elements.
ArrayView< T > view() const
Mutable view of this array.
Interface of a hashing algorithm.
virtual TraceMessage info()=0
Stream for an information message.
Management of a JSON document.
void parse(Span< const Byte > bytes)
Reads the file in UTF-8 format.
JSONValue root() const
Root element.
List of values of a JSON document.
JSONValue child(StringView name) const
Child value with name name. Returns a null value if not found.
View of an array of elements of type T.
constexpr __host__ __device__ SizeType size() const noexcept
Returns the size of the array.
View of an array of elements of type T.
View of a UTF-8 character string.
constexpr Int64 size() const ARCCORE_NOEXCEPT
Length in bytes of the character string.
constexpr Span< const Byte > bytes() const ARCCORE_NOEXCEPT
Returns the conversion of the instance in UTF-8 encoding.
Unicode character string.
bool null() const
Returns true if the string is null.
TraceAccessor(ITraceMng *m)
Constructs an accessor via the trace manager m.
TraceMessage info() const
Flow for an information message.
ITraceMng * traceMng() const
Trace manager.
1D data vector with value semantics (STL style).
Class to calculate the hash of an array.
void _readHeader()
File format header.
void _writeHeader()
File format header.
Class for writing a text file for backups/restorations.
Class for writing a text file for backups/restorations.
Integer len(const char *s)
Returns the length of the string s.
String toHexaString(ByteConstArrayView input)
Converts a byte array to its hexadecimal representation.
bool arcaneIsCheck()
True if running in check mode.
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
ConstArrayView< Int64 > Int64ConstArrayView
C equivalent of a 1D array of 64-bit integers.
void binaryRead(std::istream &istr, const Span< std::byte > &bytes)
Reads the content of bytes from the stream istr in binary format.
void arcaneCallFunctionAndTerminateIfThrow(std::function< void()> function)
Calls the function function and calls std::terminate() if an exception occurs.
double Real
Type representing a real number.
Impl::SpanTypeFromSize< conststd::byte, SizeType >::SpanType asBytes(const SpanImpl< DataType, SizeType, Extent > &s)
Converts the view into an array of non-modifiable bytes.
unsigned char Byte
Type of a byte.
Impl::SpanTypeFromSize< std::byte, SizeType >::SpanType asWritableBytes(const SpanImpl< DataType, SizeType, Extent > &s)
Converts the view into an array of modifiable bytes.
UniqueArray< Integer > IntegerUniqueArray
Dynamic 1D array of integers.
void binaryWrite(std::ostream &ostr, const Span< const std::byte > &bytes)
Writes the content of bytes to the stream ostr in binary format.
std::int32_t Int32
Signed integer type of 32 bits.