XRootD
XrdPfcIOFile.cc
Go to the documentation of this file.
1 //----------------------------------------------------------------------------------
2 // Copyright (c) 2014 by Board of Trustees of the Leland Stanford, Jr., University
3 // Author: Alja Mrak-Tadel, Matevz Tadel, Brian Bockelman
4 //----------------------------------------------------------------------------------
5 // XRootD is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // XRootD is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with XRootD. If not, see <http://www.gnu.org/licenses/>.
17 //----------------------------------------------------------------------------------
18 
19 #include "XrdPfcIOFile.hh"
20 #include "XrdPfcStats.hh"
21 #include "XrdPfcTrace.hh"
22 
23 #include "XrdOss/XrdOss.hh"
25 #include "XrdSys/XrdSysError.hh"
26 
27 #include "XrdOuc/XrdOucEnv.hh"
29 
30 #include <cstdio>
31 #include <fcntl.h>
32 
33 using namespace XrdPfc;
34 
35 //______________________________________________________________________________
37  IO(io, cache),
38  m_file(0)
39 {
40  m_file = Cache::GetInstance().GetFile(GetFilename(), this);
41 }
42 
43 //______________________________________________________________________________
45 {
46  // called from Detach() if no sync is needed or
47  // from Cache's sync thread
48  TRACEIO(Debug, "~IOFile() " << this);
49 }
50 
51 //______________________________________________________________________________
52 int IOFile::Fstat(struct stat &sbuff)
53 {
54  // This is only called during Cache::Attach / Cache::GetFile() for file creation.
55  // Should really be separate name but one needs to change virtual interface
56  // so initialStat() becomes virtual in the base-class.
57  // Also, IOFileBlock should be ditched.
58  if ( ! m_file) {
59  return initialStat(sbuff);
60  }
61 
62  return m_file->Fstat(sbuff);
63 }
64 
65 //______________________________________________________________________________
66 long long IOFile::FSize()
67 {
68  return m_file->GetFileSize();
69 }
70 
71 //______________________________________________________________________________
72 int IOFile::initialStat(struct stat &sbuff)
73 {
74  // Get stat to determine file-size.
75  // Called indirectly from the constructor, via Cache::GetFile().
76  // Either read it from cinfo file or obtain it from the remote IO.
77 
78  static const char* trace_pfx = "initialStat ";
79 
80  std::string fname = GetFilename();
81  std::string iname = fname + Info::s_infoExtension;
82  if (m_cache.GetOss()->Stat(iname.c_str(), &sbuff) == XrdOssOK &&
83  m_cache.GetOss()->Stat(fname.c_str(), &sbuff) == XrdOssOK)
84  {
85  long long file_size = m_cache.DetermineFullFileSize(fname + Info::s_infoExtension);
86  if (file_size >= 0)
87  {
88  sbuff.st_size = file_size;
89  TRACE(Info, trace_pfx << "successfully read size " << sbuff.st_size << " from info file " << iname);
90  return 0;
91  }
92  TRACE(Error, trace_pfx << "failed reading from info file " << iname << " " << XrdSysE2T(-file_size));
93  }
94 
95  int res = GetInput()->Fstat(sbuff);
96  TRACEIO(Debug, trace_pfx << "stat from client res = " << res << ", size = " << sbuff.st_size);
97 
98  return res;
99 }
100 
101 //______________________________________________________________________________
103 {
104  IO::Update(iocp);
105  m_file->ioUpdated(this);
106 }
107 
108 //______________________________________________________________________________
110 {
111  RefreshLocation();
112  return m_file->ioActive(this);
113 }
114 
115 //______________________________________________________________________________
117 {
118  // Effectively a destructor.
119 
120  TRACE(Debug, "DetachFinalize() " << this);
121 
122  m_file->RequestSyncOfDetachStats();
123  Cache::GetInstance().ReleaseFile(m_file, this);
124 
125  if (( ! m_error_counts.empty() || m_incomplete_count > 0) && XRD_TRACE What >= TRACE_Error) {
126  char info[1024];
127  int pos = 0, cap = 1024;
128  bool truncated = false;
129  for (auto [err, cnt] : m_error_counts) {
130  int len = snprintf(&info[pos], cap, " ( %d : %d)", err, cnt);
131  if (len >= cap) {
132  truncated = true;
133  break;
134  }
135  pos += len;
136  cap -= len;
137  }
138  TRACE(Error, "DetachFinalize() " << this << " n_incomplete_reads=" << m_incomplete_count
139  << ", block (error : count) report:" << info << (truncated ? " - truncated" : ""));
140  }
141 
142  delete this;
143 }
144 
145 
146 //==============================================================================
147 // Read and pgRead - sync / async and helpers
148 //==============================================================================
149 
150 //______________________________________________________________________________
151 int IOFile::Read(char *buff, long long off, int size)
152 {
154 
155  auto *rh = new ReadReqRHCond(ObtainReadSid(), nullptr);
156 
157  TRACEIO(Dump, "Read() sync " << this << " sid: " << Xrd::hex1 << rh->m_seq_id << " off: " << off << " size: " << size);
158 
159  rh->m_cond.Lock();
160  int retval = ReadBegin(buff, off, size, rh);
161  if (retval == kReadPending)
162  {
163  rh->m_cond.Wait();
164  retval = rh->m_retval;
165  }
166  rh->m_cond.UnLock();
167 
168  return ReadEnd(retval, rh);
169 }
170 
171 //______________________________________________________________________________
172 void IOFile::Read(XrdOucCacheIOCB &iocb, char *buff, long long off, int size)
173 {
174  struct ZHandler : ReadReqRH
175  { using ReadReqRH::ReadReqRH;
176  IOFile *m_io = nullptr;
177 
178  void Done(int result) override {
179  m_io->ReadEnd(result, this);
180  }
181  };
182 
184 
185  auto *rh = new ZHandler(ObtainReadSid(), &iocb);
186  rh->m_io = this;
187 
188  TRACEIO(Dump, "Read() async " << this << " sid: " << Xrd::hex1 << rh->m_seq_id << " off: " << off << " size: " << size);
189 
190  int retval = ReadBegin(buff, off, size, rh);
191  if (retval != kReadPending)
192  {
193  rh->Done(retval);
194  }
195 }
196 
197 //______________________________________________________________________________
198 void IOFile::pgRead(XrdOucCacheIOCB &iocb, char *buff, long long off, int size,
199  std::vector<uint32_t> &csvec, uint64_t opts, int *csfix)
200 {
201  struct ZHandler : ReadReqRH
202  { using ReadReqRH::ReadReqRH;
203  IOFile *m_io = nullptr;
204  std::function<void (int)> m_lambda {0};
205 
206  void Done(int result) override {
207  if (m_lambda) m_lambda(result);
208  m_io->ReadEnd(result, this);
209  }
210  };
211 
213 
214  auto *rh = new ZHandler(ObtainReadSid(), &iocb);
215  rh->m_io = this;
216 
217  TRACEIO(Dump, "pgRead() async " << this << " sid: " << Xrd::hex1 << rh->m_seq_id << " off: " << off << " size: " << size);
218 
220  rh->m_lambda = [=, &csvec](int result) {
221  if (result > 0)
222  XrdOucPgrwUtils::csCalc((const char *)buff, (ssize_t)off, (size_t)result, csvec);
223  };
224 
225  int retval = ReadBegin(buff, off, size, rh);
226  if (retval != kReadPending)
227  {
228  rh->Done(retval);
229  }
230 }
231 
232 //______________________________________________________________________________
233 int IOFile::ReadBegin(char *buff, long long off, int size, ReadReqRH *rh)
234 {
235  // protect from reads over the file size
236  if (off >= FSize()) {
237  size = 0;
238  return 0;
239  }
240  if (off < 0) {
241  return -EINVAL;
242  }
243  if (off + size > FSize()) {
244  size = FSize() - off;
245  }
246  rh->m_expected_size = size;
247 
248  return m_file->Read(this, buff, off, size, rh);
249 }
250 
251 //______________________________________________________________________________
252 int IOFile::ReadEnd(int retval, ReadReqRH *rh)
253 {
254  TRACEIO(Dump, "ReadEnd() " << (rh->m_iocb ? "a" : "") << "sync " << this << " sid: " << Xrd::hex1 << rh->m_seq_id << " retval: " << retval << " expected_size: " << rh->m_expected_size);
255 
256  if (retval < 0) {
257  TRACEIO(Debug, "ReadEnd() error in File::Read(), exit status=" << retval << ", error=" << XrdSysE2T(-retval) << " sid: " << Xrd::hex1 << rh->m_seq_id);
258  } else if (retval < rh->m_expected_size) {
259  TRACEIO(Debug, "ReadEnd() bytes missed " << rh->m_expected_size - retval << " sid: " << Xrd::hex1 << rh->m_seq_id);
260  }
261  if (rh->m_iocb)
262  rh->m_iocb->Done(retval);
263 
264  delete rh;
265 
267 
268  return retval;
269 }
270 
271 
272 //==============================================================================
273 // ReadV
274 //==============================================================================
275 
276 //______________________________________________________________________________
277 int IOFile::ReadV(const XrdOucIOVec *readV, int n)
278 {
280 
281  auto *rh = new ReadReqRHCond(ObtainReadSid(), nullptr);
282 
283  TRACEIO(Dump, "ReadV() sync " << this << " sid: " << Xrd::hex1 << rh->m_seq_id << " n_chunks: " << n);
284 
285  rh->m_cond.Lock();
286  int retval = ReadVBegin(readV, n, rh);
287  if (retval == kReadPending)
288  {
289  rh->m_cond.Wait();
290  retval = rh->m_retval;
291  }
292  rh->m_cond.UnLock();
293  return ReadVEnd(retval, rh);
294 }
295 
296 //______________________________________________________________________________
297 void IOFile::ReadV(XrdOucCacheIOCB &iocb, const XrdOucIOVec *readV, int n)
298 {
299  struct ZHandler : ReadReqRH
300  { using ReadReqRH::ReadReqRH;
301  IOFile *m_io = nullptr;
302 
303  void Done(int result) override { m_io-> ReadVEnd(result, this); }
304  };
305 
307 
308  auto *rh = new ZHandler(ObtainReadSid(), &iocb);
309  rh->m_io = this;
310 
311  TRACEIO(Dump, "ReadV() async " << this << " sid: " << Xrd::hex1 << rh->m_seq_id << " n_chunks: " << n);
312 
313  int retval = ReadVBegin(readV, n, rh);
314  if (retval != kReadPending)
315  {
316  rh->Done(retval);
317  }
318 }
319 
320 //______________________________________________________________________________
321 int IOFile::ReadVBegin(const XrdOucIOVec *readV, int n, ReadReqRH *rh)
322 {
323  long long file_size = FSize();
324  for (int i = 0; i < n; ++i)
325  {
326  const XrdOucIOVec &vr = readV[i];
327  if (vr.offset < 0 || vr.offset >= file_size ||
328  vr.offset + vr.size > file_size)
329  {
330  return -EINVAL;
331  }
332  rh->m_expected_size += vr.size;
333  }
334  rh->m_n_chunks = n;
335 
336  return m_file->ReadV(this, readV, n, rh);
337 }
338 
339 //______________________________________________________________________________
340 int IOFile::ReadVEnd(int retval, ReadReqRH *rh)
341 {
342  TRACEIO(Dump, "ReadVEnd() " << (rh->m_iocb ? "a" : "") << "sync " << this << " sid: " << Xrd::hex1 << rh->m_seq_id <<
343  " retval: " << retval << " n_chunks: " << rh->m_n_chunks << " expected_size: " << rh->m_expected_size);
344 
345  if (retval < 0) {
346  TRACEIO(Debug, "ReadVEnd() error in File::ReadV(), exit status=" << retval << ", error=" << XrdSysE2T(-retval));
347  } else if (retval < rh->m_expected_size) {
348  TRACEIO(Debug, "ReadVEnd() bytes missed " << rh->m_expected_size - retval);
349  }
350  if (rh->m_iocb)
351  rh->m_iocb->Done(retval);
352 
353  delete rh;
354 
356 
357  return retval;
358 }
#define XrdOssOK
Definition: XrdOss.hh:50
#define TRACE_Error
Definition: XrdPfcTrace.hh:7
#define TRACEIO(act, x)
Definition: XrdPfcTrace.hh:63
#define stat(a, b)
Definition: XrdPosix.hh:101
#define XRD_TRACE
Definition: XrdScheduler.cc:48
bool Debug
struct myOpts opts
const char * XrdSysE2T(int errcode)
Definition: XrdSysE2T.cc:104
@ Error
#define TRACE(act, x)
Definition: XrdTrace.hh:63
virtual int Stat(const char *path, struct stat *buff, int opts=0, XrdOucEnv *envP=0)=0
virtual void Done(int result)=0
virtual int Fstat(struct stat &sbuff)
Definition: XrdOucCache.hh:148
static const uint64_t forceCS
Definition: XrdOucCache.hh:188
static void csCalc(const char *data, off_t offs, size_t count, uint32_t *csval)
Attaches/creates and detaches/deletes cache-io objects for disk based cache.
Definition: XrdPfc.hh:163
long long DetermineFullFileSize(const std::string &cinfo_fname)
Definition: XrdPfc.cc:928
File * GetFile(const std::string &, IO *, long long off=0, long long filesize=0)
Definition: XrdPfc.cc:389
XrdOss * GetOss() const
Definition: XrdPfc.hh:280
static Cache & GetInstance()
Singleton access.
Definition: XrdPfc.cc:132
void ReleaseFile(File *, IO *)
Definition: XrdPfc.cc:473
int ReadV(IO *io, const XrdOucIOVec *readV, int readVnum, ReadReqRH *rh)
Vector read.
Definition: XrdPfcFile.cc:890
int Fstat(struct stat &sbuff)
Definition: XrdPfcFile.cc:668
void RequestSyncOfDetachStats()
Flags that detach stats should be written out in final sync. Called from CacheIO upon Detach.
Definition: XrdPfcFile.cc:319
int Read(IO *io, char *buff, long long offset, int size, ReadReqRH *rh)
Normal read.
Definition: XrdPfcFile.cc:853
void ioUpdated(IO *io)
Notification from IO that it has been updated (remote open).
Definition: XrdPfcFile.cc:233
long long GetFileSize() const
Definition: XrdPfcFile.hh:274
bool ioActive(IO *io)
Initiate close. Return true if still IO active. Used in XrdPosixXrootd::Close()
Definition: XrdPfcFile.cc:242
Downloads original file into a single file on local disk. Handles read requests as they come along.
Definition: XrdPfcIOFile.hh:39
void Update(XrdOucCacheIO &iocp) override
void DetachFinalize() override
Abstract virtual method of XrdPfc::IO Called to destruct the IO object after it is no longer used.
int Read(char *buff, long long off, int size) override
Pass Read request to the corresponding File object.
int Fstat(struct stat &sbuff) override
Definition: XrdPfcIOFile.cc:52
bool ioActive() override
Abstract virtual method of XrdPfc::IO Called to check if destruction needs to be done in a separate t...
int ReadV(const XrdOucIOVec *readV, int n) override
Pass ReadV request to the corresponding File object.
long long FSize() override
Definition: XrdPfcIOFile.cc:66
IOFile(XrdOucCacheIO *io, Cache &cache)
Definition: XrdPfcIOFile.cc:36
virtual int pgRead(char *buff, long long offs, int rdlen, std::vector< uint32_t > &csvec, uint64_t opts=0, int *csfix=0)
Definition: XrdOucCache.cc:39
Base cache-io class that implements some XrdOucCacheIO abstract methods.
Definition: XrdPfcIO.hh:16
int m_incomplete_count
Definition: XrdPfcIO.hh:88
std::map< int, int > m_error_counts
Definition: XrdPfcIO.hh:89
XrdOucCacheIO * GetInput()
Definition: XrdPfcIO.cc:31
Cache & m_cache
reference to Cache object
Definition: XrdPfcIO.hh:50
RAtomic_int m_active_read_reqs
number of active read requests
Definition: XrdPfcIO.hh:70
const char * RefreshLocation()
Definition: XrdPfcIO.hh:55
void Update(XrdOucCacheIO &iocp) override
Definition: XrdPfcIO.cc:17
unsigned short ObtainReadSid()
Definition: XrdPfcIO.hh:57
std::string GetFilename()
Definition: XrdPfcIO.cc:36
Status of cached file. Can be read from and written into a binary file.
Definition: XrdPfcInfo.hh:41
static const char * s_infoExtension
Definition: XrdPfcInfo.hh:309
Definition: XrdPfc.hh:41
constexpr int kReadPending
Definition: XrdPfcFile.hh:54
@ hex1
Definition: XrdSysTrace.hh:42
long long offset
Definition: XrdOucIOVec.hh:42
XrdOucCacheIOCB * m_iocb
Definition: XrdPfcFile.hh:61
unsigned short m_seq_id
Definition: XrdPfcFile.hh:60
ReadReqRH(unsigned short sid, XrdOucCacheIOCB *iocb)
Definition: XrdPfcFile.hh:63