/* * Give @unit and its cargo to @recipient. * No action if @recipient already owns @unit. * If @giver is non-zero, inform @recipient and @giver of the transaction. * Clears mission and group on the units given away. */ void unit_give_away(struct empobj *unit, natid recipient, natid giver) { int type; struct nstr_item ni; union empobj_storage cargo; if (unit->own == recipient) return; if (giver) { mpr(unit->own, "%s given to %s\n", unit_nameof(unit), cname(recipient)); mpr(recipient, "%s given to you by %s\n", unit_nameof(unit), cname(giver)); } unit->own = recipient; unit_wipe_orders(unit); put_empobj(unit->ef_type, unit->uid, unit); for (type = EF_PLANE; type <= EF_NUKE; type++) { snxtitem_cargo(&ni, type, unit->ef_type, unit->uid); while (nxtitem(&ni, &cargo)) unit_give_away(&cargo.gen, recipient, giver); } }
void takeover_plane(struct plnstr *pp, natid newown) { int n; if ((pp->pln_own == newown) || (pp->pln_own == 0)) return; if (pp->pln_flags & PLN_LAUNCHED) return; if (pp->pln_ship >= 0 || pp->pln_land >= 0) return; /* * XXX If this was done right, planes could escape, * flying to a nearby friendly airport. */ n = pp->pln_effic - (29 + roll(100)); if (n < 0) n = 0; pp->pln_effic = n; if (pp->pln_effic < PLANE_MINEFF || pp->pln_harden > 0) { pp->pln_effic = 0; mpr(newown, "%s blown up by the crew!\n", prplane(pp)); wu(0, pp->pln_own, "%s blown up by the crew to avoid capture by %s at %s!\n", prplane(pp), cname(newown), xyas(pp->pln_x, pp->pln_y, pp->pln_own)); } else { mpr(newown, "We have captured %s!\n", prplane(pp)); wu(0, pp->pln_own, "%s captured by %s at %s!\n", prplane(pp), cname(newown), xyas(pp->pln_x, pp->pln_y, pp->pln_own)); } takeover_unit((struct empobj *)pp, newown); }
int msl_hit(struct plnstr *pp, int hardtarget, int type, int news_item, int snews_item, int sublaunch, natid victim) { int hitchance, hit; if (nuk_on_plane(pp) >= 0) { mpr(pp->pln_own, "\tArming nuclear warheads...\n"); hit = 1; } else { hitchance = pln_hitchance(pp, hardtarget, type); hit = pct_chance(hitchance); mpr(pp->pln_own, "\t%d%% hitchance...%s\n", hitchance, hit ? "HIT!" : "miss"); } if (type != EF_PLANE) mpr(victim, "...Incoming %s missile %s\n", sublaunch ? "" : cname(pp->pln_own), hit ? "HIT!\n" : "missed\n"); if (hit && news_item) { if (sublaunch) nreport(victim, snews_item, 0, 1); else nreport(pp->pln_own, news_item, victim, 1); } return hit; }
/* * Drop cargo of @unit. * Give it to @newown, unless it's zero. */ void unit_drop_cargo(struct empobj *unit, natid newown) { int type; struct nstr_item ni; union empobj_storage cargo; for (type = EF_PLANE; type <= EF_NUKE; type++) { snxtitem_cargo(&ni, type, unit->ef_type, unit->uid); while (nxtitem(&ni, &cargo)) { switch (type) { case EF_PLANE: cargo.plane.pln_ship = cargo.plane.pln_land = -1; break; case EF_LAND: cargo.land.lnd_ship = cargo.land.lnd_land = -1; break; case EF_NUKE: cargo.nuke.nuk_plane = -1; break; } mpr(cargo.gen.own, "%s transferred off %s %d to %s\n", unit_nameof(&cargo.gen), ef_nameof(unit->ef_type), unit->uid, xyas(cargo.gen.x, cargo.gen.y, cargo.gen.own)); if (newown) unit_give_away(&cargo.gen, newown, cargo.gen.own); put_empobj(type, cargo.gen.uid, &cargo.gen); } } }
void pln_put1(struct plist *plp) { struct plnstr *pp; struct shpstr ship; struct sctstr sect; pp = &plp->plane; if (CANT_HAPPEN((pp->pln_flags & PLN_LAUNCHED) && (plchr[pp->pln_type].pl_flags & P_M) && pp->pln_effic >= PLANE_MINEFF)) pp->pln_effic = 0; /* bug: missile launched but not used up */ if (!(pp->pln_flags & PLN_LAUNCHED)) ; /* never took off */ else if (pp->pln_effic < PLANE_MINEFF) { ; /* destroyed */ } else if (pp->pln_ship >= 0) { /* It is landing on a carrier */ getship(pp->pln_ship, &ship); /* We should do more, like make sure it's really a carrier, etc. but for now just make sure it's not sunk. */ if (ship.shp_effic < SHIP_MINEFF) { mpr(pp->pln_own, "Ship #%d has been sunk, plane #%d has nowhere to land, and\n" "splashes into the sea.\n", pp->pln_ship, pp->pln_uid); pp->pln_effic = 0; } } else { /* Presume we are landing back in a sector. */ getsect(pp->pln_x, pp->pln_y, §); if (sect.sct_type == SCT_WATER || sect.sct_type == SCT_WASTE) { mpr(pp->pln_own, "Nowhere to land at %s, plane #%d crashes and burns...\n", xyas(pp->pln_x, pp->pln_y, pp->pln_own), pp->pln_uid); pp->pln_effic = 0; } } pp->pln_flags &= ~PLN_LAUNCHED; putplane(pp->pln_uid, pp); emp_remque(&plp->queue); free(plp); }
/** * For a given query, get a runner. The runner could be a SingleSolutionRunner, a * CachedQueryRunner, or a MultiPlanRunner, depending on the cache/query solver/etc. */ Status getRunner(QueryMessage& q, Runner** out) { CanonicalQuery* rawCanonicalQuery = NULL; // Canonicalize the query and wrap it in an auto_ptr so we don't leak it if something goes // wrong. Status status = CanonicalQuery::canonicalize(q, &rawCanonicalQuery); if (!status.isOK()) { return status; } verify(rawCanonicalQuery); auto_ptr<CanonicalQuery> canonicalQuery(rawCanonicalQuery); // Try to look up a cached solution for the query. // TODO: Can the cache have negative data about a solution? PlanCache* localCache = PlanCache::get(canonicalQuery->ns()); CachedSolution* cs = localCache->get(*canonicalQuery); if (NULL != cs) { // We have a cached solution. Hand the canonical query and cached solution off to the // cached plan runner, which takes ownership of both. WorkingSet* ws; PlanStage* root; verify(StageBuilder::build(*cs->solution, &root, &ws)); *out = new CachedPlanRunner(canonicalQuery.release(), cs, root, ws); return Status::OK(); } // No entry in cache for the query. We have to solve the query ourself. vector<QuerySolution*> solutions; QueryPlanner::plan(*canonicalQuery, &solutions); // We cannot figure out how to answer the query. Should this ever happen? if (0 == solutions.size()) { return Status(ErrorCodes::BadValue, "Can't create a plan for the canonical query " + canonicalQuery->toString()); } if (1 == solutions.size()) { // Only one possible plan. Run it. Build the stages from the solution. WorkingSet* ws; PlanStage* root; verify(StageBuilder::build(*solutions[0], &root, &ws)); // And, run the plan. *out = new SingleSolutionRunner(canonicalQuery.release(), solutions[0], root, ws); return Status::OK(); } else { // Many solutions. Let the MultiPlanRunner pick the best, update the cache, and so on. auto_ptr<MultiPlanRunner> mpr(new MultiPlanRunner(canonicalQuery.release())); for (size_t i = 0; i < solutions.size(); ++i) { WorkingSet* ws; PlanStage* root; verify(StageBuilder::build(*solutions[i], &root, &ws)); // Takes ownership of all arguments. mpr->addPlan(solutions[i], root, ws); } *out = mpr.release(); return Status::OK(); } }
void QwtPlot::print(QPaintDevice &paintDev, const QwtPlotPrintFilter &pfilter) const { QPaintDeviceMetrics mpr(&paintDev); QRect rect(0, 0, mpr.width(), mpr.height()); double aspect = double(rect.width())/double(rect.height()); if ((aspect < 1.0)) rect.setHeight(int(aspect*rect.width())); QPainter p(&paintDev); print(&p, rect, pfilter); }
int msl_asat_intercept(struct plnstr *msl, coord x, coord y) { struct sctstr sect; struct emp_qelem irvlist; getsect(x, y, §); mpr(sect.sct_own, "%s has positioned a satellite over %s\n", cname(msl->pln_own), xyas(x, y, sect.sct_own)); msl_sel(&irvlist, x, y, msl->pln_own, P_O, 0, 0); return msl_intercept(msl, §, 0, &irvlist, "satellite", "a-sat missile", N_SAT_KILL); }
TEST(MPRReaderV4, readMPR) { std::istringstream text ( "version4\n" "mikroprogramm:\n" "000 IFETCH 3b 00 78 60 60 00 82 00 00 84\n" "001 3d 00 78 60 60 00 82 00 00 84\n" "maschinenprogramm:\n" "0000-03ff\n" "0104\n" "0115" ); std::ostream cerr(0); MPRReaderV4 reader; MPRFile mpr("test file 1"); reader.readMPR(text, mpr, cerr); // check size of vectors ASSERT_EQ(2, mpr.getMicroLines().size()); ASSERT_EQ(2, mpr.getRamCells().size()); // check file name EXPECT_EQ("test file 1", mpr.getName()); // check first micro line std::bitset<80> bits; bits[0] = 1; bits[1] = 1; bits[3] = 1; bits[4] = 1; bits[5] = 1; bits[19] = 1; bits[20] = 1; bits[21] = 1; bits[22] = 1; bits[29] = 1; bits[30] = 1; bits[37] = 1; bits[38] = 1; bits[49] = 1; bits[55] = 1; bits[74] = 1; bits[79] = 1; EXPECT_EQ(bits, mpr.getMicroLines()[0].getBits()); // check micro line line numbers EXPECT_EQ(0, mpr.getMicroLines()[0].getLineNumber()); EXPECT_EQ(1, mpr.getMicroLines()[1].getLineNumber()); // check ram cells EXPECT_EQ("0104", mpr.getRamCells()[0].getData()); EXPECT_EQ("0115", mpr.getRamCells()[1].getData()); }
/*! \brief Render the plot to a paint device ( f.e a QPrinter ) A convenience method, that calculates the target rectangle from the paintdevice metrics. \sa renderTo(QPainter *, const QRect &) */ void QwtPolarPlot::renderTo( QPaintDevice &paintDev ) const { #if QT_VERSION < 0x040000 QPaintDeviceMetrics mpr( &paintDev ); int w = mpr.width(); int h = mpr.height(); #else int w = paintDev.width(); int h = paintDev.height(); #endif const QRect rect( 0, 0, w, h ); QPainter p( &paintDev ); renderTo( &p, rect ); }
TEST(MPRReaderV4, readMPRWithWrongContent) { std::istringstream text ( "<html>\n" "<head></head>" ); std::ostringstream errStream; MPRReaderV4 reader; MPRFile mpr("with wrong content"); bool returnCode = reader.readMPR(text, mpr, errStream); EXPECT_FALSE(returnCode) << "Should return false in case of parsing error"; EXPECT_NE("", errStream.str()) << "Should print error to error stream"; EXPECT_EQ(0, mpr.getMicroLines().size()); EXPECT_EQ(0, mpr.getRamCells().size()); }
void QwtPlot::print(QPaintDevice &paintDev, const QwtPlotPrintFilter &pfilter) const { #if QT_VERSION < 0x040000 QPaintDeviceMetrics mpr(&paintDev); int w = mpr.width(); int h = mpr.height(); #else int w = paintDev.width(); int h = paintDev.height(); #endif QRect rect(0, 0, w, h); double aspect = double(rect.width())/double(rect.height()); if ((aspect < 1.0)) rect.setHeight(int(aspect*rect.width())); QPainter p(&paintDev); print(&p, rect, pfilter); }
/* * Update cargo of @carrier for movement or destruction. * If the carrier is destroyed, destroy its cargo (planes, land units, * nukes). * Else update their location to the carrier's. Any op sectors equal * to location get updated, too. * Return number of units updated. */ int unit_update_cargo(struct empobj *carrier) { int cargo_type; struct nstr_item ni; union empobj_storage obj; int n = 0; for (cargo_type = EF_PLANE; cargo_type <= EF_NUKE; cargo_type++) { snxtitem_cargo(&ni, cargo_type, carrier->ef_type, carrier->uid); while (nxtitem(&ni, &obj)) { if (carrier->own) unit_teleport(&obj.gen, carrier->x, carrier->y); else { mpr(obj.gen.own, "%s lost!\n", unit_nameof(&obj.gen)); obj.gen.effic = 0; } put_empobj(cargo_type, obj.gen.uid, &obj); n++; } } return n; }
/** * For a given query, get a runner. The runner could be a SingleSolutionRunner, a * CachedQueryRunner, or a MultiPlanRunner, depending on the cache/query solver/etc. */ Status getRunner(Collection* collection, CanonicalQuery* rawCanonicalQuery, Runner** out, size_t plannerOptions) { verify(rawCanonicalQuery); auto_ptr<CanonicalQuery> canonicalQuery(rawCanonicalQuery); // This can happen as we're called by internal clients as well. if (NULL == collection) { const string& ns = canonicalQuery->ns(); *out = new EOFRunner(canonicalQuery.release(), ns); return Status::OK(); } // If we have an _id index we can use the idhack runner. if (canUseIDHack(*canonicalQuery) && collection->getIndexCatalog()->findIdIndex()) { *out = new IDHackRunner(collection, canonicalQuery.release()); return Status::OK(); } // If it's not NULL, we may have indices. Access the catalog and fill out IndexEntry(s) QueryPlannerParams plannerParams; IndexCatalog::IndexIterator ii = collection->getIndexCatalog()->getIndexIterator(false); while (ii.more()) { const IndexDescriptor* desc = ii.next(); plannerParams.indices.push_back(IndexEntry(desc->keyPattern(), desc->isMultikey(), desc->isSparse(), desc->indexName(), desc->infoObj())); } // If query supports index filters, filter params.indices by indices in query settings. QuerySettings* querySettings = collection->infoCache()->getQuerySettings(); AllowedIndices* allowedIndicesRaw; // Filter index catalog if index filters are specified for query. // Also, signal to planner that application hint should be ignored. if (querySettings->getAllowedIndices(*canonicalQuery, &allowedIndicesRaw)) { boost::scoped_ptr<AllowedIndices> allowedIndices(allowedIndicesRaw); filterAllowedIndexEntries(*allowedIndices, &plannerParams.indices); plannerParams.indexFiltersApplied = true; } // Tailable: If the query requests tailable the collection must be capped. if (canonicalQuery->getParsed().hasOption(QueryOption_CursorTailable)) { if (!collection->isCapped()) { return Status(ErrorCodes::BadValue, "error processing query: " + canonicalQuery->toString() + " tailable cursor requested on non capped collection"); } // If a sort is specified it must be equal to expectedSort. const BSONObj expectedSort = BSON("$natural" << 1); const BSONObj& actualSort = canonicalQuery->getParsed().getSort(); if (!actualSort.isEmpty() && !(actualSort == expectedSort)) { return Status(ErrorCodes::BadValue, "error processing query: " + canonicalQuery->toString() + " invalid sort specified for tailable cursor: " + actualSort.toString()); } } // Process the planning options. plannerParams.options = plannerOptions; if (storageGlobalParams.noTableScan) { const string& ns = canonicalQuery->ns(); // There are certain cases where we ignore this restriction: bool ignore = canonicalQuery->getQueryObj().isEmpty() || (string::npos != ns.find(".system.")) || (0 == ns.find("local.")); if (!ignore) { plannerParams.options |= QueryPlannerParams::NO_TABLE_SCAN; } } if (!(plannerParams.options & QueryPlannerParams::NO_TABLE_SCAN)) { plannerParams.options |= QueryPlannerParams::INCLUDE_COLLSCAN; } // If the caller wants a shard filter, make sure we're actually sharded. if (plannerParams.options & QueryPlannerParams::INCLUDE_SHARD_FILTER) { CollectionMetadataPtr collMetadata = shardingState.getCollectionMetadata(canonicalQuery->ns()); if (collMetadata) { plannerParams.shardKey = collMetadata->getKeyPattern(); } else { // If there's no metadata don't bother w/the shard filter since we won't know what // the key pattern is anyway... plannerParams.options &= ~QueryPlannerParams::INCLUDE_SHARD_FILTER; } } // Try to look up a cached solution for the query. // // Skip cache look up for non-cacheable queries. // See PlanCache::shouldCacheQuery() // // TODO: Can the cache have negative data about a solution? CachedSolution* rawCS; if (PlanCache::shouldCacheQuery(*canonicalQuery) && collection->infoCache()->getPlanCache()->get(*canonicalQuery, &rawCS).isOK()) { // We have a CachedSolution. Have the planner turn it into a QuerySolution. boost::scoped_ptr<CachedSolution> cs(rawCS); QuerySolution *qs, *backupQs; Status status = QueryPlanner::planFromCache(*canonicalQuery, plannerParams, *cs, &qs, &backupQs); // See SERVER-12438. Unfortunately we have to defer to the backup solution // if both a batch size is set and a sort is requested. // // TODO: it would be really nice to delete this block in the future. if (status.isOK() && NULL != backupQs && 0 < canonicalQuery->getParsed().getNumToReturn() && !canonicalQuery->getParsed().getSort().isEmpty()) { delete qs; WorkingSet* ws; PlanStage* root; verify(StageBuilder::build(*backupQs, &root, &ws)); // And, run the plan. *out = new SingleSolutionRunner(collection, canonicalQuery.release(), backupQs, root, ws); return Status::OK(); } if (status.isOK()) { if (plannerParams.options & QueryPlannerParams::PRIVATE_IS_COUNT) { if (turnIxscanIntoCount(qs)) { WorkingSet* ws; PlanStage* root; verify(StageBuilder::build(*qs, &root, &ws)); *out = new SingleSolutionRunner(collection, canonicalQuery.release(), qs, root, ws); if (NULL != backupQs) { delete backupQs; } return Status::OK(); } } WorkingSet* ws; PlanStage* root; verify(StageBuilder::build(*qs, &root, &ws)); CachedPlanRunner* cpr = new CachedPlanRunner(collection, canonicalQuery.release(), qs, root, ws); if (NULL != backupQs) { WorkingSet* backupWs; PlanStage* backupRoot; verify(StageBuilder::build(*backupQs, &backupRoot, &backupWs)); cpr->setBackupPlan(backupQs, backupRoot, backupWs); } *out = cpr; return Status::OK(); } } if (enableIndexIntersection) { plannerParams.options |= QueryPlannerParams::INDEX_INTERSECTION; } plannerParams.options |= QueryPlannerParams::KEEP_MUTATIONS; vector<QuerySolution*> solutions; Status status = QueryPlanner::plan(*canonicalQuery, plannerParams, &solutions); if (!status.isOK()) { return Status(ErrorCodes::BadValue, "error processing query: " + canonicalQuery->toString() + " planner returned error: " + status.reason()); } // We cannot figure out how to answer the query. Perhaps it requires an index // we do not have? if (0 == solutions.size()) { return Status(ErrorCodes::BadValue, str::stream() << "error processing query: " << canonicalQuery->toString() << " No query solutions"); } // See if one of our solutions is a fast count hack in disguise. if (plannerParams.options & QueryPlannerParams::PRIVATE_IS_COUNT) { for (size_t i = 0; i < solutions.size(); ++i) { if (turnIxscanIntoCount(solutions[i])) { // Great, we can use solutions[i]. Clean up the other QuerySolution(s). for (size_t j = 0; j < solutions.size(); ++j) { if (j != i) { delete solutions[j]; } } // We're not going to cache anything that's fast count. WorkingSet* ws; PlanStage* root; verify(StageBuilder::build(*solutions[i], &root, &ws)); *out = new SingleSolutionRunner(collection, canonicalQuery.release(), solutions[i], root, ws); return Status::OK(); } } } if (1 == solutions.size()) { // Only one possible plan. Run it. Build the stages from the solution. WorkingSet* ws; PlanStage* root; verify(StageBuilder::build(*solutions[0], &root, &ws)); // And, run the plan. *out = new SingleSolutionRunner(collection, canonicalQuery.release(),solutions[0], root, ws); return Status::OK(); } else { // See SERVER-12438. In an ideal world we should not arbitrarily prefer certain // solutions over others. But unfortunately for historical reasons we are forced // to prefer a solution where the index provides the sort, if the batch size // is set and a sort is requested. Read SERVER-12438 for details, if you dare. // // TODO: it would be really nice to delete this entire block in the future. if (0 < canonicalQuery->getParsed().getNumToReturn() && !canonicalQuery->getParsed().getSort().isEmpty()) { // Look for a solution without a blocking sort stage. for (size_t i = 0; i < solutions.size(); ++i) { if (!solutions[i]->hasSortStage) { WorkingSet* ws; PlanStage* root; verify(StageBuilder::build(*solutions[i], &root, &ws)); // Free unused solutions. for (size_t j = 0; j < solutions.size(); ++j) { if (j != i) { delete solutions[j]; } } // And, run the plan. *out = new SingleSolutionRunner(collection, canonicalQuery.release(), solutions[i], root, ws); return Status::OK(); } } } // Many solutions. Let the MultiPlanRunner pick the best, update the cache, and so on. auto_ptr<MultiPlanRunner> mpr(new MultiPlanRunner(collection,canonicalQuery.release())); for (size_t i = 0; i < solutions.size(); ++i) { WorkingSet* ws; PlanStage* root; if (solutions[i]->cacheData.get()) { solutions[i]->cacheData->indexFilterApplied = plannerParams.indexFiltersApplied; } verify(StageBuilder::build(*solutions[i], &root, &ws)); // Takes ownership of all arguments. mpr->addPlan(solutions[i], root, ws); } *out = mpr.release(); return Status::OK(); } }
void run() { Client::WriteContext ctx(ns()); const int N = 5000; for (int i = 0; i < N; ++i) { insert(BSON("foo" << (i % 10))); } addIndex(BSON("foo" << 1)); // Plan 0: IXScan over foo == 7 // Every call to work() returns something so this should clearly win (by current scoring // at least). IndexScanParams ixparams; ixparams.descriptor = getIndex(BSON("foo" << 1)); ixparams.bounds.isSimpleRange = true; ixparams.bounds.startKey = BSON("" << 7); ixparams.bounds.endKey = BSON("" << 7); ixparams.bounds.endKeyInclusive = true; ixparams.direction = 1; auto_ptr<WorkingSet> firstWs(new WorkingSet()); IndexScan* ix = new IndexScan(ixparams, firstWs.get(), NULL); auto_ptr<PlanStage> firstRoot(new FetchStage(firstWs.get(), ix, NULL)); // Plan 1: CollScan with matcher. CollectionScanParams csparams; csparams.ns = ns(); csparams.direction = CollectionScanParams::FORWARD; auto_ptr<WorkingSet> secondWs(new WorkingSet()); // Make the filter. BSONObj filterObj = BSON("foo" << 7); StatusWithMatchExpression swme = MatchExpressionParser::parse(filterObj); verify(swme.isOK()); auto_ptr<MatchExpression> filter(swme.getValue()); // Make the stage. auto_ptr<PlanStage> secondRoot(new CollectionScan(csparams, secondWs.get(), filter.get())); // Hand the plans off to the runner. CanonicalQuery* cq = NULL; verify(CanonicalQuery::canonicalize(ns(), BSON("foo" << 7), &cq).isOK()); verify(NULL != cq); MultiPlanRunner mpr(ctx.ctx().db()->getCollection(ns()),cq); mpr.addPlan(createQuerySolution(), firstRoot.release(), firstWs.release()); mpr.addPlan(createQuerySolution(), secondRoot.release(), secondWs.release()); // Plan 0 aka the first plan aka the index scan should be the best. size_t best; ASSERT(mpr.pickBestPlan(&best)); ASSERT_EQUALS(size_t(0), best); // Get all our results out. int results = 0; BSONObj obj; while (Runner::RUNNER_ADVANCED == mpr.getNext(&obj, NULL)) { ASSERT_EQUALS(obj["foo"].numberInt(), 7); ++results; } ASSERT_EQUALS(results, N / 10); }
int APIENTRY WinMain(HINSTANCE inst, HINSTANCE junk, char *args, int junk2) { MaHttp *http; // Http service inside our app MaServer *server; // For the HTTP server Mpr mpr("winEventLoop"); // Initialize the run time // // Do the following two statements only if you want debug trace // mp = &mpr; #if BLD_FEATURE_LOG mpr.addListener(new MprLogToFile()); mpr.setLogSpec("error.log:4"); #endif if (findInstance()) { mprError(MPR_L, MPR_LOG, "Application is already active"); return FALSE; } // // Create the window object // if (initWindow() < 0) { mprError(MPR_L, MPR_ERROR, "Can't initialize application Window"); return FALSE; } // // Use windows async select and message dispatcher rather than // select() // mp->setAsyncSelectMode(MPR_ASYNC_SELECT); // // Start the Embedthis Portable Runtime and request single threading // NOTE: this program can be compiled multi-threaded. If so, change // the parameter to a "1". // mpr.start(); // // Create Http and Server objects for this application. We set the // ServerName to be "default" and the initial serverRoot to be ".". // This will be overridden in winEventLoop.conf. // http = new MaHttp(); server = new MaServer(http, "default", "."); // // Activate the copy module and handler // new MaCopyModule(0); // // Configure the server with the configuration directive file // if (server->configure("winEventLoop.conf") < 0) { mprFprintf(MPR_STDERR, "Can't configure the server. Error on line %d\n", server->getLine()); exit(2); } // // Start the server // if (http->start() < 0) { mprFprintf(MPR_STDERR, "Can't start the server\n"); exit(2); } // // Service incoming requests until time to exit. // eventLoop(); // // Orderly shutdown // http->stop(); mpr.stop(0); delete server; delete http; // // MPR run-time will automatically stop and be cleaned up // return 0; }
int main(int argc, char** argv) { MaHttp *http; // Http service inside our app MaServer *server; // For the HTTP server Mpr mpr("simpleEsp"); // Initialize the run time #if BLD_FEATURE_LOG // // Do the following two statements only if you want debug trace // mpr.addListener(new MprLogToFile()); mpr.setLogSpec("stdout:4"); #endif // // Start the Embedthis Portable Runtime with 10 pool threads // mpr.start(MPR_SERVICE_THREAD); #if BLD_FEATURE_MULTITHREAD mpr.poolService->setMaxPoolThreads(10); #endif // // Create Http and Server objects for this application. We set the // ServerName to be "default" and the initial serverRoot to be ".". // This will be overridden in simpleEsp.conf. // http = new MaHttp(); server = new MaServer(http, "default", "."); // // Activate the ESP module and handler // new MaEspModule(0); new MaCopyModule(0); // // Configure the server with the configuration directive file // if (server->configure("simpleEsp.conf") < 0) { mprFprintf(MPR_STDERR, "Can't configure the server. Error on line %d\n", server->getLine()); exit(2); } // // Define our ESP procedures // espDefineStringCFunction(0, "helloWorld", helloWorld, 0); // // Start the server // if (http->start() < 0) { mprFprintf(MPR_STDERR, "Can't start the server\n"); exit(2); } // // Tell the MPR to loop servicing incoming requests. We can // replace this call with a variety of event servicing // mechanisms offered by AppWeb. // mpr.serviceEvents(0, -1); // // Orderly shutdown // http->stop(); delete server; delete http; // // MPR run-time will automatically stop and be cleaned up // return 0; }
/** * For a given query, get a runner. The runner could be a SingleSolutionRunner, a * CachedQueryRunner, or a MultiPlanRunner, depending on the cache/query solver/etc. */ Status getRunner(Collection* collection, CanonicalQuery* rawCanonicalQuery, Runner** out, size_t plannerOptions) { verify(rawCanonicalQuery); auto_ptr<CanonicalQuery> canonicalQuery(rawCanonicalQuery); // This can happen as we're called by internal clients as well. if (NULL == collection) { const string& ns = canonicalQuery->ns(); *out = new EOFRunner(canonicalQuery.release(), ns); return Status::OK(); } // If we have an _id index we can use the idhack runner. if (canUseIDHack(*canonicalQuery) && collection->getIndexCatalog()->findIdIndex()) { *out = new IDHackRunner(collection, canonicalQuery.release()); return Status::OK(); } // If it's not NULL, we may have indices. Access the catalog and fill out IndexEntry(s) QueryPlannerParams plannerParams; IndexCatalog::IndexIterator ii = collection->getIndexCatalog()->getIndexIterator(false); while (ii.more()) { const IndexDescriptor* desc = ii.next(); plannerParams.indices.push_back(IndexEntry(desc->keyPattern(), desc->isMultikey(), desc->isSparse(), desc->indexName(), desc->infoObj())); } // If query supports admin hint, filter params.indices by indexes in query settings. QuerySettings* querySettings = collection->infoCache()->getQuerySettings(); AllowedIndices* allowedIndicesRaw; // Filter index catalog if admin hint is specified for query. // Also, signal to planner that application hint should be ignored. if (querySettings->getAllowedIndices(*canonicalQuery, &allowedIndicesRaw)) { boost::scoped_ptr<AllowedIndices> allowedIndices(allowedIndicesRaw); filterAllowedIndexEntries(*allowedIndices, &plannerParams.indices); plannerParams.adminHintApplied = true; } // Tailable: If the query requests tailable the collection must be capped. if (canonicalQuery->getParsed().hasOption(QueryOption_CursorTailable)) { if (!collection->isCapped()) { return Status(ErrorCodes::BadValue, "error processing query: " + canonicalQuery->toString() + " tailable cursor requested on non capped collection"); } // If a sort is specified it must be equal to expectedSort. const BSONObj expectedSort = BSON("$natural" << 1); const BSONObj& actualSort = canonicalQuery->getParsed().getSort(); if (!actualSort.isEmpty() && !(actualSort == expectedSort)) { return Status(ErrorCodes::BadValue, "error processing query: " + canonicalQuery->toString() + " invalid sort specified for tailable cursor: " + actualSort.toString()); } } // Process the planning options. plannerParams.options = plannerOptions; if (storageGlobalParams.noTableScan) { const string& ns = canonicalQuery->ns(); // There are certain cases where we ignore this restriction: bool ignore = canonicalQuery->getQueryObj().isEmpty() || (string::npos != ns.find(".system.")) || (0 == ns.find("local.")); if (!ignore) { plannerParams.options |= QueryPlannerParams::NO_TABLE_SCAN; } } if (!(plannerParams.options & QueryPlannerParams::NO_TABLE_SCAN)) { plannerParams.options |= QueryPlannerParams::INCLUDE_COLLSCAN; } // If the caller wants a shard filter, make sure we're actually sharded. if (plannerParams.options & QueryPlannerParams::INCLUDE_SHARD_FILTER) { CollectionMetadataPtr collMetadata = shardingState.getCollectionMetadata(canonicalQuery->ns()); if (collMetadata) { plannerParams.shardKey = collMetadata->getKeyPattern(); } else { // If there's no metadata don't bother w/the shard filter since we won't know what // the key pattern is anyway... plannerParams.options &= ~QueryPlannerParams::INCLUDE_SHARD_FILTER; } } // Try to look up a cached solution for the query. // // Skip cache look up for non-cacheable queries. // See PlanCache::shouldCacheQuery() // // TODO: Can the cache have negative data about a solution? CachedSolution* rawCS; if (PlanCache::shouldCacheQuery(*canonicalQuery) && collection->infoCache()->getPlanCache()->get(*canonicalQuery, &rawCS).isOK()) { // We have a CachedSolution. Have the planner turn it into a QuerySolution. boost::scoped_ptr<CachedSolution> cs(rawCS); QuerySolution *qs, *backupQs; Status status = QueryPlanner::planFromCache(*canonicalQuery, plannerParams, *cs, &qs, &backupQs); if (status.isOK()) { WorkingSet* ws; PlanStage* root; verify(StageBuilder::build(*qs, &root, &ws)); CachedPlanRunner* cpr = new CachedPlanRunner(canonicalQuery.release(), qs, root, ws); if (NULL != backupQs) { WorkingSet* backupWs; PlanStage* backupRoot; verify(StageBuilder::build(*backupQs, &backupRoot, &backupWs)); cpr->setBackupPlan(backupQs, backupRoot, backupWs); } *out = cpr; return Status::OK(); } } plannerParams.options |= QueryPlannerParams::INDEX_INTERSECTION; plannerParams.options |= QueryPlannerParams::KEEP_MUTATIONS; vector<QuerySolution*> solutions; Status status = QueryPlanner::plan(*canonicalQuery, plannerParams, &solutions); if (!status.isOK()) { return Status(ErrorCodes::BadValue, "error processing query: " + canonicalQuery->toString() + " planner returned error: " + status.reason()); } /* for (size_t i = 0; i < solutions.size(); ++i) { QLOG() << "solution " << i << " is " << solutions[i]->toString() << endl; } */ // We cannot figure out how to answer the query. Should this ever happen? if (0 == solutions.size()) { return Status(ErrorCodes::BadValue, "error processing query: " + canonicalQuery->toString() + " No query solutions"); } if (1 == solutions.size()) { // Only one possible plan. Run it. Build the stages from the solution. WorkingSet* ws; PlanStage* root; verify(StageBuilder::build(*solutions[0], &root, &ws)); // And, run the plan. *out = new SingleSolutionRunner(canonicalQuery.release(), solutions[0], root, ws); return Status::OK(); } else { // Many solutions. Let the MultiPlanRunner pick the best, update the cache, and so on. auto_ptr<MultiPlanRunner> mpr(new MultiPlanRunner(canonicalQuery.release())); for (size_t i = 0; i < solutions.size(); ++i) { WorkingSet* ws; PlanStage* root; if (solutions[i]->cacheData.get()) { solutions[i]->cacheData->adminHintApplied = plannerParams.adminHintApplied; } verify(StageBuilder::build(*solutions[i], &root, &ws)); // Takes ownership of all arguments. mpr->addPlan(solutions[i], root, ws); } *out = mpr.release(); return Status::OK(); } }
int pln_damage(struct plnstr *pp, char type, int noisy) { struct plchrstr *pcp = plchr + pp->pln_type; int load, i, hitroll, aim, len; int dam = 0; int effective = 1; int pinbomber = 0; char buf[80]; if (CANT_HAPPEN(nuk_on_plane(pp) >= 0)) return 0; load = pln_load(pp); if (!load) /* e.g. ab, blowing up on launch pad */ return 0; i = roll(load) + 1; if (i > load) i = load; if (pcp->pl_flags & P_M) { if (pcp->pl_flags & P_MAR) pinbomber = 1; } else if (pcp->pl_flags & P_T) pinbomber = 1; aim = pln_acc(pp); if (type == 's') { effective = !pinbomber; aim = 30 + (pinbomber ? aim : 100 - aim); } else { effective = pinbomber; aim = 100 - aim; } len = 0; while (i--) { dam += roll(6); hitroll = roll(100); if (hitroll >= 90) { dam += 8; if (noisy) len += sprintf(buf + len, "BLAM"); } else if (hitroll < aim) { dam += 5; if (noisy) len += sprintf(buf + len, "Blam"); } else { dam += 1; if (noisy) len += sprintf(buf + len, "blam"); } if (noisy) { if (len > 75) { mpr(pp->pln_own, "%s\n", buf); len = 0; } if (i) len += sprintf(buf + len, "-"); } } if (noisy && len) mpr(pp->pln_own, "%s\n", buf); if (effective) dam *= 2; return dam; }
void takeover(struct sctstr *sp, natid newown) { struct plnstr *pp; struct lndstr *lp; int civ; int che_count; int oldche; int n; struct nstr_item ni; struct plnstr p; struct lndstr land; /* Wipe all the distribution info */ memset(sp->sct_dist, 0, sizeof(sp->sct_dist)); memset(sp->sct_del, 0, sizeof(sp->sct_del)); if (sp->sct_own == 0) sp->sct_off = 0; else sp->sct_off = 1; sp->sct_dist_x = sp->sct_x; sp->sct_dist_y = sp->sct_y; pp = &p; /* Take over planes */ snxtitem_xy(&ni, EF_PLANE, sp->sct_x, sp->sct_y); while (nxtitem(&ni, pp)) { if (pp->pln_own != sp->sct_own) continue; takeover_plane(pp, newown); } /* Take over land units */ lp = &land; snxtitem_xy(&ni, EF_LAND, sp->sct_x, sp->sct_y); while (nxtitem(&ni, lp)) { if ((lp->lnd_own == newown) || (lp->lnd_own == 0)) continue; if (lp->lnd_own != sp->sct_own) continue; if (lp->lnd_ship >= 0 || lp->lnd_land >= 0) continue; /* Spies get a chance to hide */ if (lchr[(int)lp->lnd_type].l_flags & L_SPY) { if (!(chance(LND_SPY_DETECT_CHANCE(lp->lnd_effic)))) continue; } n = lp->lnd_effic - (29 + roll(100)); if (n < 0) n = 0; lp->lnd_effic = n; if (lp->lnd_effic < LAND_MINEFF) { lp->lnd_effic = 0; mpr(newown, "%s blown up by the crew!\n", prland(lp)); wu(0, lp->lnd_own, "%s blown up by the crew when %s took %s!\n", prland(lp), cname(newown), xyas(lp->lnd_x, lp->lnd_y, lp->lnd_own)); } else { mpr(newown, "We have captured %s!\n", prland(lp)); wu(0, lp->lnd_own, "%s captured when %s took %s!\n", prland(lp), cname(newown), xyas(lp->lnd_x, lp->lnd_y, lp->lnd_own)); } takeover_land(lp, newown); } sp->sct_avail = 0; civ = sp->sct_item[I_CIVIL]; oldche = sp->sct_che; /* * create guerrillas from civilians * how spunky are these guys? * n: random number from -25:75 + (50 - loyalty) */ n = (50 - sp->sct_loyal) + (roll(100) - 26); if (n > 0 && sp->sct_own == sp->sct_oldown) { che_count = (civ * n / 3000) + 5; if (che_count * 2 > civ) che_count = civ / 2; che_count /= hap_fact(getnatp(newown), getnatp(sp->sct_own)); if (che_count + oldche > CHE_MAX) che_count = CHE_MAX - oldche; if (che_count > 0) { civ -= che_count; che_count += oldche; } else che_count = oldche; } else che_count = oldche; sp->sct_che = che_count; if (newown != sp->sct_oldown) sp->sct_che_target = newown; if (sp->sct_che_target == 0) sp->sct_che = 0; sp->sct_item[I_CIVIL] = civ; if (sp->sct_oldown == newown || civ == 0) { /* * taking over one of your old sectors */ sp->sct_loyal = 0; sp->sct_oldown = newown; } else { /* * taking over someone else's sector */ sp->sct_loyal = 50; } sp->sct_own = newown; if (opt_MOB_ACCESS) { game_tick_to_now(&sp->sct_access); sp->sct_mobil = -(etu_per_update / sect_mob_neg_factor); } else { sp->sct_mobil = 0; } }
void setrel(natid us, natid them, int rel) { struct natstr *mynp = getnatp(us); struct natstr *themnp = getnatp(them); int oldrel; char *whichway; int n_up = 0; int n_down = 0; char *addendum = NULL; if (CANT_HAPPEN(rel < AT_WAR)) rel = AT_WAR; if (CANT_HAPPEN(rel > ALLIED)) rel = ALLIED; if (CANT_HAPPEN(!mynp || !themnp)) return; if (us == them) return; oldrel = relations_with(us, them); if (oldrel == rel) return; if (rel > oldrel) whichway = "upgraded"; else whichway = "downgraded"; if (rel == ALLIED) { addendum = "Congratulations!"; n_up = N_DECL_ALLY; } else if (rel == FRIENDLY) { n_up = N_UP_FRIENDLY; n_down = N_DOWN_FRIENDLY; } else if (rel == NEUTRAL) { n_up = N_UP_NEUTRAL; n_down = N_DOWN_NEUTRAL; } else if (rel == HOSTILE) { addendum = "Another cold war..."; n_up = N_UP_HOSTILE; n_down = N_DOWN_HOSTILE; } else if (rel < HOSTILE) { addendum = "Declaration made (give 'em hell)."; n_down = N_DECL_WAR; } if (addendum && us == player->cnum && !update_running) pr("%s\n", addendum); mpr(us, "Diplomatic relations with %s %s to \"%s\".\n", cname(them), whichway, relates[rel]); if (!(getrejects(us, themnp) & REJ_TELE)) mpr(them, "Country %s has %s their relations with you to \"%s\"!\n", prnat(mynp), whichway, relates[rel]); putrel(mynp, them, rel); putnat(mynp); if (!player->god) { if (oldrel == ALLIED) nreport(us, N_DIS_ALLY, them, 1); else if (oldrel < HOSTILE && rel >= HOSTILE) nreport(us, N_DIS_WAR, them, 1); if (rel > oldrel) nreport(us, n_up, them, 1); else nreport(us, n_down, them, 1); } if (opt_HIDDEN) setcont(them, us, FOUND_TELE); }
/** * For a given query, get a runner. The runner could be a SingleSolutionRunner, a * CachedQueryRunner, or a MultiPlanRunner, depending on the cache/query solver/etc. */ Status getRunner(CanonicalQuery* rawCanonicalQuery, Runner** out) { verify(rawCanonicalQuery); auto_ptr<CanonicalQuery> canonicalQuery(rawCanonicalQuery); // Try to look up a cached solution for the query. // TODO: Can the cache have negative data about a solution? PlanCache* localCache = PlanCache::get(canonicalQuery->ns()); if (NULL != localCache) { CachedSolution* cs = localCache->get(*canonicalQuery); if (NULL != cs) { // We have a cached solution. Hand the canonical query and cached solution off to // the cached plan runner, which takes ownership of both. WorkingSet* ws; PlanStage* root; verify(StageBuilder::build(*cs->solution, &root, &ws)); *out = new CachedPlanRunner(canonicalQuery.release(), cs, root, ws); return Status::OK(); } } // No entry in cache for the query. We have to solve the query ourself. // Get the indices that we could possibly use. NamespaceDetails* nsd = nsdetails(canonicalQuery->ns().c_str()); // If this is NULL, there is no data but the query is valid. You're allowed to query for // data on an empty collection and it's not an error. There just isn't any data... if (NULL == nsd) { const std::string& ns = canonicalQuery->ns(); *out = new EOFRunner(canonicalQuery.release(), ns); return Status::OK(); } // Tailable: If the query requests tailable the collection must be capped. if (canonicalQuery->getParsed().hasOption(QueryOption_CursorTailable)) { if (!nsd->isCapped()) { return Status(ErrorCodes::BadValue, "tailable cursor requested on non capped collection"); } // If a sort is specified it must be equal to expectedSort. const BSONObj expectedSort = BSON("$natural" << 1); const BSONObj& actualSort = canonicalQuery->getParsed().getSort(); if (!actualSort.isEmpty() && !(actualSort == expectedSort)) { return Status(ErrorCodes::BadValue, "invalid sort specified for tailable cursor: " + actualSort.toString()); } } // If it's not NULL, we may have indices. vector<IndexEntry> indices; for (int i = 0; i < nsd->getCompletedIndexCount(); ++i) { auto_ptr<IndexDescriptor> desc(CatalogHack::getDescriptor(nsd, i)); indices.push_back(IndexEntry(desc->keyPattern(), desc->isMultikey(), desc->isSparse(), desc->indexName())); } vector<QuerySolution*> solutions; size_t options = QueryPlanner::DEFAULT; if (storageGlobalParams.noTableScan) { const string& ns = canonicalQuery->ns(); // There are certain cases where we ignore this restriction: bool ignore = canonicalQuery->getQueryObj().isEmpty() || (string::npos != ns.find(".system.")) || (0 == ns.find("local.")); if (!ignore) { options |= QueryPlanner::NO_TABLE_SCAN; } } else { options |= QueryPlanner::INCLUDE_COLLSCAN; } QueryPlanner::plan(*canonicalQuery, indices, options, &solutions); /* for (size_t i = 0; i < solutions.size(); ++i) { QLOG() << "solution " << i << " is " << solutions[i]->toString() << endl; } */ // We cannot figure out how to answer the query. Should this ever happen? if (0 == solutions.size()) { return Status(ErrorCodes::BadValue, "Can't create a plan for the canonical query " + canonicalQuery->toString()); } if (1 == solutions.size()) { // Only one possible plan. Run it. Build the stages from the solution. WorkingSet* ws; PlanStage* root; verify(StageBuilder::build(*solutions[0], &root, &ws)); // And, run the plan. *out = new SingleSolutionRunner(canonicalQuery.release(), solutions[0], root, ws); return Status::OK(); } else { // Many solutions. Let the MultiPlanRunner pick the best, update the cache, and so on. auto_ptr<MultiPlanRunner> mpr(new MultiPlanRunner(canonicalQuery.release())); for (size_t i = 0; i < solutions.size(); ++i) { WorkingSet* ws; PlanStage* root; verify(StageBuilder::build(*solutions[i], &root, &ws)); // Takes ownership of all arguments. mpr->addPlan(solutions[i], root, ws); } *out = mpr.release(); return Status::OK(); } }
/** * For a given query, get a runner. The runner could be a SingleSolutionRunner, a * CachedQueryRunner, or a MultiPlanRunner, depending on the cache/query solver/etc. */ Status getRunner(CanonicalQuery* rawCanonicalQuery, Runner** out, size_t plannerOptions) { verify(rawCanonicalQuery); auto_ptr<CanonicalQuery> canonicalQuery(rawCanonicalQuery); // Try to look up a cached solution for the query. // TODO: Can the cache have negative data about a solution? PlanCache* localCache = PlanCache::get(canonicalQuery->ns()); if (NULL != localCache) { CachedSolution* cs = localCache->get(*canonicalQuery); if (NULL != cs) { // We have a cached solution. Hand the canonical query and cached solution off to // the cached plan runner, which takes ownership of both. WorkingSet* ws; PlanStage* root; verify(StageBuilder::build(*cs->solution, &root, &ws)); *out = new CachedPlanRunner(canonicalQuery.release(), cs, root, ws); return Status::OK(); } } // No entry in cache for the query. We have to solve the query ourself. // Get the indices that we could possibly use. Database* db = cc().database(); verify( db ); Collection* collection = db->getCollection( canonicalQuery->ns() ); // This can happen as we're called by internal clients as well. if (NULL == collection) { const string& ns = canonicalQuery->ns(); *out = new EOFRunner(canonicalQuery.release(), ns); return Status::OK(); } // If we have an _id index we can use the idhack runner. if (canUseIDHack(*canonicalQuery) && collection->getIndexCatalog()->findIdIndex()) { *out = new IDHackRunner(collection, canonicalQuery.release()); return Status::OK(); } // If it's not NULL, we may have indices. Access the catalog and fill out IndexEntry(s) QueryPlannerParams plannerParams; for (int i = 0; i < collection->getIndexCatalog()->numIndexesReady(); ++i) { IndexDescriptor* desc = collection->getIndexCatalog()->getDescriptor( i ); plannerParams.indices.push_back(IndexEntry(desc->keyPattern(), desc->isMultikey(), desc->isSparse(), desc->indexName())); } // Tailable: If the query requests tailable the collection must be capped. if (canonicalQuery->getParsed().hasOption(QueryOption_CursorTailable)) { if (!collection->isCapped()) { return Status(ErrorCodes::BadValue, "tailable cursor requested on non capped collection"); } // If a sort is specified it must be equal to expectedSort. const BSONObj expectedSort = BSON("$natural" << 1); const BSONObj& actualSort = canonicalQuery->getParsed().getSort(); if (!actualSort.isEmpty() && !(actualSort == expectedSort)) { return Status(ErrorCodes::BadValue, "invalid sort specified for tailable cursor: " + actualSort.toString()); } } // Process the planning options. plannerParams.options = plannerOptions; if (storageGlobalParams.noTableScan) { const string& ns = canonicalQuery->ns(); // There are certain cases where we ignore this restriction: bool ignore = canonicalQuery->getQueryObj().isEmpty() || (string::npos != ns.find(".system.")) || (0 == ns.find("local.")); if (!ignore) { plannerParams.options |= QueryPlannerParams::NO_TABLE_SCAN; } } if (!(plannerParams.options & QueryPlannerParams::NO_TABLE_SCAN)) { plannerParams.options |= QueryPlannerParams::INCLUDE_COLLSCAN; } // If the caller wants a shard filter, make sure we're actually sharded. if (plannerParams.options & QueryPlannerParams::INCLUDE_SHARD_FILTER) { CollectionMetadataPtr collMetadata = shardingState.getCollectionMetadata(canonicalQuery->ns()); if (collMetadata) { plannerParams.shardKey = collMetadata->getKeyPattern(); } else { // If there's no metadata don't bother w/the shard filter since we won't know what // the key pattern is anyway... plannerParams.options &= ~QueryPlannerParams::INCLUDE_SHARD_FILTER; } } vector<QuerySolution*> solutions; QueryPlanner::plan(*canonicalQuery, plannerParams, &solutions); /* for (size_t i = 0; i < solutions.size(); ++i) { QLOG() << "solution " << i << " is " << solutions[i]->toString() << endl; } */ // We cannot figure out how to answer the query. Should this ever happen? if (0 == solutions.size()) { return Status(ErrorCodes::BadValue, "No query solutions"); } if (1 == solutions.size()) { // Only one possible plan. Run it. Build the stages from the solution. WorkingSet* ws; PlanStage* root; verify(StageBuilder::build(*solutions[0], &root, &ws)); // And, run the plan. *out = new SingleSolutionRunner(canonicalQuery.release(), solutions[0], root, ws); return Status::OK(); } else { // Many solutions. Let the MultiPlanRunner pick the best, update the cache, and so on. auto_ptr<MultiPlanRunner> mpr(new MultiPlanRunner(canonicalQuery.release())); for (size_t i = 0; i < solutions.size(); ++i) { WorkingSet* ws; PlanStage* root; verify(StageBuilder::build(*solutions[i], &root, &ws)); // Takes ownership of all arguments. mpr->addPlan(solutions[i], root, ws); } *out = mpr.release(); return Status::OK(); } }
Status getRunnerAlwaysPlan(Collection* collection, CanonicalQuery* rawCanonicalQuery, const QueryPlannerParams& plannerParams, Runner** out) { invariant(collection); invariant(rawCanonicalQuery); auto_ptr<CanonicalQuery> canonicalQuery(rawCanonicalQuery); vector<QuerySolution*> solutions; Status status = QueryPlanner::plan(*canonicalQuery, plannerParams, &solutions); if (!status.isOK()) { return Status(ErrorCodes::BadValue, "error processing query: " + canonicalQuery->toString() + " planner returned error: " + status.reason()); } // We cannot figure out how to answer the query. Perhaps it requires an index // we do not have? if (0 == solutions.size()) { return Status(ErrorCodes::BadValue, str::stream() << "error processing query: " << canonicalQuery->toString() << " No query solutions"); } // See if one of our solutions is a fast count hack in disguise. if (plannerParams.options & QueryPlannerParams::PRIVATE_IS_COUNT) { for (size_t i = 0; i < solutions.size(); ++i) { if (turnIxscanIntoCount(solutions[i])) { // Great, we can use solutions[i]. Clean up the other QuerySolution(s). for (size_t j = 0; j < solutions.size(); ++j) { if (j != i) { delete solutions[j]; } } LOG(2) << "Using fast count: " << canonicalQuery->toStringShort() << ", planSummary: " << getPlanSummary(*solutions[i]); // We're not going to cache anything that's fast count. WorkingSet* ws; PlanStage* root; verify(StageBuilder::build(collection, *solutions[i], &root, &ws)); *out = new SingleSolutionRunner(collection, canonicalQuery.release(), solutions[i], root, ws); return Status::OK(); } } } if (1 == solutions.size()) { LOG(2) << "Only one plan is available; it will be run but will not be cached. " << canonicalQuery->toStringShort() << ", planSummary: " << getPlanSummary(*solutions[0]); // Only one possible plan. Run it. Build the stages from the solution. WorkingSet* ws; PlanStage* root; verify(StageBuilder::build(collection, *solutions[0], &root, &ws)); // And, run the plan. *out = new SingleSolutionRunner(collection, canonicalQuery.release(), solutions[0], root, ws); return Status::OK(); } else { // Many solutions. Let the MultiPlanRunner pick the best, update the cache, and so on. auto_ptr<MultiPlanRunner> mpr(new MultiPlanRunner(collection,canonicalQuery.release())); for (size_t i = 0; i < solutions.size(); ++i) { WorkingSet* ws; PlanStage* root; if (solutions[i]->cacheData.get()) { solutions[i]->cacheData->indexFilterApplied = plannerParams.indexFiltersApplied; } verify(StageBuilder::build(collection, *solutions[i], &root, &ws)); // Takes ownership of all arguments. mpr->addPlan(solutions[i], root, ws); } *out = mpr.release(); return Status::OK(); } }
static int msl_intercept(struct plnstr *msl, struct sctstr *sp, int sublaunch, struct emp_qelem *irvlist, char *att_name, char *def_name, int news_item) { struct plnstr *pp; struct emp_qelem *intlist; struct emp_qelem intfoo; struct emp_qelem *qp; struct emp_qelem *next; struct plist *ip; int icount = 0; short destroyed; char *who = sublaunch ? "" : cname(msl->pln_own); intlist = &intfoo; emp_initque(intlist); /* First choose interceptors belonging to the target sector */ /* only allow two defense missiles per missile attack */ for (qp = irvlist->q_forw; qp != irvlist && icount < 2; qp = next) { next = qp->q_forw; ip = (struct plist *)qp; pp = &ip->plane; if (pp->pln_own != sp->sct_own) continue; if (mission_pln_equip(ip, NULL, 'i') < 0) { emp_remque(qp); free(qp); continue; } /* got one interceptor, delete from irv_list and * add to int_list. */ emp_remque(qp); emp_insque(qp, intlist); putplane(pp->pln_uid, pp); icount++; } /* only allow two defense missiles per missile attack */ for (qp = irvlist->q_forw; qp != irvlist && icount < 2; qp = next) { next = qp->q_forw; ip = (struct plist *)qp; pp = &ip->plane; if (mission_pln_equip(ip, NULL, 'i') < 0) { emp_remque(qp); free(qp); continue; } /* got one interceptor, delete from irv_list and * add to int_list. */ emp_remque(qp); emp_insque(qp, intlist); putplane(pp->pln_uid, pp); icount++; } /* Now, clean out the queue */ while (!QEMPTY(irvlist)) { qp = irvlist->q_forw; emp_remque(qp); free(qp); } if (icount == 0) { mpr(sp->sct_own, "No %ss launched to intercept.\n", def_name); return 0; } /* attempt to destroy incoming missile */ destroyed = 0; while (!destroyed && !QEMPTY(intlist)) { qp = intlist->q_forw; ip = (struct plist *)qp; pp = &ip->plane; mpr(msl->pln_own, "%s %s launched in defense!\n", cname(pp->pln_own), def_name); if (sp->sct_own == pp->pln_own) { mpr(sp->sct_own, "%s launched to intercept %s %s!\n", def_name, who, att_name); } else { mpr(sp->sct_own, "%s launched an %s to intercept the %s %s!\n", cname(pp->pln_own), def_name, who, att_name); mpr(pp->pln_own, "%s launched to intercept %s %s arcing towards %s territory!\n", def_name, who, att_name, cname(sp->sct_own)); } if (msl_launch(pp, EF_PLANE, att_name, sp->sct_x, sp->sct_y, msl->pln_own, NULL) >= 0 && msl_hit(pp, pln_def(msl), EF_PLANE, 0, 0, 0, msl->pln_own)) { mpr(msl->pln_own, "%s destroyed by %s %s!\n", att_name, cname(pp->pln_own), def_name); mpr(sp->sct_own, "%s %s intercepted!\n", who, att_name); if (sp->sct_own != pp->pln_own) mpr(pp->pln_own, "%s %s intercepted!\n", who, att_name); if (sublaunch) nreport(pp->pln_own, news_item, 0, 1); else nreport(pp->pln_own, news_item, msl->pln_own, 1); destroyed = 1; } /* zap the missile */ pp->pln_effic = 0; putplane(pp->pln_uid, pp); emp_remque(qp); free(qp); } /* Clean out what is left in the list */ while (!QEMPTY(intlist)) { qp = intlist->q_forw; emp_remque(qp); free(qp); } if (destroyed) return 1; if (icount) { mpr(msl->pln_own, "%s made it through %s defenses!\n", att_name, def_name); mpr(sp->sct_own, "%s made it through %s defenses!\n", att_name, def_name); } return 0; }
int msl_launch(struct plnstr *pp, int type, char *what, coord x, coord y, natid victim, int *sublaunchp) { struct shpstr ship; struct nukstr nuke; int sublaunch = 0; char *base, *in_or_at, *from; mpr(pp->pln_own, "Preparing to launch %s at %s %s %s%s\n", prplane(pp), cname(victim), what, type != EF_SECTOR ? "in " : "", xyas(x, y, pp->pln_own)); if (pp->pln_ship >= 0) { getship(pp->pln_ship, &ship); base = prship(&ship); in_or_at = " in "; if (mchr[(int)ship.shp_type].m_flags & M_SUB) { sublaunch = 1; from = "in hatch"; } else from = "on deck"; } else { if (pp->pln_harden > 0) { base = "missile silo"; in_or_at = " at "; from = "in silo"; } else { base = in_or_at = ""; from = "on launch pad"; } } mpr(pp->pln_own, "\tLaunching from %s%s%s\n", base, in_or_at, xyas(pp->pln_x, pp->pln_y, pp->pln_own)); CANT_HAPPEN(pp->pln_flags & PLN_LAUNCHED); pp->pln_flags |= PLN_LAUNCHED; putplane(pp->pln_uid, pp); if (chance((0.05 + (100 - pp->pln_effic) / 100.0) * (1 - techfact(pp->pln_tech, 1.0)))) { mpr(pp->pln_own, "KABOOOOM! Missile explodes %s!\n", from); if (getnuke(nuk_on_plane(pp), &nuke)) { mpr(pp->pln_own, "%s lost!\n", prnuke(&nuke)); nuke.nuk_effic = 0; putnuke(nuke.nuk_uid, &nuke); } #if 0 /* * Disabled for now, because it breaks callers that call * msl_launch() for each member of a list of planes, created * by msl_sel() or perform_mission(). Damage to the base can * damage other planes. Any copies of them in the list become * stale. When msl_launch() modifies and writes back such a * stale copy, the damage gets wiped out, triggering a seqno * oops. */ if (chance(0.33)) { struct sctstr sect; int dam; dam = pln_damage(pp, 'p', NULL) / 2; if (pp->pln_ship >= 0) { shipdamage(&ship, dam); putship(ship.shp_uid, &ship); } else { mpr(pp->pln_own, "Explosion damages %s %d%%\n", xyas(pp->pln_x, pp->pln_y, pp->pln_own), dam); getsect(pp->pln_x, pp->pln_y, §); sectdamage(§, dam); putsect(§); } } #endif return -1; } mpr(pp->pln_own, "\tSHWOOOOOSH! Missile launched!\n"); if (type != EF_PLANE) mpr(victim, "Incoming %s missile sighted at %s...\n", sublaunch ? "sub-launched" : cname(pp->pln_own), xyas(x, y, victim)); if (type == EF_SECTOR || type == EF_LAND) { if (msl_abm_intercept(pp, x, y, sublaunch)) return -1; } if (type == EF_SHIP) { if (shp_missile_defense(x, y, pp->pln_own, pln_def(pp))) { return -1; } } if (sublaunchp) *sublaunchp = sublaunch; return 0; }
/* Knock down a bridge span. Note that this does NOT write the * sector out to the database, it's up to the caller to do that. */ static void knockdown(struct sctstr *sp) { struct lndstr land; struct plnstr plane; struct nukstr nuke; struct nstr_item ni; mpr(sp->sct_own, "Crumble... SCREEEECH! Splash! Bridge%s falls at %s!\n", sp->sct_type == SCT_BTOWER ? " tower" : "", xyas(sp->sct_x, sp->sct_y, sp->sct_own)); if (!SCT_MINES_ARE_SEAMINES(sp)) sp->sct_mines = 0; sp->sct_type = SCT_WATER; sp->sct_newtype = SCT_WATER; sp->sct_own = 0; sp->sct_oldown = 0; sp->sct_mobil = 0; sp->sct_effic = 0; /* Sink all the units */ snxtitem_xy(&ni, EF_LAND, sp->sct_x, sp->sct_y); while (nxtitem(&ni, &land)) { if (land.lnd_own == 0) continue; if (land.lnd_ship >= 0) continue; mpr(land.lnd_own, " AARGH! %s tumbles to its doom!\n", prland(&land)); land.lnd_effic = 0; putland(land.lnd_uid, &land); } /* Sink all the planes */ snxtitem_xy(&ni, EF_PLANE, sp->sct_x, sp->sct_y); while (nxtitem(&ni, &plane)) { if (plane.pln_own == 0) continue; if (plane.pln_flags & PLN_LAUNCHED) continue; if (plane.pln_ship >= 0) continue; mpr(plane.pln_own, " AARGH! %s tumbles to its doom!\n", prplane(&plane)); plane.pln_effic = 0; putplane(plane.pln_uid, &plane); } /* Sink all the nukes */ snxtitem_xy(&ni, EF_NUKE, sp->sct_x, sp->sct_y); while (nxtitem(&ni, &nuke)) { if (nuke.nuk_own == 0) continue; if (nuke.nuk_plane >= 0) continue; mpr(nuke.nuk_own, " %s sinks to the bottom of the sea!\n", prnuke(&nuke)); nuke.nuk_effic = 0; putnuke(nuke.nuk_uid, &nuke); } memset(sp->sct_item, 0, sizeof(sp->sct_item)); memset(sp->sct_del, 0, sizeof(sp->sct_del)); memset(sp->sct_dist, 0, sizeof(sp->sct_dist)); sp->sct_pstage = PLG_HEALTHY; sp->sct_ptime = 0; sp->sct_che = 0; sp->sct_che_target = 0; }
int detonate(struct nukstr *np, coord x, coord y, int airburst) { int nuketype = np->nuk_type; struct nchrstr *ncp; struct plnstr plane; struct sctstr sect; struct shpstr ship; struct lndstr land; struct nukstr nuke; natid own; int type; int damage; int fallout; int rad; struct nstr_sect ns; struct nstr_item ni; int changed = 0; pr("Releasing RV's for %s detonation...\n", airburst ? "airburst" : "groundburst"); getsect(x, y, §); ncp = &nchr[nuketype]; kaboom(x, y, ncp->n_blast); rad = ncp->n_blast; if (!airburst) rad = rad * 2 / 3; if (sect.sct_type == SCT_WATER) rad = 0; /* Nukes falling on water affect only 1 sector */ np->nuk_effic = 0; putnuke(np->nuk_uid, np); snxtsct_dist(&ns, x, y, rad); while (nxtsct(&ns, §)) { own = sect.sct_own; type = sect.sct_type; if ((damage = nukedamage(ncp, ns.curdist, airburst)) <= 0) continue; if (type == SCT_SANCT) { pr("bounced off %s\n", xyas(ns.x, ns.y, player->cnum)); mpr(own, "%s nuclear device bounced off %s\n", cname(player->cnum), xyas(ns.x, ns.y, own)); nreport(player->cnum, N_NUKE, own, 1); continue; } sect_damage(§, damage); if (opt_FALLOUT) { fallout = sect.sct_fallout; if (ncp->n_flags & N_NEUT) fallout += damage * 30; else fallout += damage * 3; sect.sct_fallout = MIN(fallout, FALLOUT_MAX); } if (damage > 100) { sect.sct_oldown = 0; sect.sct_own = 0; if (type == SCT_WATER || type == SCT_BSPAN || type == SCT_BTOWER) { if (type != SCT_WATER) { pr("left nothing but water in %s\n", xyas(ns.x, ns.y, player->cnum)); if (own != player->cnum) mpr(own, "%s nuclear device left nothing but water in %s\n", cname(player->cnum), xyas(ns.x, ns.y, own)); sect.sct_newtype = SCT_WATER; sect.sct_type = SCT_WATER; } } else { sect.sct_newtype = SCT_WASTE; sect.sct_type = SCT_WASTE; pr("turned %s into a radioactive wasteland\n", xyas(ns.x, ns.y, player->cnum)); if (own != player->cnum) mpr(own, "%s nuclear device turned %s into a radioactive wasteland\n", cname(player->cnum), xyas(ns.x, ns.y, own)); } changed |= map_set(player->cnum, sect.sct_x, sect.sct_y, dchr[sect.sct_type].d_mnem, 0); } else { pr("did %d%% damage in %s\n", damage, xyas(ns.x, ns.y, player->cnum)); if (own != player->cnum) mpr(own, "%s nuclear device did %d%% damage in %s\n", cname(player->cnum), damage, xyas(ns.x, ns.y, own)); } (void)putsect(§); if (type != SCT_WATER) nreport(player->cnum, N_NUKE, own, 1); } if (changed) writebmap(player->cnum); snxtitem_dist(&ni, EF_PLANE, x, y, rad); while (nxtitem(&ni, &plane)) { if ((own = plane.pln_own) == 0) continue; if (plane.pln_flags & PLN_LAUNCHED) continue; damage = nukedamage(ncp, ni.curdist, airburst) - plane.pln_harden; if (damage <= 0) continue; if (plane.pln_ship >= 0) { /* Are we on a sub? */ getship(plane.pln_ship, &ship); if (mchr[(int)ship.shp_type].m_flags & M_SUB) { struct sctstr sect1; /* Should we damage this sub? */ getsect(ship.shp_x, ship.shp_y, §1); if (sect1.sct_type == SCT_BSPAN || sect1.sct_type == SCT_BTOWER || sect1.sct_type == SCT_WATER) { /* Ok, we're not in a harbor or trapped inland. Now, did we get pasted directly? */ if (ship.shp_x != x || ship.shp_y != y) { /* Nope, so don't mess with it */ continue; } } } } planedamage(&plane, damage); if (own == player->cnum) { pr("%s at %s reports %d%% damage\n", prplane(&plane), xyas(plane.pln_x, plane.pln_y, player->cnum), damage); } else { mpr(own, "%s nuclear device did %d%% damage to %s at %s\n", cname(player->cnum), damage, prplane(&plane), xyas(plane.pln_x, plane.pln_y, own)); } putplane(ni.cur, &plane); } snxtitem_dist(&ni, EF_LAND, x, y, rad); while (nxtitem(&ni, &land)) { if ((own = land.lnd_own) == 0) continue; if ((damage = nukedamage(ncp, ni.curdist, airburst)) <= 0) continue; if (land.lnd_ship >= 0) { /* Are we on a sub? */ getship(land.lnd_ship, &ship); if (mchr[(int)ship.shp_type].m_flags & M_SUB) { struct sctstr sect1; /* Should we damage this sub? */ getsect(ship.shp_x, ship.shp_y, §1); if (sect1.sct_type == SCT_BSPAN || sect1.sct_type == SCT_BTOWER || sect1.sct_type == SCT_WATER) { /* Ok, we're not in a harbor or trapped inland. Now, did we get pasted directly? */ if (ship.shp_x != x || ship.shp_y != y) { /* Nope, so don't mess with it */ continue; } } } } land_damage(&land, damage); if (own == player->cnum) { pr("%s at %s reports %d%% damage\n", prland(&land), xyas(land.lnd_x, land.lnd_y, player->cnum), damage); } else { mpr(own, "%s nuclear device did %d%% damage to %s at %s\n", cname(player->cnum), damage, prland(&land), xyas(land.lnd_x, land.lnd_y, own)); } putland(land.lnd_uid, &land); } snxtitem_dist(&ni, EF_SHIP, x, y, rad); while (nxtitem(&ni, &ship)) { if ((own = ship.shp_own) == 0) continue; if ((damage = nukedamage(ncp, ni.curdist, airburst)) <= 0) continue; if (mchr[(int)ship.shp_type].m_flags & M_SUB) { struct sctstr sect1; /* Should we damage this sub? */ getsect(ship.shp_x, ship.shp_y, §1); if (sect1.sct_type == SCT_BSPAN || sect1.sct_type == SCT_BTOWER || sect1.sct_type == SCT_WATER) { /* Ok, we're not in a harbor or trapped inland. Now, did we get pasted directly? */ if (ship.shp_x != x || ship.shp_y != y) { /* Nope, so don't mess with it */ continue; } } } ship_damage(&ship, damage); if (own == player->cnum) { pr("%s at %s reports %d%% damage\n", prship(&ship), xyas(ship.shp_x, ship.shp_y, player->cnum), damage); } else { mpr(own, "%s nuclear device did %d%% damage to %s at %s\n", cname(player->cnum), damage, prship(&ship), xyas(ship.shp_x, ship.shp_y, own)); } putship(ship.shp_uid, &ship); } snxtitem_dist(&ni, EF_NUKE, x, y, rad); while (nxtitem(&ni, &nuke)) { if ((own = nuke.nuk_own) == 0) continue; if ((damage = nukedamage(ncp, ni.curdist, airburst)) <= 0) continue; if (!pct_chance(damage)) continue; nuke.nuk_effic = 0; if (own == player->cnum) { pr("%s at %s destroyed\n", prnuke(&nuke), xyas(nuke.nuk_x, nuke.nuk_y, player->cnum)); } else { mpr(own, "%s nuclear device destroyed %s at %s\n", cname(player->cnum), prnuke(&nuke), xyas(nuke.nuk_x, nuke.nuk_y, own)); } putnuke(ni.cur, &nuke); } return nukedamage(ncp, 0, airburst); }