Status BtreeBasedAccessMethod::validateUpdate(const BSONObj &from, const BSONObj &to, const DiskLoc &record, const InsertDeleteOptions &options, UpdateTicket* status) { BtreeBasedPrivateUpdateData *data = new BtreeBasedPrivateUpdateData(); status->_indexSpecificUpdateData.reset(data); getKeys(from, &data->oldKeys); getKeys(to, &data->newKeys); data->loc = record; data->dupsAllowed = options.dupsAllowed; setDifference(data->oldKeys, data->newKeys, &data->removed); setDifference(data->newKeys, data->oldKeys, &data->added); bool checkForDups = !data->added.empty() && (KeyPattern::isIdKeyPattern(_descriptor->keyPattern()) || _descriptor->unique()) && !options.dupsAllowed; if (checkForDups) { for (vector<BSONObj*>::iterator i = data->added.begin(); i != data->added.end(); i++) { Status check = _newInterface->dupKeyCheck(**i, record); if (!check.isOK()) { status->_isValid = false; return check; } } } status->_isValid = true; return Status::OK(); }
Tree setDifference (Tree A, Tree B) { if (isNil(A)) return A; if (isNil(B)) return A; if (hd(A) == hd(B)) return setDifference(tl(A),tl(B)); if (hd(A) < hd(B)) return cons(hd(A), setDifference(tl(A),B)); /* (hd(A) > hd(B)*/ return setDifference(A,tl(B)); }
Status IndexAccessMethod::validateUpdate(OperationContext* txn, const BSONObj& from, const BSONObj& to, const RecordId& record, const InsertDeleteOptions& options, UpdateTicket* ticket, const MatchExpression* indexFilter) { if (!indexFilter || indexFilter->matchesBSON(from)) { // There's no need to compute the prefixes of the indexed fields that possibly caused the // index to be multikey when the old version of the document was written since the index // metadata isn't updated when keys are deleted. MultikeyPaths* multikeyPaths = nullptr; getKeys(from, &ticket->oldKeys, multikeyPaths); } if (!indexFilter || indexFilter->matchesBSON(to)) { getKeys(to, &ticket->newKeys, &ticket->newMultikeyPaths); } ticket->loc = record; ticket->dupsAllowed = options.dupsAllowed; std::tie(ticket->removed, ticket->added) = setDifference(ticket->oldKeys, ticket->newKeys); ticket->_isValid = true; return Status::OK(); }
void getIndexChanges(vector<IndexChanges>& v, NamespaceDetails& d, BSONObj newObj, BSONObj oldObj, bool &changedId) { int z = d.nIndexesBeingBuilt(); v.resize(z); for( int i = 0; i < z; i++ ) { IndexDetails& idx = d.idx(i); BSONObj idxKey = idx.info.obj().getObjectField("key"); // eg { ts : 1 } IndexChanges& ch = v[i]; idx.getKeysFromObject(oldObj, ch.oldkeys); idx.getKeysFromObject(newObj, ch.newkeys); if( ch.newkeys.size() > 1 ) d.setIndexIsMultikey(i); setDifference(ch.oldkeys, ch.newkeys, ch.removed); setDifference(ch.newkeys, ch.oldkeys, ch.added); if ( ch.removed.size() > 0 && ch.added.size() > 0 && idx.isIdIndex() ) { changedId = true; } } }
Status IndexAccessMethod::validateUpdate(OperationContext* txn, const BSONObj &from, const BSONObj &to, const RecordId &record, const InsertDeleteOptions &options, UpdateTicket* ticket) { getKeys(from, &ticket->oldKeys); getKeys(to, &ticket->newKeys); ticket->loc = record; ticket->dupsAllowed = options.dupsAllowed; setDifference(ticket->oldKeys, ticket->newKeys, &ticket->removed); setDifference(ticket->newKeys, ticket->oldKeys, &ticket->added); ticket->_isValid = true; return Status::OK(); }
Status IndexAccessMethod::validateUpdate(OperationContext* txn, const BSONObj& from, const BSONObj& to, const RecordId& record, const InsertDeleteOptions& options, UpdateTicket* ticket, const MatchExpression* indexFilter) { if (indexFilter == NULL || indexFilter->matchesBSON(from)) getKeys(from, &ticket->oldKeys); if (indexFilter == NULL || indexFilter->matchesBSON(to)) getKeys(to, &ticket->newKeys); ticket->loc = record; ticket->dupsAllowed = options.dupsAllowed; setDifference(ticket->oldKeys, ticket->newKeys, &ticket->removed); setDifference(ticket->newKeys, ticket->oldKeys, &ticket->added); ticket->_isValid = true; return Status::OK(); }
Status BtreeBasedAccessMethod::validateUpdate(OperationContext* txn, const BSONObj& from, const BSONObj& to, const RecordId& record, const InsertDeleteOptions& options, UpdateTicket* status) { BtreeBasedPrivateUpdateData* data = new BtreeBasedPrivateUpdateData(); status->_indexSpecificUpdateData.reset(data); getKeys(from, &data->oldKeys); getKeys(to, &data->newKeys); data->loc = record; data->dupsAllowed = options.dupsAllowed; setDifference(data->oldKeys, data->newKeys, &data->removed); setDifference(data->newKeys, data->oldKeys, &data->added); status->_isValid = true; return Status::OK(); }
/** * @brief Finds a next SCC and its represent and returns them. * * @param[in] sccs All SCCs in the call graph. * @param[in] computedFuncs Functions that already have been included in * FuncInfoCompOrder::order. * @param[in] remainingFuncs Functions that haven't been included in * FuncInfoCompOrder::order. * * @par Preconditions * - @a remainingFuncs is non-empty * - @a remainingFuncs doesn't contain a function which calls just functions * from @a computedFuncs. */ CallInfoObtainer::SCCWithRepresent CallInfoObtainer::findNextSCC(const FuncSetSet &sccs, const FuncSet &computedFuncs, const FuncSet &remainingFuncs) const { PRECONDITION(!remainingFuncs.empty(), "it should not be empty"); // // We try to locate an SCC whose members call just the functions in // the SCC or in computedFuncs. Then, if the found SCC contains a function // from remainingFuncs, return the function. // // For every SCC... for (const auto &scc : sccs) { bool sccFound = true; ShPtr<Function> funcFromRemainingFuncs; // For every function in the SCC... for (const auto &func : scc) { // Check whether the function calls just the functions in the SCC // or in computedFuncs. ShPtr<CG::CalledFuncs> calledFuncs(cg->getCalledFuncs(func)); FuncSet mayCall(setUnion(scc, computedFuncs)); if (!setDifference(calledFuncs->callees, mayCall).empty()) { sccFound = false; } else { // Have we encountered a function from remainingFuncs? if (hasItem(remainingFuncs, func)) { funcFromRemainingFuncs = func; } } } if (sccFound && funcFromRemainingFuncs) { return SCCWithRepresent(scc, funcFromRemainingFuncs); } } // TODO Can this happen? printWarningMessage("[SCCComputer] No viable SCC has been found."); FuncSet scc; ShPtr<Function> func(*(remainingFuncs.begin())); scc.insert(func); return SCCWithRepresent(scc, func); }
/** * @brief Computes the FuncInfo and returns it. */ ShPtr<OptimFuncInfo> OptimFuncInfoCFGTraversal::performComputation() { // First, we pre-compute varsAlwaysModifiedBeforeRead. The reason is that // their computation differs from the computation of the rest of the sets. precomputeAlwaysModifiedVarsBeforeRead(); // Every function's body is of the following form: // // (1) definitions of local variables, including assignments of global // variables into local variables // (2) other statements // // We store which variables are read/modified in (1). Then, we start the // traversal from (2). During the traversal, we check which variables are // read/modified and update funcInfo accordingly. The stored information // from (1) is used to compute the set of global variables which are read // in the function, but not modified. // // To give a specific example, consider the following code: // // def func(mango): // global orange // global plum // lychee = orange // achira = plum // orange = mango // plum = rand() // result = plum * apple + orange // orange = lychee // plum = achira // return result // // Here, even though the global variable orange is modified, its value // before calling func() is the same as after calling func(). Indeed, its // value is restored before the return statement. Hence, we may put it into // funcInfo->varsWithNeverChangedValue. // TODO Implement a more robust analysis. ShPtr<Statement> currStmt = traversedFunc->getBody(); while (isVarDefOrAssignStmt(currStmt)) { updateFuncInfo(currStmt); ShPtr<Expression> lhs(getLhs(currStmt)); ShPtr<Expression> rhs(getRhs(currStmt)); // If there is no right-hand side, it is a VarDefStmt with no // initializer, which we may skip. if (!rhs) { currStmt = currStmt->getSuccessor(); continue; } // If there are any function calls or dereferences, we have reached // (2). ShPtr<ValueData> currStmtData(va->getValueData(currStmt)); if (currStmtData->hasCalls() || currStmtData->hasDerefs()) { break; } // Check whether the statement is of the form localVar = globalVar. ShPtr<Variable> localVar(cast<Variable>(lhs)); ShPtr<Variable> globalVar(cast<Variable>(rhs)); if (!localVar || !globalVar || hasItem(globalVars, localVar) || !hasItem(globalVars, globalVar)) { // It is not of the abovementioned form, so skip it. currStmt = currStmt->getSuccessor(); continue; } storedGlobalVars[globalVar] = localVar; currStmt = currStmt->getSuccessor(); } // Perform the traversal only if we haven't reached the end of the function // yet. Since empty statements are not present in a CFG, skip them before // the traversal. if ((currStmt = skipEmptyStmts(currStmt))) { performTraversal(currStmt); } // We use the exit node of the CFG to check that every variable from // storedGlobalVars is retrieved its original value before every return. ShPtr<CFG::Node> exitNode(cfg->getExitNode()); // For every predecessor of the exit node... for (auto i = exitNode->pred_begin(), e = exitNode->pred_end(); i != e; ++i) { bool checkingShouldContinue = checkExitNodesPredecessor((*i)->getSrc()); if (!checkingShouldContinue) { break; } } // Update funcInfo using the remaining variables in storedGlobalVars. for (const auto &p : storedGlobalVars) { funcInfo->varsWithNeverChangedValue.insert(p.first); } // Update funcInfo->never{Read,Modified}Vars by global variables which are // untouched in this function. for (auto i = module->global_var_begin(), e = module->global_var_end(); i != e; ++i) { ShPtr<Variable> var((*i)->getVar()); if (!hasItem(funcInfo->mayBeReadVars, var) && !hasItem(funcInfo->mayBeModifiedVars, var)) { funcInfo->neverReadVars.insert(var); funcInfo->neverModifiedVars.insert(var); } } // If the cfg contains only a single non-{entry,exit} node, every // mayBe{Read,Modifed} variable can be turned into a always{Read,Modified} // variable. if (cfg->getNumberOfNodes() == 3) { addToSet(funcInfo->mayBeReadVars, funcInfo->alwaysReadVars); addToSet(funcInfo->mayBeModifiedVars, funcInfo->alwaysModifiedVars); } // Add all variables which are never read and never modified to // varsWithNeverChangedValue. VarSet neverReadAndModifedVars(setIntersection(funcInfo->neverReadVars, funcInfo->neverModifiedVars)); addToSet(neverReadAndModifedVars, funcInfo->varsWithNeverChangedValue); // Add all global variables are not read in this function into // varsAlwaysModifiedBeforeRead. addToSet(setDifference(globalVars, funcInfo->mayBeReadVars), funcInfo->varsAlwaysModifiedBeforeRead); return funcInfo; }