The Gaudi Framework  master (2e57474e)
Loading...
Searching...
No Matches
DiskBuffer.h
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 2026 CERN for the benefit of the LHCb and ATLAS collaborations *
3* *
4* This software is distributed under the terms of the Apache version 2 licence, *
5* copied verbatim in the file "LICENSE". *
6* *
7* In applying this licence, CERN does not waive the privileges and immunities *
8* granted to it by virtue of its status as an Intergovernmental Organization *
9* or submit itself to any jurisdiction. *
10\***********************************************************************************/
11#pragma once
12
13#include <cstdint>
14#include <cstdio>
15#include <filesystem>
16#include <memory>
17#include <span>
18#include <stdexcept>
19#include <string>
20#include <string_view>
21#include <vector>
22
34
36 bool zstdAvailable();
37
39 std::size_t maxBlockSize();
40
41 namespace details {
42 struct Close {
43 void operator()( std::FILE* f ) const { std::fclose( f ); }
44 };
45 } // namespace details
46
47 using FileHandle = std::unique_ptr<std::FILE, details::Close>;
48
50 class Error : public std::runtime_error {
51 public:
52 Error( const std::filesystem::path& path, std::string_view what, int err = 0 );
53 const std::filesystem::path& path() const { return m_path; }
54 int code() const { return m_code; }
55
56 private:
57 std::filesystem::path m_path;
58 int m_code;
59 };
60
61 class Writer {
62 public:
67 Writer( std::filesystem::path path, std::string_view header, int zstdLevel = 0, std::size_t blockSize = 64 * 1024 );
69 Writer( const Writer& ) = delete;
70 Writer& operator=( const Writer& ) = delete;
71
72 void beginRecord();
73 void append( const void* data, std::size_t bytes );
74 void endRecord();
75
77 void close();
78
80 std::uint64_t entries() const { return m_entries; }
82 std::uint64_t bytes() const { return m_bytes; }
84 std::uint64_t storedBytes() const { return m_stored; }
85 int zstdLevel() const { return m_level; }
86 std::size_t blockSize() const { return m_blockSize; }
87 const std::filesystem::path& path() const { return m_path; }
88
89 private:
90 void flush();
91 void write( const void* data, std::size_t bytes );
92
93 std::filesystem::path m_path;
96 std::size_t m_blockSize;
97 std::vector<char> m_buf;
98 std::size_t m_recordStart{ 0 }; // offset of the current record's length field
99 bool m_inRecord{ false };
100 std::uint64_t m_entries{ 0 };
101 std::uint64_t m_bytes{ 0 };
102 std::uint64_t m_stored{ 0 };
103 std::uint64_t m_pending{ 0 }; // records in m_buf, counted once their block is written
104 std::uint64_t m_pendingBytes{ 0 }; // and their payload
105 };
106
107 class Reader {
108 public:
110 explicit Reader( std::filesystem::path path );
112 Reader( const Reader& ) = delete;
113 Reader& operator=( const Reader& ) = delete;
114
115 const std::string& header() const { return m_header; }
116 bool compressed() const { return m_compressed; }
117
119 bool next( std::span<const char>& record );
120
121 std::uint64_t entries() const { return m_entries; }
122 const std::filesystem::path& path() const { return m_path; }
123
124 private:
125 std::size_t read( void* dest, std::size_t bytes );
126 bool readBlock();
127
128 std::filesystem::path m_path;
130 std::uintmax_t m_size{ 0 }; // file size, 0 if unknown: bounds a block length
131 std::string m_header;
132 bool m_compressed{ false };
133 std::vector<char> m_stored; // one block as read from the file
134 std::vector<char> m_block; // the same block unpacked
135 std::size_t m_pos{ 0 };
136 std::uint64_t m_entries{ 0 };
137 };
138
139} // namespace Gaudi::NTuple::DiskBuffer
const std::filesystem::path & path() const
Definition DiskBuffer.h:53
std::filesystem::path m_path
Definition DiskBuffer.h:57
Error(const std::filesystem::path &path, std::string_view what, int err=0)
std::size_t read(void *dest, std::size_t bytes)
const std::string & header() const
Definition DiskBuffer.h:115
Reader & operator=(const Reader &)=delete
Reader(std::filesystem::path path)
Open path and validate the preamble.
bool next(std::span< const char > &record)
Read the next record; false at a clean end of file. A partial block throws.
std::uint64_t entries() const
Definition DiskBuffer.h:121
const std::filesystem::path & path() const
Definition DiskBuffer.h:122
Reader(const Reader &)=delete
std::filesystem::path m_path
Definition DiskBuffer.h:128
Writer(std::filesystem::path path, std::string_view header, int zstdLevel=0, std::size_t blockSize=64 *1024)
Create (truncating) path and write the preamble and header.
void write(const void *data, std::size_t bytes)
void append(const void *data, std::size_t bytes)
std::uint64_t storedBytes() const
Bytes written to the file after the header.
Definition DiskBuffer.h:84
const std::filesystem::path & path() const
Definition DiskBuffer.h:87
std::filesystem::path m_path
Definition DiskBuffer.h:93
std::size_t blockSize() const
Definition DiskBuffer.h:86
Writer & operator=(const Writer &)=delete
void close()
Flush and close; throws on failure. Safe to call twice.
Writer(const Writer &)=delete
std::uint64_t bytes() const
Payload bytes of those records.
Definition DiskBuffer.h:82
std::uint64_t entries() const
Records written to the file; records lost to a failed flush do not count.
Definition DiskBuffer.h:80
Append-only file of length-prefixed records, used to park ntuple rows on disk during the event loop a...
Definition DiskBuffer.h:33
bool zstdAvailable()
Whether this build can write and read compressed blocks.
std::unique_ptr< std::FILE, details::Close > FileHandle
Owns an open file; close() is the checked path, this is the fallback.
Definition DiskBuffer.h:47
std::size_t maxBlockSize()
Largest block size a Writer accepts.
void operator()(std::FILE *f) const
Definition DiskBuffer.h:43