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:48:27 EDT 2005 by ken@xorian.net 00020 // modified on Wed Feb 23 13:30:02 PST 2000 by mann 00021 // modified on Tue Sep 22 10:18:55 PDT 1998 by heydon 00022 00023 // VPKFile -- A set of cache entries sharing the same primary key (PK). This 00024 // is the volatile version. The cache itself is a map: PK -> VPKFile. 00025 // 00026 // The methods in the "VPKFile" class are monitored. 00027 00028 #ifndef _VPK_FILE_H 00029 #define _VPK_FILE_H 00030 00031 #include <Basics.H> 00032 #include <FS.H> 00033 #include <SRPC.H> 00034 #include <FP.H> 00035 #include <CacheIntf.H> 00036 #include <BitVector.H> 00037 #include <CacheState.H> 00038 #include <Model.H> 00039 #include <PKEpoch.H> 00040 #include <CacheIndex.H> 00041 #include <FV.H> 00042 #include <VestaVal.H> 00043 #include <Generics.H> 00044 00045 #include "IntIntTblLR.H" 00046 #include "CacheEntry.H" 00047 #include "VPKFileChkPt.H" 00048 #include "SPKFile.H" 00049 #include "SMultiPKFileRep.H" 00050 00051 /* A "VPKFile" is a volatile PKFile, an in-memory structure for 00052 storing cache entries with the same primary key (PK). It provides 00053 methods for creating a new "VPKFile", for accessing the names of 00054 all its free variables (the "AllNames" method), for looking up a 00055 cache entry (the "Lookup" method), and for creating and adding new 00056 entries (the "NewEntry", and "AddEntry" methods). 00057 00058 There are separate methods for creating a new cache entry and for adding it 00059 to the "VPKFile". This is because the spec requires the cache server's 00060 "AddEntry" method to create the cache entry, add the entry to the cache's 00061 "cacheLog", and then to add it to the "VPKFile". 00062 00063 Some methods of a "VPKFile" are monitored, and some are not. See the 00064 REQUIRES clause of each method for details. */ 00065 00066 // exception class signalling duplicate names in "VPKFile::NewEntry" 00067 class DuplicateNames { }; 00068 00069 class VPKFile : public SPKFile { 00070 public: 00071 // Mutex for protecting private data fields; this lock is public so that 00072 // it can be acquired by a CacheS object when new entries are added. 00073 Basics::mutex mu; 00074 /* Locking order: 00075 | (forall vf: VPKFile, cache: CacheS :: 00076 | vf.mu < cache.mu) 00077 */ 00078 00079 VPKFile(const FP::Tag& pk, PKFile::Epoch newPKEpoch = 0, FV::Epoch newNamesEpoch = 0) 00080 throw (FS::Failure); 00081 /* REQUIRES Sup(LL) < SELF.mu */ 00082 /* Create a new, empty PK file for primary key "pk". First, this 00083 tries reading the "SPKFile" for "fp" from the stable cache. If 00084 there is one, it initializes this "VPKFile" from that (but with 00085 an empty "oldEntries" table). Otherwise, it simply initializes 00086 this "VPKFile" to a new, empty "VPKFile" for "fp". In that 00087 event, it initializes the "pkEpoch" and "namesEpoch" of the new 00088 "VPKFile" to "newPKEpoch" and "newNamesEpoch". This method is 00089 analogous to the "EmptyVF" function in "SVCache.spec". */ 00090 00091 bool IsEmpty() throw (); 00092 /* REQUIRES Sup(LL) < SELF.mu */ 00093 /* Return "true" iff this "VPKFile" contains no entries. */ 00094 00095 bool IsStableEmpty() const throw () 00096 { return this->isEmpty; } 00097 /* REQUIRES Sup(LL) = SELF.mu */ 00098 /* Return "true" iff this "VPKFile" contains no entries *and* 00099 there are no entries in its corresponding stable PKFile. */ 00100 00101 bool HasNewEntries() const throw () 00102 { return (newUncommon != (CE::List *)NULL) || (newCommon.Size() > 0); } 00103 /* REQUIRES Sup(LL) = SELF.mu */ 00104 /* Returns true iff this VPKFile has any new entries pending in its 00105 "newUncommon" or "newCommon" fields. */ 00106 00107 void SendAllNames(SRPC *srpc, bool debug) 00108 throw (SRPC::failure, PrefixTbl::Overflow); 00109 /* REQUIRES Sup(LL) < SELF.mu */ 00110 /* This method implements the marshalling of the FreeVariables results. 00111 If "debug" is true, it prints the "FreeVariables" return debugging 00112 message. It also calls the "Etp_CacheS_FreeVariables" function with 00113 the correct arguments for performance monitoring. Finally, it marshals 00114 the "isEmpty" value, this VPKFile's free variable names, and its 00115 "namesEpoch". This work is done here (with the lock "SELF.mu" held) 00116 to avoid having to unnecessarily copy the free variable names. */ 00117 00118 CacheIntf::LookupRes Lookup(FV::Epoch id, const FP::List &fps, 00119 /*OUT*/ CacheEntry::Index &ci, /*OUT*/ const VestaVal::T* &value, 00120 /*OUT*/ CacheIntf::LookupOutcome &outcome) throw (FS::Failure); 00121 /* REQUIRES Sup(LL) = SELF.mu */ 00122 /* Lookup an entry in the cache. First, "id" is compared to the epoch for 00123 all free variables for this VPKFile. If it is out of date, 00124 "CacheIntf::FVMismatch" is returned. Otherwise, an attempt is made to 00125 lookup the entry whose free variables have fingerprints "fps". If no 00126 matching entry is found, "CacheIntf::Miss" is returned and "outcome" is 00127 set to "LookupOutcome::AllMisses". In the event of a hit, 00128 "CacheIntf::Hit" is returned, "ci" and "value" are set to the index and 00129 result value of the corresponding cache entry, and "outcome" is set to 00130 the fine-grain outcome used for statistical purposes. Otherwise, 00131 "outcome" is set to the special value "LookupOutcome::NoOutcome". 00132 00133 The search is first performed in the volatile cache, and then in the 00134 stable cache. If there is an error reading the stable cache on disk, 00135 "FS::Failure" is thrown. */ 00136 00137 CE::T* NewEntry(CacheEntry::Index ci, FV::List* names, FP::List *fps, 00138 VestaVal::T* value, Model::T model, CacheEntry::Indices* kids, 00139 /*OUT*/ FP::Tag* &commonFP) 00140 throw (DuplicateNames); 00141 /* REQUIRES Sup(LL) = SELF.mu */ 00142 /* Create and return a new cache entry for this "VPKFile" according to 00143 the arguments (see "CacheS::AddEntry"). The "names" are the names of 00144 the free variables for the new entry, and the "fps" are their 00145 corresponding fingerprints. If "names" contains any names not in the 00146 name sequence for this "VPKFile", they are added to the sequence and 00147 the "VPKFile"'s epoch is incremented. If it contains duplicates, 00148 "DuplicateNames" is thrown. 00149 00150 The "commonFP" OUT parameter is set to NULL if this entry does not 00151 contain all of the VPKFile's common names, or to a pointer to their 00152 combined fingerprint if it does. 00153 00154 The responsibility for freeing storage for the arguments transfers 00155 from the caller to the callee. */ 00156 00157 void AddEntry(const Text* sourceFunc, CE::T *ce, FP::Tag* commonFP, 00158 PKFile::Epoch newPKEpoch = -1) throw (); 00159 /* REQUIRES Sup(LL) = SELF.mu */ 00160 /* Add the new cache entry "ce" to this "VPKFile". The argument 00161 "sourceFunc" names the source location of the function definition 00162 for this new entry. The entry "ce" should have been created by a 00163 previous call to the "NewEntry" method for this "VPKFile". If 00164 "commonFP" is NULL, then this entry is assumed not to have all the 00165 common names for its VPKFile; otherwise, "commonFP" should be the 00166 combined fingerprint of the fingerprints of the values of those 00167 common names. 00168 00169 If "newPKEpoch" is not defaulted, then "this->pkEpoch" is set 00170 to "newPKEpoch". It is a checked run-time error for 00171 "newPKEpoch < this->pkEpoch". */ 00172 00173 FP::Tag *CommonFP(const CE::T& entry) throw () 00174 /* REQUIRES Sup(LL) = SELF.mu */ 00175 /* Return the combined fingerprint of the fingerprints in "entry" for this 00176 VPKFile's common names. It is an unchecked runtime error for "entry" 00177 not to contain all the common names. */ 00178 { return entry.CombineFP(commonNames); } 00179 00180 VPKFileChkPt *CheckPoint() throw (); 00181 /* REQUIRES Sup(LL) < SELF.mu */ 00182 /* Return a newly-allocated checkpoint of this "VPKFile". The 00183 "pkEpoch" of this VPKFile is atomically incremented after the 00184 checkpoint is taken. */ 00185 00186 void DecrPKEpoch() throw () { this->pkEpoch--; } 00187 /* REQUIRES Sup(LL) = SELF.mu */ 00188 00189 void Update(const SPKFile &pf, 00190 const VPKFileChkPt &chkpt, const BitVector *toDelete, 00191 const BitVector *exCommonNames, const BitVector *exUncommonNames, 00192 BitVector *packMask, IntIntTblLR *reMap, bool becameEmpty, 00193 /*INOUT*/ EntryState &state) throw (); 00194 /* REQUIRES sup(LL) = SELF.mu */ 00195 /* Update this VPKFile to be based on the common free variables of 00196 "pf", but not to include the entries in "chkpt". "toDelete" are 00197 the entries to delete (and may be NIL), "exCommonNames", 00198 "exUncommonNames", "packMask", "reMap", and becameEmpty are the 00199 values set by the "SPKFile::Update" method for this PKFile. */ 00200 00201 void UpdateFreeEpoch(int currentEpoch) throw () 00202 /* REQUIRES Sup(LL) = SELF.mu */ 00203 { this->freePKFileEpoch = currentEpoch; } 00204 00205 int GetFreeEpoch() throw() 00206 /* REQUIRES Sup(LL) = SELF.mu */ 00207 { return this->freePKFileEpoch; } 00208 00209 void DeleteOldEntries(int sizeHint, /*INOUT*/ EntryState &state) throw (); 00210 /* REQUIRES sup(LL) = SELF.mu */ 00211 /* Delete all entries from "this->oldEntries", and update "state" to 00212 reflect the old entries so deleted from this VPKFile. */ 00213 00214 void Evict() throw() 00215 /* REQUIRES Sup(LL) = SELF.mu */ 00216 /* Indicate that this VPKFile object has been evicted from the 00217 cache. This should only be called by the cache when all 00218 references to this VPKFile have been removed from the tables in 00219 the cache itself and its owning VMultiPKFile. */ 00220 { this->evicted = true; } 00221 00222 bool Evicted() const throw() 00223 /* REQUIRES Sup(LL) = SELF.mu */ 00224 /* Has this VPKFile been evicted from the cache? */ 00225 { return this->evicted; } 00226 00227 bool ReadyForPurgeWarm(int latestEpoch) const throw(); 00228 /* REQUIRES Sup(LL) = SELF.mu */ 00229 /* Should warm entries be purged from this VPKFile? */ 00230 00231 bool ReadyForEviction(int latestEpoch) const throw(); 00232 /* REQUIRES Sup(LL) = SELF.mu */ 00233 /* Should this VPKFile be evicted from the cache? */ 00234 00235 private: 00236 // dictionary types 00237 typedef Table<FV::T,int>::Default NameMap; 00238 typedef Table<FV::T,int>::Iterator NameMapIter; 00239 00240 // data fields 00241 NameMap nameMap; // table: name -> index in "allNames" list 00242 CE::List *newUncommon; // new entries not containing all "commonNames" 00243 CFPEntryMap newCommon; // new entries containing all "commonNames" 00244 00245 /* The "nameMap" is a table that maps each name in "allNames" to its index 00246 in "allNames". Hence, the set of names in the domain of "nameMap" is 00247 exactly the set of names in "allNames". The map is defined so we have: 00248 00249 nameMap = (allNames[i], i) forall 0 <= i < allNames.len 00250 00251 The "newUncommon" field is a list of the new entries that don't contain 00252 all of this PKFile's common names. The "newCommon" field is a table 00253 (indexed by common finger print) of entries that do contain all of this 00254 PKFile's common names. */ 00255 00256 // Is this a completely empty VPKFile (i.e. has no entries and no 00257 // stable PKFile)? True in either of the following two cases: 00258 00259 // 1. This is a newly created VPKFile that has no on-disk SPKFile 00260 // and has never had any entries added to it. 00261 00262 // 2. This PK's stable PKFile has become empty by having all its 00263 // entries deleted by weeding, and no new entries have been added 00264 // since. 00265 bool isEmpty; 00266 00267 int freePKFileEpoch; // epoch of activity on this PKFile 00268 00269 bool evicted; // Has this VPKFile been evicted from 00270 // the cache? (Needed to avoid a race 00271 // between freeing VPKFiles and adding 00272 // new entries.) 00273 00274 // private methods 00275 void ReadPKFHeaderTail(const FP::Tag &pk) 00276 throw (FS::Failure, SMultiPKFileRep::NotFound); 00277 /* Read the <PKFHeaderTail> of the SPKFile for "pk" into this VPKFile. 00278 "SMultiPKFileRep::NotFound" is thrown if there is no stable MultiPKFile 00279 for "pk". */ 00280 00281 bool IsCommon(const BitVector &nms) throw () 00282 { return (!this->commonNames.IsEmpty() && this->commonNames <= nms); } 00283 /* Returns true iff an entry with names "nms" should be considered 00284 "common", i.e., stored in the "newCommon" table as opposed to the 00285 "newUncommon" list. */ 00286 00287 void PutCommonEntry(CFPEntryMap &tbl, const FP::Tag &commonFP, CE::T *ce) 00288 throw (); 00289 /* REQUIRES Sup(LL) = SELF.mu */ 00290 /* Add the entry "ce" to the table "tbl" under the common fingerprint 00291 "commonFP". */ 00292 00293 CE::T* LookupInList(const CE::List *entries, const FP::List &fps) throw (); 00294 /* REQUIRES Sup(LL) = SELF.mu AND ListLock(*entries) IN LL */ 00295 /* Look for a hit on an entry in the list "entries" where the free 00296 variables have the given fingerprints "fps". If there is a match, 00297 return the resulting cache entry; otherwise, return NULL. The "entries" 00298 are all expected to have the correct combined common fingerprint (if 00299 any); the test for a hit is based solely on the combined uncommon 00300 fingerprint. */ 00301 00302 void DeleteCheckpointedEntries(const VPKFileChkPt &chkpt, 00303 /*INOUT*/ EntryState &state) throw (); 00304 /* REQUIRES Sup(LL) = SELF.mu */ 00305 /* Remove the checkpointed entries in "chkpt" from this VPKFile's 00306 "newCommon" and "newUncommon" bins. This does not changed the set of 00307 entries stored in "chkpt". Update the counts in "state" as cache 00308 entries are removed from this VPKFile. */ 00309 00310 void MoveCommonToUncommon(const BitVector &oldCommon) throw (); 00311 /* REQUIRES newCommon.Size() > 0 */ 00312 /* Move the entries in the "newCommon" table to the "newUncommon" list, 00313 OR'ing the "oldCommon" vector into each entry's "uncommonNames". */ 00314 00315 void MoveCommonListToUncommon(CE::List *head, const BitVector &oldCommon) 00316 throw (); 00317 /* REQUIRES SELF.mu IN LL */ 00318 /* REQUIRES head != (CE::List *)NULL */ 00319 /* Move the common entries in "head" to the "newUncommon" list, XOR'ing 00320 the "oldCommon" vector into each entry's "uncommonNames". */ 00321 00322 void UpdateUncommonList(const Text* sourceFunc, 00323 /*INOUT*/ BitVector *packMask, /*INOUT*/ IntIntTblLR *reMap, 00324 bool unlazyTag) throw (); 00325 /* REQUIRES sup(LL) = SELF.mu */ 00326 /* Walk over the entries in "newUncommon", packing each entry according to 00327 "packMask" and "reMap" (if non-NULL), and unlazying the uncommon 00328 fingerprint iff "unlazyTag" is true. Each entry is added to either the 00329 "newCommon" table or the "newUncommon" list based on whether it contains 00330 all the common names or not. 00331 00332 Note: The VPKFile's "commonNames" should already have been updated 00333 before this method is called. However, since the entry's 00334 "uncommonNames" are compared to this VPKFile's "commonNames" before the 00335 "uncommonNames" have been packed, the "commonNames" should not have been 00336 packed before this call. */ 00337 00338 void RecordCIsFromList(const CE::List *ents, /*INOUT*/ IntIntTbl& keep) 00339 const throw (); 00340 /* REQUIRES ListLock(*ents) IN LL */ 00341 /* Add the CIs of all entries in "ents" to the table "keep". (Actually, 00342 the table records pairs of the form "(ci, 0)"). */ 00343 00344 void RecordCIsFromTbl(const CFPEntryMap& tbl, /*INOUT*/ IntIntTbl& keep) 00345 const throw (); 00346 /* Add the CIs of all entries in "tbl" to the table "keep". (Actually, 00347 the table records pairs of the form "(ci, 0)"). */ 00348 00349 void CopyByCIs(const CFPEntryMap& source, /*INOUT*/ IntIntTbl& cis, 00350 /*INOUT*/ EntryState &state) throw (); 00351 /* REQUIRES SELF.mu IN LL */ 00352 /* Add any entry in "source" whose CI is in the domain of "cis" to the 00353 table "this->oldEntries". "cis" is an INOUT parameter because this 00354 function has benevolent side-effects on it (it increments the range 00355 value of each CI selected from the table). */ 00356 00357 void CycleDeletedNamesInList(CE::List *curr, 00358 /*INOUT*/ BitVector &packMask, /*INOUT*/ IntIntTblLR &reMap) throw (); 00359 /* REQUIRES sup(LL) = SELF.mu */ 00360 /* For each entry in the list "curr" (all of which are assumed to be 00361 ``uncommon''), see if the entry contains any names not named in 00362 "packMask". If so, cycle such names to the end of the "this->allNames" 00363 list, update the "this->nameMap" appropriately, and update "packMask", 00364 "reMap", and the entries themselves to correspond to the new order of 00365 the names. */ 00366 00367 // make copy constructor inaccessible to clients 00368 VPKFile(const VPKFile&); 00369 }; 00370 00371 #endif // _VPK_FILE_H