00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <time.h>
00029 #include <Basics.H>
00030 #include <Table.H>
00031 #include <Generics.H>
00032 #include <SRPC.H>
00033
00034
00035 #include <FP.H>
00036
00037
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
00049 #include <Debug.H>
00050
00051
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
00087
00088 {
00089 char first;
00090 while ((first=ins.peek()) != EOF) {
00091 if (first == CommentChar) {
00092 if (echoComments) {
00093
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
00102 ins.ignore(10000, Newline);
00103 }
00104 } else if (first == Newline) {
00105
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;
00119 Model::T model = 0;
00120 CacheEntry::Indices cis;
00121 bool done = false;
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, CacheEntry::Indices& cis) throw ()
00140 {
00141 int ix = 0, sz = 10;
00142 int *ra = NEW_PTRFREE_ARRAY(int, sz);
00143
00144
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();
00158 (void) ins.unsetf(ios::skipws);
00159
00160
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, BitVector &cis) throw ()
00168 {
00169
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();
00180 (void) ins.unsetf(ios::skipws);
00181 }
00182
00183 void ReadPfxs(istream &ins, PKPrefixTbl &pfxs) throw ()
00184 {
00185
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();
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, cis);
00203 bool res = client.RenewLeases(cis);
00204 }
00205
00206 void StartMark(WeederC& client) throw (SRPC::failure)
00207 {
00208 int newLogVer;
00209 client.StartMark( 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, cis);
00236 ReadPfxs(ins, 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 CompactFV::List& names) throw (SRPC::failure)
00246 {
00247 bool isEmpty;
00248 return client.FreeVariables(pk, names, 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;
00255 VestaVal::T cacheVal;
00256 return client.Lookup(pk, epoch, fps,
00257 ci, 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
00267 Model::T model = 0;
00268 CacheEntry::Indices kids;
00269
00270
00271 CacheEntry::Index ci;
00272 return client.AddEntry(pk, types, allNames, fps,
00273 value, model, kids, SourceFunc, 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
00285 (void) ins.setf(ios::skipws);
00286 while (ins.peek() != Newline) {
00287 ins >> buff;
00288 FV2::T *nm = NEW_CONSTR(FV2::T, (buff));
00289
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();
00297
00298
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
00305 Text firstArc(name->remlo());
00306 types[i] = firstArc[0];
00307 }
00308
00309
00310 FP::List fps(allNames.len);
00311 for (i = 0; ins.peek() != Newline; i++) {
00312 ins >> buff;
00313 if (i > fps.len) {
00314
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;
00326 (void) ins.get();
00327
00328
00329 ins >> buff;
00330 VestaVal::T value(buff);
00331 (void) ins.unsetf(ios::skipws);
00332
00333 CacheIntf::LookupRes res;
00334 while (true) {
00335
00336 CompactFV::List names;
00337 FV::Epoch epoch = FreeVariables(client, pk, names);
00338
00339
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(), j)) {
00346
00347 fps2.fp[i] = fps.fp[j];
00348 } else {
00349
00350 fps2.fp[i] = FP::Tag("");
00351 }
00352 }
00353
00354
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
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\"", false);
00368 case CacheIntf::BadAddEntryArgs:
00369 ErrMsg("bad arguments to \"AddEntry\"", false);
00370 }
00371 }
00372 }
00373
00374 void RunTest(istream& ins, bool echoComments) throw (SRPC::failure)
00375 {
00376 CacheC cacheC( CacheIntf::All);
00377 DebugC debugC( CacheIntf::All);
00378 WeederC weederC( CacheIntf::All);
00379 while (SkipWhite(ins, echoComments)) {
00380
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
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
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
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 }