void ServerConfig::CrossCheckConnectBlocks(ServerConfig* current) { typedef std::map<std::string, ConnectClass*> ClassMap; ClassMap oldBlocksByMask; if (current) { for(ClassVector::iterator i = current->Classes.begin(); i != current->Classes.end(); ++i) { ConnectClass* c = *i; if (c->name.substr(0, 8) != "unnamed-") { oldBlocksByMask["n" + c->name] = c; } else if (c->type == CC_ALLOW || c->type == CC_DENY) { std::string typeMask = (c->type == CC_ALLOW) ? "a" : "d"; typeMask += c->host; oldBlocksByMask[typeMask] = c; } } } int blk_count = config_data.count("connect"); if (blk_count == 0) { // No connect blocks found; make a trivial default block std::vector<KeyVal>* items; ConfigTag* tag = ConfigTag::create("connect", "<auto>", 0, items); items->push_back(std::make_pair("allow", "*")); config_data.insert(std::make_pair("connect", tag)); blk_count = 1; } Classes.resize(blk_count); std::map<std::string, int> names; bool try_again = true; for(int tries=0; try_again; tries++) { try_again = false; ConfigTagList tags = ConfTags("connect"); int i=0; for(ConfigIter it = tags.first; it != tags.second; ++it, ++i) { ConfigTag* tag = it->second; if (Classes[i]) continue; ConnectClass* parent = NULL; std::string parentName = tag->getString("parent"); if (!parentName.empty()) { std::map<std::string,int>::iterator parentIter = names.find(parentName); if (parentIter == names.end()) { try_again = true; // couldn't find parent this time. If it's the last time, we'll never find it. if (tries >= blk_count) throw CoreException("Could not find parent connect class \"" + parentName + "\" for connect block at " + tag->getTagLocation()); continue; } parent = Classes[parentIter->second]; } std::string name = tag->getString("name"); std::string mask, typeMask; char type; if (tag->readString("allow", mask, false)) { type = CC_ALLOW; typeMask = 'a' + mask; } else if (tag->readString("deny", mask, false)) { type = CC_DENY; typeMask = 'd' + mask; } else if (!name.empty()) { type = CC_NAMED; mask = name; typeMask = 'n' + mask; } else { throw CoreException("Connect class must have allow, deny, or name specified at " + tag->getTagLocation()); } if (name.empty()) { name = "unnamed-" + ConvToStr(i); } else { typeMask = 'n' + name; } if (names.find(name) != names.end()) throw CoreException("Two connect classes with name \"" + name + "\" defined!"); names[name] = i; ConnectClass* me = parent ? new ConnectClass(tag, type, mask, *parent) : new ConnectClass(tag, type, mask); me->name = name; me->registration_timeout = tag->getInt("timeout", me->registration_timeout); me->pingtime = tag->getInt("pingfreq", me->pingtime); std::string sendq; if (tag->readString("sendq", sendq)) { // attempt to guess a good hard/soft sendq from a single value long value = atol(sendq.c_str()); if (value > 16384) me->softsendqmax = value / 16; else me->softsendqmax = value; me->hardsendqmax = value * 8; } me->softsendqmax = tag->getInt("softsendq", me->softsendqmax); me->hardsendqmax = tag->getInt("hardsendq", me->hardsendqmax); me->recvqmax = tag->getInt("recvq", me->recvqmax); me->penaltythreshold = tag->getInt("threshold", me->penaltythreshold); me->commandrate = tag->getInt("commandrate", me->commandrate); me->fakelag = tag->getBool("fakelag", me->fakelag); me->maxlocal = tag->getInt("localmax", me->maxlocal); me->maxglobal = tag->getInt("globalmax", me->maxglobal); me->maxchans = tag->getInt("maxchans", me->maxchans); me->maxconnwarn = tag->getBool("maxconnwarn", me->maxconnwarn); me->limit = tag->getInt("limit", me->limit); me->nouserdns = tag->getBool("nouserdns", me->nouserdns); ClassMap::iterator oldMask = oldBlocksByMask.find(typeMask); if (oldMask != oldBlocksByMask.end()) { ConnectClass* old = oldMask->second; oldBlocksByMask.erase(oldMask); old->Update(me); delete me; me = old; } Classes[i] = me; } } }
/** * Controller helper routine. * * Wait for the next running slave to finish a task. Note that if no * slaves are currently processing tasks, this routine will block forever! */ int ctrlWaitForSlave() { long result; MPI_Status status; MPI_Recv(&result, 1, MPI_LONG, MPI_ANY_SOURCE, TAG_RESULT, MPI_COMM_WORLD, &status); nRunningSlaves--; int slave = status.MPI_SOURCE; ctrlLogStamp() << "Task completed by slave " << slave << "." << std::endl; char triLabel[MAX_TRI_LABEL_LEN + 1]; if (result == RESULT_OK || result == RESULT_HAS_NEW) { if (result == RESULT_HAS_NEW) { // The original packet label comes through first so we can // write it to the log. It will come through again shortly // as part of the set of equivalent triangulations. MPI_Recv(triLabel, MAX_TRI_LABEL_LEN + 1, MPI_CHAR, slave, TAG_RESULT_DATA, MPI_COMM_WORLD, &status); ctrlLogStamp() << "WARNING: Has unseen equivalent: " << triLabel << std::endl; nHasNew++; } equivs.clear(); NPacket* p; NTriangulation* tri; while (1) { MPI_Recv(triLabel, MAX_TRI_LABEL_LEN + 1, MPI_CHAR, slave, TAG_RESULT_DATA, MPI_COMM_WORLD, &status); if (*triLabel == 0) break; p = tree->findPacketLabel(triLabel); if (! p) { ctrlLogStamp() << "ERROR: Returned equivalent [" << triLabel << "] not found." << std::endl; hasError = true; } else { tri = dynamic_cast<NTriangulation*>(p); if (! tri) { ctrlLogStamp() << "ERROR: Returned equivalent [" << triLabel << "] is not a triangulation!" << std::endl; hasError = true; } else equivs.insert(tri); } } ctrlLogStamp() << "Resulting set contains " << equivs.size() << " equivalent(s)." << std::endl; // In equivs we now have a list of all triangulations // equivalent to orig. // Is this an equivalence class we're already seen? TriSet::iterator tit; ClassMap::iterator cit, cit2; for (tit = equivs.begin(); tit != equivs.end(); tit++) { cit = eClass.find(*tit); if (cit != eClass.end()) break; } if (tit != equivs.end()) { // We found an equivalence class. Insert everything we // haven't seen yet, and merge the classes of everything // we have. int c, cOld; c = cit->second; for (tit = equivs.begin(); tit != equivs.end(); tit++) { cit = eClass.find(*tit); if (cit == eClass.end()) eClass.insert(std::make_pair(*tit, c)); else if (cit->second != c) { // Merge the two equivalence classes. cOld = cit->second; for (cit = eClass.begin(); cit != eClass.end(); cit++) if (cit->second == cOld) cit->second = c; nClasses--; } } } else { // No such equivalence class. Insert everything. int c = nextClass++; for (tit = equivs.begin(); tit != equivs.end(); tit++) eClass.insert(std::make_pair(*tit, c)); nClasses++; } } else if (result == RESULT_NON_MINIMAL) { MPI_Recv(triLabel, MAX_TRI_LABEL_LEN + 1, MPI_CHAR, slave, TAG_RESULT_DATA, MPI_COMM_WORLD, &status); ctrlLogStamp() << "Non-minimal triangulation: " << triLabel << std::endl; nNonMin++; } else if (result == RESULT_ERR) { char errMsg[MAX_ERR_MSG_LEN + 1]; MPI_Recv(errMsg, MAX_ERR_MSG_LEN + 1, MPI_CHAR, slave, TAG_RESULT_DATA, MPI_COMM_WORLD, &status); ctrlLogStamp() << "ERROR: " << errMsg << std::endl; hasError = true; } else { ctrlLogStamp() << "ERROR: Unknown result code " << result << " received from slave." << std::endl; hasError = true; } return slave; }
/** * Main routine for the controller. */ int mainController() { NTriangulation* t; // Start logging. logger.open(logFile); if (! logger) { fprintf(stderr, "Could not open %s for writing.\n", logFile); return 1; } // Do it. for (NPacket* p = tree; p; p = p->nextTreePacket()) if (p->type() == PACKET_TRIANGULATION) { nTris++; ctrlFarmTri(static_cast<NTriangulation*>(p)); } // Kill off any slaves that never started working, since there are no // tasks left to give them. if (nRunningSlaves < nSlaves) for (int i = nRunningSlaves; i < nSlaves; i++) ctrlStopSlave(i + 1); // Wait for remaining slaves to finish. while (nRunningSlaves > 0) ctrlFarmTri(0); // Done! ctrlLogStamp() << "All slaves finished." << std::endl; // Write the summary of results. if (nClasses) { printf("EQUIVALENCE CLASSES:\n\n"); if (outFile) { newTree = new NContainer(); newTree->setLabel("Equivalence Classes"); } int classNum = 1; std::string className; NContainer* classCnt = 0; ClassMap::iterator cit, cit2; int c; for (cit = eClass.begin(); cit != eClass.end(); cit++) if (cit->second >= 0) { // The first triangulation of a new equivalence class. c = cit->second; std::ostringstream s; s << "Class " << classNum << " : " << cit->first->homology().str(); className = s.str(); classNum++; printf("%s\n\n", className.c_str()); if (outFile) { classCnt = new NContainer(); classCnt->setLabel(className); newTree->insertChildLast(classCnt); } // Find the triangulations in this class, and erase the // class as we go. for (cit2 = cit; cit2 != eClass.end(); cit2++) if (cit2->second == c) { printf(" %s\n", cit2->first->label().c_str()); if (outFile) { t = new NTriangulation(*(cit2->first)); t->setLabel(cit2->first->label()); classCnt->insertChildLast(t); } cit2->second = -1; } printf("\n"); } } printf("Final statistics:\n"); printf(" Triangulations read: %ld\n", nTris); printf(" Equivalence classes: %ld\n", nClasses); printf(" Non-minimal triangulations: %ld\n", nNonMin); printf(" Triangulations with new equivs: %ld\n", nHasNew); // Are we saving results? if (outFile && newTree) { ctrlLogStamp() << "Saving results to " << outFile << "." << std::endl; newTree->save(outFile); } else ctrlLogStamp() << "Not saving results." << std::endl; // Clean up and exit. if (newTree) delete newTree; if (hasError) { ctrlLogStamp() << "ERROR: One or more errors occurred; " "read back through the log for details." << std::endl; printf("\nERROR: One or more errors occurred.\n"); printf( " Please read through the log file %s for details.\n", logFile); } else ctrlLogStamp() << "All done." << std::endl; return 0; }
void processTree() { TriSet::iterator tit; ClassMap::iterator cit, cit2; int c, cOld; NTriangulation* t; for (NPacket* p = tree; p; p = p->nextTreePacket()) if (p->type() == PACKET_TRIANGULATION) { // A triangulation to process. t = static_cast<NTriangulation*>(p); fprintf(stderr, "Processing %s ...\n", t->label().c_str()); nTris++; nonMin = false; orig = static_cast<NTriangulation*>(p); equivs.clear(); equivs.insert(orig); tryMovesUp(orig, argUp); if (nonMin) { allNonMin.push_back(orig); nNonMin++; continue; } // In equivs we now have a list of all triangulations // equivalent to orig. // Is this an equivalence class we're already seen? for (tit = equivs.begin(); tit != equivs.end(); tit++) { cit = eClass.find(*tit); if (cit != eClass.end()) break; } if (tit != equivs.end()) { // We found an equivalence class. Insert everything we // haven't seen yet, and merge the classes of everything // we have. c = cit->second; for (tit = equivs.begin(); tit != equivs.end(); tit++) { cit = eClass.find(*tit); if (cit == eClass.end()) eClass.insert(std::make_pair(*tit, c)); else if (cit->second != c) { // Merge the two equivalence classes. cOld = cit->second; for (cit = eClass.begin(); cit != eClass.end(); cit++) if (cit->second == cOld) cit->second = c; nClasses--; } } } else { // No such equivalence class. Insert everything. c = nextClass++; for (tit = equivs.begin(); tit != equivs.end(); tit++) eClass.insert(std::make_pair(*tit, c)); nClasses++; } } // Finished progress reporting. fprintf(stderr, "\n"); // Write the summary of results. if (! allNonMin.empty()) { printf("NON-MINIMAL TRIANGULATIONS:\n\n"); for (std::list<NTriangulation*>::const_iterator it = allNonMin.begin(); it != allNonMin.end(); it++) printf(" %s\n", (*it)->label().c_str()); printf("\n"); } if (nClasses) { printf("EQUIVALENCE CLASSES:\n\n"); if (outFile) { newTree = new NContainer(); newTree->setLabel("Equivalence Classes"); } int classNum = 1; std::string className; NContainer* classCnt = 0; for (cit = eClass.begin(); cit != eClass.end(); cit++) if (cit->second >= 0) { // The first triangulation of a new equivalence class. c = cit->second; std::ostringstream s; s << "Class " << classNum << " : " << cit->first->homology().str(); className = s.str(); classNum++; printf("%s\n\n", className.c_str()); if (outFile) { classCnt = new NContainer(); classCnt->setLabel(className); newTree->insertChildLast(classCnt); } // Find the triangulations in this class, and erase the // class as we go. for (cit2 = cit; cit2 != eClass.end(); cit2++) if (cit2->second == c) { printf(" %s\n", cit2->first->label().c_str()); if (outFile) { t = new NTriangulation(*(cit2->first)); t->setLabel(cit2->first->label()); classCnt->insertChildLast(t); } cit2->second = -1; } printf("\n"); } } printf("Final statistics:\n"); printf(" Triangulations read: %ld\n", nTris); printf(" Equivalence classes: %ld\n", nClasses); printf(" New triangulations: %ld\n", nNew); printf(" Non-minimal triangulations: %ld\n", nNonMin); }