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:30:48 EDT 2005 by ken@xorian.net 00020 // modified on Wed Feb 23 17:09:29 PST 2000 by mann 00021 // modified on Sat Aug 22 15:47:18 PDT 1998 by heydon 00022 00023 #ifndef _EMPTY_PK_LOG_H 00024 #define _EMPTY_PK_LOG_H 00025 00026 #include <Basics.H> 00027 #include <Table.H> 00028 #include <VestaLog.H> 00029 #include <Recovery.H> 00030 #include <FP.H> 00031 #include <CacheIntf.H> 00032 #include <PKEpoch.H> 00033 00034 /* Description: 00035 00036 An "EmptyPKLog" is a log of "(pk, pkEpoch)" pairs for recording which 00037 PKFile's have become empty and their corresponding "pkEpoch" values. 00038 In the on-disk log, the successive "pkEpoch" values associated with any 00039 given PK appear in strictly monotonically increasing order. 00040 00041 An "EmptyPKLog" also keeps an in-memory table corresponding to the on-disk 00042 pairs; when the log contains multiple pairs with the same "pk", the table 00043 stores the *maximum* "pkEpoch" associated with that "pk". 00044 00045 Usage: 00046 00047 The EmptyPKLog is read during recovery. Its purpose is to prevent cache 00048 entries in the cache log from being recovered that belonged to PKFiles that 00049 have since been deleted. If a cache entry's "pkEpoch" is less than the 00050 corresponding "pkEpoch" in the EmptyPKLog, or if it is less than the 00051 "pkEpoch" of the corresponding SPKFile in the stable cache, the cache entry 00052 can be ignored. The same technique is used to delete cache entries from the 00053 cache log when the cache log is cleaned. 00054 00055 When a new VPKFile is created and no corresponding SPKFile is found for it, 00056 the empty PK table is consulted to see if the new VPKFile should be given a 00057 non-zero "pkEpoch" (this is necessary because there may still be entries in 00058 the cache log for "pk" that would be erroneously recovered if the VPKFile's 00059 epoch was initialized to 0). 00060 00061 When all of the entries are deleted from a PKFile, a new "(pk, pkEpoch)" 00062 pair is written to the EmptyPKLog and added to the table for that PKFile. 00063 00064 Note: 00065 00066 A pair is written to the log whenever a PKFile becomes empty, but cache 00067 entries might subsequently be created for that PKFile. Hence, the PKFiles 00068 corresponding to the "pk" values in the EmptyPKLog are not guaranteed to be 00069 empty. Rather, the log contains the "pkEpoch" values corresponding to 00070 PKFiles that were once known to be empty. The stable cache must still be 00071 consulted to confirm that the PKFile is actually empty. 00072 */ 00073 00074 class EmptyPKLog { 00075 public: 00076 // dictionary types 00077 typedef Table<FP::Tag,PKFile::Epoch>::Default PKEpochTbl; 00078 typedef Table<FP::Tag,PKFile::Epoch>::Default PKEpochIter; 00079 00080 EmptyPKLog(Basics::mutex *mu, CacheIntf::DebugLevel, bool readonly = false) 00081 throw (VestaLog::Error); 00082 /* REQUIRES Sup(LL) = CacheS.mu */ 00083 /* Allocate the private log and open it in the ``recovering'' state. The 00084 corresponding empty PK table is initially empty. The mutex "mu" should 00085 be the centralized lock "CacheS.mu". If "readonly" is true, the log 00086 is opened in read-only mode. */ 00087 00088 ~EmptyPKLog() throw () { this->log->close(); } 00089 /* Close the private log. */ 00090 00091 // Recovery methods ------------------------------------------------------- 00092 00093 /* These methods require "CacheS.mu" because the intention is for the 00094 client to acquire the mutex at the start of recovery and release it 00095 when recovery is complete. */ 00096 00097 bool EndOfFile() throw (VestaLog::Error) { return this->rd->eof(); } 00098 /* REQUIRES Sup(LL) = CacheS.mu && ``private log in recovering state'' */ 00099 /* Return true iff the log is at end of file. */ 00100 00101 bool NextLog() throw (VestaLog::Error) { return this->log->nextLog(); } 00102 /* REQUIRES Sup(LL) = CacheS.mu && ``private log in recovering state'' */ 00103 /* Return true iff there is another log to recover. */ 00104 00105 void Read(/*OUT*/ FP::Tag &pk, /*OUT*/ PKFile::Epoch &pkEpoch) 00106 throw (VestaLog::Error, VestaLog::Eof); 00107 /* REQUIRES Sup(LL) = CacheS.mu && ``private log in recovering state'' */ 00108 /* Read the next entry in the log, setting "pk" and "pkEpoch" 00109 to the values read. The pair is also added to this EmptyPKLog's 00110 in-memory table. */ 00111 00112 void EndRecovery() throw (VestaLog::Error) 00113 { this->rd = (RecoveryReader *)NULL; this->log->loggingBegin(); } 00114 /* REQUIRES Sup(LL) = CacheS.mu && ``private log in recovering state'' */ 00115 /* Switch the private log from the ``recovering'' state to the 00116 ``ready'' state. */ 00117 00118 // Checkpoint methods ----------------------------------------------------- 00119 00120 void CheckpointBegin() 00121 throw (FS::Failure, VestaLog::Error); 00122 /* REQUIRES Sup(LL) < CacheS.mu && ``private log in ready state'' */ 00123 /* Write an empty checkpoint for the log, and move the corresponding 00124 in-memory table to be oldEmptyPKTable. When the checkpoint is 00125 complete, the "CheckpointEnd" method below should be called to commit 00126 it, which will delete oldEmptyPKTable. In the interim, other threads 00127 can still append new entries to the log, and lookups will look both in 00128 emptyPKTable and oldEmptyPKTable. */ 00129 00130 void CheckpointEnd() throw (VestaLog::Error); 00131 /* REQUIRES Sup(LL) < CacheS.mu && ``private log in ready state'' */ 00132 /* Atomically commit the current checkpoint. */ 00133 00134 // Writing methods -------------------------------------------------------- 00135 00136 void Write(const FP::Tag &pk, PKFile::Epoch pkEpoch) 00137 throw (VestaLog::Error); 00138 /* REQUIRES Sup(LL) < CacheS.mu && ``private log in ready state'' */ 00139 /* Atomically append the pair "(pk, pkEpoch)" to the private log. The pair 00140 is also added to the empty PK table. The "pkEpoch" is required to be 00141 at least as large as any existing entry for this "pk"; if "pkEpoch" 00142 is equal to the existing entry, this method is a no-op. */ 00143 00144 // Empty PK Table methods ------------------------------------------------- 00145 00146 bool GetEpoch0(const FP::Tag &pk, /*OUT*/ PKFile::Epoch &pkEpoch) throw (); 00147 /* REQUIRES Sup(LL) = CacheS.mu */ 00148 /* If the empty PK table includes an entry for "pk", set "pkEpoch" to the 00149 corresponding epoch and return "true". Otherwise, leave "pkEpoch" 00150 unchanged and return "false". */ 00151 00152 bool GetEpoch(const FP::Tag &pk, /*OUT*/ PKFile::Epoch &pkEpoch) throw (); 00153 /* REQUIRES Sup(LL) < CacheS.mu */ 00154 /* Like "GetEpoch0" above, but with a different locking level. */ 00155 00156 private: 00157 // read-only after init 00158 CacheIntf::DebugLevel debug; // cache server's debugging level 00159 00160 // data fields 00161 Basics::mutex *mu; // actually points to "CacheS.mu" 00162 VestaLog *log; 00163 RecoveryReader *rd; // only non-NULL during recovery 00164 PKEpochTbl *oldEmptyPKTbl; 00165 PKEpochTbl *emptyPKTbl; 00166 00167 /* Invariant: "oldEmptyPKTbl + emptyPKTbl" (where + is overlay, 00168 as in the Vesta SDL) is the set of pairs "(pk, pkEpoch)" such 00169 that: 00170 00171 (pk, pkEpoch) \in log /\ 00172 pkEpoch = max( (pk, pkEpoch') \in log : pkEpoch' ) 00173 00174 A similar invariant is true for oldEmptyPKTbl and the portion 00175 of the log preceding the start of the most recent checkpoint. 00176 */ 00177 }; 00178 00179 #endif // _EMPTY_PK_LOG_H