30#include "XrdOuc/XrdOucJson.hh"
39#include <unordered_map>
48const int BLOCK_WRITE_MAX_ATTEMPTS = 4;
54const char *File::m_traceID =
"File";
58File::File(
const std::string& path,
long long iOffset,
long long iFileSize) :
62 m_cfi(
Cache::TheOne().GetTrace(),
Cache::TheOne().is_prefetch_enabled()),
65 m_file_size(iFileSize),
66 m_current_io(m_io_set.end()),
70 m_detach_time_logged(false),
76 m_prefetch_state(kOff),
78 m_prefetch_read_cnt(0),
79 m_prefetch_hit_cnt(0),
106 m_info_file->Close();
108 m_info_file =
nullptr;
114 m_data_file->Close();
116 m_data_file =
nullptr;
119 if (m_resmon_token >= 0)
124 if (m_stats.m_BytesWritten > 0 && ! m_in_shutdown) {
127 if (sr == 0 && s.st_blocks != m_st_blocks) {
130 m_st_blocks = s.st_blocks;
138 TRACEF(
Debug,
"Close() finished, prefetch score = " << m_prefetch_score);
145 File *file =
new File(path, offset, fileSize);
146 if ( ! file->Open(inputIO))
171 m_in_shutdown =
true;
173 if (m_prefetch_state != kStopped && m_prefetch_state != kComplete)
175 m_prefetch_state = kStopped;
176 cache()->DeRegisterPrefetchFile(
this);
179 report_and_merge_delta_stats();
186void File::check_delta_stats()
191 report_and_merge_delta_stats();
194void File::report_and_merge_delta_stats()
198 m_data_file->
Fstat(&s);
201 long long max_st_blocks_to_report = (m_file_size & 0xfff) ? ((m_file_size >> 12) + 1) << 3
203 long long st_blocks_to_report = std::min((
long long) s.st_blocks, max_st_blocks_to_report);
205 m_st_blocks = st_blocks_to_report;
207 m_stats.
AddUp(m_delta_stats);
208 m_delta_stats.
Reset();
215 TRACEF(Dump,
"BlockRemovedFromWriteQ() block = " << (
void*) b <<
" idx= " << b->
m_offset/m_block_size);
223 TRACEF(Dump,
"BlocksRemovedFromWriteQ() n_blocks = " << blocks.size());
227 for (std::list<Block*>::iterator i = blocks.begin(); i != blocks.end(); ++i)
239 insert_remote_location(loc);
255 IoSet_i mi = m_io_set.find(io);
257 if (mi != m_io_set.end())
262 ", active_reads " << n_active_reads <<
263 ", active_prefetches " << io->m_active_prefetches <<
264 ", allow_prefetching " << io->m_allow_prefetching <<
265 ", ios_in_detach " << m_ios_in_detach);
267 "\tio_map.size() " << m_io_set.size() <<
268 ", block_map.size() " << m_block_map.size() <<
", file");
270 insert_remote_location(loc);
272 io->m_allow_prefetching =
false;
273 io->m_in_detach =
true;
276 if (m_prefetch_state == kOn || m_prefetch_state == kHold)
278 if ( ! select_current_io_or_disable_prefetching(
false) )
280 TRACEF(
Debug,
"ioActive stopping prefetching after io " << io <<
" retreat.");
287 bool io_active_result;
289 if (n_active_reads > 0)
291 io_active_result =
true;
293 else if (m_io_set.size() - m_ios_in_detach == 1)
295 io_active_result = ! m_block_map.empty();
299 io_active_result = io->m_active_prefetches > 0;
302 if ( ! io_active_result)
307 TRACEF(
Info,
"ioActive for io " << io <<
" returning " << io_active_result <<
", file");
309 return io_active_result;
313 TRACEF(
Error,
"ioActive io " << io <<
" not found in IoSet. This should not happen.");
324 m_detach_time_logged =
false;
333 if ( ! m_in_shutdown)
335 if ( ! m_writes_during_sync.empty() || m_non_flushed_cnt > 0 || ! m_detach_time_logged)
337 report_and_merge_delta_stats();
338 m_cfi.WriteIOStatDetach(m_stats);
339 m_detach_time_logged =
true;
341 TRACEF(
Debug,
"FinalizeSyncBeforeExit requesting sync to write detach stats");
345 TRACEF(
Debug,
"FinalizeSyncBeforeExit sync not required");
357 time_t now = time(0);
362 IoSet_i mi = m_io_set.find(io);
364 if (mi == m_io_set.end())
367 io->m_attach_time = now;
368 m_delta_stats.IoAttach();
370 insert_remote_location(loc);
372 if (m_prefetch_state == kStopped)
374 m_prefetch_state = kOn;
375 cache()->RegisterPrefetchFile(
this);
380 TRACEF(
Error,
"AddIO() io = " << (
void*)io <<
" already registered.");
383 m_state_cond.UnLock();
394 time_t now = time(0);
398 IoSet_i mi = m_io_set.find(io);
400 if (mi != m_io_set.end())
402 if (mi == m_current_io)
407 m_delta_stats.IoDetach(now - io->m_attach_time);
411 if (m_io_set.empty() && m_prefetch_state != kStopped && m_prefetch_state != kComplete)
413 TRACEF(
Error,
"RemoveIO() io = " << (
void*)io <<
" Prefetching is not stopped/complete -- it should be by now.");
414 m_prefetch_state = kStopped;
415 cache()->DeRegisterPrefetchFile(
this);
420 TRACEF(
Error,
"RemoveIO() io = " << (
void*)io <<
" is NOT registered.");
423 m_state_cond.UnLock();
432 static const char *tpfx =
"Open() ";
434 TRACEF(Dump, tpfx <<
"entered");
445 struct stat data_stat, info_stat;
449 bool data_existed = (myOss.
Stat(m_filename.c_str(), &data_stat) ==
XrdOssOK);
450 bool info_existed = (myOss.
Stat(ifn.c_str(), &info_stat) ==
XrdOssOK);
453 char size_str[32]; sprintf(size_str,
"%lld", m_file_size);
454 myEnv.
Put(
"oss.asize", size_str);
466 m_data_file = myOss.
newFile(myUser);
467 if ((res = m_data_file->
Open(m_filename.c_str(), O_RDWR, 0600, myEnv)) !=
XrdOssOK)
471 delete m_data_file; m_data_file = 0;
472 if ( ! data_existed) myOss.
Unlink(m_filename.c_str());
476 myEnv.
Put(
"oss.asize",
"64k");
482 m_data_file->Close();
delete m_data_file; m_data_file = 0;
483 if ( ! data_existed) myOss.
Unlink(m_filename.c_str());
487 m_info_file = myOss.
newFile(myUser);
488 if ((res = m_info_file->Open(ifn.c_str(), O_RDWR, 0600, myEnv)) !=
XrdOssOK)
492 delete m_info_file; m_info_file = 0;
493 m_data_file->Close();
delete m_data_file; m_data_file = 0;
496 if ( ! info_existed) myOss.
Unlink(ifn.c_str());
497 if ( ! data_existed) myOss.
Unlink(m_filename.c_str());
501 bool initialize_info_file =
true;
503 if (info_existed && m_cfi.Read(m_info_file, ifn.c_str()))
505 TRACEF(
Debug, tpfx <<
"Reading existing info file. (data_existed=" << data_existed <<
506 ", data_size_stat=" << (data_existed ? data_stat.st_size : -1ll) <<
507 ", data_size_from_last_block=" << m_cfi.GetExpectedDataFileSize() <<
508 ", block_size=" << (m_cfi.GetBufferSize() >> 10) <<
"k)");
511 if (data_existed && data_stat.st_size >= m_cfi.GetExpectedDataFileSize())
513 initialize_info_file =
false;
515 TRACEF(Warning, tpfx <<
"Basic sanity checks on data file failed, resetting info file, truncating data file.");
516 m_cfi.ResetAllAccessStats();
517 m_data_file->Ftruncate(0);
523 else if (info_existed)
527 TRACEF(Warning, tpfx <<
"Reading existing info file failed, resetting info file, truncating data file.");
528 m_cfi.ResetAllAccessStats();
529 m_data_file->Ftruncate(0);
534 if ( ! initialize_info_file && m_cfi.GetCkSumState() != conf.
get_cs_Chk())
539 TRACEF(Info, tpfx <<
"Cksum state of file insufficient, uvkeep test failed, resetting info file, truncating data file.");
540 initialize_info_file =
true;
541 m_cfi.ResetAllAccessStats();
542 m_data_file->Ftruncate(0);
556 parse_pfc_url_args(inputIO, pfc_blocksize, pfc_prefetch);
559 if (initialize_info_file)
561 m_cfi.SetBufferSizeFileSizeAndCreationTime(pfc_blocksize, m_file_size);
563 m_cfi.ResetNoCkSumTime();
564 m_cfi.Write(m_info_file, ifn.c_str());
565 m_info_file->Fsync();
566 cache()->WriteFileSizeXAttr(m_info_file->getFD(), m_file_size);
568 if (data_existed && ! info_existed) {
569 m_data_file->Ftruncate(0);
573 if (cache()->RefConfiguration().m_httpcc)
575 std::string responseFctl;
579 std::string cc_str = responseFctl;
580 nlohmann::json cc_json = nlohmann::json::parse(cc_str);
581 if (cc_json.contains(
"max-age"))
583 time_t ma = cc_json[
"max-age"];
585 cc_json[
"expire"] = ma;
586 cc_str = cc_json.dump();
588 TRACE(
Error,
"GetFile() XrdCl::File::Fcntl value " << cc_str);
589 cache()->WriteCacheControlXAttr(m_info_file->getFD(),
nullptr, cc_str);
593 TRACE(
Error,
"GetFile() XrdCl::File::Fcntl query XrdCl::QueryCode::FInfo failed " << inputIO->
Path());
597 TRACEF(
Debug, tpfx <<
"Creating new file info, data size = " << m_file_size <<
598 " num blocks = " << m_cfi.GetNBlocks() <<
599 " block size = " << pfc_blocksize);
603 if (futimens(m_info_file->getFD(), NULL)) {
607 TRACEF(Info, tpfx <<
"URL CGI pfc.blocksize ignored for an already existing file");
611 m_cfi.WriteIOStatAttach();
615 if (m_resmon_token < 0)
617 TRACEF(
Error, tpfx <<
"no resource-monitor token available, not caching it; "
618 "this indicates a token leak in XrdPfc, please report it.");
619 m_info_file->Close();
delete m_info_file; m_info_file =
nullptr;
620 m_data_file->Close();
delete m_data_file; m_data_file =
nullptr;
622 if ( ! info_existed) myOss.
Unlink(ifn.c_str());
623 if ( ! data_existed) myOss.
Unlink(m_filename.c_str());
629 m_block_size = m_cfi.GetBufferSize();
630 m_num_blocks = m_cfi.GetNBlocks();
631 m_prefetch_state = (m_cfi.IsComplete()) ? kComplete : kStopped;
632 m_prefetch_max_blocks_in_flight = pfc_prefetch;
634 TRACEF(
Debug, tpfx <<
"pfc.prefetch set to " << pfc_prefetch <<
" via CGI parameter");
636 m_data_file->Fstat(&data_stat);
637 m_st_blocks = data_stat.st_blocks;
639 constexpr long long MB = 1024 * 1024;
640 m_resmon_report_threshold = std::min(std::max(10 * MB, m_file_size / 20), 500 * MB);
647void File::parse_pfc_url_args(XrdOucCacheIO* inputIO,
long long &pfc_blocksize,
int &pfc_prefetch)
const
651 XrdCl::URL url(inputIO->
Path());
652 auto const & urlp = url.GetParams();
654 auto extract = [&](
const std::string &key, std::string &value) ->
bool {
655 auto it = urlp.find(key);
656 if (it != urlp.end()) {
668 const char *tpfx =
"File::Open::urlcgi pfc.blocksize ";
670 if (
Cache::TheOne().blocksize_str2value(tpfx, val.c_str(), bsize,
673 pfc_blocksize = bsize;
675 TRACEF(
Error, tpfx <<
"Error processing the parameter.");
680 const char *tpfx =
"File::Open::urlcgi pfc.prefetch ";
682 if (
Cache::TheOne().prefetch_str2value(tpfx, val.c_str(), pref,
687 TRACEF(
Error, tpfx <<
"Error processing the parameter.");
705 if ((res = m_data_file->Fstat(&sbuff)))
return res;
707 sbuff.st_size = m_file_size;
709 bool is_cached = cache()->DecideIfConsideredCached(m_file_size, sbuff.st_blocks * 512ll);
720bool File::overlap(
int blk,
729 const long long beg = blk * blk_size;
730 const long long end = beg + blk_size;
731 const long long req_end = req_off + req_size;
733 if (req_off < end && req_end > beg)
735 const long long ovlp_beg = std::max(beg, req_off);
736 const long long ovlp_end = std::min(end, req_end);
738 off = ovlp_beg - req_off;
739 blk_off = ovlp_beg - beg;
740 size = (int) (ovlp_end - ovlp_beg);
742 assert(size <= blk_size);
753Block* File::PrepareBlockRequest(
int i,
IO *io,
void *req_id,
bool prefetch)
761 const long long off = i * m_block_size;
762 const int last_block = m_num_blocks - 1;
763 const bool cs_net = cache()->RefConfiguration().is_cschk_net();
765 int blk_size, req_size;
766 if (i == last_block) {
767 blk_size = req_size = m_file_size - off;
768 if (cs_net && req_size & 0xFFF) req_size = (req_size & ~0xFFF) + 0x1000;
770 blk_size = req_size = m_block_size;
774 char *buf = cache()->RequestRAM(req_size);
778 b =
new (std::nothrow)
Block(
this, io, req_id, buf, off, blk_size, req_size, prefetch, cs_net);
786 if (m_prefetch_state == kOn && (
int) m_block_map.size() >= m_prefetch_max_blocks_in_flight)
788 m_prefetch_state = kHold;
789 cache()->DeRegisterPrefetchFile(
this);
794 TRACEF(Dump,
"PrepareBlockRequest() " << i <<
" prefetch " << prefetch <<
", allocation failed.");
801void File::ProcessBlockRequest(
Block *b)
809 snprintf(buf, 256,
"idx=%lld, block=%p, prefetch=%d, off=%lld, req_size=%d, buff=%p, resp_handler=%p ",
810 b->
get_offset()/m_block_size, (
void*)b, b->m_prefetch, b->get_offset(), b->get_req_size(), (
void*)b->get_buff(), (
void*)brh);
811 TRACEF(Dump,
"ProcessBlockRequest() " << buf);
827 for (
BlockList_i bi = blks.begin(); bi != blks.end(); ++bi)
829 ProcessBlockRequest(*bi);
835void File::RequestBlocksDirect(
IO *io,
ReadRequest *read_req, std::vector<XrdOucIOVec>& ioVec,
int expected_size)
837 int n_chunks = ioVec.size();
838 int n_vec_reads = (n_chunks - 1) / XrdProto::maxRvecsz + 1;
840 TRACEF(DumpXL,
"RequestBlocksDirect() issuing ReadV for n_chunks = " << n_chunks <<
841 ", total_size = " << expected_size <<
", n_vec_reads = " << n_vec_reads);
846 while (n_chunks > XrdProto::maxRvecsz) {
847 io->
GetInput()->
ReadV( *handler, ioVec.data() + pos, XrdProto::maxRvecsz);
851 io->
GetInput()->
ReadV( *handler, ioVec.data() + pos, n_chunks);
856int File::ReadBlocksFromDisk(std::vector<XrdOucIOVec>& ioVec,
int expected_size)
858 TRACEF(DumpXL,
"ReadBlocksFromDisk() issuing ReadV for n_chunks = " << (
int) ioVec.size() <<
", total_size = " << expected_size);
860 long long rs = m_data_file->ReadV(ioVec.data(), (
int) ioVec.size());
864 TRACEF(
Error,
"ReadBlocksFromDisk neg retval = " << rs);
868 if (rs != expected_size)
870 TRACEF(
Error,
"ReadBlocksFromDisk incomplete size = " << rs);
889 if (m_in_shutdown || io->m_in_detach)
891 m_state_cond.UnLock();
892 return m_in_shutdown ? -ENOENT : -EBADF;
897 if (m_cfi.IsComplete())
899 m_state_cond.UnLock();
900 int ret = m_data_file->Read(iUserBuff, iUserOff, iUserSize);
903 m_delta_stats.AddBytesHit(ret);
909 XrdOucIOVec readV( { iUserOff, iUserSize, 0, iUserBuff } );
911 return ReadOpusCoalescere(io, &readV, 1, rh,
"Read() ");
918 TRACEF(Dump,
"ReadV() for " << readVnum <<
" chunks.");
922 if (m_in_shutdown || io->m_in_detach)
924 m_state_cond.UnLock();
925 return m_in_shutdown ? -ENOENT : -EBADF;
930 if (m_cfi.IsComplete())
932 m_state_cond.UnLock();
933 int ret = m_data_file->ReadV(
const_cast<XrdOucIOVec*
>(readV), readVnum);
936 m_delta_stats.AddBytesHit(ret);
942 return ReadOpusCoalescere(io, readV, readVnum, rh,
"ReadV() ");
947int File::ReadOpusCoalescere(
IO *io,
const XrdOucIOVec *readV,
int readVnum,
959 int prefetch_cnt = 0;
964 std::unordered_map<Block*, std::vector<ChunkRequest>> blks_ready;
966 std::vector<XrdOucIOVec> iovec_disk;
967 std::vector<XrdOucIOVec> iovec_direct;
968 int iovec_disk_total = 0;
969 int iovec_direct_total = 0;
971 for (
int iov_idx = 0; iov_idx < readVnum; ++iov_idx)
978 const int idx_first = iUserOff / m_block_size;
979 const int idx_last = (iUserOff + iUserSize - 1) / m_block_size;
981 TRACEF(DumpXL, tpfx <<
"sid: " <<
Xrd::hex1 << rh->
m_seq_id <<
" idx_first: " << idx_first <<
" idx_last: " << idx_last);
983 enum LastBlock_e { LB_other, LB_disk, LB_direct };
985 LastBlock_e lbe = LB_other;
987 for (
int block_idx = idx_first; block_idx <= idx_last; ++block_idx)
990 BlockMap_i bi = m_block_map.find(block_idx);
994 long long blk_off = 0;
997 overlap(block_idx, m_block_size, iUserOff, iUserSize, off, blk_off, size);
1000 if (bi != m_block_map.end())
1002 inc_ref_count(bi->second);
1003 TRACEF(Dump, tpfx << (
void*) iUserBuff <<
" inc_ref_count for existing block " << bi->second <<
" idx = " << block_idx);
1005 if (bi->second->is_finished())
1009 assert(bi->second->is_ok());
1011 blks_ready[bi->second].emplace_back(
ChunkRequest(
nullptr, iUserBuff + off, blk_off, size) );
1013 if (bi->second->m_prefetch)
1024 bi->second->m_chunk_reqs.emplace_back(
ChunkRequest(read_req, iUserBuff + off, blk_off, size) );
1031 else if (m_cfi.TestBitWritten(offsetIdx(block_idx)))
1033 TRACEF(DumpXL, tpfx <<
"read from disk " << (
void*)iUserBuff <<
" idx = " << block_idx);
1036 iovec_disk.back().size += size;
1038 iovec_disk.push_back( { block_idx * m_block_size + blk_off, size, 0, iUserBuff + off } );
1039 iovec_disk_total += size;
1041 if (m_cfi.TestBitPrefetch(offsetIdx(block_idx)))
1053 Block *b = PrepareBlockRequest(block_idx, io, read_req,
false);
1056 TRACEF(Dump, tpfx <<
"inc_ref_count new " << (
void*)iUserBuff <<
" idx = " << block_idx);
1058 blks_to_request.push_back(b);
1067 TRACEF(DumpXL, tpfx <<
"direct block " << block_idx <<
", blk_off " << blk_off <<
", size " << size);
1069 iovec_direct_total += size;
1075 if (lbe == LB_direct && iovec_direct.back().size + size <= XrdProto::maxRVdsz) {
1076 iovec_direct.back().size += size;
1078 long long in_offset = block_idx * m_block_size + blk_off;
1079 char *out_pos = iUserBuff + off;
1080 while (size > XrdProto::maxRVdsz) {
1086 iovec_direct.push_back( { in_offset, size, 0, out_pos } );
1095 inc_prefetch_hit_cnt(prefetch_cnt);
1097 m_state_cond.UnLock();
1100 if ( ! blks_to_request.empty())
1102 ProcessBlockRequests(blks_to_request);
1103 blks_to_request.clear();
1107 if ( ! iovec_direct.empty())
1109 RequestBlocksDirect(io, read_req, iovec_direct, iovec_direct_total);
1111 TRACEF(Dump, tpfx <<
"direct read requests sent out, n_chunks = " << (
int) iovec_direct.size() <<
", total_size = " << iovec_direct_total);
1116 long long bytes_read = 0;
1120 if ( ! blks_ready.empty())
1122 for (
auto &bvi : blks_ready)
1124 for (
auto &cr : bvi.second)
1126 TRACEF(DumpXL, tpfx <<
"ub=" << (
void*)cr.m_buf <<
" from pre-finished block " << bvi.first->m_offset/m_block_size <<
" size " << cr.m_size);
1127 memcpy(cr.m_buf, bvi.first->m_buff + cr.m_off, cr.m_size);
1128 bytes_read += cr.m_size;
1134 if ( ! iovec_disk.empty())
1136 int rc = ReadBlocksFromDisk(iovec_disk, iovec_disk_total);
1137 TRACEF(DumpXL, tpfx <<
"from disk finished size = " << rc);
1152 m_state_cond.Lock();
1154 for (
auto &bvi : blks_ready)
1155 dec_ref_count(bvi.first, (
int) bvi.second.size());
1168 m_delta_stats.AddReadStats(read_req->
m_stats);
1169 check_delta_stats();
1170 m_state_cond.UnLock();
1178 m_state_cond.UnLock();
1184 m_delta_stats.m_BytesHit += bytes_read;
1185 check_delta_stats();
1186 m_state_cond.UnLock();
1190 return error_cond ? error_cond : bytes_read;
1202 long long offset = b->
m_offset - m_offset;
1206 if (m_cfi.IsCkSumCache())
1210 retval = m_data_file->pgWrite(b->
get_buff(), offset, size, 0, 0);
1212 retval = m_data_file->Write(b->
get_buff(), offset, size);
1217 TRACEF(
Error,
"WriteToDisk() write error " << retval);
1219 TRACEF(
Error,
"WriteToDisk() incomplete block write ret=" << retval <<
" (should be " << size <<
")");
1229 const int blk_idx = (b->
m_offset - m_offset) / m_block_size;
1232 TRACEF(Dump,
"WriteToDisk() success set bit for block " << b->
m_offset <<
" size=" << size);
1234 bool schedule_sync =
false;
1238 m_cfi.SetBitWritten(blk_idx);
1242 m_cfi.SetBitPrefetch(blk_idx);
1246 m_cfi.ResetCkSumNet();
1253 m_writes_during_sync.push_back(blk_idx);
1257 m_cfi.SetBitSynced(blk_idx);
1258 ++m_non_flushed_cnt;
1259 if ((m_cfi.IsComplete() || m_non_flushed_cnt >=
Cache::GetInstance().RefConfiguration().m_flushCnt) &&
1262 schedule_sync =
true;
1264 m_non_flushed_cnt = 0;
1270 if (!schedule_sync) {
1277 cache()->ScheduleFileSync(
this);
1289 int ret = m_data_file->Fsync();
1290 bool errorp =
false;
1296 report_and_merge_delta_stats();
1297 loc_stats = m_stats;
1299 m_cfi.WriteIOStat(loc_stats);
1300 m_cfi.Write(m_info_file, m_filename.c_str());
1301 int cret = m_info_file->Fsync();
1304 TRACEF(
Error,
"Sync cinfo file sync error " << cret);
1310 TRACEF(
Error,
"Sync data file sync error " << ret <<
", cinfo file has not been updated");
1316 TRACEF(
Error,
"Sync failed, unlinking local files and initiating shutdown of File object");
1323 m_writes_during_sync.clear();
1329 int written_while_in_sync;
1330 bool resync =
false;
1333 for (std::vector<int>::iterator i = m_writes_during_sync.begin(); i != m_writes_during_sync.end(); ++i)
1335 m_cfi.SetBitSynced(*i);
1337 written_while_in_sync = m_non_flushed_cnt = (int) m_writes_during_sync.size();
1338 m_writes_during_sync.clear();
1342 if (written_while_in_sync > 0 && m_cfi.IsComplete() && ! m_in_shutdown)
1347 TRACEF(Dump,
"Sync "<< written_while_in_sync <<
" blocks written during sync." << (resync ?
" File is now complete - resyncing." :
""));
1358void File::free_block(
Block* b)
1361 int i = b->
m_offset / m_block_size;
1362 TRACEF(Dump,
"free_block block " << b <<
" idx = " << i);
1363 size_t ret = m_block_map.erase(i);
1367 TRACEF(
Error,
"free_block did not erase " << i <<
" from map");
1375 if (m_prefetch_state == kHold && (
int) m_block_map.size() < m_prefetch_max_blocks_in_flight)
1377 m_prefetch_state = kOn;
1378 cache()->RegisterPrefetchFile(
this);
1384bool File::select_current_io_or_disable_prefetching(
bool skip_current)
1388 int io_size = (int) m_io_set.size();
1393 io_ok = (*m_io_set.begin())->m_allow_prefetching;
1396 m_current_io = m_io_set.begin();
1399 else if (io_size > 1)
1401 IoSet_i mi = m_current_io;
1402 if (skip_current && mi != m_io_set.end()) ++mi;
1404 for (
int i = 0; i < io_size; ++i)
1406 if (mi == m_io_set.end()) mi = m_io_set.begin();
1408 if ((*mi)->m_allow_prefetching)
1420 m_current_io = m_io_set.end();
1421 m_prefetch_state = kStopped;
1422 cache()->DeRegisterPrefetchFile(
this);
1430void File::ProcessDirectReadFinished(
ReadRequest *rreq,
int bytes_read,
int error_cond)
1436 TRACEF(
Error,
"Read(), direct read finished with error " << -error_cond <<
" " <<
XrdSysE2T(-error_cond));
1438 m_state_cond.Lock();
1451 m_state_cond.UnLock();
1454 FinalizeReadRequest(rreq);
1481 TRACEF(Dump,
"ProcessBlockSuccess() ub=" << (
void*)creq.
m_buf <<
" from finished block " << b->
m_offset/m_block_size <<
" size " << creq.
m_size);
1484 m_state_cond.Lock();
1489 rreq->m_stats.m_BytesMissed += creq.
m_size;
1491 rreq->m_stats.m_BytesHit += creq.
m_size;
1493 --rreq->m_n_chunk_reqs;
1496 inc_prefetch_hit_cnt(1);
1500 bool rreq_complete = rreq->is_complete();
1502 m_state_cond.UnLock();
1505 FinalizeReadRequest(rreq);
1513 XrdSysCondVarHelper _lck(m_state_cond);
1514 m_delta_stats.AddReadStats(rreq->
m_stats);
1515 check_delta_stats();
1522void File::ProcessBlockResponse(
Block *b,
int res)
1524 static const char* tpfx =
"ProcessBlockResponse ";
1526 TRACEF(Dump, tpfx <<
"block=" << b <<
", idx=" << b->
m_offset/m_block_size <<
", off=" << b->
m_offset <<
", res=" << res);
1528 if (res >= 0 && res != b->
get_size())
1532 TRACEF(
Error, tpfx <<
"Wrong number of bytes received, assuming remote/local file size mismatch, unlinking local files and initiating shutdown of File object");
1536 m_state_cond.Lock();
1542 IoSet_i mi = m_io_set.find(io);
1543 if (mi != m_io_set.end())
1545 --io->m_active_prefetches;
1548 if (res < 0 && io->m_allow_prefetching)
1550 TRACEF(
Debug, tpfx <<
"after failed prefetch on io " << io <<
" disabling prefetching on this io.");
1551 io->m_allow_prefetching =
false;
1554 if (m_prefetch_state == kOn || m_prefetch_state == kHold)
1556 if ( ! select_current_io_or_disable_prefetching(
false) )
1558 TRACEF(
Debug, tpfx <<
"stopping prefetching after io " << b->
get_io() <<
" marked as bad.");
1564 if (b->
m_refcnt == 0 && (res < 0 || m_in_shutdown))
1567 m_state_cond.UnLock();
1581 TRACEF(Dump, tpfx <<
"inc_ref_count idx=" << b->
m_offset/m_block_size);
1582 if ( ! m_in_shutdown)
1588 cache()->AddWriteTask(b,
true);
1595 m_state_cond.UnLock();
1597 for (
auto &creq : creqs_to_notify)
1599 ProcessBlockSuccess(b, creq);
1608 <<
", io=" << b->
get_io() <<
", error=" << res);
1613 <<
", io=" << b->
get_io() <<
" incomplete, got " << res <<
" expected " << b->
get_size());
1614#if defined(__APPLE__) || defined(__GNU__) || (defined(__FreeBSD_kernel__) && defined(__GLIBC__)) || defined(__FreeBSD__)
1625 std::list<ReadRequest*> rreqs_to_complete;
1634 ProcessBlockError(b, rreq);
1637 rreqs_to_complete.push_back(rreq);
1642 creqs_to_keep.push_back(creq);
1646 bool reissue =
false;
1647 if ( ! creqs_to_keep.empty())
1649 ReadRequest *rreq = creqs_to_keep.front().m_read_req;
1651 TRACEF(
Debug,
"ProcessBlockResponse() requested block " << (
void*)b <<
" failed with another io " <<
1652 b->
get_io() <<
" - reissuing request with my io " << rreq->
m_io);
1659 m_state_cond.UnLock();
1661 for (
auto rreq : rreqs_to_complete)
1662 FinalizeReadRequest(rreq);
1665 ProcessBlockRequest(b);
1673 return m_filename.c_str();
1678int File::offsetIdx(
int iIdx)
const
1680 return iIdx - m_offset/m_block_size;
1694 TRACEF(DumpXL,
"Prefetch() entering.");
1698 if (m_prefetch_state != kOn)
1703 if ( ! select_current_io_or_disable_prefetching(
true) )
1705 TRACEF(
Error,
"Prefetch no available IO object found, prefetching stopped. This should not happen, i.e., prefetching should be stopped before.");
1710 for (
int f = 0; f < m_num_blocks; ++f)
1712 if ( ! m_cfi.TestBitWritten(f))
1714 int f_act = f + m_offset / m_block_size;
1716 BlockMap_i bi = m_block_map.find(f_act);
1717 if (bi == m_block_map.end())
1719 Block *b = PrepareBlockRequest(f_act, *m_current_io,
nullptr,
true);
1722 TRACEF(Dump,
"Prefetch take block " << f_act);
1726 inc_prefetch_read_cnt(1);
1731 TRACEF(Warning,
"Prefetch allocation failed for block " << f_act);
1740 TRACEF(
Debug,
"Prefetch file is complete, stopping prefetch.");
1741 m_prefetch_state = kComplete;
1742 cache()->DeRegisterPrefetchFile(
this);
1746 (*m_current_io)->m_active_prefetches += (int) blks.size();
1750 if ( ! blks.empty())
1752 ProcessBlockRequests(blks);
1761 return m_prefetch_score;
1774void File::insert_remote_location(
const std::string &loc)
1778 size_t p = loc.find_first_of(
'@');
1779 m_remote_locations.insert(&loc[p != std::string::npos ? p + 1 : 0]);
1786 if ( ! m_remote_locations.empty())
1790 for (std::set<std::string>::iterator i = m_remote_locations.begin(); i != m_remote_locations.end(); ++i, ++nl)
1794 s.reserve(2 + sl + 2*nl + nl - 1 + 1);
1797 for (std::set<std::string>::iterator i = m_remote_locations.begin(); i != m_remote_locations.end(); ++i, ++j)
1799 s +=
'"'; s += *i; s +=
'"';
1800 if (j < nl) s +=
',';
#define ERRNO_AND_ERRSTR(err_code)
#define TRACEF_INT(act, x)
const char * XrdSysE2T(int errcode)
virtual int Fstat(struct stat *buf)
virtual int Open(const char *path, int Oflag, mode_t Mode, XrdOucEnv &env)
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 int Fcntl(XrdOucCacheOp::Code opc, const std::string &args, std::string &resp)
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)
virtual int ReadV(const XrdOucIOVec *readV, int rnum)
void Put(const char *varname, const char *value)
void Done(int result) override
BlockResponseHandler(Block *b)
int * ptr_n_cksum_errors()
Block(File *f, IO *io, void *rid, char *buf, long long off, int size, int rsize, bool m_prefetch, bool cks_net)
vCkSum_t & ref_cksum_vec()
long long get_offset() const
vChunkRequest_t m_chunk_reqs
void * get_req_id() const
bool req_cksum_net() const
void reset_error_and_set_io(IO *io, void *rid)
Attaches/creates and detaches/deletes cache-io objects for disk based cache.
XrdSysError * GetLog() const
const Configuration & RefConfiguration() const
Reference XrdPfc configuration.
static ResourceMonitor & ResMon()
static Cache & GetInstance()
Singleton access.
XrdSysTrace * GetTrace() const
int UnlinkFile(const std::string &f_name, bool fail_if_open)
Remove cinfo and data files from cache.
static const Cache & TheOne()
void Done(int result) override
DirectResponseHandler(File *file, ReadRequest *rreq, int to_wait)
bool FinalizeSyncBeforeExit()
Returns true if any of blocks need sync. Called from Cache::dec_ref_cnt on zero ref cnt.
const char * lPath() const
Log path.
int ReadV(IO *io, const XrdOucIOVec *readV, int readVnum, ReadReqRH *rh)
Vector read.
void WriteBlockToDisk(Block *b)
float GetPrefetchScore() const
friend class BlockResponseHandler
std::string GetRemoteLocations() const
int Fstat(struct stat &sbuff)
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.
void RequestSyncOfDetachStats()
Flags that detach stats should be written out in final sync. Called from CacheIO upon Detach.
void BlocksRemovedFromWriteQ(std::list< Block * > &)
Handle removal of a set of blocks from Cache's write queue.
friend class DirectResponseHandler
void Sync()
Sync file cache inf o and output data with disk.
XrdSysTrace * GetTrace() const
int Read(IO *io, char *buff, long long offset, int size, ReadReqRH *rh)
Normal read.
void ioUpdated(IO *io)
Notification from IO that it has been updated (remote open).
long long initiate_emergency_shutdown()
void BlockRemovedFromWriteQ(Block *)
Handle removal of a block from Cache's write queue.
XrdSysError * GetLog() const
bool ioActive(IO *io)
Initiate close. Return true if still IO active. Used in XrdPosixXrootd::Close().
Base cache-io class that implements some XrdOucCacheIO abstract methods.
bool register_incomplete_read()
XrdOucCacheIO * GetInput()
bool register_block_error(int res)
RAtomic_int m_active_read_reqs
number of active read requests
const char * GetLocation()
Status of cached file. Can be read from and written into a binary file.
static const char * s_infoExtension
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.
long long m_StBlocksAdded
number of 512-byte blocks the file has grown by
long long m_BytesBypassed
number of bytes served directly through XrdCl
void AddUp(const Stats &s)
long long BytesReadAndWritten() const
long long m_BytesHit
number of bytes served from disk
std::list< Block * > BlockList_t
constexpr int kReadPending
std::vector< ChunkRequest > vChunkRequest_t
std::list< Block * >::iterator BlockList_i
static const int maxRVdsz
static const int maxRvecsz
ChunkRequest(ReadRequest *rreq, char *buf, long long off, int size)
Contains parameters configurable from the xrootd config file.
long long m_cgi_max_bufferSize
max buffer size allowed in pfc.blocksize
int m_cgi_min_prefetch_max_blocks
min prefetch block count allowed in pfc.prefetch
bool does_cschk_have_missing_bits(CkSumCheck_e cks_on_file) const
bool m_cgi_prefetch_allowed
allow cgi setting of prefetch
CkSumCheck_e get_cs_Chk() const
int m_prefetch_max_blocks
default maximum number of blocks to prefetch per file
bool should_uvkeep_purge(time_t delta) const
std::string m_data_space
oss space for data files
long long m_bufferSize
cache block size, default 128 kB
long long m_cgi_min_bufferSize
min buffer size allowed in pfc.blocksize
std::string m_meta_space
oss space for metadata files (cinfo)
int m_cgi_max_prefetch_max_blocks
max prefetch block count allowed in pfc.prefetch
std::string m_username
username passed to oss plugin
bool m_cgi_blocksize_allowed
allow cgi setting of blocksize
void update_error_cond(int ec)
ReadRequest(IO *io, ReadReqRH *rh)