BmnRoot 26.10.0-18-g4e3414f9
Software framework of the BM@N experiment
Loading...
Searching...
No Matches
BmnFileReaderZStd.cxx
Go to the documentation of this file.
1// headers from this target
2#include "BmnFileReaderZStd.h"
3
4#include "BmnDefinitions.h"
5// std:: headers
6#include <cassert>
7#include <filesystem>
8// FairLogger headers
9#include <fairlogger/Logger.h>
10// the main Zstd header
11#ifdef BMNCOMPRESSION_WITH_ZSTD
12#include <zstd.h>
13#else
14// If we build without the library, it would be find to use #pragma on the entire object, without push
15// and pop, but it's nothing too important for us here - just for simplicity I'm going with this def
17#endif // BMNCOMPRESSION_WITH_ZSTD
18
19// o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
20// ================== BmnFileReaderZStd public methods ==================
21// o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
22
23// ========== BmnIFileReaderInterface ==========
24
25BmnFileReaderZStd::BmnFileReaderZStd(const std::string& fileName)
26 : BmnIFileReader(BmnFileType::ZStd, fileName)
27 , fZstdStream(nullptr)
28 , fArchiveReadManager(*this)
29 , fNumberOfReadBytes(0ull)
31{
32#ifdef BMNCOMPRESSION_WITH_ZSTD
33 // Keeping it hidden so ZStd would be PRIVATE in CMake
34 static_assert(ZSTD_VERSION_MAJOR >= 1 && ZSTD_VERSION_MINOR > 2,
35 "You are trying to use an old version of ZStd - in that version `ZSTD_DStream` was not the same as "
36 "`ZSTD_DCtx_s`!");
37#endif // BMNCOMPRESSION_WITH_ZSTD
38}
39
41 : BmnIFileReader(BmnFileType::ZStd, std::move(fileName))
42 , fZstdStream(nullptr)
43 , fArchiveReadManager(*this)
44 , fNumberOfReadBytes(0ull)
46{}
47
48BmnFileReaderZStd::BmnFileReaderZStd(const std::filesystem::path& filePath)
49 : BmnIFileReader(BmnFileType::ZStd, filePath)
50 , fZstdStream(nullptr)
51 , fArchiveReadManager(*this)
52 , fNumberOfReadBytes(0ull)
54{}
55
56BmnFileReaderZStd::BmnFileReaderZStd(std::filesystem::path&& filePath)
57 : BmnIFileReader(BmnFileType::ZStd, std::move(filePath))
58 , fZstdStream(nullptr)
59 , fArchiveReadManager(*this)
60 , fNumberOfReadBytes(0ull)
62{}
63
68
70{
71#ifdef BMNCOMPRESSION_WITH_ZSTD
72 /*
73 While we actually don't need so many comments and checks here, we are still performing them just to ensure
74 one doesn't make an accidental mistake - it might be easier to catch it
75 */
76 if (fZstdStream) {
77 LOG(error) << "ZStd stream is already valid! The purpose of the BMN ZStd classes is to compress/decompress "
78 "huge files - if you however\n"
79 "really need to support compressing/decompressing many small files (frames), please let us know "
80 "and we will allow it along\n"
81 "with dictionaries (preferred for small files)\n";
82 return;
83 }
84 if (!PerformStandardChecksBeforeOpening(processingFlags))
85 return;
86 fArchiveReadManager.Open(fFilePath, std::ios::in | std::ios::binary);
87 fZstdStream = ZSTD_createDStream();
88#else
89 throw std::runtime_error{"Trying to use ZSTD while BMN is not compiled with it!"};
90#endif // BMNCOMPRESSION_WITH_ZSTD
91}
92
94{
95#ifdef BMNCOMPRESSION_WITH_ZSTD
96 if (!fZstdStream)
97 return;
98 assert(fArchiveReadManager.IsOpen());
99 fLastReadReturnValue = ZSTD_freeDStream(fZstdStream);
100 if (ZSTD_isError(fLastReadReturnValue)) {
101 LOG(fatal) << "Failed to free ZStd stream - possible huge memory leak! Failure reason: "
102 << ZSTD_getErrorName(fLastReadReturnValue) << '\n';
103 std::terminate();
104 }
105 fZstdStream = nullptr;
106 fArchiveReadManager.Close();
107 fNumberOfReadBytes = 0ull;
109#endif // BMNCOMPRESSION_WITH_ZSTD
110}
111
112int64_t BmnFileReaderZStd::Read(void* dataToFill, const int64_t sizeToFill)
113{
114#ifdef BMNCOMPRESSION_WITH_ZSTD
115 if (ZSTD_isError(fLastReadReturnValue))
116 return 0ll;
117 return fArchiveReadManager.Read(dataToFill, sizeToFill);
118#else
119 throw std::runtime_error{"Trying to use ZSTD while BMN is not compiled with it!"};
120#endif // BMNCOMPRESSION_WITH_ZSTD
121}
122
123int64_t BmnFileReaderZStd::Tell() const noexcept
124{
125 return fNumberOfReadBytes + fArchiveReadManager.GetCurrentOutputBufferPosition()
126 - fArchiveReadManager.GetTotalOutputBufferFilledSize();
127}
128
129void BmnFileReaderZStd::Seek(int64_t value)
130{
131#ifdef BMNCOMPRESSION_WITH_ZSTD
132 if (value < 0ll || (size_t)value == fNumberOfReadBytes)
133 return;
134 if (ZSTD_isError(fLastReadReturnValue)) {
135 LOG(error) << "Before calling `BmnFileReaderZStd::Seek` ensure to clear bad flags!\n";
136 return;
137 }
138 if (!fZstdStream) {
139 LOG(error) << "Before calling `BmnFileReaderZStd::Seek` ensure to open the stream!\n";
140 return;
141 }
142 if (!fArchiveReadManager.IsOpen()) {
143 LOG(error) << "Reading file missing while calling `BmnFileReaderZStd::Seek`\n";
144 return;
145 }
146 if ((size_t)value < (fNumberOfReadBytes - fArchiveReadManager.GetTotalOutputBufferFilledSize())) {
147 Close();
149 }
150 // in theory I could check IsOpen again for unexpected errors, but....
151 fArchiveReadManager.MoveToDecompressingLocation(value);
152#else
153 throw std::runtime_error{"Trying to use ZSTD while BMN is not compiled with it!"};
154#endif // BMNCOMPRESSION_WITH_ZSTD
155}
156
157bool BmnFileReaderZStd::IsGood() const noexcept
158{
159#ifdef BMNCOMPRESSION_WITH_ZSTD
160 return fZstdStream && !ZSTD_isError(fLastReadReturnValue) && fArchiveReadManager.IsGood();
161#else
162 return false;
163#endif // BMNCOMPRESSION_WITH_ZSTD
164}
165
166bool BmnFileReaderZStd::IsEOF() const noexcept
167{
168 return fArchiveReadManager.IsEOF();
169}
170
172{
173 // I don't like this method much
175 fArchiveReadManager.Clear();
176}
177
178bool BmnFileReaderZStd::IsOpen() const noexcept
179{
180 return fArchiveReadManager.IsOpen() && fZstdStream;
181}
182
183// ========== BmnIArchiveLib Interface ==========
184
186 const size_t sourceTotalSize,
187 size_t& numberOfReadBytes,
188 void* output,
189 const size_t outputTotalSize,
190 size_t& numberOfSetOutputBytes)
191{
192 if (!fZstdStream)
194#ifdef BMNCOMPRESSION_WITH_ZSTD
195 if (ZSTD_isError(fLastReadReturnValue))
197 ZSTD_outBuffer outBuffer{output, outputTotalSize, 0ull};
198 ZSTD_inBuffer inBuffer{source, sourceTotalSize, 0ull};
199 fLastReadReturnValue = ZSTD_decompressStream(fZstdStream, &outBuffer, &inBuffer);
200 if (ZSTD_isError(fLastReadReturnValue))
202 numberOfReadBytes = inBuffer.pos;
203 numberOfSetOutputBytes = outBuffer.pos;
204 fNumberOfReadBytes += outBuffer.pos;
205 if (fLastReadReturnValue == 0ull)
208#else
209 throw std::runtime_error{"Trying to use ZSTD while BMN is not compiled with it!"};
210#endif // BMNCOMPRESSION_WITH_ZSTD
211}
212
214{
215#ifdef BMNCOMPRESSION_WITH_ZSTD
216 std::string strToReturn{};
217 if (ZSTD_isError(fLastReadReturnValue))
218 strToReturn = std::string{ZSTD_getErrorName(fLastReadReturnValue)};
219 return strToReturn;
220#else
221 return std::string{"BMN NOT BUILT WITH ZSTD"};
222#endif // BMNCOMPRESSION_WITH_ZSTD
223}
224
226{
227 return false;
228}
229
231{
232 /*
233 Most compression libraries (including this one), don't like (read allow) jumping over the files and random
234 reads. In Zstd, it would be possible to implement it, but only at the compression level. In other words, we
235 would need to write the data in independent blocks or something similar. As we don't know what kind of a
236 compressed file we are currently reading, we cannot rely on that and we must read all the data to get to the
237 needed location - which is also what we currently need in BMN. If for some reason one needs to take some
238 other approach and allow fast random access, inherit this class and override this method
239 */
240 LOG(warning) << "Calling `BmnFileReaderZStd::JumpTo` while the type doesn't allow jumping!\n";
241}
242
244{
245 return fNumberOfReadBytes;
246}
247
249{
250#ifdef BMNCOMPRESSION_WITH_ZSTD
251 if (ZSTD_isError(fLastReadReturnValue))
252 return true;
253 return fLastReadReturnValue == 0;
254#else
255 return true;
256#endif // BMNCOMPRESSION_WITH_ZSTD
257}
258
260{
261#ifdef BMNCOMPRESSION_WITH_ZSTD
262 return !ZSTD_isError(fLastReadReturnValue);
263#else
264 return false;
265#endif // BMNCOMPRESSION_WITH_ZSTD
266}
267
268#ifndef BMNCOMPRESSION_WITH_ZSTD
270#endif // BMNCOMPRESSION_WITH_ZSTD
#define RESTORE_UNUSED_PARAM_WARNING
#define DISABLE_UNUSED_PARAM_WARNING
virtual void Seek(int64_t value) override
virtual BmnFileStreamResults Uncompress(const void *source, const size_t sourceTotalSize, size_t &numberOfReadBytes, void *output, const size_t outputTotalSize, size_t &numberOfSetOutputBytes) override
virtual bool IsGood() const noexcept override
virtual ~BmnFileReaderZStd() override
virtual void Close() noexcept override
BmnReaderCacheManager< 32ull *1024ull, 64ull *1024ull > fArchiveReadManager
virtual void ClearStateFlags() override
virtual size_t GetNumberOfDecompressedBytes() const noexcept override
virtual bool IsStreamInGoodState() const noexcept override
virtual int64_t Tell() const noexcept override
virtual std::string GetLastUncompressErrorDescription() const noexcept override
virtual void JumpTo(size_t) override
virtual bool HasReachedTheEndOfStream() const noexcept override
virtual int64_t Read(void *dataToFill, const int64_t sizeToFill) override
BmnFileReaderZStd(const std::string &fileName="")
virtual bool IsOpen() const noexcept override
ZSTD_DCtx_s * fZstdStream
virtual bool IsEOF() const noexcept override
virtual void Open(const BmnBinaryFileProcessingOptions processingFlags=BmnBinaryFileProcessingOptions::ReadBinary) override
virtual bool JumpsAllowed() const noexcept override
BmnIFileReader(const BmnFileType fileType, const std::string &fileName="")
std::filesystem::path fFilePath
bool PerformStandardChecksBeforeOpening(const BmnBinaryFileProcessingOptions processingFlags)
BmnBinaryFileProcessingOptions
Definition json.hpp:4446