Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

EmptyPKLog.H

Go to the documentation of this file.
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

Generated on Mon May 8 00:48:34 2006 for Vesta by  doxygen 1.4.2