Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
RRawFile.cxx
Go to the documentation of this file.
1// @(#)root/io:$Id$
2// Author: Jakob Blomer
3
4/*************************************************************************
5 * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#include <ROOT/RConfig.h>
13#include <ROOT/RRawFile.hxx>
14#ifdef _WIN32
15#include <ROOT/RRawFileWin.hxx>
16#else
17#include <ROOT/RRawFileUnix.hxx>
18#endif
19
20#include "TError.h"
21#include "TPluginManager.h"
22#include "TROOT.h"
23
24#include <algorithm>
25#include <cctype> // for towlower
26#include <cerrno>
27#include <cstddef>
28#include <cstdint>
29#include <cstring>
30#include <stdexcept>
31#include <string>
32
33namespace {
34const char *kTransportSeparator = "://";
35// Corresponds to ELineBreaks
36#ifdef _WIN32
37const char *kLineBreakTokens[] = {"", "\r\n", "\n", "\r\n"};
38constexpr unsigned int kLineBreakTokenSizes[] = {0, 2, 1, 2};
39#else
40const char *kLineBreakTokens[] = {"", "\n", "\n", "\r\n"};
41constexpr unsigned int kLineBreakTokenSizes[] = {0, 1, 1, 2};
42#endif
43constexpr unsigned int kLineBuffer = 128; // On Readln, look for line-breaks in chunks of 128 bytes
44} // anonymous namespace
45
46size_t ROOT::Internal::RRawFile::RBlockBuffer::CopyTo(void *buffer, size_t nbytes, std::uint64_t offset)
47{
48 if (offset < fBufferOffset)
49 return 0;
50
51 size_t copiedBytes = 0;
52 std::uint64_t offsetInBuffer = offset - fBufferOffset;
53 if (offsetInBuffer < static_cast<std::uint64_t>(fBufferSize)) {
54 size_t bytesInBuffer = std::min(nbytes, static_cast<size_t>(fBufferSize - offsetInBuffer));
55 memcpy(buffer, fBuffer + offsetInBuffer, bytesInBuffer);
56 copiedBytes = bytesInBuffer;
57 }
58 return copiedBytes;
59}
60
61ROOT::Internal::RRawFile::RRawFile(std::string_view url, ROptions options) : fUrl(url), fOptions(options) {}
62
63std::unique_ptr<ROOT::Internal::RRawFile>
64ROOT::Internal::RRawFile::Create(std::string_view url, ROptions options)
65{
66 std::string transport = GetTransport(url);
67 if (transport == "file") {
68#ifdef _WIN32
69 return std::unique_ptr<RRawFile>(new RRawFileWin(url, options));
70#else
71 return std::unique_ptr<RRawFile>(new RRawFileUnix(url, options));
72#endif
73 }
74 if (transport == "http" || transport == "https" || transport == "root" || transport == "roots") {
75 std::string plgclass = transport.compare(0, 4, "http") == 0 ? "RRawFileDavix" : "RRawFileNetXNG";
76 if (TPluginHandler *h =
77 gROOT->GetPluginManager()->FindHandler("ROOT::Internal::RRawFile", std::string(url).c_str())) {
78 if (h->LoadPlugin() == 0) {
79 return std::unique_ptr<RRawFile>(reinterpret_cast<RRawFile *>(h->ExecPlugin(2, &url, &options)));
80 }
81 throw std::runtime_error("Cannot load plugin handler for " + plgclass);
82 }
83 throw std::runtime_error("Cannot find plugin handler for " + plgclass);
84 }
85 throw std::runtime_error("Unsupported transport protocol: " + transport);
86}
87
89{
90 if (fIsOpen)
91 return;
92
93 OpenImpl();
94 fIsOpen = true;
96}
97
98void ROOT::Internal::RRawFile::ReadVImpl(RIOVec *ioVec, unsigned int nReq)
99{
100 for (unsigned i = 0; i < nReq; ++i) {
101 ioVec[i].fOutBytes = ReadAt(ioVec[i].fBuffer, ioVec[i].fSize, ioVec[i].fOffset);
102 }
103}
104
105std::string ROOT::Internal::RRawFile::GetLocation(std::string_view url)
106{
107 auto idx = url.find(kTransportSeparator);
108 if (idx == std::string_view::npos)
109 return std::string(url);
110 return std::string(url.substr(idx + strlen(kTransportSeparator)));
111}
112
114{
116 return fFileSize;
117
118 EnsureOpen();
120 return fFileSize;
121}
122
124 return fUrl;
125}
126
127std::string ROOT::Internal::RRawFile::GetTransport(std::string_view url)
128{
129 auto idx = url.find(kTransportSeparator);
130 if (idx == std::string_view::npos)
131 return "file";
132 std::string transport(url.substr(0, idx));
133 std::transform(transport.begin(), transport.end(), transport.begin(), ::tolower);
134 return transport;
135}
136
137size_t ROOT::Internal::RRawFile::Read(void *buffer, size_t nbytes)
138{
139 size_t res = ReadAt(buffer, nbytes, fFilePos);
140 fFilePos += res;
141 return res;
142}
143
144size_t ROOT::Internal::RRawFile::ReadAt(void *buffer, size_t nbytes, std::uint64_t offset)
145{
146 EnsureOpen();
147
148 // Early return for empty requests
149 if (nbytes == 0)
150 return 0;
151
152 // "Large" reads are served directly, bypassing the cache; since nbytes > 0, fBlockSize == 0 is also handled here
153 if (!fIsBuffering || nbytes > static_cast<unsigned int>(fOptions.fBlockSize))
154 return ReadAtImpl(buffer, nbytes, offset);
155
156 if (!fBufferSpace) {
157 fBufferSpace.reset(new unsigned char[kNumBlockBuffers * fOptions.fBlockSize]);
158 for (unsigned int i = 0; i < kNumBlockBuffers; ++i) {
159 fBlockBuffers[i].fBuffer = fBufferSpace.get() + i * fOptions.fBlockSize;
160 fBlockBuffers[i].fBufferSize = 0;
161 }
162 }
163
164 size_t totalBytes = 0;
165 size_t copiedBytes = 0;
166 /// Try to serve as many bytes as possible from the block buffers
167 for (unsigned int idx = fBlockBufferIdx; idx < fBlockBufferIdx + kNumBlockBuffers; ++idx) {
168 copiedBytes = fBlockBuffers[idx % kNumBlockBuffers].CopyTo(buffer, nbytes, offset);
169 buffer = reinterpret_cast<unsigned char *>(buffer) + copiedBytes;
170 nbytes -= copiedBytes;
171 offset += copiedBytes;
172 totalBytes += copiedBytes;
173 if (copiedBytes > 0)
174 fBlockBufferIdx = idx;
175 if (nbytes == 0)
176 return totalBytes;
177 }
179
180 /// The request was not fully satisfied and fBlockBufferIdx now points to the previous shadow buffer
181
182 /// The remaining bytes populate the newly promoted main buffer
184 size_t res = ReadAtImpl(thisBuffer->fBuffer, fOptions.fBlockSize, offset);
185 thisBuffer->fBufferOffset = offset;
186 thisBuffer->fBufferSize = res;
187 size_t remainingBytes = std::min(res, nbytes);
188 memcpy(buffer, thisBuffer->fBuffer, remainingBytes);
189 totalBytes += remainingBytes;
190 return totalBytes;
191}
192
193void ROOT::Internal::RRawFile::ReadV(RIOVec *ioVec, unsigned int nReq)
194{
195 EnsureOpen();
196 ReadVImpl(ioVec, nReq);
197}
198
200{
201 fIsBuffering = value;
202 if (!fIsBuffering)
203 fBufferSpace.reset();
204 if (fIsOpen)
206}
207
209{
210 if (fOptions.fLineBreak == ELineBreaks::kAuto) {
211 // Auto-detect line breaks according to the break discovered in the first line
212 fOptions.fLineBreak = ELineBreaks::kUnix;
213 bool res = Readln(line);
214 if ((line.length() > 0) && (*line.rbegin() == '\r')) {
215 fOptions.fLineBreak = ELineBreaks::kWindows;
216 line.resize(line.length() - 1);
217 }
218 return res;
219 }
220
221 line.clear();
222 char buffer[kLineBuffer];
223 size_t nbytes;
224 do {
225 nbytes = Read(buffer, sizeof(buffer));
226 std::string_view bufferView(buffer, nbytes);
227 auto idx = bufferView.find(kLineBreakTokens[static_cast<int>(fOptions.fLineBreak)]);
228 if (idx != std::string_view::npos) {
229 // Line break found, return the string and skip the linebreak itself
230 line.append(buffer, idx);
231 fFilePos -= nbytes - idx;
232 fFilePos += kLineBreakTokenSizes[static_cast<int>(fOptions.fLineBreak)];
233 return true;
234 }
235 line.append(buffer, nbytes);
236 } while (nbytes > 0);
237
238 return !line.empty();
239}
240
241void ROOT::Internal::RRawFile::Seek(std::uint64_t offset)
242{
243 fFilePos = offset;
244}
fBuffer
#define h(i)
Definition RSha256.hxx:106
#define gROOT
Definition TROOT.h:417
The RRawFileUnix class uses POSIX calls to read from a mounted file system.
The RRawFileWin class uses portable C I/O calls to read from a drive.
virtual std::uint64_t GetSizeImpl()=0
Derived classes should return the file size.
static std::string GetLocation(std::string_view url)
Returns only the file location, e.g. "server/file" for http://server/file.
Definition RRawFile.cxx:105
unsigned int fBlockBufferIdx
To be used modulo kNumBlockBuffers, points to the last used block buffer in fBlockBuffers.
Definition RRawFile.hxx:110
RRawFile(std::string_view url, ROptions options)
Definition RRawFile.cxx:61
std::uint64_t fFilePos
The current position in the file, which can be changed by Seek, Read, and Readln.
Definition RRawFile.hxx:128
virtual void ReadVImpl(RIOVec *ioVec, unsigned int nReq)
By default implemented as a loop of ReadAt calls but can be overwritten, e.g. XRootD or DAVIX impleme...
Definition RRawFile.cxx:98
static std::string GetTransport(std::string_view url)
Returns only the transport protocol in lower case, e.g. "http" for HTTP://server/file.
Definition RRawFile.cxx:127
static constexpr unsigned int kNumBlockBuffers
Don't change without adapting ReadAt().
Definition RRawFile.hxx:92
std::uint64_t GetSize()
Returns the size of the file.
Definition RRawFile.cxx:113
bool fIsBuffering
Runtime switch to decide if reads are buffered or directly sent to ReadAtImpl().
Definition RRawFile.hxx:122
static std::unique_ptr< RRawFile > Create(std::string_view url, ROptions options=ROptions())
Factory method that returns a suitable concrete implementation according to the transport in the url.
Definition RRawFile.cxx:64
void Seek(std::uint64_t offset)
Change the cursor fFilePos.
Definition RRawFile.cxx:241
static constexpr std::uint64_t kUnknownFileSize
Used as a marker that the file size was not yet queried.
Definition RRawFile.hxx:116
size_t ReadAt(void *buffer, size_t nbytes, std::uint64_t offset)
Buffered read from a random position.
Definition RRawFile.cxx:144
bool fIsOpen
Files are opened lazily and only when required; the open state is kept by this flag.
Definition RRawFile.hxx:120
virtual size_t ReadAtImpl(void *buffer, size_t nbytes, std::uint64_t offset)=0
Derived classes should implement low-level reading without buffering.
bool Readln(std::string &line)
Read the next line starting from the current value of fFilePos. Returns false if the end of the file ...
Definition RRawFile.cxx:208
void EnsureOpen()
Open the file if not already open. Otherwise noop.
Definition RRawFile.cxx:88
virtual void SetDiscourageReadAheadImpl(bool)
Definition RRawFile.hxx:144
std::unique_ptr< unsigned char[]> fBufferSpace
Memory block containing the block buffers consecutively.
Definition RRawFile.hxx:114
void ReadV(RIOVec *ioVec, unsigned int nReq)
Opens the file if necessary and calls ReadVImpl.
Definition RRawFile.cxx:193
virtual void OpenImpl()=0
OpenImpl() is called at most once and before any call to either DoReadAt or DoGetSize.
size_t Read(void *buffer, size_t nbytes)
Read from fFilePos offset. Returns the actual number of bytes read.
Definition RRawFile.cxx:137
void SetBuffering(bool value)
Turn on/off buffered reads; if off, all scalar read requests go directly to the implementation.
Definition RRawFile.cxx:199
std::string GetUrl() const
Returns the url of the file.
Definition RRawFile.cxx:123
std::uint64_t fFileSize
The cached file size.
Definition RRawFile.hxx:118
RBlockBuffer fBlockBuffers[kNumBlockBuffers]
An active buffer and a shadow buffer, which supports "jumping back" to a previously used location in ...
Definition RRawFile.hxx:112
TLine * line
std::uint64_t fBufferOffset
Where in the open file does fBuffer start.
Definition RRawFile.hxx:95
unsigned char * fBuffer
Points into the I/O buffer with data from the file, not owned.
Definition RRawFile.hxx:99
size_t CopyTo(void *buffer, size_t nbytes, std::uint64_t offset)
Tries to copy up to nbytes starting at offset from fBuffer into buffer. Returns number of bytes copie...
Definition RRawFile.cxx:46
size_t fBufferSize
The number of currently buffered bytes in fBuffer.
Definition RRawFile.hxx:97
Used for vector reads from multiple offsets into multiple buffers.
Definition RRawFile.hxx:61
std::size_t fOutBytes
The number of actually read bytes, set by ReadV().
Definition RRawFile.hxx:69
On construction, an ROptions parameter can customize the RRawFile behavior.
Definition RRawFile.hxx:49