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 Thu Aug 5 00:19:51 EDT 2004 by ken@xorian.net 00020 // modified on Tue May 4 11:16:46 PDT 1999 by heydon 00021 00022 // SMultiPKFile -- operations for reading/writing MultiPKFile's on disk 00023 00024 /* The cache entries for a single primary key (PK) are grouped together on the 00025 disk in what is called a PKFile. It would be too expensive to use a single 00026 disk file for each PKFile, so PKFiles are grouped together into so-called 00027 MultiPKFiles on the disk. 00028 00029 An SMultiPKFile exports operations for reading/writing MultiPKFiles on 00030 disk in the stable cache. 00031 00032 The start of a MultiPKFile has an index for locating the PKFile within the 00033 MultiPKFile for a particular PK. The methods of this interface are used for 00034 opening MultiPKFiles, and for reading and writing their indices. See the 00035 PKFile interface for reading and writing individual PKFile's. 00036 00037 The mapping from a PK to its MultiPKFile is implemented by the file system. 00038 The MultiPKFile for a given PK is formed from a prefix of the PK. The size 00039 used for the prefix determines the {\def granularity} of the MultiPKFile's, 00040 and is defined by the "PKPrefix" interface. The implementation is allowed 00041 to change the PKPrefix granularity, but it must of course support the 00042 ability to find MultiPKFile's of older granularity, and to write files of 00043 the latest granularity from older ones when the granularity changes. The 00044 ability to support MultiPKFiles of differing granularity is currently not 00045 supported. */ 00046 00047 #ifndef _S_MULTI_PK_FILE_H 00048 #define _S_MULTI_PK_FILE_H 00049 00050 #include <Basics.H> 00051 #include <FS.H> 00052 #include <Table.H> 00053 #include <VestaLog.H> 00054 #include <AtomicFile.H> 00055 #include <FP.H> 00056 #include <BitVector.H> 00057 #include <CacheState.H> 00058 #include <PKPrefix.H> 00059 00060 #include "EmptyPKLog.H" 00061 #include "SMultiPKFileRep.H" 00062 #include "VPKFile.H" 00063 00064 class SMultiPKFile { 00065 public: 00066 // dictionary types 00067 typedef Table<FP::Tag,VPKFile*>::Default VPKFileMap; 00068 typedef Table<FP::Tag,VPKFile*>::Iterator VPKFileIter; 00069 00070 // ChkPtTbl: FP::Tag -> (VPKFileChkPt *) 00071 typedef Table<FP::Tag,VPKFileChkPt*>::Default ChkPtTbl; 00072 typedef Table<FP::Tag,VPKFileChkPt*>::Iterator ChkPtIter; 00073 00074 static void OpenRead(const PKPrefix::T &pfx, /*OUT*/ std::ifstream &ifs) 00075 throw (SMultiPKFileRep::NotFound, FS::Failure); 00076 /* Open the MultiPKFile with prefix "pfx" for reading, and set "ifs" to 00077 an input file stream on it. If there is no such MultiPKFile, raise 00078 "SMultiPKFileRep::NotFound". 00079 00080 The name of the MultiPKFile for "pfx" is determined from the values of 00081 the "[CacheServer]/MetaDataRoot", "[CacheServer]/MetaDataDir", and 00082 "[CacheServer]/SCacheDir" configuration variables, from the "pfx" 00083 itself, and from the "granularity" at which the latest MultiPKFile 00084 for "pfx" was written. */ 00085 00086 static std::streampos SeekToPKFile(std::ifstream &ifs, const FP::Tag &pk, 00087 /*OUT*/ int &version) 00088 throw (SMultiPKFileRep::NotFound, FS::Failure); 00089 /* REQUIRES ifs.tellg() == ``start of <MultiPKFile>'' */ 00090 /* Assuming "ifs" is positioned at the start of the MultiPKFile "ifs", 00091 seek to the position in that file where the PKFile for "pk" begins 00092 if such a PKFile exists, set "version" to the version number found 00093 in the MultiPKFile <Header>, and return that position; raise 00094 "SMultiPKFileRep::NotFound" otherwise. */ 00095 00096 static bool ChkptForRewrite(VPKFileMap& vpkFiles, 00097 const BitVector *toDelete, 00098 /*OUT*/ ChkPtTbl &vpkChkptTbl) throw(); 00099 /* REQUIRES (forall vf: VPKFile :: Sup(LL) < vf.mu) */ 00100 /* In preparation for rewriting a MultiPKFile, checkpoint in 00101 memory all of its VPKFiles to capture what is to be written. 00102 This is neceessary because new entries may be added in parallel 00103 with re-writng. "vpkFiles" is a table of "VPKFiles" stored in 00104 the cache; this table must be a *superset* of the "SPKFiles" 00105 stored in the corresponding MultiPKFile on disk. If "toDelete" 00106 is non-NULL, it points to a bit vector whose set bits 00107 correspond to the indices of cache entries to delete from the 00108 cache. 00109 00110 "vpkChkptTbl" is filled with VPKFileChkPt objects, one per 00111 VPKFile in "vpkFiles". The return value indicates whether a 00112 re-write is neccessary. If toDelete is NULL and there are no 00113 new entries in any of the VPKFiles, the result will be false 00114 (indicating that there is nothing that needs to be written to 00115 disk). */ 00116 00117 static bool PrepareForRewrite(const PKPrefix::T &pfx, 00118 std::ifstream &ifs, 00119 /*OUT*/ SMultiPKFileRep::Header *&hdr) 00120 throw (FS::Failure, FS::EndOfFile); 00121 /* Perform the initial steps of re-writing the MultiPKFile with 00122 prefix "pfx". 00123 00124 The return value indicates if the stable MultiPKFile already 00125 exists on disk. If it does, it will be opened with "ifs" and 00126 its header and header entries will be read into "hdr". If it 00127 does not, "hdr" will be set to a new empty 00128 SMultiPKFileRep::Header. 00129 00130 This step is separated from Rewrite (below) to allow the cache 00131 to create VPKFiles for all PKFiles in the stable copy of the 00132 MultiPKFile. Doing so avoids a race between rewriting and 00133 client requests. */ 00134 00135 static void Rewrite(const PKPrefix::T &pfx, 00136 00137 // From PrepareForRewrite above 00138 bool mpkFileExists, std::ifstream &ifs, 00139 SMultiPKFileRep::Header *hdr, 00140 00141 // In-memory representations to be updated 00142 VPKFileMap &vpkFiles, 00143 00144 // Changes to be committed 00145 ChkPtTbl &vpkChkptTbl, 00146 00147 const BitVector *toDelete, EmptyPKLog *emptyPKLog, 00148 /*INOUT*/ EntryState & state) 00149 throw (FS::Failure, FS::EndOfFile, VestaLog::Error); 00150 /* REQUIRES (forall vf: VPKFile :: Sup(LL) < vf.mu) */ 00151 /* Rewrite the MultiPKFile with prefix "pfx". 00152 00153 "mpkFileExists" is the return value of PrepareForRewrite 00154 (above). "ifs" and "hdr" are also prepared by the same 00155 function. 00156 00157 "vpkFiles" is a table of "VPKFiles" stored in the cache under 00158 PK's with prefix "pfx"; this table must be a *superset* of the 00159 "SPKFiles" stored in the corresponding MultiPKFile on 00160 disk. "vpkChkptTbl" is a table of checkpoints of the VPKFiles 00161 in "vpkFiles", generated by calling 00162 SMultiPKFile::ChkptForRewrite (above). If "toDelete" is 00163 non-NULL, it points to a bit vector whose set bits correspond 00164 to the indices of cache entries to delete from the cache. 00165 00166 This is the only method that reads and writes MultiPKFiles on disk. 00167 It is unmonitored; that is, its correctness requires that it is only 00168 called by one thread at a time. */ 00169 00170 private: 00171 // lookup private methods ------------------------------------------------- 00172 00173 static std::streampos SeekInListV1(std::ifstream &ifs, 00174 SMultiPKFileRep::UShort numEntries, 00175 const FP::Tag &pk) 00176 throw (SMultiPKFileRep::NotFound, FS::EndOfFile, FS::Failure); 00177 /* REQUIRES ifs.tellg() == ``start of <SeqHeader>'' */ 00178 /* Return the absolute offset for "pk" in the file "ifs", assumming "ifs" 00179 is positioned at the start of a <SeqHeader>, version 1. Throws 00180 "SMultiPKFileRep::NotFound" if there is no entry in the header matching 00181 "pk", "FS::EndOfFile" in the event of premature end-of-file, and 00182 "FS::Failure" in the event of any other file error. */ 00183 00184 static std::streampos SeekInSortedListV1(std::ifstream &ifs, 00185 SMultiPKFileRep::UShort numEntries, 00186 const FP::Tag &pk) 00187 throw (SMultiPKFileRep::NotFound, FS::EndOfFile, FS::Failure); 00188 /* REQUIRES ifs.tellg() == ``start of <SeqHeader>'' */ 00189 /* Return the absolute offset for "pk" in the file "ifs", assumming "ifs" 00190 is positioned at the start of a sorted <SeqHeader>, version 1. Throws 00191 "SMultiPKFileRep::NotFound" if there is no entry in the header matching 00192 "pk", "FS::EndOfFile" in the event of premature end-of-file, and 00193 "FS::Failure" in the event of any other file error. */ 00194 00195 // rewrite private methods ------------------------------------------------ 00196 00197 static SMultiPKFileRep::Header* ReadHeader(const PKPrefix::T &pfx, 00198 bool readEntries, 00199 std::ifstream &ifs) 00200 throw (FS::Failure, FS::EndOfFile); 00201 /* Read the <Header> of the MultiPKFile for "pfx" from "ifs", and if 00202 "readEntries" is "true", fill in its "pkTbl" with the <HeaderEntry>'s. 00203 Even if "readEntries" is true, the PKFiles themselves are not read. 00204 Throw "FS::Failure" for any other I/O error. */ 00205 00206 static Text Name(const PKPrefix::T &pfx, int granBits) throw (); 00207 /* Return the pathname for the MultiPKFile of granularity "granBits" 00208 with prefix "p". */ 00209 00210 static Text FullName(const PKPrefix::T &pfx) throw (); 00211 /* Return the complete filename of the SMultiPKFile for prefix "pfx". */ 00212 00213 static void OpenAtomicWrite(const PKPrefix::T &pfx, 00214 /*OUT*/ AtomicFile &ofs) throw (FS::Failure); 00215 /* Open the stream "ofs" for writing on the MultiPKFile for "pfx" at the 00216 current granularity. This opens the file under a different name; the 00217 "close" method on the "ofs" can then be used to atomically rename the 00218 file to its correct name. */ 00219 00220 static void DeleteFile(const PKPrefix::T &pfx) throw (FS::Failure); 00221 /* Delete the SMultiPKFile for prefix "pfx". */ 00222 00223 static void MakeDirs(const Text &name) throw (FS::Failure); 00224 /* Create any necessary directories along the path named by the file 00225 "name". If one of the directories cannot be created, throw 00226 "FS::Failure". */ 00227 00228 static void PauseDeletionThread() throw (); 00229 /* Print debugging information to standard output and pause the calling 00230 thread for the number of seconds specified in the global configuration 00231 variable "Config_WeedPauseDur". */ 00232 }; 00233 00234 #endif // _S_MULTI_PK_FILE_H