00001 // Copyright (C) 2001, Compaq Computer Corporation 00002 // 00003 // This file is part of Vesta. 00004 // 00005 // Vesta is free software; you can redistribute it and/or 00006 // modify it under the terms of the GNU Lesser General Public 00007 // License as published by the Free Software Foundation; either 00008 // version 2.1 of the License, or (at your option) any later version. 00009 // 00010 // Vesta is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 // Lesser General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU Lesser General Public 00016 // License along with Vesta; if not, write to the Free Software 00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00018 00019 // Last modified on Mon May 23 22:52:04 EDT 2005 by ken@xorian.net 00020 // modified on Fri Sep 18 16:30:19 PDT 1998 by heydon 00021 00022 // VMultiPKFile -- a set of VPKFile's stored in memory 00023 00024 /* A "VMultiPKFile" holds all "VPKFile"'s in the cache with a common prefix. 00025 The size of the prefix is determined by the current MultiPKFile 00026 granularity; see "SMultiPKFile.H". When one "VPKFile" is flushed to the 00027 stable cache, the "VMultiPKFile" containing is used to see which other 00028 "VPKFile"'s in the same MultiPKFile on disk can also be rewritten. 00029 00030 The methods exported by a "VMultiPKFile" object have been designed to allow 00031 a high degree of concurrency within the cache server. The only restriction 00032 they introduce is that a MultiPKFile cannot be rewritten by more than one 00033 thread at a time. See the locking level specifications for each method. */ 00034 00035 #ifndef _V_MULTI_PK_FILE_H 00036 #define _V_MULTI_PK_FILE_H 00037 00038 #include <Basics.H> 00039 #include <FS.H> 00040 #include <VestaLog.H> 00041 #include <FP.H> 00042 #include <PKPrefix.H> 00043 #include <BitVector.H> 00044 #include <CacheState.H> 00045 #include "EmptyPKLog.H" 00046 #include "VPKFile.H" 00047 #include "SMultiPKFile.H" 00048 00049 class VMultiPKFile { 00050 public: 00051 VMultiPKFile(const PKPrefix::T &pfx) throw () 00052 : prefix(pfx), freeMPKFileEpoch(-1), numWaiting(0), numRunning(0), 00053 numNewEntries(0), autoFlushPending(false) { /*SKIP*/ } 00054 /* Return a new, empty "VMultiPKFile", all of whose "VPKFile"'s 00055 will share the same prefix "pfx". */ 00056 00057 bool Get(const FP::Tag &pk, /*OUT*/ VPKFile* &vpk) throw () 00058 { return tbl.Get(pk, /*OUT*/ vpk); } 00059 /* REQUIRES Sup(LL) = CacheS.mu */ 00060 /* If there is an entry in this "VMultiPKFile" under "pk", set "vpk" to 00061 the associated value and return "true"; otherwise, return false. */ 00062 00063 bool Put(const FP::Tag &pk, VPKFile *vpk) throw () 00064 { return tbl.Put(pk, vpk); } 00065 /* REQUIRES Sup(LL) = CacheS.mu */ 00066 /* Add "vpk" to this "VMultiPKFile" under the key "pk". Return "true" iff 00067 there was already an entry in this "VMultiPKFile" under key "pk". */ 00068 00069 bool Delete(const FP::Tag &pk, VPKFile *&vpk) throw () 00070 { return tbl.Delete(pk, vpk); } 00071 /* REQUIRES Sup(LL) = CacheS.mu */ 00072 /* Remove the key "pk" from this VMultiPKFile under the key 00073 "pk". Return "true" iff there was an entry in this VMultiPKFile 00074 under key "pk". If there was an entry with key "pk", set "vpk" 00075 to the associated value. */ 00076 00077 int NumVPKFiles() const throw () 00078 { return tbl.Size(); } 00079 /* REQUIRES Sup(LL) = CacheS.mu */ 00080 /* Returns the number of VPKFiles contained by this 00081 VMultiPKFile. */ 00082 00083 const SMultiPKFile::VPKFileMap & VPKFileTbl() const throw() 00084 /* REQUIRES Sup(LL) = CacheS.mu */ 00085 /* Returns the table of VPKFiles contained by this VMultiPKFile. 00086 Note that it is unsafe to access this table without holding 00087 CacheS.mu. */ 00088 { return tbl; } 00089 00090 void IncEntries() throw () { this->numNewEntries++; } 00091 /* REQUIRES Sup(LL) = CacheS.mu */ 00092 /* Increment the count of total entries in this MultiPKFile. The count is 00093 used by "IsFull" to decide if the MPKFile should be flushed to the 00094 stable cache. */ 00095 00096 bool IsFull() throw (); 00097 /* REQUIRES Sup(LL) = CacheS.mu */ 00098 /* If the number of entries in this MPKFile exceeds some threshold and 00099 some thread is not already pending to flush it, return true and set 00100 state indicating that a thread is pending to flush the MPKFile to the 00101 stable cache. Otherwise, return false. */ 00102 00103 bool LockForWrite(Basics::mutex &mu, const BitVector *toDelete) 00104 throw(); 00105 /* REQUIRES Sup(LL) = CacheS.mu */ 00106 /* The first argument "mu" should be "CacheS.mu". It is the mutex 00107 used to protect the internal fields of a VMultiPKFile. 00108 00109 The return value indicates whether to proceed with flushing 00110 this "MultiPKFile" to disk. If a write should take place, this 00111 function will have acquired a lock which ensures that this 00112 thread is the exclusive writer of this MultiPKFile. (If 00113 another thread is already re-writing the same MultiPKFile, this 00114 function will block.) If the return value is true, the caller 00115 is responsible for calling either ChkptForRewrite followed by 00116 ToSCache (to complete the write) or ReleaseWriteLock (in case 00117 of an error prior to writing). */ 00118 00119 bool ChkptForWrite(Basics::mutex &mu, const BitVector *toDelete, 00120 /*OUT*/ SMultiPKFile::VPKFileMap &toFlush, 00121 /*OUT*/ SMultiPKFile::ChkPtTbl &vpkChkptTbl) 00122 throw(); 00123 /* REQUIRES (FORALL vf: VPKFile :: Sup(LL) < vf.mu) */ 00124 /* REQUIRES Sup(LL) = CacheS.mu */ 00125 /* The first argument "mu" should be "CacheS.mu". It is the mutex 00126 used to protect the internal fields of a VMultiPKFile. 00127 00128 Continue perparations to flush to the stable cache all 00129 VPKFile's added to this "MultiPKFile" since the last time it 00130 was flushed, and update the corresponding VPKFile's in the 00131 volatile cache. 00132 00133 The return value indicates whether a write should take place. 00134 The caller must have previously called LockForWrite (above) and 00135 it must have also indicated that a write should take place. If 00136 the return value is true, the caller is responsible for calling 00137 either ToSCache (to complete the write) or ReleaseWriteLock (in 00138 case of an error prior to writing). 00139 00140 The argument "toFlush" is filled with a map of all the VPKFiles 00141 to be written to the stable MultiPKFile. "vpkChkptTbl" is 00142 filled with in-memory checkpoints of the current contents of 00143 these VPKFiles. These capture the exact set of entries which 00144 will be written to the stable cache. This must be done 00145 *before* flushing the graph log, since new entries may be added 00146 concurrently with the re-writing process and new entries *must* 00147 be written to the graph log before being written to the stable 00148 cache. */ 00149 00150 void ReleaseWriteLock(Basics::mutex &mu) throw(); 00151 /* Release the write lock acquired by PrepareForWrite (above). 00152 This should be called if an operation between PrepareForWrite 00153 and ToSCache (below) fails. (For instance, if flushing the 00154 graph log fails.) */ 00155 00156 void ToSCache(Basics::mutex &mu, 00157 00158 // From SMultiPKFile::PrepareForRewrite 00159 bool mpkFileExists, std::ifstream &ifs, 00160 SMultiPKFileRep::Header *hdr, 00161 00162 // From ChkptForWrite above 00163 SMultiPKFile::VPKFileMap &toFlush, 00164 SMultiPKFile::ChkPtTbl &vpkChkptTbl, 00165 00166 const BitVector *toDelete, 00167 EmptyPKLog *emptyPKLog, /*INOUT*/ EntryState &state) 00168 throw (FS::Failure, FS::EndOfFile, VestaLog::Error); 00169 /* REQUIRES (FORALL vf: VPKFile :: Sup(LL) < vf.mu) */ 00170 /* The first argument "mu" should be "CacheS.mu". It is the mutex used to 00171 protect the internal fields of a VMultiPKFile. 00172 00173 The second, third, and fourth arguments must be acquired by 00174 calling SMultiPKFile::PrepareForRewrite. (These are passed 00175 directory on to SMultiPKFile::Rewrite.) 00176 00177 The fifth and sixth arguments must be acquired by calling 00178 ChkptForWrite (above). 00179 00180 Flush to the stable cache all VPKFile's added to this "MultiPKFile" 00181 since the last time it was flushed, and update the corresponding 00182 VPKFile's in the volatile cache. If "toDelete" is non-NULL, then any 00183 cache entries in this MultiPKFile with indices in "toDelete" are 00184 deleted. 00185 00186 This is a potentially long-running operation. Since only one 00187 thread at a time can be re-writing a MultiPKFile, the caller 00188 must first call PrepareForWrite which will block if some other 00189 thread is already in the process of doing so. When the 00190 operation is complete, the state set by "IsFull" indicating 00191 that a thread is pending to flush the MultiPKFile is cleared. */ 00192 00193 void UpdateEpoch(int currentEpoch) throw () 00194 /* REQUIRES Sup(LL) = CacheS.mu */ 00195 { this->freeMPKFileEpoch = currentEpoch; } 00196 00197 bool IsStale(int latestEpoch) throw (); 00198 /* REQUIRES Sup(LL) = CacheS.mu */ 00199 /* Return "true" iff this VMultiPKFile needs to be flushed by the 00200 background thread to free its memory because its last time of 00201 use was before "latestEpoch". */ 00202 00203 inline const PKPrefix::T &Prefix() const throw() 00204 /* REQUIRES Sup(LL) = CacheS.mu */ 00205 { return prefix; } 00206 00207 bool IsUnmodified() const throw () 00208 { return this->freeMPKFileEpoch == -1; } 00209 /* REQUIRES Sup(LL) = CacheS.mu */ 00210 /* Return "true" iff this VMultiPKFile has not had any entries 00211 added since it was last flushed (or created). */ 00212 00213 bool FlushRunning() const throw() 00214 { return (this->numRunning > 0); } 00215 /* REQUIRES Sup(LL) = CacheS.mu */ 00216 /* Return "true" iff this VMultiPKFile is currently being flushed 00217 to the stable cache. */ 00218 00219 bool FlushPending() const throw() 00220 { return ((this->numWaiting > 0) || autoFlushPending); } 00221 /* REQUIRES Sup(LL) = CacheS.mu */ 00222 /* Return "true" if there are threads waiting to flush this 00223 VMultiPKFile to the stable cache, or a thread should start 00224 flushing it soon. */ 00225 00226 private: 00227 // read-only after initialization 00228 PKPrefix::T prefix; 00229 00230 // data fields -- protected by CacheS.mu 00231 SMultiPKFile::VPKFileMap tbl; // set of VPKFiles 00232 int freeMPKFileEpoch; // epoch of activity on this MultiPKFile 00233 int numWaiting; // number of threads queued by ToSCache() 00234 int numRunning; // number of threads running "ToSCache" 00235 Basics::cond noneRunning; // !oneRunning 00236 int numNewEntries; // number of new entries in all VPKFiles 00237 bool autoFlushPending; // did "IsFull" recently return "true"? 00238 00239 /* The "freeMPKFileEpoch" is the epoch at which an entry was last added 00240 to some VPKFile of this MultiPKFile. It is -1 if no entries have been 00241 added since the MultiPKFile was last flushed (or created). 00242 00243 Since at most one thread can flush a MultiPKFile at a time, the value 00244 "numRunning" should only take on the values 0 and 1. Hence, it could be 00245 implemented as a Boolean value. However, we use an integer to represent 00246 it so we can check that the invariant is not violated on return from 00247 flushing the MultiPKFile. 00248 00249 The "numNewEntries" field is an upper bound on the total number of new 00250 entries in all of this MultiPKFile's PKFiles that are not scheduled to 00251 be flushed. Before flushing the VMultiPKFile, the "ToSCache" method 00252 resets "numNewEntries" to zero. After that, new entries could be added, 00253 but those new entries might be flushed also. In that case, the total 00254 number of new entries after the flush completed would be 0, but 00255 "numNewEntries" would be strictly positive. The "numNewEntries" field 00256 is used heuristically by "ToSCache" to avoid flushing the MultiPKFile 00257 if possible. 00258 00259 The set of VPKFiles is represented by a map "tbl: PK -> VPKFile*". If 00260 "(pk, vpkfile)" is an entry in the table, then "pk" has prefix 00261 "prefix", and "vpkfile" is a VPKFile for entries with PK "pk". */ 00262 }; 00263 00264 #endif // _V_MULTI_PK_FILE_H