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

TestCache.C

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 Fri Apr 22 22:31:33 EDT 2005 by ken@xorian.net  
00020 //      modified on Sat Feb 12 17:33:35 PST 2000 by mann  
00021 //      modified on Thu Feb 10 12:14:10 PST 2000 by heydon 
00022 //      modified on Sat Jan 29 14:30:58 PST 2000 by heydon
00023 
00024 // TestCache -- make calls on the cache server according to a file describing
00025 //   function arguments and results.
00026 
00027 // base libs
00028 #include <time.h>
00029 #include <Basics.H>
00030 #include <Table.H>
00031 #include <Generics.H>
00032 #include <SRPC.H>
00033 
00034 // vesta/fp
00035 #include <FP.H>
00036 
00037 // cache-common
00038 #include <CacheArgs.H>
00039 #include <CacheIntf.H>
00040 #include <PKPrefix.H>
00041 #include <Model.H>
00042 #include <CacheIndex.H>
00043 #include <FV.H>
00044 #include <VestaVal.H>
00045 #include <CompactFV.H>
00046 #include <FV2.H>
00047 
00048 // cache-debug
00049 #include <Debug.H>
00050 
00051 // cache-client
00052 #include "CacheC.H"
00053 #include "DebugC.H"
00054 #include "WeederC.H"
00055 
00056 using std::ios;
00057 using std::istream;
00058 using std::ifstream;
00059 using std::cout;
00060 using std::cin;
00061 using std::cerr;
00062 using std::endl;
00063 using std::ws;
00064 
00065 const char CommentChar = '%';
00066 const char Newline = '\n';
00067 const int  MaxWordLen = 80;
00068 const char *CheckpointOnlyCmd = "CheckpointOnly";
00069 const char *CheckpointCmd = "Checkpoint";
00070 const char *PauseCmd = "Pause";
00071 const char *RenewCmd = "RenewLeases";
00072 const char *WeedCmd = "Weed";
00073 
00074 static char buff[MaxWordLen];
00075 
00076 typedef TextIntTbl NameMap;
00077 
00078 void ErrMsg(char *msg, bool halt = true) throw ()
00079 {
00080     cerr << "**" << endl << "** Error: " << msg << endl << "**" <<endl<<endl;
00081     cerr.flush();
00082     if (halt) exit(2);
00083 }
00084 
00085 bool SkipWhite(istream& ins, bool echoComments)
00086 /* Returns true if there are pending commands to read; false if EOF is reached
00087    after skipping whitespace and comments. */
00088 {
00089     char first;
00090     while ((first=ins.peek()) != EOF) {
00091         if (first == CommentChar) {
00092             if (echoComments) {
00093                 // echo this line to "cout"
00094                 int c;
00095                 do {
00096                     c = ins.get();
00097                     cout << (char)c;
00098                 } while (c != EOF && c != Newline);
00099                 cout.flush();
00100             } else {
00101                 // ignore the rest of the line
00102                 ins.ignore(10000, Newline);
00103             }
00104         } else if (first == Newline) {
00105             // skip empty line
00106             ins.ignore(1);
00107         } else {
00108             return true;
00109         }
00110     }
00111     return false;
00112 }
00113 
00114 void Checkpoint(istream& ins, CacheC& client) throw (SRPC::failure)
00115 {
00116     if (ins.get() != Newline)
00117         ErrMsg("unexpected chars after Checkpoint command");
00118     FP::Tag pkgVersion;      // leave empty
00119     Model::T model = 0;      // default value
00120     CacheEntry::Indices cis; // leave empty
00121     bool done = false;       // default value
00122     client.Checkpoint(pkgVersion, model, cis, done);
00123 }
00124 
00125 void FlushAll(DebugC& debug) throw (SRPC::failure)
00126 {
00127     debug.FlushAll();
00128 }
00129 
00130 void Pause(istream& ins) throw ()
00131 {
00132     if (ins.get() != Newline)
00133         ErrMsg("unexpected chars after Pause command");
00134     cerr << "Hit <Enter> to continue.";
00135     (void)cin.get();
00136     cout << endl;
00137 }
00138 
00139 void ReadCIs(istream& ins, /*OUT*/ CacheEntry::Indices& cis) throw ()
00140 {
00141     int ix = 0, sz = 10;
00142     int *ra = NEW_PTRFREE_ARRAY(int, sz);
00143 
00144     // read CI's
00145     (void) ins.setf(ios::skipws);
00146     while (ins.peek() != Newline) {
00147         if (ix == sz) {
00148             sz *= 2;
00149             int *ra2 = NEW_PTRFREE_ARRAY(int, sz);
00150             for (int i = 0; i < ix; i++) ra2[i] = ra[i];
00151             delete ra;
00152             ra = ra2;
00153         }
00154         ins >> ra[ix];
00155         ix++;
00156     }
00157     (void) ins.get(); // skip newline
00158     (void) ins.unsetf(ios::skipws);
00159 
00160     // copy to result
00161     cis.len = ix;
00162     cis.index = NEW_PTRFREE_ARRAY(CacheEntry::Index, ix);
00163     for (int i = 0; i < ix; i++) cis.index[i] = ra[i];
00164     delete ra;
00165 }
00166 
00167 void ReadBits(istream& ins, /*OUT*/ BitVector &cis) throw ()
00168 {
00169     // read CI's
00170     cis.ResetAll();
00171     (void) ins.setf(ios::skipws);
00172     while (ins.peek() != Newline) {
00173         int ix;
00174         ins >> ix;
00175         if (cis.Set(ix)) {
00176             ErrMsg("duplicate cache index");
00177         }
00178     }
00179     (void) ins.get(); // skip newline
00180     (void) ins.unsetf(ios::skipws);
00181 }
00182 
00183 void ReadPfxs(istream &ins, /*OUT*/ PKPrefixTbl &pfxs) throw ()
00184 {
00185     // read prefixes into sequence
00186     (void) ins.setf(ios::skipws);
00187     while (ins.peek() != Newline) {
00188         ins >> buff;
00189         FP::Tag pk(buff);
00190         PKPrefix::T pfx(pk);
00191         (void)pfxs.Put(pfx, (char)true);
00192     }
00193     (void) ins.get(); // skip newline
00194     (void) ins.unsetf(ios::skipws);
00195 }
00196 
00197 void RenewLeases(istream& ins, CacheC& client) throw (SRPC::failure)
00198 {
00199     if (ins.get() != Newline)
00200         ErrMsg("unexpected chars after RenewLeases command");
00201     CacheEntry::Indices cis;
00202     ReadCIs(ins, /*OUT*/ cis);
00203     bool res = client.RenewLeases(cis);
00204 }
00205 
00206 void StartMark(WeederC& client) throw (SRPC::failure)
00207 {
00208     int newLogVer;
00209     client.StartMark(/*OUT*/ newLogVer);
00210 }
00211 
00212 void SetHitFilter(WeederC& client, const BitVector &cis) throw (SRPC::failure)
00213 {
00214     client.SetHitFilter(cis);
00215 }
00216 
00217 void ResumeLeaseExp(WeederC& client) throw (SRPC::failure)
00218 {
00219     client.ResumeLeaseExp();
00220 }
00221 
00222 void EndMark(WeederC& client, const BitVector &cis,
00223   const PKPrefixTbl &pfxs) throw (SRPC::failure)
00224 {
00225     int chkptVer = client.EndMark(cis, pfxs);
00226 }
00227 
00228 void Weed(istream &ins, WeederC &client) throw (SRPC::failure)
00229 {
00230     if (ins.get() != Newline)
00231         ErrMsg("unexpected chars after Weed command");
00232 
00233     BitVector cis;
00234     PKPrefixTbl pfxs;
00235     ReadBits(ins, /*OUT*/ cis);
00236     ReadPfxs(ins, /*OUT*/ pfxs);
00237 
00238     StartMark(client);
00239     SetHitFilter(client, cis);
00240     ResumeLeaseExp(client);
00241     EndMark(client, cis, pfxs);
00242 }
00243 
00244 FV::Epoch FreeVariables(CacheC& client, const FP::Tag& pk,
00245   /*OUT*/ CompactFV::List& names) throw (SRPC::failure)
00246 {
00247     bool isEmpty; // unused
00248     return client.FreeVariables(pk, /*OUT*/ names, /*OUT*/ isEmpty);
00249 }
00250 
00251 CacheIntf::LookupRes Lookup(CacheC& client, const FP::Tag& pk,
00252   FV::Epoch epoch, const FP::List& fps) throw (SRPC::failure)
00253 {
00254     CacheEntry::Index ci; // unused
00255     VestaVal::T cacheVal; // unused
00256     return client.Lookup(pk, epoch, fps,
00257      /*OUT*/ ci, /*OUT*/ cacheVal);
00258 }
00259 
00260 static const Text SourceFunc("TestCache source function location");
00261 
00262 CacheIntf::AddEntryRes AddEntry(CacheC& client, const FP::Tag& pk,
00263   const char* types, const FV2::ListApp& allNames, const FP::List& fps,
00264   const VestaVal::T& value) throw (SRPC::failure)
00265 {
00266     // prepare args
00267     Model::T model = 0;       // default value
00268     CacheEntry::Indices kids; // empty kids list
00269 
00270     // make call
00271     CacheEntry::Index ci;
00272     return client.AddEntry(pk, types, allNames, fps,
00273       value, model, kids, SourceFunc, /*OUT*/ ci);
00274 }
00275 
00276 void CallCache(istream& ins, CacheC& client, const FP::Tag& pk)
00277   throw (SRPC::failure)
00278 {
00279     if (ins.get() != Newline)
00280         ErrMsg("chars after primary key text");
00281     FV2::ListApp allNames;
00282     NameMap nameMap;
00283 
00284     // read free variables
00285     (void) ins.setf(ios::skipws);
00286     while (ins.peek() != Newline) {
00287         ins >> buff;
00288         FV2::T *nm = NEW_CONSTR(FV2::T, (buff));
00289         // prepend type if none was supplied
00290         if (nm->getlo().Length() != 1) {
00291             nm->addlo(Text("N"));
00292         }
00293         int i = allNames.Append(nm);
00294         (void) nameMap.Put(nm->ToText(), i);
00295     }
00296     (void) ins.get(); // skip newline
00297 
00298     // allocate types
00299     char *types = NEW_PTRFREE_ARRAY(char, allNames.len);
00300     int i;
00301     for (i = 0; i < allNames.len; i++) {
00302         FV2::T *name = allNames.name[i];
00303         assert(name->size() > 1 && name->getlo().Length() == 1);
00304         // strip type from name
00305         Text firstArc(name->remlo());
00306         types[i] = firstArc[0];
00307     }
00308 
00309     // read fingerprints
00310     FP::List fps(allNames.len);
00311     for (i = 0; ins.peek() != Newline; i++) {
00312         ins >> buff;
00313         if (i > fps.len) {
00314             // expand array if necessary
00315             int newLen = fps.len * 2;
00316             FP::Tag *newFP = NEW_PTRFREE_ARRAY(FP::Tag, newLen);
00317             for (int j = 0; j > fps.len; j++) {
00318                 newFP[j] = fps.fp[j];
00319             }
00320             fps.len = newLen;
00321             fps.fp = newFP;
00322         }
00323         fps.fp[i] = FP::Tag(buff);
00324     }
00325     fps.len = i; // set final length
00326     (void) ins.get(); // skip newline
00327 
00328     // read value
00329     ins >> buff;
00330     VestaVal::T value(buff);
00331     (void) ins.unsetf(ios::skipws);
00332 
00333     CacheIntf::LookupRes res;
00334     while (true) {
00335         // make "FreeVariables" call
00336         CompactFV::List names;
00337         FV::Epoch epoch = FreeVariables(client, pk, /*OUT*/ names);
00338 
00339         // fill in new "fps" list for call to "Lookup"
00340         FP::List fps2(names.num);
00341         for (int i = 0; i < names.num; i++) {
00342             FV2::T *fv2 = names.tbl.Get(names.idx[i]);
00343             fv2->addlo(Text(names.types[i]));
00344             int j;
00345             if (nameMap.Get(fv2->ToText(), /*OUT*/ j)) {
00346                 // we have supplied an FP for this one
00347                 fps2.fp[i] = fps.fp[j];
00348             } else {
00349                 // use default FP
00350                 fps2.fp[i] = FP::Tag("");
00351             }
00352         }
00353 
00354         // make "Lookup" call
00355         res = Lookup(client, pk, epoch, fps2);
00356         if (res != CacheIntf::FVMismatch) break;
00357     }
00358     if (res == CacheIntf::BadLookupArgs)
00359         ErrMsg("bad arguments to \"Lookup\"");
00360 
00361     // make "AddEntry" call (if necessary)
00362     if (res == CacheIntf::Miss) {
00363         CacheIntf::AddEntryRes res =
00364           AddEntry(client, pk, types, allNames, fps, value);
00365         switch (res) {
00366           case CacheIntf::NoLease:
00367             ErrMsg("missing lease in \"AddEntry\"", /*halt=*/ false);
00368           case CacheIntf::BadAddEntryArgs:
00369             ErrMsg("bad arguments to \"AddEntry\"", /*halt=*/ false);
00370         }
00371     }
00372 }
00373 
00374 void RunTest(istream& ins, bool echoComments) throw (SRPC::failure)
00375 {
00376     CacheC cacheC(/*debug=*/ CacheIntf::All);
00377     DebugC debugC(/*debug=*/ CacheIntf::All);
00378     WeederC weederC(/*debug=*/ CacheIntf::All);
00379     while (SkipWhite(ins, echoComments)) {
00380         // read first word
00381         ins >> ws >> buff;
00382         assert(strlen(buff) >= 1);
00383 
00384         if (strcmp(buff, CheckpointOnlyCmd) == 0) {
00385             Checkpoint(ins, cacheC);
00386         } else if (strcmp(buff, CheckpointCmd) == 0) {
00387             Checkpoint(ins, cacheC);
00388             FlushAll(debugC);
00389         } else if (strcmp(buff, PauseCmd) == 0) {
00390             Pause(ins);
00391         } else if (strcmp(buff, RenewCmd) == 0) {
00392             RenewLeases(ins, cacheC);
00393         } else if (strcmp(buff, WeedCmd) == 0) {
00394             Weed(ins, weederC);
00395         } else {
00396             FP::Tag pk(buff);
00397             CallCache(ins, cacheC, pk);
00398         }
00399     }
00400 }
00401 
00402 void Exit(char *msg) throw ()
00403 {
00404     cerr << "Error: " << msg << endl;
00405     cerr << "Syntax: TestCache [ -comments ] [ file ]" << endl;
00406     cerr.flush();
00407     exit(1);
00408 }
00409 
00410 int main(int argc, char *argv[]) 
00411 {
00412     bool echoComments = false;
00413     istream *input = &(cin);
00414 
00415     // process command-line
00416     for (int arg = 1; arg < argc; arg++) {
00417         if (*(argv[arg]) == '-') {
00418             if (CacheArgs::StartsWith(argv[arg], "-comments")) {
00419                 echoComments = true;
00420             } else {
00421                 Exit("unrecognized command-line switch");
00422             }
00423         } else if (arg + 1 == argc) {
00424           if(!FS::IsFile(argv[arg]))
00425             {
00426               Text errMsg = "\"";
00427               errMsg += argv[arg];
00428               errMsg += "\" doesn't exist or isn't a file";
00429               Exit(errMsg.chars());
00430             }
00431             // open file
00432           input = NEW_CONSTR(ifstream, (argv[arg]));
00433           if (input->fail()) {
00434             Text errMsg("unable to open file \"");
00435             errMsg += argv[arg]; errMsg += "\" for reading";
00436             ErrMsg(errMsg.chars());
00437           }
00438         } else {
00439             Exit("too many arguments");
00440         }
00441     }
00442 
00443     // run test
00444     try {
00445         RunTest(*input, echoComments);
00446     }
00447     catch (SRPC::failure f) {
00448         cerr << "SRPC failure: " << f.msg << endl;
00449         exit(2);
00450     }
00451     return 0;
00452 }

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