XRootD
XrdPfcFile.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
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 
20 #include "XrdPfcFile.hh"
21 #include "XrdPfc.hh"
22 #include "XrdPfcResourceMonitor.hh"
23 #include "XrdPfcIO.hh"
24 #include "XrdPfcTrace.hh"
25 
26 #include "XProtocol/XProtocol.hh"
27 #include "XrdSys/XrdSysTimer.hh"
28 #include "XrdOss/XrdOss.hh"
29 #include "XrdOuc/XrdOucEnv.hh"
31 
32 #include "XrdCl/XrdClURL.hh"
33 
34 #include <cassert>
35 #include <cstdio>
36 #include <sstream>
37 #include <unordered_map>
38 
39 #include <fcntl.h>
40 
41 using namespace XrdPfc;
42 
43 namespace
44 {
45 
46 const int BLOCK_WRITE_MAX_ATTEMPTS = 4;
47 
48 Cache* cache() { return &Cache::GetInstance(); }
49 
50 }
51 
52 const char *File::m_traceID = "File";
53 
54 //------------------------------------------------------------------------------
55 
56 File::File(const std::string& path, long long iOffset, long long iFileSize) :
57  m_ref_cnt(0),
58  m_data_file(0),
59  m_info_file(0),
60  m_cfi(Cache::TheOne().GetTrace(), Cache::TheOne().is_prefetch_enabled()),
61  m_filename(path),
62  m_offset(iOffset),
63  m_file_size(iFileSize),
64  m_current_io(m_io_set.end()),
65  m_ios_in_detach(0),
66  m_non_flushed_cnt(0),
67  m_in_sync(false),
68  m_detach_time_logged(false),
69  m_in_shutdown(false),
70  m_state_cond(0),
71  m_block_size(0),
72  m_num_blocks(0),
73  m_resmon_token(-1),
74  m_prefetch_state(kOff),
75  m_prefetch_bytes(0),
76  m_prefetch_read_cnt(0),
77  m_prefetch_hit_cnt(0),
78  m_prefetch_score(0)
79 {}
80 
81 File::~File()
82 {
83  TRACEF(Debug, "~File() for ");
84 }
85 
86 void File::Close()
87 {
88  // Close is called while nullptr is put into Cache::m_active map, see Cache::dec_ref_count(File*).
89  // A stat is called after close to re-check that m_stat_blocks have been reported correctly
90  // to the resource-monitor. Note that the reporting is already clamped down to m_file_size
91  // in report_and_merge_delta_stats() below.
92  //
93  // XFS can pre-allocate significant amount of blocks (1 GB at 1GB mark, 4 GB above 4GB) and those
94  // get reported in as stat.st_blocks.
95  // The reported number is correct in a stat immediately following a close.
96  // If one starts off by writing the last byte of the file, this pre-allocation does not get
97  // triggered up to that point. But comes back with a vengeance right after.
98  //
99  // To be determined if other FSes do something similar (Ceph, ZFS, ...). Ext4 doesn't.
100 
101  if (m_info_file)
102  {
103  TRACEF(Debug, "Close() closing info-file ");
104  m_info_file->Close();
105  delete m_info_file;
106  m_info_file = nullptr;
107  }
108 
109  if (m_data_file)
110  {
111  TRACEF(Debug, "Close() closing data-file ");
112  m_data_file->Close();
113  delete m_data_file;
114  m_data_file = nullptr;
115  }
116 
117  if (m_resmon_token >= 0)
118  {
119  // Last update of file stats has been sent from the final Sync unless we are in_shutdown --
120  // but in this case the file will get unlinked by the cache and reported as purge event.
121  // We check if the reported st_blocks so far is correct.
122  if (m_stats.m_BytesWritten > 0 && ! m_in_shutdown) {
123  struct stat s;
124  int sr = Cache::GetInstance().GetOss()->Stat(m_filename.c_str(), &s);
125  if (sr == 0 && s.st_blocks != m_st_blocks) {
126  Stats stats;
127  stats.m_StBlocksAdded = s.st_blocks - m_st_blocks;
128  m_st_blocks = s.st_blocks;
129  Cache::ResMon().register_file_update_stats(m_resmon_token, stats);
130  }
131  }
132 
133  Cache::ResMon().register_file_close(m_resmon_token, time(0), m_stats);
134  }
135 
136  TRACEF(Debug, "Close() finished, prefetch score = " << m_prefetch_score);
137 }
138 
139 //------------------------------------------------------------------------------
140 
141 File* File::FileOpen(const std::string &path, long long offset, long long fileSize, XrdOucCacheIO* inputIO)
142 {
143  File *file = new File(path, offset, fileSize);
144  if ( ! file->Open(inputIO))
145  {
146  delete file;
147  file = 0;
148  }
149  return file;
150 }
151 
152 //------------------------------------------------------------------------------
153 
155 {
156  // Called from Cache::Unlink() when the file is currently open.
157  // Cache::Unlink is also called on FSync error and when wrong number of bytes
158  // is received from a remote read.
159  //
160  // From this point onward the file will not be written to, cinfo file will
161  // not be updated, and all new read requests will return -ENOENT.
162  //
163  // File's entry in the Cache's active map is set to nullptr and will be
164  // removed from there shortly, in any case, well before this File object
165  // shuts down. Cache::Unlink() also reports the appropriate purge event.
166 
167  XrdSysCondVarHelper _lck(m_state_cond);
168 
169  m_in_shutdown = true;
170 
171  if (m_prefetch_state != kStopped && m_prefetch_state != kComplete)
172  {
173  m_prefetch_state = kStopped;
174  cache()->DeRegisterPrefetchFile(this);
175  }
176 
177  report_and_merge_delta_stats();
178 
179  return m_st_blocks;
180 }
181 
182 //------------------------------------------------------------------------------
183 
184 void File::check_delta_stats()
185 {
186  // Called under m_state_cond lock.
187  // BytesWritten indirectly trigger an unconditional merge through periodic Sync().
188  if (m_delta_stats.BytesReadAndWritten() >= m_resmon_report_threshold && ! m_in_shutdown)
189  report_and_merge_delta_stats();
190 }
191 
192 void File::report_and_merge_delta_stats()
193 {
194  // Called under m_state_cond lock.
195  struct stat s;
196  m_data_file->Fstat(&s);
197  // Do not report st_blocks beyond 4kB round-up over m_file_size. Some FSs report
198  // aggressive pre-allocation in this field (XFS, 4GB).
199  long long max_st_blocks_to_report = (m_file_size & 0xfff) ? ((m_file_size >> 12) + 1) << 3
200  : m_file_size >> 9;
201  long long st_blocks_to_report = std::min((long long) s.st_blocks, max_st_blocks_to_report);
202  m_delta_stats.m_StBlocksAdded = st_blocks_to_report - m_st_blocks;
203  m_st_blocks = st_blocks_to_report;
204  Cache::ResMon().register_file_update_stats(m_resmon_token, m_delta_stats);
205  m_stats.AddUp(m_delta_stats);
206  m_delta_stats.Reset();
207 }
208 
209 //------------------------------------------------------------------------------
210 
212 {
213  TRACEF(Dump, "BlockRemovedFromWriteQ() block = " << (void*) b << " idx= " << b->m_offset/m_block_size);
214 
215  XrdSysCondVarHelper _lck(m_state_cond);
216  dec_ref_count(b);
217 }
218 
219 void File::BlocksRemovedFromWriteQ(std::list<Block*>& blocks)
220 {
221  TRACEF(Dump, "BlocksRemovedFromWriteQ() n_blocks = " << blocks.size());
222 
223  XrdSysCondVarHelper _lck(m_state_cond);
224 
225  for (std::list<Block*>::iterator i = blocks.begin(); i != blocks.end(); ++i)
226  {
227  dec_ref_count(*i);
228  }
229 }
230 
231 //------------------------------------------------------------------------------
232 
234 {
235  std::string loc(io->GetLocation());
236  XrdSysCondVarHelper _lck(m_state_cond);
237  insert_remote_location(loc);
238 }
239 
240 //------------------------------------------------------------------------------
241 
243 {
244  // Returns true if delay is needed.
245 
246  TRACEF(Debug, "ioActive start for io " << io);
247 
248  std::string loc(io->GetLocation());
249 
250  {
251  XrdSysCondVarHelper _lck(m_state_cond);
252 
253  IoSet_i mi = m_io_set.find(io);
254 
255  if (mi != m_io_set.end())
256  {
257  unsigned int n_active_reads = io->m_active_read_reqs;
258 
259  TRACE(Info, "ioActive for io " << io <<
260  ", active_reads " << n_active_reads <<
261  ", active_prefetches " << io->m_active_prefetches <<
262  ", allow_prefetching " << io->m_allow_prefetching <<
263  ", ios_in_detach " << m_ios_in_detach);
264  TRACEF(Info,
265  "\tio_map.size() " << m_io_set.size() <<
266  ", block_map.size() " << m_block_map.size() << ", file");
267 
268  insert_remote_location(loc);
269 
270  io->m_allow_prefetching = false;
271  io->m_in_detach = true;
272 
273  // Check if any IO is still available for prfetching. If not, stop it.
274  if (m_prefetch_state == kOn || m_prefetch_state == kHold)
275  {
276  if ( ! select_current_io_or_disable_prefetching(false) )
277  {
278  TRACEF(Debug, "ioActive stopping prefetching after io " << io << " retreat.");
279  }
280  }
281 
282  // On last IO, consider write queue blocks. Note, this also contains
283  // blocks being prefetched.
284 
285  bool io_active_result;
286 
287  if (n_active_reads > 0)
288  {
289  io_active_result = true;
290  }
291  else if (m_io_set.size() - m_ios_in_detach == 1)
292  {
293  io_active_result = ! m_block_map.empty();
294  }
295  else
296  {
297  io_active_result = io->m_active_prefetches > 0;
298  }
299 
300  if ( ! io_active_result)
301  {
302  ++m_ios_in_detach;
303  }
304 
305  TRACEF(Info, "ioActive for io " << io << " returning " << io_active_result << ", file");
306 
307  return io_active_result;
308  }
309  else
310  {
311  TRACEF(Error, "ioActive io " << io <<" not found in IoSet. This should not happen.");
312  return false;
313  }
314  }
315 }
316 
317 //------------------------------------------------------------------------------
318 
320 {
321  XrdSysCondVarHelper _lck(m_state_cond);
322  m_detach_time_logged = false;
323 }
324 
326 {
327  // Returns true if sync is required.
328  // This method is called after corresponding IO is detached from PosixCache.
329 
330  XrdSysCondVarHelper _lck(m_state_cond);
331  if ( ! m_in_shutdown)
332  {
333  if ( ! m_writes_during_sync.empty() || m_non_flushed_cnt > 0 || ! m_detach_time_logged)
334  {
335  report_and_merge_delta_stats();
336  m_cfi.WriteIOStatDetach(m_stats);
337  m_detach_time_logged = true;
338  m_in_sync = true;
339  TRACEF(Debug, "FinalizeSyncBeforeExit requesting sync to write detach stats");
340  return true;
341  }
342  }
343  TRACEF(Debug, "FinalizeSyncBeforeExit sync not required");
344  return false;
345 }
346 
347 //------------------------------------------------------------------------------
348 
349 void File::AddIO(IO *io)
350 {
351  // Called from Cache::GetFile() when a new IO asks for the file.
352 
353  TRACEF(Debug, "AddIO() io = " << (void*)io);
354 
355  time_t now = time(0);
356  std::string loc(io->GetLocation());
357 
358  m_state_cond.Lock();
359 
360  IoSet_i mi = m_io_set.find(io);
361 
362  if (mi == m_io_set.end())
363  {
364  m_io_set.insert(io);
365  io->m_attach_time = now;
366  m_delta_stats.IoAttach();
367 
368  insert_remote_location(loc);
369 
370  if (m_prefetch_state == kStopped)
371  {
372  m_prefetch_state = kOn;
373  cache()->RegisterPrefetchFile(this);
374  }
375  }
376  else
377  {
378  TRACEF(Error, "AddIO() io = " << (void*)io << " already registered.");
379  }
380 
381  m_state_cond.UnLock();
382 }
383 
384 //------------------------------------------------------------------------------
385 
387 {
388  // Called from Cache::ReleaseFile.
389 
390  TRACEF(Debug, "RemoveIO() io = " << (void*)io);
391 
392  time_t now = time(0);
393 
394  m_state_cond.Lock();
395 
396  IoSet_i mi = m_io_set.find(io);
397 
398  if (mi != m_io_set.end())
399  {
400  if (mi == m_current_io)
401  {
402  ++m_current_io;
403  }
404 
405  m_delta_stats.IoDetach(now - io->m_attach_time);
406  m_io_set.erase(mi);
407  --m_ios_in_detach;
408 
409  if (m_io_set.empty() && m_prefetch_state != kStopped && m_prefetch_state != kComplete)
410  {
411  TRACEF(Error, "RemoveIO() io = " << (void*)io << " Prefetching is not stopped/complete -- it should be by now.");
412  m_prefetch_state = kStopped;
413  cache()->DeRegisterPrefetchFile(this);
414  }
415  }
416  else
417  {
418  TRACEF(Error, "RemoveIO() io = " << (void*)io << " is NOT registered.");
419  }
420 
421  m_state_cond.UnLock();
422 }
423 
424 //------------------------------------------------------------------------------
425 
426 bool File::Open(XrdOucCacheIO* inputIO)
427 {
428  // Sets errno accordingly.
429 
430  static const char *tpfx = "Open() ";
431 
432  TRACEF(Dump, tpfx << "entered");
433 
434  // Before touching anything, check with ResourceMonitor if a scan is in progress.
435  // This function will wait internally if needed until it is safe to proceed.
436  Cache::ResMon().CrossCheckIfScanIsInProgress(m_filename, m_state_cond);
437 
439 
440  XrdOss &myOss = * Cache::GetInstance().GetOss();
441  const char *myUser = conf.m_username.c_str();
442  XrdOucEnv myEnv;
443  struct stat data_stat, info_stat;
444 
445  std::string ifn = m_filename + Info::s_infoExtension;
446 
447  bool data_existed = (myOss.Stat(m_filename.c_str(), &data_stat) == XrdOssOK);
448  bool info_existed = (myOss.Stat(ifn.c_str(), &info_stat) == XrdOssOK);
449 
450  // Create the data file itself.
451  char size_str[32]; sprintf(size_str, "%lld", m_file_size);
452  myEnv.Put("oss.asize", size_str);
453  myEnv.Put("oss.cgroup", conf.m_data_space.c_str());
454 
455  int res;
456 
457  if ((res = myOss.Create(myUser, m_filename.c_str(), 0600, myEnv, XRDOSS_mkpath)) != XrdOssOK)
458  {
459  TRACEF(Error, tpfx << "Create failed " << ERRNO_AND_ERRSTR(-res));
460  errno = -res;
461  return false;
462  }
463 
464  m_data_file = myOss.newFile(myUser);
465  if ((res = m_data_file->Open(m_filename.c_str(), O_RDWR, 0600, myEnv)) != XrdOssOK)
466  {
467  TRACEF(Error, tpfx << "Open failed " << ERRNO_AND_ERRSTR(-res));
468  errno = -res;
469  delete m_data_file; m_data_file = 0;
470  if ( ! data_existed) myOss.Unlink(m_filename.c_str());
471  return false;
472  }
473 
474  myEnv.Put("oss.asize", "64k"); // Advisory, block-map and access list lengths vary.
475  myEnv.Put("oss.cgroup", conf.m_meta_space.c_str());
476  if ((res = myOss.Create(myUser, ifn.c_str(), 0600, myEnv, XRDOSS_mkpath)) != XrdOssOK)
477  {
478  TRACE(Error, tpfx << "Create failed for info file " << ifn << ERRNO_AND_ERRSTR(-res));
479  errno = -res;
480  m_data_file->Close(); delete m_data_file; m_data_file = 0;
481  if ( ! data_existed) myOss.Unlink(m_filename.c_str());
482  return false;
483  }
484 
485  m_info_file = myOss.newFile(myUser);
486  if ((res = m_info_file->Open(ifn.c_str(), O_RDWR, 0600, myEnv)) != XrdOssOK)
487  {
488  TRACEF(Error, tpfx << "Failed for info file " << ifn << ERRNO_AND_ERRSTR(-res));
489  errno = -res;
490  delete m_info_file; m_info_file = 0;
491  m_data_file->Close(); delete m_data_file; m_data_file = 0;
492  // Remove only what this call created, so a failed open leaves no
493  // uncounted data/cinfo pair behind.
494  if ( ! info_existed) myOss.Unlink(ifn.c_str());
495  if ( ! data_existed) myOss.Unlink(m_filename.c_str());
496  return false;
497  }
498 
499  bool initialize_info_file = true;
500 
501  if (info_existed && m_cfi.Read(m_info_file, ifn.c_str()))
502  {
503  TRACEF(Debug, tpfx << "Reading existing info file. (data_existed=" << data_existed <<
504  ", data_size_stat=" << (data_existed ? data_stat.st_size : -1ll) <<
505  ", data_size_from_last_block=" << m_cfi.GetExpectedDataFileSize() <<
506  ", block_size=" << (m_cfi.GetBufferSize() >> 10) << "k)");
507 
508  // Check if data file exists and is of reasonable size.
509  if (data_existed && data_stat.st_size >= m_cfi.GetExpectedDataFileSize())
510  {
511  initialize_info_file = false;
512  } else {
513  TRACEF(Warning, tpfx << "Basic sanity checks on data file failed, resetting info file, truncating data file.");
514  m_cfi.ResetAllAccessStats();
515  m_data_file->Ftruncate(0);
516  // data-file might not have existed at entry -- data_stat is then undefined
517  if (data_existed)
518  Cache::ResMon().register_file_purge(m_filename, data_stat.st_blocks);
519  }
520  }
521  else if (info_existed)
522  {
523  // The info file is about to be rewritten, so the cached blocks are lost:
524  // reset it like a rejected file.
525  TRACEF(Warning, tpfx << "Reading existing info file failed, resetting info file, truncating data file.");
526  m_cfi.ResetAllAccessStats();
527  m_data_file->Ftruncate(0);
528  if (data_existed)
529  Cache::ResMon().register_file_purge(m_filename, data_stat.st_blocks);
530  }
531 
532  if ( ! initialize_info_file && m_cfi.GetCkSumState() != conf.get_cs_Chk())
533  {
534  if (conf.does_cschk_have_missing_bits(m_cfi.GetCkSumState()) &&
535  conf.should_uvkeep_purge(time(0) - m_cfi.GetNoCkSumTimeForUVKeep()))
536  {
537  TRACEF(Info, tpfx << "Cksum state of file insufficient, uvkeep test failed, resetting info file, truncating data file.");
538  initialize_info_file = true;
539  m_cfi.ResetAllAccessStats();
540  m_data_file->Ftruncate(0);
541  // data-file is known to exist due to checks in the previous if block
542  Cache::ResMon().register_file_purge(m_filename, data_stat.st_blocks);
543  } else {
544  // TODO: If the file is complete, we don't need to reset net cksums.
545  m_cfi.DowngradeCkSumState(conf.get_cs_Chk());
546  }
547  }
548 
549  // Check if we have pfc url arguments.
550  long long pfc_blocksize = conf.m_bufferSize;
551  int pfc_prefetch = conf.m_prefetch_max_blocks;
553  {
554  parse_pfc_url_args(inputIO, pfc_blocksize, pfc_prefetch);
555  }
556 
557  if (initialize_info_file)
558  {
559  m_cfi.SetBufferSizeFileSizeAndCreationTime(pfc_blocksize, m_file_size);
560  m_cfi.SetCkSumState(conf.get_cs_Chk());
561  m_cfi.ResetNoCkSumTime();
562  m_cfi.Write(m_info_file, ifn.c_str());
563  m_info_file->Fsync();
564  cache()->WriteFileSizeXAttr(m_info_file->getFD(), m_file_size);
565  // There is still a chance we had an orphaned data-file.
566  if (data_existed && ! info_existed) {
567  m_data_file->Ftruncate(0);
568  // Resource-monitor does not count orphaned files (planned for 6.x) so no register_purge().
569  }
570  TRACEF(Debug, tpfx << "Creating new file info, data size = " << m_file_size << " num blocks = " << m_cfi.GetNBlocks()
571  << " block size = " << pfc_blocksize);
572  }
573  else
574  {
575  if (futimens(m_info_file->getFD(), NULL)) {
576  TRACEF(Error, tpfx << "failed setting modification time " << ERRNO_AND_ERRSTR(errno));
577  }
578  if (pfc_blocksize != conf.m_bufferSize) {
579  TRACEF(Info, tpfx << "URL CGI pfc.blocksize ignored for an already existing file");
580  }
581  }
582 
583  m_cfi.WriteIOStatAttach();
584 
585  // An open file must have a token, else its usage is never accounted.
586  m_resmon_token = Cache::ResMon().register_file_open(m_filename, time(0), ! initialize_info_file);
587  if (m_resmon_token < 0)
588  {
589  TRACEF(Error, tpfx << "no resource-monitor token available, not caching it; "
590  "this indicates a token leak in XrdPfc, please report it.");
591  m_info_file->Close(); delete m_info_file; m_info_file = nullptr;
592  m_data_file->Close(); delete m_data_file; m_data_file = nullptr;
593  // Remove only what this call created.
594  if ( ! info_existed) myOss.Unlink(ifn.c_str());
595  if ( ! data_existed) myOss.Unlink(m_filename.c_str());
596  errno = EMFILE;
597  return false;
598  }
599 
600  m_state_cond.Lock();
601  m_block_size = m_cfi.GetBufferSize();
602  m_num_blocks = m_cfi.GetNBlocks();
603  m_prefetch_state = (m_cfi.IsComplete()) ? kComplete : kStopped; // Will engage in AddIO().
604  m_prefetch_max_blocks_in_flight = pfc_prefetch;
605  if (pfc_prefetch != conf.m_prefetch_max_blocks)
606  TRACEF(Debug, tpfx << "pfc.prefetch set to " << pfc_prefetch << " via CGI parameter");
607 
608  m_data_file->Fstat(&data_stat);
609  m_st_blocks = data_stat.st_blocks;
610 
611  constexpr long long MB = 1024 * 1024;
612  m_resmon_report_threshold = std::min(std::max(10 * MB, m_file_size / 20), 500 * MB);
613  // m_resmon_report_threshold_scaler; // something like 10% of original threshold, to adjust
614  // actual threshold based on return values from register_file_update_stats().
615 
616  m_state_cond.UnLock();
617 
618  return true;
619 }
620 
621 void File::parse_pfc_url_args(XrdOucCacheIO* inputIO, long long &pfc_blocksize, int &pfc_prefetch) const
622 {
623  const Configuration &conf = Cache::TheOne().RefConfiguration();
624 
625  XrdCl::URL url(inputIO->Path());
626  auto const & urlp = url.GetParams();
627 
628  auto extract = [&](const std::string &key, std::string &value) -> bool {
629  auto it = urlp.find(key);
630  if (it != urlp.end()) {
631  value = it->second;
632  return true;
633  } else {
634  value.clear();
635  return false;
636  }
637  };
638 
639  std::string val;
640  if (conf.m_cgi_blocksize_allowed && extract("pfc.blocksize", val))
641  {
642  const char *tpfx = "File::Open::urlcgi pfc.blocksize ";
643  long long bsize;
644  if (Cache::TheOne().blocksize_str2value(tpfx, val.c_str(), bsize,
646  {
647  pfc_blocksize = bsize;
648  } else {
649  TRACEF(Error, tpfx << "Error processing the parameter.");
650  }
651  }
652  if (conf.m_cgi_prefetch_allowed && extract("pfc.prefetch", val))
653  {
654  const char *tpfx = "File::Open::urlcgi pfc.prefetch ";
655  int pref;
656  if (Cache::TheOne().prefetch_str2value(tpfx, val.c_str(), pref,
658  {
659  pfc_prefetch = pref;
660  } else {
661  TRACEF(Error, tpfx << "Error processing the parameter.");
662  }
663  }
664 }
665 
666 //------------------------------------------------------------------------------
667 
668 int File::Fstat(struct stat &sbuff)
669 {
670  // Stat on an open file.
671  // Corrects size to actual full size of the file.
672  // Sets atime to 0 if the file is only partially downloaded, in accordance
673  // with pfc.onlyifcached settings.
674  // Called from IO::Fstat() and Cache::Stat() when the file is active.
675  // Returns 0 on success, -errno on error.
676 
677  int res;
678 
679  if ((res = m_data_file->Fstat(&sbuff))) return res;
680 
681  sbuff.st_size = m_file_size;
682 
683  bool is_cached = cache()->DecideIfConsideredCached(m_file_size, sbuff.st_blocks * 512ll);
684  if ( ! is_cached)
685  sbuff.st_atime = 0;
686 
687  return 0;
688 }
689 
690 //==============================================================================
691 // Read and helpers
692 //==============================================================================
693 
694 bool File::overlap(int blk, // block to query
695  long long blk_size, //
696  long long req_off, // offset of user request
697  int req_size, // size of user request
698  // output:
699  long long &off, // offset in user buffer
700  long long &blk_off, // offset in block
701  int &size) // size to copy
702 {
703  const long long beg = blk * blk_size;
704  const long long end = beg + blk_size;
705  const long long req_end = req_off + req_size;
706 
707  if (req_off < end && req_end > beg)
708  {
709  const long long ovlp_beg = std::max(beg, req_off);
710  const long long ovlp_end = std::min(end, req_end);
711 
712  off = ovlp_beg - req_off;
713  blk_off = ovlp_beg - beg;
714  size = (int) (ovlp_end - ovlp_beg);
715 
716  assert(size <= blk_size);
717  return true;
718  }
719  else
720  {
721  return false;
722  }
723 }
724 
725 //------------------------------------------------------------------------------
726 
727 Block* File::PrepareBlockRequest(int i, IO *io, void *req_id, bool prefetch)
728 {
729  // Must be called w/ state_cond locked.
730  // Checks on size etc should be done before.
731  //
732  // Reference count is 0 so increase it in calling function if you want to
733  // catch the block while still in memory.
734 
735  const long long off = i * m_block_size;
736  const int last_block = m_num_blocks - 1;
737  const bool cs_net = cache()->RefConfiguration().is_cschk_net();
738 
739  int blk_size, req_size;
740  if (i == last_block) {
741  blk_size = req_size = m_file_size - off;
742  if (cs_net && req_size & 0xFFF) req_size = (req_size & ~0xFFF) + 0x1000;
743  } else {
744  blk_size = req_size = m_block_size;
745  }
746 
747  Block *b = 0;
748  char *buf = cache()->RequestRAM(req_size);
749 
750  if (buf)
751  {
752  b = new (std::nothrow) Block(this, io, req_id, buf, off, blk_size, req_size, prefetch, cs_net);
753 
754  if (b)
755  {
756  m_block_map[i] = b;
757 
758  // Actual Read request is issued in ProcessBlockRequests().
759 
760  if (m_prefetch_state == kOn && (int) m_block_map.size() >= m_prefetch_max_blocks_in_flight)
761  {
762  m_prefetch_state = kHold;
763  cache()->DeRegisterPrefetchFile(this);
764  }
765  }
766  else
767  {
768  TRACEF(Dump, "PrepareBlockRequest() " << i << " prefetch " << prefetch << ", allocation failed.");
769  }
770  }
771 
772  return b;
773 }
774 
775 void File::ProcessBlockRequest(Block *b)
776 {
777  // This *must not* be called with block_map locked.
778 
780 
781  if (XRD_TRACE What >= TRACE_Dump) {
782  char buf[256];
783  snprintf(buf, 256, "idx=%lld, block=%p, prefetch=%d, off=%lld, req_size=%d, buff=%p, resp_handler=%p ",
784  b->get_offset()/m_block_size, (void*)b, b->m_prefetch, b->get_offset(), b->get_req_size(), (void*)b->get_buff(), (void*)brh);
785  TRACEF(Dump, "ProcessBlockRequest() " << buf);
786  }
787 
788  if (b->req_cksum_net())
789  {
790  b->get_io()->GetInput()->pgRead(*brh, b->get_buff(), b->get_offset(), b->get_req_size(),
791  b->ref_cksum_vec(), 0, b->ptr_n_cksum_errors());
792  } else {
793  b->get_io()->GetInput()-> Read(*brh, b->get_buff(), b->get_offset(), b->get_size());
794  }
795 }
796 
797 void File::ProcessBlockRequests(BlockList_t& blks)
798 {
799  // This *must not* be called with block_map locked.
800 
801  for (BlockList_i bi = blks.begin(); bi != blks.end(); ++bi)
802  {
803  ProcessBlockRequest(*bi);
804  }
805 }
806 
807 //------------------------------------------------------------------------------
808 
809 void File::RequestBlocksDirect(IO *io, ReadRequest *read_req, std::vector<XrdOucIOVec>& ioVec, int expected_size)
810 {
811  int n_chunks = ioVec.size();
812  int n_vec_reads = (n_chunks - 1) / XrdProto::maxRvecsz + 1;
813 
814  TRACEF(DumpXL, "RequestBlocksDirect() issuing ReadV for n_chunks = " << n_chunks <<
815  ", total_size = " << expected_size << ", n_vec_reads = " << n_vec_reads);
816 
817  DirectResponseHandler *handler = new DirectResponseHandler(this, read_req, n_vec_reads);
818 
819  int pos = 0;
820  while (n_chunks > XrdProto::maxRvecsz) {
821  io->GetInput()->ReadV( *handler, ioVec.data() + pos, XrdProto::maxRvecsz);
822  pos += XrdProto::maxRvecsz;
823  n_chunks -= XrdProto::maxRvecsz;
824  }
825  io->GetInput()->ReadV( *handler, ioVec.data() + pos, n_chunks);
826 }
827 
828 //------------------------------------------------------------------------------
829 
830 int File::ReadBlocksFromDisk(std::vector<XrdOucIOVec>& ioVec, int expected_size)
831 {
832  TRACEF(DumpXL, "ReadBlocksFromDisk() issuing ReadV for n_chunks = " << (int) ioVec.size() << ", total_size = " << expected_size);
833 
834  long long rs = m_data_file->ReadV(ioVec.data(), (int) ioVec.size());
835 
836  if (rs < 0)
837  {
838  TRACEF(Error, "ReadBlocksFromDisk neg retval = " << rs);
839  return rs;
840  }
841 
842  if (rs != expected_size)
843  {
844  TRACEF(Error, "ReadBlocksFromDisk incomplete size = " << rs);
845  return -EIO;
846  }
847 
848  return (int) rs;
849 }
850 
851 //------------------------------------------------------------------------------
852 
853 int File::Read(IO *io, char* iUserBuff, long long iUserOff, int iUserSize, ReadReqRH *rh)
854 {
855  // rrc_func is ONLY called from async processing.
856  // If this function returns anything other than kReadPending, rrc_func needs to be called by the caller.
857  // This streamlines implementation of synchronous IO::Read().
858 
859  TRACEF(Dump, "Read() sid: " << Xrd::hex1 << rh->m_seq_id << " size: " << iUserSize);
860 
861  m_state_cond.Lock();
862 
863  if (m_in_shutdown || io->m_in_detach)
864  {
865  m_state_cond.UnLock();
866  return m_in_shutdown ? -ENOENT : -EBADF;
867  }
868 
869  // Shortcut -- file is fully downloaded.
870 
871  if (m_cfi.IsComplete())
872  {
873  m_state_cond.UnLock();
874  int ret = m_data_file->Read(iUserBuff, iUserOff, iUserSize);
875  if (ret > 0) {
876  XrdSysCondVarHelper _lck(m_state_cond);
877  m_delta_stats.AddBytesHit(ret);
878  check_delta_stats();
879  }
880  return ret;
881  }
882 
883  XrdOucIOVec readV( { iUserOff, iUserSize, 0, iUserBuff } );
884 
885  return ReadOpusCoalescere(io, &readV, 1, rh, "Read() ");
886 }
887 
888 //------------------------------------------------------------------------------
889 
890 int File::ReadV(IO *io, const XrdOucIOVec *readV, int readVnum, ReadReqRH *rh)
891 {
892  TRACEF(Dump, "ReadV() for " << readVnum << " chunks.");
893 
894  m_state_cond.Lock();
895 
896  if (m_in_shutdown || io->m_in_detach)
897  {
898  m_state_cond.UnLock();
899  return m_in_shutdown ? -ENOENT : -EBADF;
900  }
901 
902  // Shortcut -- file is fully downloaded.
903 
904  if (m_cfi.IsComplete())
905  {
906  m_state_cond.UnLock();
907  int ret = m_data_file->ReadV(const_cast<XrdOucIOVec*>(readV), readVnum);
908  if (ret > 0) {
909  XrdSysCondVarHelper _lck(m_state_cond);
910  m_delta_stats.AddBytesHit(ret);
911  check_delta_stats();
912  }
913  return ret;
914  }
915 
916  return ReadOpusCoalescere(io, readV, readVnum, rh, "ReadV() ");
917 }
918 
919 //------------------------------------------------------------------------------
920 
921 int File::ReadOpusCoalescere(IO *io, const XrdOucIOVec *readV, int readVnum,
922  ReadReqRH *rh, const char *tpfx)
923 {
924  // Non-trivial processing for Read and ReadV.
925  // Entered under lock.
926  //
927  // loop over reqired blocks:
928  // - if on disk, ok;
929  // - if in ram or incoming, inc ref-count
930  // - otherwise request and inc ref count (unless RAM full => request direct)
931  // unlock
932 
933  int prefetch_cnt = 0;
934 
935  ReadRequest *read_req = nullptr;
936  BlockList_t blks_to_request; // blocks we are issuing a new remote request for
937 
938  std::unordered_map<Block*, std::vector<ChunkRequest>> blks_ready;
939 
940  std::vector<XrdOucIOVec> iovec_disk;
941  std::vector<XrdOucIOVec> iovec_direct;
942  int iovec_disk_total = 0;
943  int iovec_direct_total = 0;
944 
945  for (int iov_idx = 0; iov_idx < readVnum; ++iov_idx)
946  {
947  const XrdOucIOVec &iov = readV[iov_idx];
948  long long iUserOff = iov.offset;
949  int iUserSize = iov.size;
950  char *iUserBuff = iov.data;
951 
952  const int idx_first = iUserOff / m_block_size;
953  const int idx_last = (iUserOff + iUserSize - 1) / m_block_size;
954 
955  TRACEF(DumpXL, tpfx << "sid: " << Xrd::hex1 << rh->m_seq_id << " idx_first: " << idx_first << " idx_last: " << idx_last);
956 
957  enum LastBlock_e { LB_other, LB_disk, LB_direct };
958 
959  LastBlock_e lbe = LB_other;
960 
961  for (int block_idx = idx_first; block_idx <= idx_last; ++block_idx)
962  {
963  TRACEF(DumpXL, tpfx << "sid: " << Xrd::hex1 << rh->m_seq_id << " idx: " << block_idx);
964  BlockMap_i bi = m_block_map.find(block_idx);
965 
966  // overlap and read
967  long long off = 0; // offset in user buffer
968  long long blk_off = 0; // offset in block
969  int size = 0; // size to copy
970 
971  overlap(block_idx, m_block_size, iUserOff, iUserSize, off, blk_off, size);
972 
973  // In RAM or incoming?
974  if (bi != m_block_map.end())
975  {
976  inc_ref_count(bi->second);
977  TRACEF(Dump, tpfx << (void*) iUserBuff << " inc_ref_count for existing block " << bi->second << " idx = " << block_idx);
978 
979  if (bi->second->is_finished())
980  {
981  // note, blocks with error should not be here !!!
982  // they should be either removed or reissued in ProcessBlockResponse()
983  assert(bi->second->is_ok());
984 
985  blks_ready[bi->second].emplace_back( ChunkRequest(nullptr, iUserBuff + off, blk_off, size) );
986 
987  if (bi->second->m_prefetch)
988  ++prefetch_cnt;
989  }
990  else
991  {
992  if ( ! read_req)
993  read_req = new ReadRequest(io, rh);
994 
995  // We have a lock on state_cond --> as we register the request before releasing the lock,
996  // we are sure to get a call-in via the ChunkRequest handling when this block arrives.
997 
998  bi->second->m_chunk_reqs.emplace_back( ChunkRequest(read_req, iUserBuff + off, blk_off, size) );
999  ++read_req->m_n_chunk_reqs;
1000  }
1001 
1002  lbe = LB_other;
1003  }
1004  // On disk?
1005  else if (m_cfi.TestBitWritten(offsetIdx(block_idx)))
1006  {
1007  TRACEF(DumpXL, tpfx << "read from disk " << (void*)iUserBuff << " idx = " << block_idx);
1008 
1009  if (lbe == LB_disk)
1010  iovec_disk.back().size += size;
1011  else
1012  iovec_disk.push_back( { block_idx * m_block_size + blk_off, size, 0, iUserBuff + off } );
1013  iovec_disk_total += size;
1014 
1015  if (m_cfi.TestBitPrefetch(offsetIdx(block_idx)))
1016  ++prefetch_cnt;
1017 
1018  lbe = LB_disk;
1019  }
1020  // Neither ... then we have to go get it ...
1021  else
1022  {
1023  if ( ! read_req)
1024  read_req = new ReadRequest(io, rh);
1025 
1026  // Is there room for one more RAM Block?
1027  Block *b = PrepareBlockRequest(block_idx, io, read_req, false);
1028  if (b)
1029  {
1030  TRACEF(Dump, tpfx << "inc_ref_count new " << (void*)iUserBuff << " idx = " << block_idx);
1031  inc_ref_count(b);
1032  blks_to_request.push_back(b);
1033 
1034  b->m_chunk_reqs.emplace_back(ChunkRequest(read_req, iUserBuff + off, blk_off, size));
1035  ++read_req->m_n_chunk_reqs;
1036 
1037  lbe = LB_other;
1038  }
1039  else // Nope ... read this directly without caching.
1040  {
1041  TRACEF(DumpXL, tpfx << "direct block " << block_idx << ", blk_off " << blk_off << ", size " << size);
1042 
1043  iovec_direct_total += size;
1044  read_req->m_direct_done = false;
1045 
1046  // Make sure we do not issue a ReadV with chunk size above XrdProto::maxRVdsz.
1047  // Number of actual ReadVs issued so as to not exceed the XrdProto::maxRvecsz limit
1048  // is determined in the RequestBlocksDirect().
1049  if (lbe == LB_direct && iovec_direct.back().size + size <= XrdProto::maxRVdsz) {
1050  iovec_direct.back().size += size;
1051  } else {
1052  long long in_offset = block_idx * m_block_size + blk_off;
1053  char *out_pos = iUserBuff + off;
1054  while (size > XrdProto::maxRVdsz) {
1055  iovec_direct.push_back( { in_offset, XrdProto::maxRVdsz, 0, out_pos } );
1056  in_offset += XrdProto::maxRVdsz;
1057  out_pos += XrdProto::maxRVdsz;
1058  size -= XrdProto::maxRVdsz;
1059  }
1060  iovec_direct.push_back( { in_offset, size, 0, out_pos } );
1061  }
1062 
1063  lbe = LB_direct;
1064  }
1065  }
1066  } // end for over blocks in an IOVec
1067  } // end for over readV IOVec
1068 
1069  inc_prefetch_hit_cnt(prefetch_cnt);
1070 
1071  m_state_cond.UnLock();
1072 
1073  // First, send out remote requests for new blocks.
1074  if ( ! blks_to_request.empty())
1075  {
1076  ProcessBlockRequests(blks_to_request);
1077  blks_to_request.clear();
1078  }
1079 
1080  // Second, send out remote direct read requests.
1081  if ( ! iovec_direct.empty())
1082  {
1083  RequestBlocksDirect(io, read_req, iovec_direct, iovec_direct_total);
1084 
1085  TRACEF(Dump, tpfx << "direct read requests sent out, n_chunks = " << (int) iovec_direct.size() << ", total_size = " << iovec_direct_total);
1086  }
1087 
1088  // Begin synchronous part where we process data that is already in RAM or on disk.
1089 
1090  long long bytes_read = 0;
1091  int error_cond = 0; // to be set to -errno
1092 
1093  // Third, process blocks that are available in RAM.
1094  if ( ! blks_ready.empty())
1095  {
1096  for (auto &bvi : blks_ready)
1097  {
1098  for (auto &cr : bvi.second)
1099  {
1100  TRACEF(DumpXL, tpfx << "ub=" << (void*)cr.m_buf << " from pre-finished block " << bvi.first->m_offset/m_block_size << " size " << cr.m_size);
1101  memcpy(cr.m_buf, bvi.first->m_buff + cr.m_off, cr.m_size);
1102  bytes_read += cr.m_size;
1103  }
1104  }
1105  }
1106 
1107  // Fourth, read blocks from disk.
1108  if ( ! iovec_disk.empty())
1109  {
1110  int rc = ReadBlocksFromDisk(iovec_disk, iovec_disk_total);
1111  TRACEF(DumpXL, tpfx << "from disk finished size = " << rc);
1112  if (rc >= 0)
1113  {
1114  bytes_read += rc;
1115  }
1116  else
1117  {
1118  error_cond = rc;
1119  TRACEF(Error, tpfx << "failed read from disk");
1120  }
1121  }
1122 
1123  // End synchronous part -- update with sync stats and determine actual state of this read.
1124  // Note: remote reads might have already finished during disk-read!
1125 
1126  m_state_cond.Lock();
1127 
1128  for (auto &bvi : blks_ready)
1129  dec_ref_count(bvi.first, (int) bvi.second.size());
1130 
1131  if (read_req)
1132  {
1133  read_req->m_bytes_read += bytes_read;
1134  if (error_cond)
1135  read_req->update_error_cond(error_cond);
1136  read_req->m_stats.m_BytesHit += bytes_read;
1137  read_req->m_sync_done = true;
1138 
1139  if (read_req->is_complete())
1140  {
1141  // Almost like FinalizeReadRequest(read_req) -- but no callout!
1142  m_delta_stats.AddReadStats(read_req->m_stats);
1143  check_delta_stats();
1144  m_state_cond.UnLock();
1145 
1146  int ret = read_req->return_value();
1147  delete read_req;
1148  return ret;
1149  }
1150  else
1151  {
1152  m_state_cond.UnLock();
1153  return kReadPending;
1154  }
1155  }
1156  else
1157  {
1158  m_delta_stats.m_BytesHit += bytes_read;
1159  check_delta_stats();
1160  m_state_cond.UnLock();
1161 
1162  // !!! No callout.
1163 
1164  return error_cond ? error_cond : bytes_read;
1165  }
1166 }
1167 
1168 
1169 //==============================================================================
1170 // WriteBlock and Sync
1171 //==============================================================================
1172 
1174 {
1175  // write block buffer into disk file
1176  long long offset = b->m_offset - m_offset;
1177  long long size = b->get_size();
1178  ssize_t retval;
1179 
1180  if (m_cfi.IsCkSumCache())
1181  if (b->has_cksums())
1182  retval = m_data_file->pgWrite(b->get_buff(), offset, size, b->ref_cksum_vec().data(), 0);
1183  else
1184  retval = m_data_file->pgWrite(b->get_buff(), offset, size, 0, 0);
1185  else
1186  retval = m_data_file->Write(b->get_buff(), offset, size);
1187 
1188  if (retval < size)
1189  {
1190  if (retval < 0) {
1191  TRACEF(Error, "WriteToDisk() write error " << retval);
1192  } else {
1193  TRACEF(Error, "WriteToDisk() incomplete block write ret=" << retval << " (should be " << size << ")");
1194  }
1195 
1196  XrdSysCondVarHelper _lck(m_state_cond);
1197 
1198  dec_ref_count(b);
1199 
1200  return;
1201  }
1202 
1203  const int blk_idx = (b->m_offset - m_offset) / m_block_size;
1204 
1205  // Set written bit.
1206  TRACEF(Dump, "WriteToDisk() success set bit for block " << b->m_offset << " size=" << size);
1207 
1208  bool schedule_sync = false;
1209  {
1210  XrdSysCondVarHelper _lck(m_state_cond);
1211 
1212  m_cfi.SetBitWritten(blk_idx);
1213 
1214  if (b->m_prefetch)
1215  {
1216  m_cfi.SetBitPrefetch(blk_idx);
1217  }
1218  if (b->req_cksum_net() && ! b->has_cksums() && m_cfi.IsCkSumNet())
1219  {
1220  m_cfi.ResetCkSumNet();
1221  }
1222 
1223  // Set synced bit or stash block index if in actual sync.
1224  // Synced state is only written out to cinfo file when data file is synced.
1225  if (m_in_sync)
1226  {
1227  m_writes_during_sync.push_back(blk_idx);
1228  }
1229  else
1230  {
1231  m_cfi.SetBitSynced(blk_idx);
1232  ++m_non_flushed_cnt;
1233  if ((m_cfi.IsComplete() || m_non_flushed_cnt >= Cache::GetInstance().RefConfiguration().m_flushCnt) &&
1234  ! m_in_shutdown)
1235  {
1236  schedule_sync = true;
1237  m_in_sync = true;
1238  m_non_flushed_cnt = 0;
1239  }
1240  }
1241  // As soon as the reference count is decreased on the block, the
1242  // file object may be deleted. Thus, to avoid holding both locks at a time,
1243  // we defer the ref count decrease until later if a sync is needed
1244  if (!schedule_sync) {
1245  dec_ref_count(b);
1246  }
1247  }
1248 
1249  if (schedule_sync)
1250  {
1251  cache()->ScheduleFileSync(this);
1252  XrdSysCondVarHelper _lck(m_state_cond);
1253  dec_ref_count(b);
1254  }
1255 }
1256 
1257 //------------------------------------------------------------------------------
1258 
1260 {
1261  TRACEF(Dump, "Sync()");
1262 
1263  int ret = m_data_file->Fsync();
1264  bool errorp = false;
1265  if (ret == XrdOssOK)
1266  {
1267  Stats loc_stats;
1268  {
1269  XrdSysCondVarHelper _lck(&m_state_cond);
1270  report_and_merge_delta_stats();
1271  loc_stats = m_stats;
1272  }
1273  m_cfi.WriteIOStat(loc_stats);
1274  m_cfi.Write(m_info_file, m_filename.c_str());
1275  int cret = m_info_file->Fsync();
1276  if (cret != XrdOssOK)
1277  {
1278  TRACEF(Error, "Sync cinfo file sync error " << cret);
1279  errorp = true;
1280  }
1281  }
1282  else
1283  {
1284  TRACEF(Error, "Sync data file sync error " << ret << ", cinfo file has not been updated");
1285  errorp = true;
1286  }
1287 
1288  if (errorp)
1289  {
1290  TRACEF(Error, "Sync failed, unlinking local files and initiating shutdown of File object");
1291 
1292  // Unlink will also call this->initiate_emergency_shutdown()
1293  Cache::GetInstance().UnlinkFile(m_filename, false);
1294 
1295  XrdSysCondVarHelper _lck(&m_state_cond);
1296 
1297  m_writes_during_sync.clear();
1298  m_in_sync = false;
1299 
1300  return;
1301  }
1302 
1303  int written_while_in_sync;
1304  bool resync = false;
1305  {
1306  XrdSysCondVarHelper _lck(&m_state_cond);
1307  for (std::vector<int>::iterator i = m_writes_during_sync.begin(); i != m_writes_during_sync.end(); ++i)
1308  {
1309  m_cfi.SetBitSynced(*i);
1310  }
1311  written_while_in_sync = m_non_flushed_cnt = (int) m_writes_during_sync.size();
1312  m_writes_during_sync.clear();
1313 
1314  // If there were writes during sync and the file is now complete,
1315  // let us call Sync again without resetting the m_in_sync flag.
1316  if (written_while_in_sync > 0 && m_cfi.IsComplete() && ! m_in_shutdown)
1317  resync = true;
1318  else
1319  m_in_sync = false;
1320  }
1321  TRACEF(Dump, "Sync "<< written_while_in_sync << " blocks written during sync." << (resync ? " File is now complete - resyncing." : ""));
1322 
1323  if (resync)
1324  Sync();
1325 }
1326 
1327 
1328 //==============================================================================
1329 // Block processing
1330 //==============================================================================
1331 
1332 void File::free_block(Block* b)
1333 {
1334  // Method always called under lock.
1335  int i = b->m_offset / m_block_size;
1336  TRACEF(Dump, "free_block block " << b << " idx = " << i);
1337  size_t ret = m_block_map.erase(i);
1338  if (ret != 1)
1339  {
1340  // assert might be a better option than a warning
1341  TRACEF(Error, "free_block did not erase " << i << " from map");
1342  }
1343  else
1344  {
1345  cache()->ReleaseRAM(b->m_buff, b->m_req_size);
1346  delete b;
1347  }
1348 
1349  if (m_prefetch_state == kHold && (int) m_block_map.size() < m_prefetch_max_blocks_in_flight)
1350  {
1351  m_prefetch_state = kOn;
1352  cache()->RegisterPrefetchFile(this);
1353  }
1354 }
1355 
1356 //------------------------------------------------------------------------------
1357 
1358 bool File::select_current_io_or_disable_prefetching(bool skip_current)
1359 {
1360  // Method always called under lock. It also expects prefetch to be active.
1361 
1362  int io_size = (int) m_io_set.size();
1363  bool io_ok = false;
1364 
1365  if (io_size == 1)
1366  {
1367  io_ok = (*m_io_set.begin())->m_allow_prefetching;
1368  if (io_ok)
1369  {
1370  m_current_io = m_io_set.begin();
1371  }
1372  }
1373  else if (io_size > 1)
1374  {
1375  IoSet_i mi = m_current_io;
1376  if (skip_current && mi != m_io_set.end()) ++mi;
1377 
1378  for (int i = 0; i < io_size; ++i)
1379  {
1380  if (mi == m_io_set.end()) mi = m_io_set.begin();
1381 
1382  if ((*mi)->m_allow_prefetching)
1383  {
1384  m_current_io = mi;
1385  io_ok = true;
1386  break;
1387  }
1388  ++mi;
1389  }
1390  }
1391 
1392  if ( ! io_ok)
1393  {
1394  m_current_io = m_io_set.end();
1395  m_prefetch_state = kStopped;
1396  cache()->DeRegisterPrefetchFile(this);
1397  }
1398 
1399  return io_ok;
1400 }
1401 
1402 //------------------------------------------------------------------------------
1403 
1404 void File::ProcessDirectReadFinished(ReadRequest *rreq, int bytes_read, int error_cond)
1405 {
1406  // Called from DirectResponseHandler.
1407  // NOT under lock.
1408 
1409  if (error_cond)
1410  TRACEF(Error, "Read(), direct read finished with error " << -error_cond << " " << XrdSysE2T(-error_cond));
1411 
1412  m_state_cond.Lock();
1413 
1414  if (error_cond)
1415  rreq->update_error_cond(error_cond);
1416  else {
1417  rreq->m_stats.m_BytesBypassed += bytes_read;
1418  rreq->m_bytes_read += bytes_read;
1419  }
1420 
1421  rreq->m_direct_done = true;
1422 
1423  bool rreq_complete = rreq->is_complete();
1424 
1425  m_state_cond.UnLock();
1426 
1427  if (rreq_complete)
1428  FinalizeReadRequest(rreq);
1429 }
1430 
1431 void File::ProcessBlockError(Block *b, ReadRequest *rreq)
1432 {
1433  // Called from ProcessBlockResponse().
1434  // YES under lock -- we have to protect m_block_map for recovery through multiple IOs.
1435  // Does not manage m_read_req.
1436  // Will not complete the request.
1437 
1438  TRACEF(Debug, "ProcessBlockError() io " << b->m_io << ", block "<< b->m_offset/m_block_size <<
1439  " finished with error " << -b->get_error() << " " << XrdSysE2T(-b->get_error()));
1440 
1441  rreq->update_error_cond(b->get_error());
1442  --rreq->m_n_chunk_reqs;
1443 
1444  dec_ref_count(b);
1445 }
1446 
1447 void File::ProcessBlockSuccess(Block *b, ChunkRequest &creq)
1448 {
1449  // Called from ProcessBlockResponse().
1450  // NOT under lock as it does memcopy ofor exisf block data.
1451  // Acquires lock for block, m_read_req and rreq state update.
1452 
1453  ReadRequest *rreq = creq.m_read_req;
1454 
1455  TRACEF(Dump, "ProcessBlockSuccess() ub=" << (void*)creq.m_buf << " from finished block " << b->m_offset/m_block_size << " size " << creq.m_size);
1456  memcpy(creq.m_buf, b->m_buff + creq.m_off, creq.m_size);
1457 
1458  m_state_cond.Lock();
1459 
1460  rreq->m_bytes_read += creq.m_size;
1461 
1462  if (b->get_req_id() == (void*) rreq)
1463  rreq->m_stats.m_BytesMissed += creq.m_size;
1464  else
1465  rreq->m_stats.m_BytesHit += creq.m_size;
1466 
1467  --rreq->m_n_chunk_reqs;
1468 
1469  if (b->m_prefetch)
1470  inc_prefetch_hit_cnt(1);
1471 
1472  dec_ref_count(b);
1473 
1474  bool rreq_complete = rreq->is_complete();
1475 
1476  m_state_cond.UnLock();
1477 
1478  if (rreq_complete)
1479  FinalizeReadRequest(rreq);
1480 }
1481 
1482 void File::FinalizeReadRequest(ReadRequest *rreq)
1483 {
1484  // called from ProcessBlockResponse()
1485  // NOT under lock -- does callout
1486  {
1487  XrdSysCondVarHelper _lck(m_state_cond);
1488  m_delta_stats.AddReadStats(rreq->m_stats);
1489  check_delta_stats();
1490  }
1491 
1492  rreq->m_rh->Done(rreq->return_value());
1493  delete rreq;
1494 }
1495 
1496 void File::ProcessBlockResponse(Block *b, int res)
1497 {
1498  static const char* tpfx = "ProcessBlockResponse ";
1499 
1500  TRACEF(Dump, tpfx << "block=" << b << ", idx=" << b->m_offset/m_block_size << ", off=" << b->m_offset << ", res=" << res);
1501 
1502  if (res >= 0 && res != b->get_size())
1503  {
1504  // Incorrect number of bytes received, apparently size of the file on the remote
1505  // is different than what the cache expects it to be.
1506  TRACEF(Error, tpfx << "Wrong number of bytes received, assuming remote/local file size mismatch, unlinking local files and initiating shutdown of File object");
1507  Cache::GetInstance().UnlinkFile(m_filename, false);
1508  }
1509 
1510  m_state_cond.Lock();
1511 
1512  // Deregister block from IO's prefetch count, if needed.
1513  if (b->m_prefetch)
1514  {
1515  IO *io = b->get_io();
1516  IoSet_i mi = m_io_set.find(io);
1517  if (mi != m_io_set.end())
1518  {
1519  --io->m_active_prefetches;
1520 
1521  // If failed and IO is still prefetching -- disable prefetching on this IO.
1522  if (res < 0 && io->m_allow_prefetching)
1523  {
1524  TRACEF(Debug, tpfx << "after failed prefetch on io " << io << " disabling prefetching on this io.");
1525  io->m_allow_prefetching = false;
1526 
1527  // Check if any IO is still available for prfetching. If not, stop it.
1528  if (m_prefetch_state == kOn || m_prefetch_state == kHold)
1529  {
1530  if ( ! select_current_io_or_disable_prefetching(false) )
1531  {
1532  TRACEF(Debug, tpfx << "stopping prefetching after io " << b->get_io() << " marked as bad.");
1533  }
1534  }
1535  }
1536 
1537  // If failed with no subscribers -- delete the block and exit.
1538  if (b->m_refcnt == 0 && (res < 0 || m_in_shutdown))
1539  {
1540  free_block(b);
1541  m_state_cond.UnLock();
1542  return;
1543  }
1544  m_prefetch_bytes += b->get_size();
1545  }
1546  else
1547  {
1548  TRACEF(Error, tpfx << "io " << b->get_io() << " not found in IoSet.");
1549  }
1550  }
1551 
1552  if (res == b->get_size())
1553  {
1554  b->set_downloaded();
1555  TRACEF(Dump, tpfx << "inc_ref_count idx=" << b->m_offset/m_block_size);
1556  if ( ! m_in_shutdown)
1557  {
1558  // Increase ref-count for the writer.
1559  inc_ref_count(b);
1560  m_delta_stats.AddWriteStats(b->get_size(), b->get_n_cksum_errors());
1561  // No check for writes, report-and-merge forced during Sync().
1562  cache()->AddWriteTask(b, true);
1563  }
1564 
1565  // Swap chunk-reqs vector out of Block, it will be processed outside of lock.
1566  vChunkRequest_t creqs_to_notify;
1567  creqs_to_notify.swap( b->m_chunk_reqs );
1568 
1569  m_state_cond.UnLock();
1570 
1571  for (auto &creq : creqs_to_notify)
1572  {
1573  ProcessBlockSuccess(b, creq);
1574  }
1575  }
1576  else
1577  {
1578  if (res < 0) {
1579  bool new_error = b->get_io()->register_block_error(res);
1580  int tlvl = new_error ? TRACE_Error : TRACE_Debug;
1581  TRACEF_INT(tlvl, tpfx << "block " << b << ", idx=" << b->m_offset/m_block_size << ", off=" << b->m_offset
1582  << ", io=" << b->get_io() << ", error=" << res);
1583  } else {
1584  bool first_p = b->get_io()->register_incomplete_read();
1585  int tlvl = first_p ? TRACE_Error : TRACE_Debug;
1586  TRACEF_INT(tlvl, tpfx << "block " << b << ", idx=" << b->m_offset/m_block_size << ", off=" << b->m_offset
1587  << ", io=" << b->get_io() << " incomplete, got " << res << " expected " << b->get_size());
1588 #if defined(__APPLE__) || defined(__GNU__) || (defined(__FreeBSD_kernel__) && defined(__GLIBC__)) || defined(__FreeBSD__)
1589  res = -EIO;
1590 #else
1591  res = -EREMOTEIO;
1592 #endif
1593  }
1594  b->set_error(res);
1595 
1596  // Loop over Block's chunk-reqs vector, error out ones with the same IO.
1597  // Collect others with a different IO, the first of them will be used to reissue the request.
1598  // This is then done outside of lock.
1599  std::list<ReadRequest*> rreqs_to_complete;
1600  vChunkRequest_t creqs_to_keep;
1601 
1602  for(ChunkRequest &creq : b->m_chunk_reqs)
1603  {
1604  ReadRequest *rreq = creq.m_read_req;
1605 
1606  if (rreq->m_io == b->get_io())
1607  {
1608  ProcessBlockError(b, rreq);
1609  if (rreq->is_complete())
1610  {
1611  rreqs_to_complete.push_back(rreq);
1612  }
1613  }
1614  else
1615  {
1616  creqs_to_keep.push_back(creq);
1617  }
1618  }
1619 
1620  bool reissue = false;
1621  if ( ! creqs_to_keep.empty())
1622  {
1623  ReadRequest *rreq = creqs_to_keep.front().m_read_req;
1624 
1625  TRACEF(Debug, "ProcessBlockResponse() requested block " << (void*)b << " failed with another io " <<
1626  b->get_io() << " - reissuing request with my io " << rreq->m_io);
1627 
1628  b->reset_error_and_set_io(rreq->m_io, rreq);
1629  b->m_chunk_reqs.swap( creqs_to_keep );
1630  reissue = true;
1631  }
1632 
1633  m_state_cond.UnLock();
1634 
1635  for (auto rreq : rreqs_to_complete)
1636  FinalizeReadRequest(rreq);
1637 
1638  if (reissue)
1639  ProcessBlockRequest(b);
1640  }
1641 }
1642 
1643 //------------------------------------------------------------------------------
1644 
1645 const char* File::lPath() const
1646 {
1647  return m_filename.c_str();
1648 }
1649 
1650 //------------------------------------------------------------------------------
1651 
1652 int File::offsetIdx(int iIdx) const
1653 {
1654  return iIdx - m_offset/m_block_size;
1655 }
1656 
1657 
1658 //------------------------------------------------------------------------------
1659 
1661 {
1662  // Check that block is not on disk and not in RAM.
1663  // TODO: Could prefetch several blocks at once!
1664  // blks_max could be an argument
1665 
1666  BlockList_t blks;
1667 
1668  TRACEF(DumpXL, "Prefetch() entering.");
1669  {
1670  XrdSysCondVarHelper _lck(m_state_cond);
1671 
1672  if (m_prefetch_state != kOn)
1673  {
1674  return;
1675  }
1676 
1677  if ( ! select_current_io_or_disable_prefetching(true) )
1678  {
1679  TRACEF(Error, "Prefetch no available IO object found, prefetching stopped. This should not happen, i.e., prefetching should be stopped before.");
1680  return;
1681  }
1682 
1683  // Select block(s) to fetch.
1684  for (int f = 0; f < m_num_blocks; ++f)
1685  {
1686  if ( ! m_cfi.TestBitWritten(f))
1687  {
1688  int f_act = f + m_offset / m_block_size;
1689 
1690  BlockMap_i bi = m_block_map.find(f_act);
1691  if (bi == m_block_map.end())
1692  {
1693  Block *b = PrepareBlockRequest(f_act, *m_current_io, nullptr, true);
1694  if (b)
1695  {
1696  TRACEF(Dump, "Prefetch take block " << f_act);
1697  blks.push_back(b);
1698  // Note: block ref_cnt not increased, it will be when placed into write queue.
1699 
1700  inc_prefetch_read_cnt(1);
1701  }
1702  else
1703  {
1704  // This shouldn't happen as prefetching stops when RAM is 70% full.
1705  TRACEF(Warning, "Prefetch allocation failed for block " << f_act);
1706  }
1707  break;
1708  }
1709  }
1710  }
1711 
1712  if (blks.empty())
1713  {
1714  TRACEF(Debug, "Prefetch file is complete, stopping prefetch.");
1715  m_prefetch_state = kComplete;
1716  cache()->DeRegisterPrefetchFile(this);
1717  }
1718  else
1719  {
1720  (*m_current_io)->m_active_prefetches += (int) blks.size();
1721  }
1722  }
1723 
1724  if ( ! blks.empty())
1725  {
1726  ProcessBlockRequests(blks);
1727  }
1728 }
1729 
1730 
1731 //------------------------------------------------------------------------------
1732 
1734 {
1735  return m_prefetch_score;
1736 }
1737 
1739 {
1740  return Cache::TheOne().GetLog();
1741 }
1742 
1744 {
1745  return Cache::TheOne().GetTrace();
1746 }
1747 
1748 void File::insert_remote_location(const std::string &loc)
1749 {
1750  if ( ! loc.empty())
1751  {
1752  size_t p = loc.find_first_of('@');
1753  m_remote_locations.insert(&loc[p != std::string::npos ? p + 1 : 0]);
1754  }
1755 }
1756 
1757 std::string File::GetRemoteLocations() const
1758 {
1759  std::string s;
1760  if ( ! m_remote_locations.empty())
1761  {
1762  size_t sl = 0;
1763  int nl = 0;
1764  for (std::set<std::string>::iterator i = m_remote_locations.begin(); i != m_remote_locations.end(); ++i, ++nl)
1765  {
1766  sl += i->size();
1767  }
1768  s.reserve(2 + sl + 2*nl + nl - 1 + 1);
1769  s = '[';
1770  int j = 1;
1771  for (std::set<std::string>::iterator i = m_remote_locations.begin(); i != m_remote_locations.end(); ++i, ++j)
1772  {
1773  s += '"'; s += *i; s += '"';
1774  if (j < nl) s += ',';
1775  }
1776  s += ']';
1777  }
1778  else
1779  {
1780  s = "[]";
1781  }
1782  return s;
1783 }
1784 
1785 //==============================================================================
1786 //======================= RESPONSE HANDLERS ==============================
1787 //==============================================================================
1788 
1790 {
1791  m_block->m_file->ProcessBlockResponse(m_block, res);
1792  delete this;
1793 }
1794 
1795 //------------------------------------------------------------------------------
1796 
1798 {
1799  m_mutex.Lock();
1800 
1801  int n_left = --m_to_wait;
1802 
1803  if (res < 0) {
1804  if (m_errno == 0) m_errno = res; // store first reported error
1805  } else {
1806  m_bytes_read += res;
1807  }
1808 
1809  m_mutex.UnLock();
1810 
1811  if (n_left == 0)
1812  {
1813  m_file->ProcessDirectReadFinished(m_read_req, m_bytes_read, m_errno);
1814  delete this;
1815  }
1816 }
#define TRACE_Debug
Definition: XrdCmsTrace.hh:37
#define XrdOssOK
Definition: XrdOss.hh:50
#define XRDOSS_mkpath
Definition: XrdOss.hh:466
#define TRACE_Error
Definition: XrdPfcTrace.hh:7
#define TRACE_Dump
Definition: XrdPfcTrace.hh:11
#define TRACEF(act, x)
Definition: XrdPfcTrace.hh:67
#define ERRNO_AND_ERRSTR(err_code)
Definition: XrdPfcTrace.hh:46
#define TRACEF_INT(act, x)
Definition: XrdPfcTrace.hh:71
#define stat(a, b)
Definition: XrdPosix.hh:101
#define XRD_TRACE
Definition: XrdScheduler.cc:48
bool Debug
XrdOucString File
const char * XrdSysE2T(int errcode)
Definition: XrdSysE2T.cc:104
@ Error
#define TRACE(act, x)
Definition: XrdTrace.hh:63
URL representation.
Definition: XrdClURL.hh:31
virtual int Fsync()
Definition: XrdOss.hh:144
virtual int Ftruncate(unsigned long long flen)
Definition: XrdOss.hh:164
virtual int Fstat(struct stat *buf)
Definition: XrdOss.hh:136
virtual int Close(long long *retsz=0)=0
virtual int getFD()
Definition: XrdOss.hh:426
virtual int Open(const char *path, int Oflag, mode_t Mode, XrdOucEnv &env)
Definition: XrdOss.hh:200
virtual ssize_t Read(off_t offset, size_t size)
Definition: XrdOss.hh:281
virtual ssize_t pgWrite(void *buffer, off_t offset, size_t wrlen, uint32_t *csvec, uint64_t opts)
Definition: XrdOss.cc:198
virtual ssize_t ReadV(XrdOucIOVec *readV, int rdvcnt)
Definition: XrdOss.cc:236
virtual ssize_t Write(const void *buffer, off_t offset, size_t size)
Definition: XrdOss.hh:345
virtual int Create(const char *tid, const char *path, mode_t mode, XrdOucEnv &env, int opts=0)=0
virtual XrdOssDF * newFile(const char *tident)=0
virtual int Stat(const char *path, struct stat *buff, int opts=0, XrdOucEnv *envP=0)=0
virtual int Unlink(const char *path, int Opts=0, XrdOucEnv *envP=0)=0
virtual void Done(int result)=0
virtual const char * Path()=0
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
virtual int ReadV(const XrdOucIOVec *readV, int rnum)
Definition: XrdOucCache.cc:86
void Put(const char *varname, const char *value)
Definition: XrdOucEnv.hh:85
void Done(int result) override
Definition: XrdPfcFile.cc:1789
int * ptr_n_cksum_errors()
Definition: XrdPfcFile.hh:170
int get_size() const
Definition: XrdPfcFile.hh:143
int get_error() const
Definition: XrdPfcFile.hh:157
int get_n_cksum_errors()
Definition: XrdPfcFile.hh:169
void * get_req_id() const
Definition: XrdPfcFile.hh:149
long long get_offset() const
Definition: XrdPfcFile.hh:145
vChunkRequest_t m_chunk_reqs
Definition: XrdPfcFile.hh:132
void set_error(int err)
Definition: XrdPfcFile.hh:156
vCkSum_t & ref_cksum_vec()
Definition: XrdPfcFile.hh:168
char * get_buff() const
Definition: XrdPfcFile.hh:142
IO * get_io() const
Definition: XrdPfcFile.hh:148
void set_downloaded()
Definition: XrdPfcFile.hh:155
bool req_cksum_net() const
Definition: XrdPfcFile.hh:166
bool has_cksums() const
Definition: XrdPfcFile.hh:167
long long m_offset
Definition: XrdPfcFile.hh:121
void reset_error_and_set_io(IO *io, void *rid)
Definition: XrdPfcFile.hh:159
int get_req_size() const
Definition: XrdPfcFile.hh:144
Attaches/creates and detaches/deletes cache-io objects for disk based cache.
Definition: XrdPfc.hh:163
XrdOss * GetOss() const
Definition: XrdPfc.hh:280
bool blocksize_str2value(const char *from, const char *str, long long &val, long long min, long long max) const
const Configuration & RefConfiguration() const
Reference XrdPfc configuration.
Definition: XrdPfc.hh:215
static ResourceMonitor & ResMon()
Definition: XrdPfc.cc:135
static Cache & GetInstance()
Singleton access.
Definition: XrdPfc.cc:132
XrdSysTrace * GetTrace() const
Definition: XrdPfc.hh:295
int UnlinkFile(const std::string &f_name, bool fail_if_open)
Remove cinfo and data files from cache.
Definition: XrdPfc.cc:1191
static const Cache & TheOne()
Definition: XrdPfc.cc:133
XrdSysError * GetLog() const
Definition: XrdPfc.hh:294
void Done(int result) override
Definition: XrdPfcFile.cc:1797
bool FinalizeSyncBeforeExit()
Returns true if any of blocks need sync. Called from Cache::dec_ref_cnt on zero ref cnt.
Definition: XrdPfcFile.cc:325
const char * lPath() const
Log path.
Definition: XrdPfcFile.cc:1645
int ReadV(IO *io, const XrdOucIOVec *readV, int readVnum, ReadReqRH *rh)
Vector read.
Definition: XrdPfcFile.cc:890
void WriteBlockToDisk(Block *b)
Definition: XrdPfcFile.cc:1173
float GetPrefetchScore() const
Definition: XrdPfcFile.cc:1733
friend class BlockResponseHandler
Definition: XrdPfcFile.hh:212
void Prefetch()
Definition: XrdPfcFile.cc:1660
std::string GetRemoteLocations() const
Definition: XrdPfcFile.cc:1757
int Fstat(struct stat &sbuff)
Definition: XrdPfcFile.cc:668
void AddIO(IO *io)
Definition: XrdPfcFile.cc:349
static File * FileOpen(const std::string &path, long long offset, long long fileSize, XrdOucCacheIO *inputIO)
Static constructor that also does Open. Returns null ptr if Open fails.
Definition: XrdPfcFile.cc:141
void RequestSyncOfDetachStats()
Flags that detach stats should be written out in final sync. Called from CacheIO upon Detach.
Definition: XrdPfcFile.cc:319
void BlocksRemovedFromWriteQ(std::list< Block * > &)
Handle removal of a set of blocks from Cache's write queue.
Definition: XrdPfcFile.cc:219
friend class DirectResponseHandler
Definition: XrdPfcFile.hh:213
void Sync()
Sync file cache inf o and output data with disk.
Definition: XrdPfcFile.cc:1259
XrdSysTrace * GetTrace() const
Definition: XrdPfcFile.cc:1743
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 initiate_emergency_shutdown()
Definition: XrdPfcFile.cc:154
void RemoveIO(IO *io)
Definition: XrdPfcFile.cc:386
void BlockRemovedFromWriteQ(Block *)
Handle removal of a block from Cache's write queue.
Definition: XrdPfcFile.cc:211
XrdSysError * GetLog() const
Definition: XrdPfcFile.cc:1738
bool ioActive(IO *io)
Initiate close. Return true if still IO active. Used in XrdPosixXrootd::Close()
Definition: XrdPfcFile.cc:242
Base cache-io class that implements some XrdOucCacheIO abstract methods.
Definition: XrdPfcIO.hh:16
bool register_incomplete_read()
Definition: XrdPfcIO.hh:90
XrdOucCacheIO * GetInput()
Definition: XrdPfcIO.cc:31
bool register_block_error(int res)
Definition: XrdPfcIO.hh:93
RAtomic_int m_active_read_reqs
number of active read requests
Definition: XrdPfcIO.hh:70
const char * GetLocation()
Definition: XrdPfcIO.hh:44
Status of cached file. Can be read from and written into a binary file.
Definition: XrdPfcInfo.hh:41
void SetBitPrefetch(int i)
Mark block as obtained through prefetch.
Definition: XrdPfcInfo.hh:365
static const char * s_infoExtension
Definition: XrdPfcInfo.hh:309
void SetBitSynced(int i)
Mark block as synced to disk.
Definition: XrdPfcInfo.hh:387
time_t GetNoCkSumTimeForUVKeep() const
Definition: XrdPfcInfo.hh:301
CkSumCheck_e GetCkSumState() const
Definition: XrdPfcInfo.hh:286
void WriteIOStatAttach()
Write open time in the last entry of access statistics.
Definition: XrdPfcInfo.cc:420
void ResetCkSumNet()
Definition: XrdPfcInfo.cc:213
bool Write(XrdOssDF *fp, const char *dname, const char *fname=0)
Definition: XrdPfcInfo.cc:266
void DowngradeCkSumState(CkSumCheck_e css_ref)
Definition: XrdPfcInfo.hh:295
bool IsCkSumNet() const
Definition: XrdPfcInfo.hh:290
void ResetAllAccessStats()
Reset IO Stats.
Definition: XrdPfcInfo.cc:359
bool TestBitPrefetch(int i) const
Test if block at the given index has been prefetched.
Definition: XrdPfcInfo.hh:376
bool IsComplete() const
Get complete status.
Definition: XrdPfcInfo.hh:447
bool IsCkSumCache() const
Definition: XrdPfcInfo.hh:289
void SetBitWritten(int i)
Mark block as written to disk.
Definition: XrdPfcInfo.hh:352
long long GetBufferSize() const
Get prefetch buffer size.
Definition: XrdPfcInfo.hh:469
void WriteIOStat(Stats &s)
Write bytes missed, hits, and disk.
Definition: XrdPfcInfo.cc:429
long long GetExpectedDataFileSize() const
Get expected data file size.
Definition: XrdPfcInfo.hh:420
bool TestBitWritten(int i) const
Test if block at the given index is written to disk.
Definition: XrdPfcInfo.hh:343
bool Read(XrdOssDF *fp, const char *dname, const char *fname=0)
Read content of cinfo file into this object.
Definition: XrdPfcInfo.cc:294
void SetCkSumState(CkSumCheck_e css)
Definition: XrdPfcInfo.hh:294
void ResetNoCkSumTime()
Definition: XrdPfcInfo.hh:302
void SetBufferSizeFileSizeAndCreationTime(long long bs, long long fs)
Definition: XrdPfcInfo.cc:161
void WriteIOStatDetach(Stats &s)
Write close time together with bytes missed, hits, and disk.
Definition: XrdPfcInfo.cc:438
int GetNBlocks() const
Get number of blocks represented in download-state bit-vector.
Definition: XrdPfcInfo.hh:437
void CrossCheckIfScanIsInProgress(const std::string &lfn, XrdSysCondVar &cond)
int register_file_open(const std::string &filename, time_t open_timestamp, bool existing_file)
void register_file_purge(DirState *target, long long size_in_st_blocks)
void register_file_update_stats(int token_id, const Stats &stats)
void register_file_close(int token_id, time_t close_timestamp, const Stats &full_stats)
Statistics of cache utilisation by a File object.
Definition: XrdPfcStats.hh:35
void IoAttach()
Definition: XrdPfcStats.hh:85
void AddReadStats(const Stats &s)
Definition: XrdPfcStats.hh:67
long long m_StBlocksAdded
number of 512-byte blocks the file has grown by
Definition: XrdPfcStats.hh:43
long long m_BytesBypassed
number of bytes served directly through XrdCl
Definition: XrdPfcStats.hh:41
void AddUp(const Stats &s)
Definition: XrdPfcStats.hh:119
void AddWriteStats(long long bytes_written, int n_cks_errs)
Definition: XrdPfcStats.hh:79
long long BytesReadAndWritten() const
Definition: XrdPfcStats.hh:102
void AddBytesHit(long long bh)
Definition: XrdPfcStats.hh:74
long long m_BytesHit
number of bytes served from disk
Definition: XrdPfcStats.hh:39
long long m_BytesWritten
number of bytes written to disk
Definition: XrdPfcStats.hh:42
void IoDetach(int duration)
Definition: XrdPfcStats.hh:90
@ Warning
OpenImpl< false > Open(Ctx< File > file, Arg< std::string > url, Arg< OpenFlags::Flags > flags, Arg< Access::Mode > mode=Access::None, uint16_t timeout=0)
Factory for creating ReadImpl objects.
Definition: XrdPfc.hh:41
std::vector< ChunkRequest > vChunkRequest_t
Definition: XrdPfcFile.hh:108
constexpr int kReadPending
Definition: XrdPfcFile.hh:54
std::list< Block * > BlockList_t
Definition: XrdPfcFile.hh:173
std::list< Block * >::iterator BlockList_i
Definition: XrdPfcFile.hh:174
static const int maxRVdsz
Definition: XProtocol.hh:688
static const int maxRvecsz
Definition: XProtocol.hh:686
@ hex1
Definition: XrdSysTrace.hh:42
long long offset
Definition: XrdOucIOVec.hh:42
char * data
Definition: XrdOucIOVec.hh:45
ReadRequest * m_read_req
Definition: XrdPfcFile.hh:98
Contains parameters configurable from the xrootd config file.
Definition: XrdPfc.hh:64
long long m_flushCnt
nuber of unsynced blcoks on disk before flush is called
Definition: XrdPfc.hh:122
long long m_cgi_max_bufferSize
max buffer size allowed in pfc.blocksize
Definition: XrdPfc.hh:115
int m_cgi_min_prefetch_max_blocks
min prefetch block count allowed in pfc.prefetch
Definition: XrdPfc.hh:116
bool does_cschk_have_missing_bits(CkSumCheck_e cks_on_file) const
Definition: XrdPfc.hh:80
bool m_cgi_prefetch_allowed
allow cgi setting of prefetch
Definition: XrdPfc.hh:119
CkSumCheck_e get_cs_Chk() const
Definition: XrdPfc.hh:73
int m_prefetch_max_blocks
default maximum number of blocks to prefetch per file
Definition: XrdPfc.hh:112
bool should_uvkeep_purge(time_t delta) const
Definition: XrdPfc.hh:82
std::string m_data_space
oss space for data files
Definition: XrdPfc.hh:88
long long m_bufferSize
cache block size, default 128 kB
Definition: XrdPfc.hh:107
long long m_cgi_min_bufferSize
min buffer size allowed in pfc.blocksize
Definition: XrdPfc.hh:114
std::string m_meta_space
oss space for metadata files (cinfo)
Definition: XrdPfc.hh:89
int m_cgi_max_prefetch_max_blocks
max prefetch block count allowed in pfc.prefetch
Definition: XrdPfc.hh:117
std::string m_username
username passed to oss plugin
Definition: XrdPfc.hh:87
bool m_cgi_blocksize_allowed
allow cgi setting of blocksize
Definition: XrdPfc.hh:118
unsigned short m_seq_id
Definition: XrdPfcFile.hh:60
void update_error_cond(int ec)
Definition: XrdPfcFile.hh:88
ReadReqRH * m_rh
Definition: XrdPfcFile.hh:73
bool is_complete() const
Definition: XrdPfcFile.hh:90
int return_value() const
Definition: XrdPfcFile.hh:91
long long m_bytes_read
Definition: XrdPfcFile.hh:75