xrootd
|
00001 00002 // // 00003 // XrdClientReadCache // 00004 // // 00005 // Author: Fabrizio Furano (INFN Padova, 2006) // 00006 // // 00007 // Classes to handle cache reading and cache placeholders // 00008 // // 00010 00011 // $Id$ 00012 00013 #ifndef XRD_READCACHE_H 00014 #define XRD_READCACHE_H 00015 00016 #include "XrdSys/XrdSysHeaders.hh" 00017 #include "XrdClient/XrdClientInputBuffer.hh" 00018 #include "XrdClient/XrdClientMessage.hh" 00019 #include "XrdClient/XrdClientVector.hh" 00020 #include "XrdClient/XrdClientConst.hh" 00021 00022 00023 // 00024 // XrdClientReadCacheItem 00025 // 00026 // An item is nothing more than an interval of bytes taken from a file. 00027 // Extremes are included. 00028 // Since a cache object is to be associated to a single instance 00029 // of TXNetFile, we do not have to keep here any filehandle 00030 // 00031 00032 class XrdClientReadCacheItem { 00033 private: 00034 // A placeholder block is a "fake block" used to mark outstanding data 00035 bool fIsPlaceholder; 00036 00037 long long fBeginOffset; // Offset of the first byte of data 00038 void *fData; 00039 long long fEndOffset; // Offset of the last byte of data 00040 long fTimestampTicks; // timestamp updated each time it's referenced 00041 00042 public: 00043 XrdClientReadCacheItem(const void *buffer, long long begin_offs, 00044 long long end_offs, long long ticksnow, 00045 bool placeholder=false); 00046 ~XrdClientReadCacheItem(); 00047 00048 inline long long BeginOffset() { return fBeginOffset; } 00049 inline long long EndOffset() { return fEndOffset; } 00050 00051 // Is this obj contained in the given interval (which is going to be inserted) ? 00052 inline bool ContainedInInterval(long long begin_offs, long long end_offs) { 00053 return ( (end_offs >= begin_offs) && 00054 (fBeginOffset >= begin_offs) && 00055 (fEndOffset <= end_offs) ); 00056 } 00057 00058 // Does this obj contain the given interval (which is going to be requested) ? 00059 inline bool ContainsInterval(long long begin_offs, long long end_offs) { 00060 return ( (end_offs > begin_offs) && 00061 (fBeginOffset <= begin_offs) && (fEndOffset >= end_offs) ); 00062 } 00063 00064 // Are the two intervals intersecting in some way? 00065 inline bool IntersectInterval(long long begin_offs, long long end_offs) { 00066 if ( ContainsOffset( begin_offs ) || ContainsOffset( end_offs ) ) return true; 00067 if ( (fBeginOffset >= begin_offs) && (fBeginOffset <= end_offs) ) return true; 00068 return false; 00069 } 00070 00071 00072 inline bool ContainsOffset(long long offs) { 00073 return (fBeginOffset <= offs) && (fEndOffset >= offs); 00074 } 00075 00076 void *GetData() { return fData; } 00077 00078 // Get the requested interval, if possible 00079 inline bool GetInterval(const void *buffer, long long begin_offs, 00080 long long end_offs) { 00081 if (!ContainsInterval(begin_offs, end_offs)) 00082 return FALSE; 00083 memcpy((void *)buffer, ((char *)fData)+(begin_offs - fBeginOffset), 00084 end_offs - begin_offs + 1); 00085 return TRUE; 00086 } 00087 00088 // Get as many bytes as possible, starting from the beginning of the given 00089 // interval 00090 inline long GetPartialInterval(const void *buffer, long long begin_offs, 00091 long long end_offs) { 00092 00093 long long b = -1, e, l; 00094 00095 if (begin_offs > end_offs) return 0; 00096 00097 // Try to set the starting point, if contained in the given interval 00098 if ( (begin_offs >= fBeginOffset) && 00099 (begin_offs <= fEndOffset) ) 00100 b = begin_offs; 00101 00102 if (b < 0) return 0; 00103 00104 // The starting point is in the interval. Let's get the minimum endpoint 00105 e = xrdmin(end_offs, fEndOffset); 00106 00107 l = e - b + 1; 00108 00109 if (buffer && fData) 00110 memcpy((void *)buffer, ((char *)fData)+(b - fBeginOffset), l); 00111 00112 return l; 00113 } 00114 00115 inline long long GetTimestampTicks() { return(fTimestampTicks); } 00116 00117 inline bool IsPlaceholder() { return fIsPlaceholder; } 00118 00119 long Size() { return (fEndOffset - fBeginOffset + 1); } 00120 00121 inline void Touch(long long ticksnow) { fTimestampTicks = ticksnow; } 00122 00123 bool Pinned; 00124 }; 00125 00126 // 00127 // XrdClientReadCache 00128 // 00129 // The content of the cache. Not cache blocks, but 00130 // variable length Items 00131 // 00132 typedef XrdClientVector<XrdClientReadCacheItem *> ItemVect; 00133 00134 // A cache interval, extremes included 00135 struct XrdClientCacheInterval { 00136 long long beginoffs; 00137 long long endoffs; 00138 }; 00139 00140 typedef XrdClientVector<XrdClientCacheInterval> XrdClientIntvList; 00141 00142 class XrdClientReadCache { 00143 private: 00144 00145 long long fBytesHit; // Total number of bytes read with a cache hit 00146 long long fBytesSubmitted; // Total number of bytes inserted 00147 float fBytesUsefulness; 00148 ItemVect fItems; 00149 long long fMaxCacheSize; 00150 long long fMissCount; // Counter of the cache misses 00151 float fMissRate; // Miss rate 00152 XrdSysRecMutex fMutex; 00153 long long fReadsCounter; // Counter of all the attempted reads (hit or miss) 00154 int fBlkRemPolicy; // The algorithm used to remove "old" chunks 00155 long long fTimestampTickCounter; // Aging mechanism yuk! 00156 long long fTotalByteCount; 00157 00158 long long GetTimestampTick(); 00159 bool MakeFreeSpace(long long bytes); 00160 00161 bool RemoveItem(); 00162 bool RemoveLRUItem(); 00163 bool RemoveFirstItem(); 00164 00165 inline void UpdatePerfCounters() { 00166 if (fReadsCounter > 0) 00167 fMissRate = (float)fMissCount / fReadsCounter; 00168 if (fBytesSubmitted > 0) 00169 fBytesUsefulness = (float)fBytesHit / fBytesSubmitted; 00170 } 00171 00172 int FindInsertionApprox(long long begin_offs); 00173 int FindInsertionApprox_rec(int startidx, int endidx, 00174 long long begin_offs); 00175 public: 00176 00177 // The algos available for the removal of "old" blocks 00178 enum { 00179 kRmBlk_LRU = 0, 00180 kRmBlk_LeastOffs, 00181 kRmBlk_FIFO 00182 }; 00183 00184 XrdClientReadCache(); 00185 ~XrdClientReadCache(); 00186 00187 long GetDataIfPresent(const void *buffer, long long begin_offs, 00188 long long end_offs, bool PerfCalc, 00189 XrdClientIntvList &missingblks, long &outstandingblks); 00190 00191 void GetInfo( 00192 // The actual cache size 00193 int &size, 00194 00195 // The number of bytes submitted since the beginning 00196 long long &bytessubmitted, 00197 00198 // The number of bytes found in the cache (estimate) 00199 long long &byteshit, 00200 00201 // The number of reads which did not find their data 00202 // (estimate) 00203 long long &misscount, 00204 00205 // miss/totalreads ratio (estimate) 00206 float &missrate, 00207 00208 // number of read requests towards the cache 00209 long long &readreqcnt, 00210 00211 // ratio between bytes found / bytes submitted 00212 float &bytesusefulness 00213 ); 00214 00215 inline long long GetTotalByteCount() { 00216 XrdSysMutexHelper m(fMutex); 00217 return fTotalByteCount; 00218 } 00219 00220 void PutPlaceholder(long long begin_offs, long long end_offs); 00221 00222 inline void PrintPerfCounters() { 00223 XrdSysMutexHelper m(fMutex); 00224 00225 cout << "Low level caching info:" << endl; 00226 cout << " StallsRate=" << fMissRate << endl; 00227 cout << " StallsCount=" << fMissCount << endl; 00228 cout << " ReadsCounter=" << fReadsCounter << endl; 00229 cout << " BytesUsefulness=" << fBytesUsefulness << endl; 00230 cout << " BytesSubmitted=" << fBytesSubmitted << " BytesHit=" << 00231 fBytesHit << endl << endl; 00232 } 00233 00234 00235 void PrintCache(); 00236 00237 void SubmitXMessage(XrdClientMessage *xmsg, long long begin_offs, 00238 long long end_offs); 00239 00240 bool SubmitRawData(const void *buffer, long long begin_offs, 00241 long long end_offs, bool pinned=false); 00242 00243 void RemoveItems(bool leavepinned=true); 00244 void RemoveItems(long long begin_offs, long long end_offs, bool remove_overlapped = false); 00245 void RemovePlaceholders(); 00246 00247 00248 void SetSize(int sz) { 00249 fMaxCacheSize = sz; 00250 } 00251 00252 void SetBlkRemovalPolicy(int p) { 00253 fBlkRemPolicy = p; 00254 } 00255 00256 void UnPinCacheBlk(long long begin_offs, long long end_offs); 00257 void *FindBlk(long long begin_offs, long long end_offs); 00258 00259 // To check if a block dimension will fit into the cache 00260 inline bool WillFit(long long bc) { 00261 XrdSysMutexHelper m(fMutex); 00262 return (bc < fMaxCacheSize); 00263 } 00264 00265 }; 00266 00267 #endif