#ifndef XRD_READCACHE_H
#define XRD_READCACHE_H
/******************************************************************************/
/* */
/* X r d C l i e n t R e a d C a c h e . h h */
/* */
/* Author: Fabrizio Furano (INFN Padova, 2006) */
/* */
/* This file is part of the XRootD software suite. */
/* */
/* XRootD is free software: you can redistribute it and/or modify it under */
/* the terms of the GNU Lesser General Public License as published by the */
/* Free Software Foundation, either version 3 of the License, or (at your */
/* option) any later version. */
/* */
/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public License */
/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
/* COPYING (GPL license). If not, see . */
/* */
/* The copyright holder's institutional names and contributor's names may not */
/* be used to endorse or promote products derived from this software without */
/* specific prior written permission of the institution or contributor. */
/******************************************************************************/
//////////////////////////////////////////////////////////////////////////
// //
// Classes to handle cache reading and cache placeholders //
// //
//////////////////////////////////////////////////////////////////////////
#include "XrdSys/XrdSysHeaders.hh"
#include "XrdClient/XrdClientInputBuffer.hh"
#include "XrdClient/XrdClientMessage.hh"
#include "XrdClient/XrdClientVector.hh"
#include "XrdClient/XrdClientConst.hh"
//
// XrdClientReadCacheItem
//
// An item is nothing more than an interval of bytes taken from a file.
// Extremes are included.
// Since a cache object is to be associated to a single instance
// of TXNetFile, we do not have to keep here any filehandle
//
class XrdClientReadCacheItem {
private:
// A placeholder block is a "fake block" used to mark outstanding data
bool fIsPlaceholder;
long long fBeginOffset; // Offset of the first byte of data
void *fData;
long long fEndOffset; // Offset of the last byte of data
long fTimestampTicks; // timestamp updated each time it's referenced
public:
XrdClientReadCacheItem(const void *buffer, long long begin_offs,
long long end_offs, long long ticksnow,
bool placeholder=false);
~XrdClientReadCacheItem();
inline long long BeginOffset() { return fBeginOffset; }
inline long long EndOffset() { return fEndOffset; }
// Is this obj contained in the given interval (which is going to be inserted) ?
inline bool ContainedInInterval(long long begin_offs, long long end_offs) {
return ( (end_offs >= begin_offs) &&
(fBeginOffset >= begin_offs) &&
(fEndOffset <= end_offs) );
}
// Does this obj contain the given interval (which is going to be requested) ?
inline bool ContainsInterval(long long begin_offs, long long end_offs) {
return ( (end_offs > begin_offs) &&
(fBeginOffset <= begin_offs) && (fEndOffset >= end_offs) );
}
// Are the two intervals intersecting in some way?
inline bool IntersectInterval(long long begin_offs, long long end_offs) {
if ( ContainsOffset( begin_offs ) || ContainsOffset( end_offs ) ) return true;
if ( (fBeginOffset >= begin_offs) && (fBeginOffset <= end_offs) ) return true;
return false;
}
inline bool ContainsOffset(long long offs) {
return (fBeginOffset <= offs) && (fEndOffset >= offs);
}
void *GetData() { return fData; }
// Get the requested interval, if possible
inline bool GetInterval(const void *buffer, long long begin_offs,
long long end_offs) {
if (!ContainsInterval(begin_offs, end_offs))
return FALSE;
memcpy((void *)buffer, ((char *)fData)+(begin_offs - fBeginOffset),
end_offs - begin_offs + 1);
return TRUE;
}
// Get as many bytes as possible, starting from the beginning of the given
// interval
inline long GetPartialInterval(const void *buffer, long long begin_offs,
long long end_offs) {
long long b = -1, e, l;
if (begin_offs > end_offs) return 0;
// Try to set the starting point, if contained in the given interval
if ( (begin_offs >= fBeginOffset) &&
(begin_offs <= fEndOffset) )
b = begin_offs;
if (b < 0) return 0;
// The starting point is in the interval. Let's get the minimum endpoint
e = xrdmin(end_offs, fEndOffset);
l = e - b + 1;
if (buffer && fData)
memcpy((void *)buffer, ((char *)fData)+(b - fBeginOffset), l);
return l;
}
inline long long GetTimestampTicks() { return(fTimestampTicks); }
inline bool IsPlaceholder() { return fIsPlaceholder; }
long Size() { return (fEndOffset - fBeginOffset + 1); }
inline void Touch(long long ticksnow) { fTimestampTicks = ticksnow; }
bool Pinned;
};
//
// XrdClientReadCache
//
// The content of the cache. Not cache blocks, but
// variable length Items
//
typedef XrdClientVector ItemVect;
// A cache interval, extremes included
struct XrdClientCacheInterval {
long long beginoffs;
long long endoffs;
};
typedef XrdClientVector XrdClientIntvList;
class XrdClientReadCache {
private:
long long fBytesHit; // Total number of bytes read with a cache hit
long long fBytesSubmitted; // Total number of bytes inserted
float fBytesUsefulness;
ItemVect fItems;
long long fMaxCacheSize;
long long fMissCount; // Counter of the cache misses
float fMissRate; // Miss rate
XrdSysRecMutex fMutex;
long long fReadsCounter; // Counter of all the attempted reads (hit or miss)
int fBlkRemPolicy; // The algorithm used to remove "old" chunks
long long fTimestampTickCounter; // Aging mechanism yuk!
long long fTotalByteCount;
long long GetTimestampTick();
bool MakeFreeSpace(long long bytes);
bool RemoveItem();
bool RemoveLRUItem();
bool RemoveFirstItem();
inline void UpdatePerfCounters() {
if (fReadsCounter > 0)
fMissRate = (float)fMissCount / fReadsCounter;
if (fBytesSubmitted > 0)
fBytesUsefulness = (float)fBytesHit / fBytesSubmitted;
}
int FindInsertionApprox(long long begin_offs);
int FindInsertionApprox_rec(int startidx, int endidx,
long long begin_offs);
public:
// The algos available for the removal of "old" blocks
enum {
kRmBlk_LRU = 0,
kRmBlk_LeastOffs,
kRmBlk_FIFO
};
XrdClientReadCache();
~XrdClientReadCache();
long GetDataIfPresent(const void *buffer, long long begin_offs,
long long end_offs, bool PerfCalc,
XrdClientIntvList &missingblks, long &outstandingblks);
void GetInfo(
// The actual cache size
int &size,
// The number of bytes submitted since the beginning
long long &bytessubmitted,
// The number of bytes found in the cache (estimate)
long long &byteshit,
// The number of reads which did not find their data
// (estimate)
long long &misscount,
// miss/totalreads ratio (estimate)
float &missrate,
// number of read requests towards the cache
long long &readreqcnt,
// ratio between bytes found / bytes submitted
float &bytesusefulness
);
inline long long GetTotalByteCount() {
XrdSysMutexHelper m(fMutex);
return fTotalByteCount;
}
void PutPlaceholder(long long begin_offs, long long end_offs);
inline void PrintPerfCounters() {
XrdSysMutexHelper m(fMutex);
cout << "Low level caching info:" << endl;
cout << " StallsRate=" << fMissRate << endl;
cout << " StallsCount=" << fMissCount << endl;
cout << " ReadsCounter=" << fReadsCounter << endl;
cout << " BytesUsefulness=" << fBytesUsefulness << endl;
cout << " BytesSubmitted=" << fBytesSubmitted << " BytesHit=" <<
fBytesHit << endl << endl;
}
void PrintCache();
void SubmitXMessage(XrdClientMessage *xmsg, long long begin_offs,
long long end_offs);
bool SubmitRawData(const void *buffer, long long begin_offs,
long long end_offs, bool pinned=false);
void RemoveItems(bool leavepinned=true);
void RemoveItems(long long begin_offs, long long end_offs, bool remove_overlapped = false);
void RemovePlaceholders();
void SetSize(int sz) {
fMaxCacheSize = sz;
}
void SetBlkRemovalPolicy(int p) {
fBlkRemPolicy = p;
}
void UnPinCacheBlk(long long begin_offs, long long end_offs);
void *FindBlk(long long begin_offs, long long end_offs);
// To check if a block dimension will fit into the cache
inline bool WillFit(long long bc) {
XrdSysMutexHelper m(fMutex);
return (bc < fMaxCacheSize);
}
};
#endif