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

ApplyCache.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 // File: ApplyCache.C
00020 
00021 #include <Basics.H>
00022 #include <FP.H>
00023 #include <Model.H>
00024 #include <FV.H>
00025 #include <CacheIndex.H>
00026 #include <CacheC.H>
00027 #include "ApplyCache.H"
00028 #include "Expr.H"
00029 #include "Val.H"
00030 #include "Pickle.H"
00031 #include "Err.H"
00032 #include "PrimRunTool.H"
00033 #include "Debug.H"
00034 #include "ThreadData.H"
00035 #include <Table.H>
00036 
00037 using std::ostream;
00038 using std::cerr;
00039 using std::endl;
00040 using Basics::OBufStream;
00041 
00042 // KCS, 2001-12-6: Changed both evaluatorRunToolVersion and
00043 // evaluatorFunctionVersion, as integer values are now fingerprinted
00044 // as 32-bit values.
00045 
00046 // KCS, 2002-8-20: Changed evaluatorFunctionVersion due to a fix to
00047 // dependency analysis in several primitive functions for boundary
00048 // cases with empty lists and bindings.
00049 
00050 // KCS, 2002-11-6: Changed evaluatorFunctionVersion due to a bug fix
00051 // to dependency collection code which iadvertently munged dependency
00052 // paths.  This bug *seemed* to only add additional bogus secondary
00053 // dependencies, but it's safer to update evaluatorFunctionVersion.
00054 
00055 // KCS, 2003-2-11: Changed both evaluatorRunToolVersion and
00056 // evaluatorFunctionVersion, as the pickle version has changed for
00057 // the network byte order conversion.
00058 
00059 // KCS, 2004-04-05: Changed evaluatorFunctionVersion due to
00060 // dependency analysis bug fixes in CollectModel.
00061 
00062 // STV&KCS, 2004-12-25: Changed evaluatorRunToolVersion after adding
00063 // "dumped_core" to _run_tool result.
00064 
00065 // Runtool call version:
00066 const char *evaluatorRunToolVersion = "Fri Feb 11 13:30:46 2005";
00067 const FP::Tag evaluatorRunToolVersionTag(evaluatorRunToolVersion);
00068 
00069 // Function call version:
00070 const char *evaluatorFunctionVersion = "Fri Feb 11 13:30:46 2005";
00071 const FP::Tag evaluatorFunctionVersionTag(evaluatorFunctionVersion);
00072 
00073 // The number of addentry calls to the cache:
00074 static int addEntryCount = 0;
00075 
00076 // The mutex protects all the orphans in all the workers and the
00077 // addEntryCount.
00078 static Basics::mutex frontierMu;
00079 
00080 // The mutex protects the variables lastRenewed and
00081 // renewLease_failure.
00082 static Basics::mutex leaseMu;
00083 static time_t lastRenewed;
00084 static bool renewLease_failure = false;
00085 
00086 // A table to keep from running identical tools in parallel.
00087 // This checks for a PK and waits on a condition if that PK
00088 // is already in progress.
00089 static Basics::mutex runToolTableMu;
00090 class rtt_cond {
00091         Basics::cond cond;
00092         int count; // number of in progress _run_tool()
00093                    // calls with this PK
00094         bool dec_and_del() {
00095                 assert(count > 0);
00096                 if(--count == 0) {
00097                         delete this;
00098                         return false;
00099                 } else {
00100                         return true;
00101                 }
00102         };
00103     public:
00104         rtt_cond() { count = 1; };
00105         void wait() {
00106                 count++;
00107                 cond.wait(runToolTableMu);
00108                 (void) dec_and_del();
00109         };
00110         void wake() {
00111                 if(dec_and_del()) {
00112                         cond.broadcast();
00113                 }
00114         };
00115         
00116 };
00117 static Table<FP::Tag, rtt_cond *>::Default runToolTable;
00118 
00119 
00120 void Tags(const CompactFV::List& names, const Context& c, 
00121           /*OUT*/ FP::List& tags) {
00122   // Used for cache lookup:
00123   int len = names.num;
00124   if (len > 0) {
00125     tags.len = len;
00126     tags.fp = NEW_PTRFREE_ARRAY(FP::Tag, len);
00127     int size = names.tbl.NumArcs();
00128     Val *vals = NEW_ARRAY(Val, size);
00129     int i;
00130     for (i = 0; i < size; i++) { vals[i] = NULL; }
00131     for (i = 0; i < len; i++)   {
00132       short int idx = names.idx[i];
00133       PathKind pkind = (PathKind)names.types[i];
00134       tags.fp[i] = LookupPath(idx, pkind, names.tbl, c, vals)->FingerPrint();
00135     }
00136   } else {
00137     tags.len = 0;
00138     tags.fp = NULL;
00139   }
00140   return;
00141 }
00142 
00143 bool NamesTagsPickle(Val val, bool cutoff, const Context& inPKArgs,
00144                      /*OUT*/ char*& types, /*OUT*/ FV2::List& names,
00145                      /*OUT*/ FP::List& tags, /*OUT*/ VestaVal::T& vval) {
00146   /* Create all the stuff needed for an AddEntry call. */
00147 
00148   // We now create the secondary key of the entry. Since some dependencies
00149   // on the function arguments have already been encoded in the primary key,
00150   // they are redundant, and therefore removed.
00151   DPaths *sk = NEW_CONSTR(DPaths, (val->SizeOfDPS()));
00152   sk->Merge(val->dps);
00153   ValueDpnd(val, sk);
00154   DepPathTbl::TIter iter(sk);
00155   DepPathTbl::KVPairPtr ptr;
00156   Context work = inPKArgs;
00157   Text id;
00158   while (!work.Null()) {
00159     id = work.Pop()->name;
00160     iter.Reset();
00161     while (iter.Next(ptr)) {
00162       if (ptr->key.content->path->getlo() == id)
00163         sk->Delete(ptr->key, ptr, false);
00164     }
00165   }
00166   sk->Resize();
00167   // Set names and tags:
00168   int len = sk->Size();
00169   names.len = len;
00170   tags.len = len;
00171   if (len > 0) {
00172     types = NEW_PTRFREE_ARRAY(char, len);    
00173     names.name = NEW_ARRAY(FV2::TPtr, len);
00174     tags.fp = NEW_PTRFREE_ARRAY(FP::Tag, len);
00175     iter.Reset();
00176     int index = 0;
00177     while (iter.Next(ptr)) {
00178       types[index] = (char)ptr->key.content->pKind;
00179       names.name[index] = ptr->key.content->path;
00180       if (ptr->val->vKind != FpVK && ptr->key.content->pKind == ExprPK) {
00181         if (ptr->val->vKind == ClosureVK)
00182           tags.fp[index++] = ((ClosureVC*)ptr->val)->FingerPrintExpr();
00183         else {
00184           assert(ptr->val->vKind == ModelVK);
00185           tags.fp[index++] = ((ModelVC*)ptr->val)->FingerPrintFile();
00186         }
00187       }
00188       else
00189         tags.fp[index++] = ptr->val->FingerPrint();
00190     }
00191   }
00192   // Pickle the value:
00193   if (cutoff) ModelCutOff(val);
00194   return Pickle(val, vval);
00195 }
00196 
00197 static void CheckLeases() {
00198   leaseMu.lock();    
00199   bool expired = (time(NULL) - lastRenewed) > leaseDuration;
00200   bool failed = renewLease_failure;
00201   leaseMu.unlock();
00202   if (expired) {
00203     throw(Evaluator::failure("Leases timed out. Start over.", true));
00204   } else if(failed) {
00205     throw(Evaluator::failure("Lease renewal failed.", true));
00206   }
00207 }
00208 
00209 void CollectKids(CacheEntry::IndicesApp* orphanCIs, int kidsIndex,
00210                  CacheEntry::Indices& kids) {
00211   CheckLeases();
00212   kids.len = orphanCIs->len - kidsIndex;
00213   kids.index = orphanCIs->index + kidsIndex;
00214 }
00215     
00216 void UpdateOrphans(CacheEntry::IndicesApp* orphanCIs, int kidsIndex,
00217                    CacheEntry::Index ci) {
00218   frontierMu.lock();
00219   orphanCIs->len = kidsIndex;
00220   orphanCIs->Append(ci);
00221   frontierMu.unlock();  
00222 }
00223 
00224 void Checkpoint() {
00225   CheckLeases();
00226   frontierMu.lock();        
00227   addEntryCount++;
00228   if ((addEntryCount & 0x3f) == 0) {
00229     CacheEntry::IndicesApp orphanCIs;
00230     ThreadData::mu.lock();
00231     ThreadData* cur = ThreadData::head;
00232     while (cur) {
00233       assert(cur->orphanCIs != 0);
00234       for (int i = 0; i < cur->orphanCIs->len; i++) {
00235         orphanCIs.Append(cur->orphanCIs->index[i]);
00236       }
00237       cur = cur->next;
00238     }
00239     ThreadData::mu.unlock();
00240     theCache->Checkpoint(topModelRoot->fptag, topModelSid, orphanCIs, false);
00241   }
00242   frontierMu.unlock();
00243 }
00244 
00245 void FreeNamesTags(CompactFV::List& names, FP::List& tags) {
00246   // Free names and tags after cache lookup:
00247   names.tbl = PrefixTbl();
00248   tags.len = 0;
00249   tags.fp = NULL;
00250 }
00251 
00252 // General function application:
00253 Context BindApplicationArgs(ClosureVC *clos, ArgList actuals, const Context& c) {
00254   Context result, closCon = clos->con;
00255   Exprs forms = clos->func->args->elems;
00256   Exprs acts = actuals->elems;
00257   int fSize = forms.size();
00258   int aSize = acts.size();
00259   Expr fe;
00260   AssignEC *formal;
00261   Text name;
00262   int i;
00263 
00264   if (aSize > fSize + 1) {
00265     outputMu.lock();    
00266     actuals->EError("Too many actual parameters:");
00267     outputMu.unlock();        
00268     return conEmpty;
00269   }
00270   for (i = 0; i < aSize; i++) { // Actuals to formals
00271     if (i == fSize)
00272       name = nameDot;
00273     else {
00274       fe = forms.get(i);
00275       if (fe->kind == NameEK)
00276         name = ((Name)fe)->id;
00277       else if (fe->kind == AssignEK)
00278         name = ((AssignEC*)fe)->lhs->id;
00279       else {
00280         outputMu.lock();        
00281         actuals->EError("Bad parameter list. It is neither actual nor default: `");
00282         ErrorExpr(fe);
00283         ErrorDetail("'.");
00284         outputMu.unlock();      
00285         return conEmpty;
00286       }
00287     }
00288     PushToContext(name, acts.get(i), c, result);
00289   }
00290   for (i = aSize; i < fSize; i++) { // Default rest of formals
00291     fe = forms.get(i);
00292     if (fe->kind == AssignEK) {
00293       formal = (AssignEC*)fe;
00294       PushToContext(formal->lhs->id, formal->rhs, closCon, result);
00295     }
00296     else {
00297       outputMu.lock();          
00298       actuals->EError("Bad parameter list. Must have default: `");
00299       ErrorExpr(fe);
00300       ErrorDetail("'.");
00301       outputMu.unlock();          
00302       return conEmpty;
00303     }
00304   }
00305   if (aSize <= fSize) {
00306     Name eDot = NEW_CONSTR(NameEC, (nameDot, actuals->loc));
00307     PushToContext(nameDot, eDot, c, result);
00308   }
00309   return result;
00310 }
00311 
00312 Val ApplicationFromCache(ClosureVC* clos, const Context& argsCon, SrcLoc *loc) {
00313   FP::Tag pk(evaluatorFunctionVersionTag);
00314   CompactFV::List fvNames;
00315   FV2::List entryNames;
00316   FP::List tags;
00317   CacheEntry::Index cIndex;
00318   VestaVal::T cVal;
00319   CacheIntf::LookupRes cResult = CacheIntf::Miss;
00320   Model::T model = clos->func->body->loc->shortId;
00321   Val result;
00322 
00323   IncCounter(&appCallCounter);
00324   Context evalCon = argsCon.Append(clos->con);
00325 
00326   ostream *traceRes = ThreadDataGet()->traceRes;
00327   // Evaluate in the nocaching cases:
00328   if (cacheOption != 3 || clos->func->noCache) {
00329     // Normal function caching is disabled.
00330     if (traceRes) *traceRes << ": disabled\n";
00331     result = clos->func->body->Eval(evalCon);
00332     if (cacheOption < 2) return result;
00333     return FuncDpnd(result, clos, argsCon);
00334   }
00335 
00336   // Compute the primary key:
00337   // The pk consists of the fingerprints of the closure body, the argumnets
00338   // that either is specified by pk pragma or evaluates to simple values.
00339   pk.Extend(clos->FingerPrintExpr());
00340   Context work = argsCon;
00341   (void)work.Pop();   // Do not put the dot into pk.
00342   int last = clos->func->args->elems.size();
00343   Bit64 inPKs = clos->func->args->inPKs;
00344   Context inPKArgs;
00345   while (!work.Null()) {
00346     Assoc elem = work.Pop();
00347     if (inPKs & ((Bit64)1 << --last)) {
00348       // Add this argument into pk.
00349       pk.Extend(elem->FingerPrint());
00350       inPKArgs.Push(elem);
00351     }
00352     else {
00353       switch (elem->val->vKind) {
00354       case BooleanVK: case IntegerVK: case PrimitiveVK:
00355       case TextVK: case ErrorVK:
00356         pk.Extend(elem->FingerPrint());
00357         inPKArgs.Push(elem);
00358         break;
00359       case ClosureVK:
00360         {
00361           FP::Tag tag(elem->name);
00362           tag.Extend(((ClosureVC*)elem->val)->FingerPrintExpr());
00363           pk.Extend(tag);
00364           break;
00365         }
00366       case ModelVK:
00367         {
00368           FP::Tag tag(elem->name);
00369           tag.Extend(((ModelVC*)elem->val)->FingerPrintFile());
00370           pk.Extend(tag);
00371           break;
00372         }
00373       case FpVK:
00374         assert(false);
00375       default:
00376         break;
00377       }
00378     }
00379   }
00380   // Evaluate with caching:
00381   ThreadData *thdata = ThreadDataGet();
00382   CacheEntry::IndicesApp* orphanCIs = thdata->orphanCIs;  
00383   try {
00384     while (true) {
00385       bool noEntry;
00386       FV::Epoch epoch = theCache->FreeVariables(pk, /*OUT*/ fvNames, /*OUT*/ noEntry);
00387       if (noEntry)
00388         cResult = CacheIntf::Miss;
00389       else {
00390         Tags(fvNames, evalCon, /*OUT*/ tags);
00391         cResult = theCache->Lookup(pk, epoch, tags, /*OUT*/ cIndex, /*OUT*/ cVal);
00392       }
00393       FreeNamesTags(fvNames, tags);
00394       if (cResult == CacheIntf::Hit) {
00395         if (Unpickle(cVal, evalCon, result)) {
00396           if (traceRes) {
00397             *traceRes << ": hit (ci=" << cIndex << ")\n";
00398           }
00399           IncCounter(&appHitCounter);
00400           UpdateOrphans(orphanCIs, orphanCIs->len, cIndex);
00401           /****
00402           while (!inPKArgs.Null()) {
00403             Assoc elem = inPKArgs.Pop();
00404             result->AddToDPS(NEW_CONSTR(DepPath,(elem->name, NormPK)), 
00405                              elem->val);
00406           }
00407           ****/
00408           return FuncDpnd(result, clos, argsCon);
00409         }
00410         outputMu.lock();
00411         OBufStream l_msg;
00412         l_msg << "ApplicationFromCache: Cache hit but bad cache data." << endl << endl
00413               << "\tpk = " << pk << endl
00414               << "\tci = " << cIndex << endl << endl
00415               << "Evaluate as cache miss." << endl;
00416         Error(Text(l_msg.str()), loc);
00417         outputMu.unlock();      
00418         cResult = CacheIntf::Miss;
00419       }
00420       if (cResult == CacheIntf::Miss) {
00421         if (traceRes) *traceRes << ": miss\n";
00422         int kidsIndex = orphanCIs->len;
00423         result = clos->func->body->Eval(evalCon);
00424         if (!noAddEntry) {
00425           // Create a new cache entry:
00426           char *types;
00427           if (NamesTagsPickle(result, false, inPKArgs, /*OUT*/ types, /*OUT*/ entryNames,
00428                               /*OUT*/ tags, /*OUT*/ cVal)) {
00429             CacheEntry::Indices kids;
00430             CollectKids(orphanCIs, kidsIndex, kids);
00431             Text pksource(clos->func->loc->file);
00432             pksource += "/" + clos->func->name;
00433             pksource += "(), line " + IntToText(clos->func->loc->line);
00434             pksource += ", col " + IntToText(clos->func->loc->character);
00435             // Add the entry, capturing the result of the call.
00436             CacheIntf::AddEntryRes ae_res =
00437               theCache->AddEntry(pk, types, entryNames, tags, cVal, model,
00438                                  kids, pksource, /*OUT*/ cIndex);
00439             // If the AddEntry fails, die with an error.
00440             if(ae_res != CacheIntf::EntryAdded)
00441               {
00442                 outputMu.lock();        
00443                 Error(Text("AddEntry failed: ")+
00444                       CacheIntf::AddEntryResName(ae_res)+"\n"
00445                       "This may be an evaluator bug.  "
00446                       "Please report it.\n",
00447                       loc);
00448                 outputMu.unlock();
00449                 if (traceRes) *traceRes << endl;
00450                 throw(Evaluator::failure(Text("AddEntry failed (may be an "
00451                                               "evaluator bug)"),
00452                                          false));
00453               }
00454             UpdateOrphans(orphanCIs, kidsIndex, cIndex);
00455             Checkpoint();
00456             if (traceRes) {
00457               *traceRes << "  " << thdata->funcCallDepth << ". "
00458                 << clos->func->args->loc->file << ": "
00459                 << clos->func->name << "(): add (ci=" << cIndex << ")\n";
00460             }
00461           }
00462         }
00463         return FuncDpnd(result, clos, argsCon);
00464       } 
00465       if (cResult != CacheIntf::FVMismatch) {
00466         if (traceRes) *traceRes << ": mismatch\n";
00467         OBufStream err_msg;
00468         err_msg << "ApplicationFromCache got bad result: "
00469                 << CacheIntf::LookupResName(cResult) << endl
00470                 << "\tpk = " << pk << endl
00471                 << "\tFV epoch = " << epoch << endl
00472                 << "\ttags.len = " << tags.len << endl
00473                 << "This may be an evaluator bug.  Please report it." << endl;
00474         outputMu.lock();
00475         Error(Text(err_msg.str()), loc);
00476         outputMu.unlock();      
00477         result = NEW(ErrorVC);
00478         return result;
00479       }
00480     }
00481   } catch (PrefixTbl::Overflow) {
00482     outputMu.lock();        
00483     Error(Text("Internal limits exceeded: PrefixTbl overflow\n"),
00484           loc);
00485     cerr << "Caching function \"" << clos->func->name
00486          << "\" defined at:" << endl << endl
00487          << "  " << clos->func->loc->file
00488          << ", line " << clos->func->loc->line
00489          << ", char " << clos->func->loc->character
00490          << endl << endl
00491          << Text("This usually means that there are too many free variables "
00492                  "in the secondary key of the function being cached.  This "
00493                  "can often be alleviated by marking more arguments with "
00494                  "the /**pk**/ pragma.  (Fixing this will also reduce the CPU "
00495                  "load of your evaluator and cache server, and improve "
00496                  "build performance.)").WordWrap()
00497          << endl << endl;
00498     // This is a fatal error.  Exit and dump core.
00499     abort();
00500     outputMu.unlock();
00501   } catch (SRPC::failure f) {
00502     outputMu.lock();        
00503     Error(Text("ApplicationFromCache: SRPC failure (")
00504              + IntToText(f.r) + "): " + f.msg + ".\n",
00505           loc);
00506     outputMu.unlock();        
00507     if (traceRes) *traceRes << endl;
00508     throw(Evaluator::failure(Text("Cache server is possibly down"), false));
00509   }
00510   //return result; // not reached
00511 }
00512 
00513 Val ApplyFunction(ClosureVC* clos, ApplyEC *ae, const Context& c) {
00514   ArgList args = ae->args;
00515   Context argsCon;
00516 
00517   argsCon = BindApplicationArgs(clos, args, c);
00518 
00519   ThreadData *thdata = ThreadDataGet();
00520   ostream *traceRes = thdata->traceRes;
00521   thdata->funcCallDepth++;
00522   if (traceRes) {
00523     *traceRes << "  " << thdata->funcCallDepth << ". "
00524       << clos->func->args->loc->file << ": "
00525       << clos->func->name << "()";
00526   }
00527   if (argsCon == conEmpty) {
00528     // when argsCon is correct, it can not be empty since `dot' must be
00529     // defined in argsCon.
00530     outputMu.lock();    
00531     ErrorDetail("\n  Formal list is ");
00532     ErrorExpr(clos->func->args);
00533     ErrorDetail("\n  Actual list is ");
00534     ErrorExpr(args);
00535     ErrorDetail("\n");
00536     outputMu.unlock();        
00537     if (traceRes) *traceRes << ": badargs\n";
00538     return NEW(ErrorVC);
00539   }
00540 
00541   // Evaluate:
00542   Val result = ApplicationFromCache(clos, argsCon, ae->loc);
00543   thdata->funcCallDepth--;
00544   return result;
00545 }
00546   
00547 // Model application:
00548 Val NormalModelFromCache(ModelVC *fun, const Context& evalCon, SrcLoc *loc) {
00549   Model::T model = fun->content->sid;
00550   FP::Tag pk(evaluatorFunctionVersionTag);
00551   CompactFV::List fvNames;
00552   FV2::List entryNames;
00553   FP::List tags;
00554   CacheEntry::Index cIndex;
00555   VestaVal::T cVal;
00556   CacheIntf::LookupRes cResult = CacheIntf::Miss;
00557   Val result;
00558 
00559   ThreadData *thdata = ThreadDataGet();
00560   ostream *traceRes = thdata->traceRes;
00561   
00562   // Evaluate as nocache if the model imports a local model:
00563   if (((ModelEC*)fun->content->model)->ImportLocalModel()) {
00564     result = ((ModelEC*)fun->content->model)->block->Eval(evalCon);
00565     ModelCutOff(result);
00566     return result;
00567   }
00568   
00569   IncCounter(&nModelCallCounter);
00570   // Record this call if traced:
00571   if (traceRes) {
00572     *traceRes << "  " << thdata->funcCallDepth << ". " << fun->content->name;
00573   }
00574 
00575   // Compute the primary key:
00576   pk.Extend(fun->FingerPrintFile());
00577 
00578   // Evaluate:
00579   CacheEntry::IndicesApp* orphanCIs = ThreadDataGet()->orphanCIs;  
00580   try {
00581     while (true) {
00582       bool noEntry;
00583       FV::Epoch epoch = theCache->FreeVariables(pk, /*OUT*/ fvNames, /*OUT*/ noEntry);
00584       if (noEntry)
00585         cResult = CacheIntf::Miss;
00586       else {
00587         Tags(fvNames, evalCon, /*OUT*/ tags);
00588         cResult = theCache->Lookup(pk, epoch, tags, /*OUT*/ cIndex, /*OUT*/ cVal);
00589       }
00590       FreeNamesTags(fvNames, tags);
00591       if (cResult == CacheIntf::Hit) {
00592         if (Unpickle(cVal, evalCon, result)) {
00593           if (traceRes) {
00594             *traceRes << ": hit (ci=" << cIndex << ")\n";
00595           }
00596           IncCounter(&nModelHitCounter);
00597           UpdateOrphans(orphanCIs, orphanCIs->len, cIndex);
00598           return result;
00599         }
00600         outputMu.lock();
00601         OBufStream l_msg;
00602         l_msg << "NormalModelFromCache: Cache hit but bad cache data." << endl << endl
00603               << "\tpk = " << pk << endl
00604               << "\tci = " << cIndex << endl << endl
00605               << "Evaluate as cache miss." << endl; 
00606         Error(Text(l_msg.str()), loc);  
00607         outputMu.unlock();      
00608         throw(Evaluator::failure(Text("Bad cache data"), false));
00609       }
00610       if (cResult == CacheIntf::Miss) {
00611         if (traceRes) *traceRes << ": miss\n";
00612         int kidsIndex = orphanCIs->len;
00613         result = ((ModelEC*)fun->content->model)->block->Eval(evalCon);
00614         if (!noAddEntry) {
00615           // Create the normal-case model entry:
00616           char *types;
00617           if (NamesTagsPickle(result, true, conEmpty, /*OUT*/ types, /*OUT*/ entryNames,
00618                               /*OUT*/ tags, /*OUT*/ cVal)) {
00619             CacheEntry::Indices kids;
00620             CollectKids(orphanCIs, kidsIndex, kids);
00621             Text pksource(fun->content->name);
00622             pksource += "() (normal)";
00623             // Add the entry, capturing the result of the call.
00624             CacheIntf::AddEntryRes ae_res =
00625               theCache->AddEntry(pk, types, entryNames, tags, cVal, model,
00626                                  kids, pksource, /*OUT*/ cIndex);
00627             // If the AddEntry fails, die with an error.
00628             if(ae_res != CacheIntf::EntryAdded)
00629               {
00630                 outputMu.lock();        
00631                 Error(Text("AddEntry failed: ")+
00632                       CacheIntf::AddEntryResName(ae_res)+"\n"
00633                       "This may be an evaluator bug.  "
00634                       "Please report it.\n",
00635                       loc);
00636                 outputMu.unlock();
00637                 if (traceRes) *traceRes << endl;
00638                 throw(Evaluator::failure(Text("AddEntry failed (may be an "
00639                                               "evaluator bug)"),
00640                                          false));
00641               }
00642             UpdateOrphans(orphanCIs, kidsIndex, cIndex);
00643             Checkpoint();
00644             if (traceRes) {
00645               *traceRes << "  " << thdata->funcCallDepth << ". " << fun->content->name
00646                         << ": add (ci=" << cIndex << ")\n";
00647             }
00648           }
00649         }
00650         return result;
00651       }
00652       if (cResult != CacheIntf::FVMismatch) {
00653         if (traceRes) *traceRes << ": mismatch\n";
00654         OBufStream err_msg;
00655         err_msg << "NormalModelFromCache got bad result: "
00656                 << CacheIntf::LookupResName(cResult) << endl
00657                 << "\tpk = " << pk << endl
00658                 << "\tFV epoch = " << epoch << endl
00659                 << "\ttags.len = " << tags.len << endl
00660                 << "This may be an evaluator bug.  Please report it." << endl;
00661         outputMu.lock();        
00662         Error(Text(err_msg.str()), loc);
00663         outputMu.unlock();      
00664         result = NEW(ErrorVC);
00665         return result;
00666       }
00667     }
00668   } catch (PrefixTbl::Overflow) {
00669     outputMu.lock();        
00670     Error(Text("Internal limits exceeded: PrefixTbl overflow\n"),
00671           loc);
00672     cerr << "Caching model (normal):" << endl << endl
00673          << "  " << fun->content->name
00674          << endl << endl
00675          << Text("This usually means that there are too many free variables "
00676                  "in the secondary key of the function being cached.  For "
00677                  "models, this may mean too much work is being done in a "
00678                  "single model file.  Try splitting up the work of this "
00679                  "model file into several separate model files each doing "
00680                  "a smaller amount of work.  (Fixing this will also reduce "
00681                  "the CPU load of your evaluator and cache server, and "
00682                  "improve build performance.)").WordWrap()
00683          << endl << endl;
00684     // This is a fatal error.  Exit and dump core.
00685     abort();
00686     outputMu.unlock();
00687   } catch (SRPC::failure f) {
00688     outputMu.lock();        
00689     fun->VError(Text("NormalModelFromCache: SRPC failure (")
00690                 + IntToText(f.r) + "): " + f.msg + ".\n");
00691     outputMu.unlock();        
00692     if (traceRes) *traceRes << endl;
00693     throw(Evaluator::failure(Text("Cache server is possibly down"), false));
00694   }
00695 }
00696 
00697 Val ModelFromCache(ModelVC* fun, const Context& argsCon, SrcLoc *loc) {
00698   Context evalCon;
00699   Model::T model = fun->content->sid;
00700   FP::Tag pk(evaluatorFunctionVersionTag);
00701   CompactFV::List fvNames;
00702   FV2::List entryNames;
00703   FP::List tags;
00704   CacheEntry::Index cIndex;
00705   VestaVal::T cVal;
00706   CacheIntf::LookupRes cResult = CacheIntf::Miss;
00707   Val result;
00708 
00709   IncCounter(&sModelCallCounter);
00710   ThreadData *thdata = ThreadDataGet();
00711   ostream *traceRes = thdata->traceRes;
00712   
00713   // Evaluate in the nocache cases:
00714   if (cacheOption < 2) {
00715     if (traceRes) *traceRes << ": disabled\n";
00716     Val fun1 = ((ModelVC*)fun)->Force();
00717     if (fun1->vKind == ModelVK) {
00718       ModelEC *modelExpr = (ModelEC*)((ModelVC*)fun1)->content->model;
00719       evalCon = argsCon.Append(((ModelVC*)fun1)->content->c);
00720       return modelExpr->block->Eval(evalCon);
00721     }
00722     outputMu.lock();        
00723     Error("Trying to apply a model that failed to parse: `", loc);
00724     ErrorVal(fun1);
00725     ErrorDetail("'.\n");
00726     outputMu.unlock();        
00727     result = NEW(ErrorVC);
00728     return result;
00729   }
00730   
00731   // Compute the primary key:
00732   pk.Extend(fun->FingerPrint());
00733 
00734   // Evaluate with caching:
00735   CacheEntry::IndicesApp* orphanCIs = ThreadDataGet()->orphanCIs;  
00736   try {
00737     while (true) {
00738       bool noEntry;
00739       FV::Epoch epoch = theCache->FreeVariables(pk, /*OUT*/ fvNames, /*OUT*/ noEntry);
00740       if (noEntry)
00741         cResult = CacheIntf::Miss;
00742       else {
00743         Tags(fvNames, argsCon, /*OUT*/ tags);
00744         cResult = theCache->Lookup(pk, epoch, tags, /*OUT*/ cIndex, /*OUT*/ cVal);
00745       }
00746       FreeNamesTags(fvNames, tags);
00747       if (cResult == CacheIntf::Hit) {
00748         if (Unpickle(cVal, argsCon, result)) {
00749           if (traceRes) {
00750             *traceRes << ": hit (ci=" << cIndex << ")\n";
00751           }
00752           IncCounter(&sModelHitCounter);
00753           UpdateOrphans(orphanCIs, orphanCIs->len, cIndex);
00754           return ModelDpnd(result, fun, argsCon);
00755         }
00756         outputMu.lock();        
00757         OBufStream l_msg;
00758         l_msg << "ModelFromCache: Cache hit but bad cache data." << endl << endl
00759               << "\tpk = " << pk << endl
00760               << "\tci = " << cIndex << endl << endl
00761               << "Evaluate as cache miss." << endl;
00762         Error(Text(l_msg.str()), loc);
00763         outputMu.unlock();      
00764         throw(Evaluator::failure(Text("Bad cache data"), false));
00765       }
00766       if (cResult == CacheIntf::Miss) {
00767         if (traceRes) *traceRes << ": miss\n";
00768         int kidsIndex = orphanCIs->len;
00769         Val fun1 = ((ModelVC*)fun)->Force();
00770         if (fun1->vKind == ModelVK) {
00771           evalCon = argsCon.Append(((ModelVC*)fun1)->content->c);
00772           result = NormalModelFromCache(fun, evalCon, loc);
00773           if (noAddEntry) {
00774             ModelCutOff(result);
00775           }
00776           else {
00777             // Create the special-case model entry:
00778             char *types;
00779             if (NamesTagsPickle(result, false, conEmpty, /*OUT*/ types, /*OUT*/ entryNames,
00780                                 /*OUT*/ tags, /*OUT*/ cVal)) {
00781               CacheEntry::Indices kids;
00782               CollectKids(orphanCIs, kidsIndex, kids);
00783               Text pksource(fun->content->name);
00784               pksource += "() (special)";             
00785               // Add the entry, capturing the result of the call.
00786               CacheIntf::AddEntryRes ae_res =
00787                 theCache->AddEntry(pk, types, entryNames, tags, cVal, model,
00788                                    kids, pksource, /*OUT*/ cIndex);
00789               // If the AddEntry fails, die with an error.
00790               if(ae_res != CacheIntf::EntryAdded)
00791                 {
00792                   outputMu.lock();      
00793                   Error(Text("AddEntry failed: ")+
00794                         CacheIntf::AddEntryResName(ae_res)+"\n"
00795                         "This may be an evaluator bug.  "
00796                         "Please report it.\n",
00797                         loc);
00798                   outputMu.unlock();
00799                   if (traceRes) *traceRes << endl;
00800                   throw(Evaluator::failure(Text("AddEntry failed (may be an "
00801                                                 "evaluator bug)"),
00802                                            false));
00803                 }
00804               UpdateOrphans(orphanCIs, kidsIndex, cIndex);
00805               Checkpoint();
00806               if (traceRes) {
00807                 *traceRes << "  " << thdata->funcCallDepth << ". " << fun->content->name
00808                           << ": add (ci=" << cIndex << ")\n";
00809               }
00810             }
00811           }
00812           return ModelDpnd(result, fun, argsCon);
00813         }
00814         outputMu.lock();        
00815         Error("Trying to apply a model that failed to parse: `", loc);
00816         ErrorVal(fun1);
00817         ErrorDetail("'.\n");
00818         outputMu.unlock();      
00819         result = NEW(ErrorVC);
00820         return result->Merge(fun);
00821       }
00822       if (cResult != CacheIntf::FVMismatch) {
00823         if (traceRes) *traceRes << ": mismatch\n";
00824         OBufStream err_msg;
00825         err_msg << "ModelFromCache got bad result: "
00826                 << CacheIntf::LookupResName(cResult) << endl
00827                 << "\tpk = " << pk << endl
00828                 << "\tFV epoch = " << epoch << endl
00829                 << "\ttags.len = " << tags.len << endl
00830                 << "This may be an evaluator bug.  Please report it." << endl;
00831         outputMu.lock();        
00832         Error(Text(err_msg.str()), loc);
00833         outputMu.unlock();      
00834         result = NEW(ErrorVC);
00835         return result;
00836       }
00837     }
00838   } catch (PrefixTbl::Overflow) {
00839     outputMu.lock();        
00840     Error(Text("Internal limits exceeded: PrefixTbl overflow\n"),
00841           loc);
00842     cerr << "Caching model (special):" << endl << endl
00843          << "  " << fun->content->name
00844          << endl << endl
00845          << Text("This usually means that there are too many free variables "
00846                  "in the secondary key of the function being cached.  For "
00847                  "models, this may mean too much work is being done in a "
00848                  "single model file.  Try splitting up the work of this "
00849                  "model file into several separate model files each doing "
00850                  "a smaller amount of work.  (Fixing this will also reduce "
00851                  "the CPU load of your evaluator and cache server, and "
00852                  "improve build performance.)").WordWrap()
00853          << endl << endl;
00854     // This is a fatal error.  Exit and dump core.
00855     abort();
00856     outputMu.unlock();
00857   } catch (SRPC::failure f) {
00858     outputMu.lock();        
00859     Error(Text("ModelFromCache: SRPC failure (") + IntToText(f.r) + "): " + f.msg + ".\n",
00860           loc);
00861     outputMu.unlock();        
00862     if (traceRes) *traceRes << endl;
00863     throw(Evaluator::failure(Text("Cache server is possibly down"), false));
00864   }
00865   //return result; // not reached
00866 }
00867 
00868 Val ApplyModel(ModelVC* fun, ApplyEC *ae, const Context& c) {
00869   /* There are two cache entries created.  The first one created in
00870      NormalModelFromCache is the normal-case model entry, the second one
00871      is the special-case model entry.  In cache lookup, we always first
00872      look up the special-case model entry, and then the normal-case
00873      model entry.   */
00874   ArgList args = ae->args;
00875   Exprs acts = args->elems;
00876   Context argsCon;
00877 
00878   ThreadData *thdata = ThreadDataGet();
00879   ostream *traceRes = thdata->traceRes;
00880 
00881   // Bind model argument:
00882   int aSize = acts.size();
00883   if (aSize == 0) {
00884     Name eDot = NEW_CONSTR(NameEC, (nameDot, args->loc));
00885     PushToContext(nameDot, eDot, c, argsCon);
00886   }
00887   else if (aSize == 1)
00888     PushToContext(nameDot, acts.getlo(), c, argsCon);
00889   else {
00890     outputMu.lock();        
00891     args->EError("Too many actual parameters:");
00892     outputMu.unlock();        
00893     thdata->funcCallDepth++;
00894     if (traceRes) {
00895       *traceRes << "  " << thdata->funcCallDepth << ". " << fun->content->name;
00896       *traceRes << ": badargs\n";
00897     }
00898     thdata->funcCallDepth--;
00899     return NEW(ErrorVC);
00900   }
00901 
00902   thdata->funcCallDepth++;
00903   // Record this call if traced:
00904   if (traceRes) {
00905     *traceRes << "  " << thdata->funcCallDepth << ". " << fun->content->name;
00906   }
00907 
00908   // Evaluate:
00909   Val result = ModelFromCache(fun, argsCon, ae->loc);
00910   thdata->funcCallDepth--;
00911   return result;
00912 }  
00913 
00914 // RunTool application:
00915 bool CheckTreatment(TextVC *tr) {
00916   Text txt(tr->NDS());
00917   return (txt == "ignore" || 
00918           txt == "report" || 
00919           txt == "report_nocache" ||
00920           txt == "value" ||
00921           txt == "report_value");         
00922 }
00923 
00924 bool AllTexts(BindingVC *b) {
00925   Context work = b->elems;
00926   while (!work.Null()) {
00927     Assoc a = work.Pop();
00928     if (a->val->vKind != TextVK) return false;
00929   }
00930   return true; 
00931 }
00932 
00933 bool BindRunToolArgs(ArgList args, const Context& c,
00934                      RunToolArgs& runToolArgs) {
00935   // Handle type-checking and defaulting of arguments to _run_tool
00936   int nArgs = args->Length();
00937   Exprs elems = args->elems;
00938   Val val;
00939 
00940   if (nArgs < 2) {
00941     outputMu.lock();        
00942     args->EError("Too few actual parameters:");
00943     outputMu.unlock();        
00944     return false;
00945   }
00946   if (nArgs > 11) {
00947     outputMu.lock();        
00948     args->EError("Too many actual parameters:");
00949     outputMu.unlock();        
00950     return false;
00951   }
00952   
00953   // platform:
00954   val = elems.get(0)->Eval(c);
00955   if (val->vKind != TextVK) {
00956     outputMu.lock();        
00957     args->EError("The `platform' argument to _run_tool must be a text:");
00958     outputMu.unlock();        
00959     return false;
00960   }
00961   runToolArgs.platform = (TextVC*)val;
00962 
00963   // command:
00964   val = elems.get(1)->Eval(c);
00965   bool ok = false;
00966   if (val->vKind == ListVK) {
00967     Vals vs = ((ListVC*)val)->elems;
00968     ok = true;
00969     while (!vs.Null())
00970       if (vs.Pop()->vKind != TextVK) { ok = false; break; }
00971   }
00972   if (!ok) {
00973     outputMu.lock();        
00974     args->EError("The `command' argument to _run_tool must be a list of texts:");
00975     outputMu.unlock();        
00976     return false;
00977   }
00978   runToolArgs.command_line = (ListVC*)val;
00979 
00980   // stdin:
00981   if (nArgs <= 2) {
00982     Text stdin_default(emptyText);
00983     val = NEW_CONSTR(TextVC, (stdin_default));
00984   }
00985   else {
00986     val = elems.get(2)->Eval(c);
00987     if (val->vKind != TextVK) {
00988       outputMu.lock();          
00989       args->EError("The `stdin' argument to _run_tool must be a text:");
00990       outputMu.unlock();          
00991       return false;
00992     }
00993   }
00994   runToolArgs.stdin_data = (TextVC*)val;
00995 
00996   // stdout_treatment:
00997   if (nArgs <= 3) {
00998     Text stdout_treatment_default("report");
00999     val = NEW_CONSTR(TextVC, (stdout_treatment_default));
01000   }
01001   else {
01002     val = elems.get(3)->Eval(c);
01003     if (val->vKind != TextVK || !CheckTreatment((TextVC*)val)) {
01004       outputMu.lock();          
01005       args->EError("The `stdout_treatment' argument to _run_tool is not a suitable text:");
01006       outputMu.unlock();          
01007       return false;
01008     }
01009   }
01010   runToolArgs.stdout_treatment = (TextVC*)val;
01011 
01012   // stderr_treatment:
01013   if (nArgs <= 4) {
01014     Text stderr_treatment_default("report");
01015     val = NEW_CONSTR(TextVC, (stderr_treatment_default));
01016   }
01017   else {
01018     val = elems.get(4)->Eval(c);
01019     if (val->vKind != TextVK || !CheckTreatment((TextVC *)val)) {
01020       outputMu.lock();          
01021       args->EError("The `stderr_treatment' argument to _run_tool is not a suitable text:");
01022       outputMu.unlock();          
01023       return false;
01024     }
01025   }
01026   runToolArgs.stderr_treatment = (TextVC*)val;
01027 
01028   // status_treatment:
01029   if (nArgs <= 5) {
01030     Text status_treatment_default("report_nocache");
01031     val = NEW_CONSTR(TextVC, (status_treatment_default));
01032   }
01033   else {
01034     val = elems.get(5)->Eval(c);
01035     if (val->vKind != TextVK || !CheckTreatment((TextVC *)val)) {
01036       outputMu.lock();    
01037       args->EError("The `status_treatment' argument to _run_tool is not a suitable text:");
01038       outputMu.unlock();    
01039       return false;
01040     }
01041   }
01042   runToolArgs.status_treatment = (TextVC*)val;
01043 
01044   // signal_treatment:
01045   if (nArgs <= 6) {
01046     Text signal_treatment_default("report_nocache");
01047     val = NEW_CONSTR(TextVC, (signal_treatment_default));
01048   }
01049   else {
01050     val = elems.get(6)->Eval(c);
01051     if (val->vKind != TextVK || !CheckTreatment((TextVC *)val)) {
01052       outputMu.lock();          
01053       args->EError("The `signal_treatment' argument to _run_tool is not a suitable text:");
01054       outputMu.unlock();          
01055       return false;
01056     }
01057   }
01058   runToolArgs.signal_treatment = (TextVC*)val;
01059 
01060   // fp_content:
01061   if (nArgs <= 7) {
01062     val = fpContent;
01063   }
01064   else {
01065     val = elems.get(7)->Eval(c);
01066     if (val->vKind == BooleanVK) {
01067       val = NEW_CONSTR(IntegerVC, (((BooleanVC*)val)->b ? -1 : 0));
01068     }
01069     else if (val->vKind != IntegerVK) {
01070       outputMu.lock();          
01071       args->EError("The `fp_content' argument to _run_tool must be an integer or boolean:");
01072       outputMu.unlock();          
01073       return false;
01074     }
01075     else if (((IntegerVC*)val)->num == -2) {
01076       val = fpContent;
01077     }
01078   }
01079   runToolArgs.fp_content = (IntegerVC*)val;
01080 
01081   // wd:
01082   if (nArgs <= 8) {
01083     Text wd_name(".WD");
01084     val = NEW_CONSTR(TextVC, (wd_name));
01085   }
01086   else {
01087     val = elems.get(8)->Eval(c);
01088     if (val->vKind != TextVK) {
01089       outputMu.lock();          
01090       args->EError("The `wd' argument to _run_tool must be a text:");
01091       outputMu.unlock();          
01092       return false;
01093     }
01094   }
01095   runToolArgs.wd_name = (TextVC*)val;
01096 
01097   // existing_writable:
01098   if (nArgs <= 9) {
01099     val = NEW_CONSTR(BooleanVC, (false));
01100   }
01101   else {
01102     val = elems.get(9)->Eval(c);
01103     if (val->vKind != BooleanVK) {
01104       outputMu.lock();          
01105       args->EError("The `existing_writable' argument to _run_tool must be a boolean:");
01106       outputMu.unlock();          
01107       return false;
01108     }      
01109   }
01110   runToolArgs.existing_writable = (BooleanVC*)val;
01111 
01112   // .:
01113   if (nArgs <= 10) {
01114     val = LookupInContext(nameDot, c);
01115     if (val->vKind != BindingVK) {
01116       outputMu.lock();          
01117       args->EError("The `.' argument to _run_tool must be a binding:");
01118       outputMu.unlock();          
01119       return false;
01120     }
01121   }
01122   else {
01123     val = elems.get(10)->Eval(c);
01124     if (val->vKind != BindingVK) {
01125       outputMu.lock();          
01126       args->EError("The `.' argument to _run_tool must be a binding:");
01127       outputMu.unlock();          
01128       return false;
01129     }
01130   }
01131   runToolArgs.dot = (BindingVC *)val;
01132   Val envVars = runToolArgs.dot->Lookup("envVars");
01133   if (envVars->vKind != BindingVK || !AllTexts((BindingVC*)envVars)) {
01134     outputMu.lock();        
01135     args->EError("./envVars isn't a binding of texts:");
01136     outputMu.unlock();        
01137     return false;
01138   }
01139   Val root = runToolArgs.dot->Lookup("root"); 
01140   if (root->vKind != BindingVK) {
01141     outputMu.lock();        
01142     args->EError("./root isn't a binding:");
01143     outputMu.unlock();        
01144     return false;
01145   }
01146 
01147   // RunTool arguments are ok.
01148   runToolArgs.loc = args->loc;
01149   return true;
01150 }
01151 
01152 void RunToolPK(const RunToolArgs& runToolArgs, FP::Tag &pk) {
01153   // Primary key for a runtool call:
01154   // We combine fingerprints of relevant arguments to _run_tool, 
01155   // except for ./root, whose dependencies are fine-grained. 
01156   pk.Extend("_run_tool");
01157   pk.Extend(runToolArgs.platform->FingerPrint());
01158   pk.Extend(runToolArgs.command_line->FingerPrint());
01159   pk.Extend(runToolArgs.stdin_data->FingerPrint());
01160   pk.Extend(runToolArgs.stdout_treatment->FingerPrint());
01161   pk.Extend(runToolArgs.stderr_treatment->FingerPrint());
01162   pk.Extend(runToolArgs.status_treatment->FingerPrint());
01163   pk.Extend(runToolArgs.signal_treatment->FingerPrint());
01164   pk.Extend(runToolArgs.fp_content->FingerPrint());
01165   pk.Extend(runToolArgs.wd_name->FingerPrint());
01166   if (runToolArgs.existing_writable->b)
01167     pk.Extend(runToolArgs.existing_writable->FingerPrint());
01168   Val envVars = runToolArgs.dot->Lookup("envVars");
01169   pk.Extend(envVars->FingerPrint());
01170 }
01171 
01172 Val MergeArgsDpnd(Val result, const RunToolArgs& args) {
01173   // Add the dependency of the arguments of this runtool call.
01174   result->Merge(args.platform);
01175 
01176   ListVC *command = args.command_line;
01177   result->Merge(command);
01178   if (!command->path) {
01179     if (command->lenDps != NULL &&
01180         command->lenDps->Size() != 0) {
01181       DPaths psTemp;
01182       ValueDpnd(command, &psTemp);
01183       result->MergeDPS(&psTemp);
01184     }
01185     else {
01186       Vals vs = command->elems;
01187       while (!vs.Null())
01188         result->Merge(vs.Pop());
01189     }
01190   }
01191   result->Merge(args.stdin_data);
01192   result->Merge(args.stdout_treatment);
01193   result->Merge(args.stderr_treatment);
01194   result->Merge(args.wd_name);
01195   return result;
01196 }
01197 
01198 static Basics::thread renewLeaseThread;
01199 
01200 static void* RenewLeases(void *arg) throw () {
01201   time_t tsStart;
01202   // time_t sleepDuration = (time_t)(leaseDuration * 0.8);
01203   time_t sleepDuration = 10;
01204 
01205   // Remember how many time we've hit the "server busy" case.
01206   unsigned int server_busy_count = 0;
01207   
01208   while (true) {
01209     int left = sleepDuration;
01210     do {
01211       left = sleep(left);
01212     } while (left > 0);
01213 
01214     // If lease already expired, quit.
01215     leaseMu.lock();
01216     if (time(&tsStart) - lastRenewed > leaseDuration) {
01217       leaseMu.unlock();
01218       // If we've had trouble getting the cache server to accept our
01219       // calls and the leases expired, print a message about that.
01220       if(server_busy_count > 0)
01221         {
01222           outputMu.lock();
01223           Error(Text("RenewLeases thread got \"connection refused: server busy\" ") +
01224                 IntToText(server_busy_count) + " times, and now leases have expired!\n");
01225           outputMu.unlock();
01226         }
01227       return NULL;
01228     }
01229     leaseMu.unlock();
01230     
01231     // Renew leases:
01232     CacheEntry::IndicesApp orphanCIs;    
01233     frontierMu.lock();
01234     ThreadData::mu.lock();
01235     ThreadData* cur = ThreadData::head;
01236     while (cur) {
01237       assert(cur->orphanCIs != 0);
01238       for (int i = 0; i < cur->orphanCIs->len; i++) {
01239         orphanCIs.Append(cur->orphanCIs->index[i]);
01240       }
01241       cur = cur->next;
01242     }
01243     ThreadData::mu.unlock();
01244     frontierMu.unlock();
01245 
01246     bool renewed = false;
01247     try
01248       {
01249         // Renew the leases, remembering whether we succeeded.
01250         renewed = theCache->RenewLeases(orphanCIs);
01251 
01252         // No "server busy" SRPC failure.
01253         server_busy_count = 0;
01254 
01255         // If we didn't renew successfully, print an error message,
01256         // remember that we've failed, and exit the thread.
01257         if(!renewed)
01258           {
01259             outputMu.lock();
01260             Error(Text("RenewLeases returned failure!\n") +
01261                   "This may be a bug.  Please reposrt it.\n");
01262             outputMu.unlock();
01263 
01264             leaseMu.lock();
01265             renewLease_failure = true;
01266             leaseMu.unlock();
01267 
01268             return NULL;
01269           }
01270       }
01271     // If we get an SRPC failure...
01272     catch (SRPC::failure f)
01273       {
01274         // If this looks like hitting the cache server's connection
01275         // limits, ignore it (but remember it).  (Presumably we'll get
01276         // in on a subsequent call.)
01277         if((f.r == 1) && (f.msg.FindText("connection refused: server busy") != -1))
01278           {
01279             server_busy_count++;
01280           }
01281         // If it doesn't look like the LimService message...
01282         else
01283           {
01284             // ...assume the cache server went down.  Print an error
01285             // message with the SRPC failure, note that we've failed,
01286             // and exit the thread.
01287             outputMu.lock();
01288             Error(Text("RenewLeases thread: SRPC failure (")
01289                   + IntToText(f.r) + "): " + f.msg + ".\n");
01290             outputMu.unlock();
01291 
01292             leaseMu.lock();
01293             renewLease_failure = true;
01294             leaseMu.unlock();
01295 
01296             return NULL;
01297           }
01298       }
01299     
01300     // If lease expires during renewing, quit.
01301     leaseMu.lock();
01302     if (time(NULL) - lastRenewed > leaseDuration) {
01303       leaseMu.unlock();
01304       // If we've had trouble getting the cache server to accept our
01305       // calls and the leases expired, print a message about that.
01306       if(server_busy_count > 0)
01307         {
01308           outputMu.lock();
01309           Error(Text("RenewLeases thread got \"connection refused: server busy\" ") +
01310                 IntToText(server_busy_count) + " times, and now leases have expired!\n");
01311           outputMu.unlock();
01312         }
01313       return NULL;
01314     }
01315     
01316     if(renewed)
01317       {
01318         // Leases are renewed successfully:
01319         lastRenewed = tsStart;
01320       }
01321     leaseMu.unlock();    
01322   }
01323 }
01324 
01325 void StartRenewLeaseThread() {
01326   if (cacheOption != 0) {
01327     time(&lastRenewed);  
01328     renewLeaseThread.fork_and_detach(RenewLeases, (void*)NULL);
01329   }
01330 }
01331 
01332 Val RunToolFromCache(const RunToolArgs& runToolArgs, const Context& c, SrcLoc *loc) {
01333   FP::Tag pk(evaluatorRunToolVersionTag);
01334   CompactFV::List fvNames;
01335   FV2::List entryNames;
01336   FP::List tags;
01337   CacheEntry::Index cIndex;
01338   VestaVal::T cVal;
01339   CacheIntf::LookupRes cResult = CacheIntf::Miss;
01340   Model::T model = NullShortId;
01341   Val result;
01342   VestaSource* rootForTool;
01343 
01344   ThreadData *thdata = ThreadDataGet();
01345   ostream *traceRes = thdata->traceRes;
01346 
01347   // Evaluate in the nocaching cases:
01348   if (cacheOption == 0) {
01349     if (traceRes) *traceRes << ": disabled\n";
01350     result = RunTool(runToolArgs, rootForTool);
01351     DeleteRootForTool(rootForTool);
01352     return result;
01353   }
01354 
01355   // Compute the primary key:
01356   RunToolPK(runToolArgs, pk);
01357 
01358   // Evaluate with caching:
01359   CacheEntry::IndicesApp* orphanCIs = ThreadDataGet()->orphanCIs;    
01360   try {
01361     while (true) {
01362       bool noEntry;
01363       FV::Epoch epoch = theCache->FreeVariables(pk, /*OUT*/ fvNames, /*OUT*/ noEntry);
01364       if (noEntry)
01365         cResult = CacheIntf::Miss;
01366       else {
01367         Tags(fvNames, c, /*OUT*/ tags);
01368         cResult = theCache->Lookup(pk, epoch, tags, /*OUT*/ cIndex, /*OUT*/ cVal);
01369       }
01370       FreeNamesTags(fvNames, tags);
01371       if (cResult == CacheIntf::Hit) {
01372         if (Unpickle(cVal, c, result)) {
01373           if (traceRes) *traceRes << ": hit(ci=" << cIndex << ")\n";
01374           IncCounter(&toolHitCounter);
01375           if (cacheOption == 1) {
01376             result->dps = NULL;
01377             return result;
01378           }
01379           UpdateOrphans(orphanCIs, orphanCIs->len, cIndex);
01380           return MergeArgsDpnd(result, runToolArgs);
01381         }
01382         outputMu.lock();        
01383         OBufStream l_msg;
01384         l_msg << "RunToolFromCache: Cache hit but bad cache data." << endl << endl
01385               << "\tpk = " << pk << endl
01386               << "\tci = " << cIndex << endl << endl
01387               << "Evaluate as cache miss." << endl;
01388         Error(Text(l_msg.str()), loc);
01389         outputMu.unlock();      
01390         cResult = CacheIntf::Miss;
01391       }
01392       if (cResult == CacheIntf::Miss) {
01393         if (traceRes) *traceRes << ": miss\n";
01394         int kidsIndex = orphanCIs->len;
01395 
01396         // Check to make sure there isn't an outstanding tool run with the same pk
01397         rtt_cond *rttCond;
01398         runToolTableMu.lock();
01399         bool found = runToolTable.Get(pk, /*OUT*/ rttCond);
01400         if(!found) {
01401                 rttCond = NEW(rtt_cond);
01402                 runToolTable.Put(pk, rttCond);
01403                 runToolTableMu.unlock();
01404         } else {
01405                 // There's already a tool with this PK running...
01406                 // We'll wait for it to finish
01407                 outputMu.lock();
01408                 cerr << ThreadLabel() << "Waiting on possbily identical tool run" << endl;
01409                 outputMu.unlock();
01410                 rttCond->wait();
01411                 // Woken up, tool must have finished.  Go around the
01412                 // loop and try another cache lookup.
01413                 runToolTableMu.unlock();
01414                 continue;
01415         }
01416         // run the tool
01417         try {
01418                 result = RunTool(runToolArgs, rootForTool);
01419                 char *types;
01420                 if (!noAddEntry &&
01421                     NamesTagsPickle(result, false, conEmpty, /*OUT*/ types, /*OUT*/ entryNames,
01422                                     /*OUT*/ tags, /*OUT*/ cVal)) {
01423                   CacheEntry::Indices kids;
01424                   CollectKids(orphanCIs, kidsIndex, kids);
01425                   // kids should be empty when evaluating eagerly.
01426 
01427                   Text pksource("_run_tool, command line: ");
01428                   pksource += ToolCommandLineAsText(runToolArgs);
01429 
01430                   // Add the entry, capturing the result of the call.
01431                   CacheIntf::AddEntryRes ae_res =
01432                     theCache->AddEntry(pk, types, entryNames, tags, cVal, model,
01433                                        kids, pksource, /*OUT*/ cIndex);
01434                   // If the AddEntry fails, die with an error.
01435                   if(ae_res != CacheIntf::EntryAdded)
01436                     {
01437                       outputMu.lock();          
01438                       Error(Text("AddEntry failed: ")+
01439                             CacheIntf::AddEntryResName(ae_res)+"\n"
01440                             "This may be an evaluator bug.  "
01441                             "Please report it.\n",
01442                             loc);
01443                       outputMu.unlock();
01444                       if (traceRes) *traceRes << endl;
01445                       throw(Evaluator::failure(Text("AddEntry failed (may be an "
01446                                                     "evaluator bug)"),
01447                                                false));
01448                     }
01449                   // cIndex is added to the orphans.
01450                   UpdateOrphans(orphanCIs, kidsIndex, cIndex);
01451                   Checkpoint();
01452                   if (traceRes) {
01453                     *traceRes << "  " << thdata->funcCallDepth << ". " << loc->file << ": "
01454                               << "_run_tool(): add (ci=" << cIndex << ")\n";
01455                   }
01456                 }
01457                 // now wake up the other threads waiting for the same PK
01458                 runToolTableMu.lock();
01459                 runToolTable.Delete(pk, /*OUT*/ rttCond);
01460                 rttCond->wake();
01461                 runToolTableMu.unlock();
01462         } catch(...) {
01463                 runToolTableMu.lock();
01464                 runToolTable.Delete(pk, /*OUT*/ rttCond);
01465                 rttCond->wake();
01466                 runToolTableMu.unlock();
01467                 throw;
01468         }
01469 
01470         // delete the volatile dir for root after adding cache entry.
01471         // The new cache entry is now protecting the deriveds from weeding.
01472         DeleteRootForTool(rootForTool);   
01473         if (cacheOption == 1) {
01474           result->dps = NULL;
01475           return result;
01476         }
01477         return MergeArgsDpnd(result, runToolArgs);
01478       }
01479       if (cResult != CacheIntf::FVMismatch) {
01480         if (traceRes) *traceRes << ": mismatch\n";
01481         OBufStream err_msg;
01482         err_msg << "RunToolFromCache got bad result: "
01483                 << CacheIntf::LookupResName(cResult) << endl
01484                 << "\tpk = " << pk << endl
01485                 << "\tFV epoch = " << epoch << endl
01486                 << "\ttags.len = " << tags.len << endl
01487                 << "This may be an evaluator bug.  Please report it." << endl;
01488         outputMu.lock();        
01489         Error(Text(err_msg.str()), loc);
01490         outputMu.unlock();      
01491         result = NEW(ErrorVC);
01492         return result;
01493       }
01494     }
01495   } catch (PrefixTbl::Overflow) {
01496     outputMu.lock();        
01497     Error(Text("Internal limits exceeded: PrefixTbl overflow\n"),
01498           loc);
01499     cerr << "Caching _run_tool with command line:" << endl << endl
01500          << "  " << ToolCommandLineAsText(runToolArgs) << endl << endl
01501          << Text("This usually means that there are too many free variables "
01502                  "in the secondary key of the function being cached.  For "
01503                  "_run_tool calls, this may mean you're trying to do too "
01504                  "much work in a single tool invocation.  Try splitting the "
01505                  "work of this tool invocation into several separate tool "
01506                  "invocations each doing a smaller amount of work and using "
01507                  "a smaller number of source files.  (Fixing this will also "
01508                  "reduce the CPU load of your evaluator and cache server, and "
01509                  "improve build performance.)").WordWrap()
01510          << endl << endl;
01511     // This is a fatal error.  Exit and dump core.
01512     abort();
01513     outputMu.unlock();
01514   } catch (SRPC::failure f) {
01515     outputMu.lock();        
01516     Error(Text("RunToolFromCache: SRPC failure (")
01517              + IntToText(f.r) + "): " + f.msg + ".\n",
01518           loc);
01519     outputMu.unlock();        
01520     if (traceRes) *traceRes << endl;
01521     throw(Evaluator::failure(Text("Cache server is possibly down"), false));
01522   }
01523   // return result;  // not reached
01524 }
01525 
01526 Val ApplyRunTool(ArgList args, const Context& c) {
01527   RunToolArgs runToolArgs;
01528 
01529   ThreadData *thdata = ThreadDataGet();
01530   ostream *traceRes = thdata->traceRes;
01531   
01532   IncCounter(&toolCallCounter);
01533   if (!BindRunToolArgs(args, c, runToolArgs)) {
01534     thdata->funcCallDepth++;
01535     if (traceRes) {
01536       *traceRes << "  " << thdata->funcCallDepth << ". " << args->loc->file << ": ";
01537       *traceRes << "_run_tool()";
01538       *traceRes << ": badargs\n";
01539     }
01540     thdata->funcCallDepth--;
01541     return NEW(ErrorVC);
01542   }
01543   thdata->funcCallDepth++;
01544   if (traceRes) {
01545     *traceRes << "  " << thdata->funcCallDepth << ". " << args->loc->file << ": ";
01546     *traceRes << "_run_tool()";
01547   }
01548 
01549   // Evaluate:
01550   Val result = RunToolFromCache(runToolArgs, c, args->loc);
01551   thdata->funcCallDepth--;
01552   return result;
01553 }

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