Example #1
0
    Status PlanCache::feedback(const CanonicalQuery& cq, PlanCacheEntryFeedback* feedback) {
        if (NULL == feedback) {
            return Status(ErrorCodes::BadValue, "feedback is NULL");
        }
        std::auto_ptr<PlanCacheEntryFeedback> autoFeedback(feedback);
        const PlanCacheKey& ck = cq.getPlanCacheKey();

        boost::lock_guard<boost::mutex> cacheLock(_cacheMutex);
        PlanCacheEntry* entry;
        Status cacheStatus = _cache.get(ck, &entry);
        if (!cacheStatus.isOK()) {
            return cacheStatus;
        }
        invariant(entry);

        if (entry->feedback.size() >= size_t(internalQueryCacheFeedbacksStored)) {
            // If we have enough feedback, then use it to determine whether
            // we should get rid of the cached solution.
            if (hasCachedPlanPerformanceDegraded(entry, autoFeedback.get())) {
                LOG(1) << _ns << ": removing plan cache entry " << entry->toString()
                       << " - detected degradation in performance of cached solution.";
                _cache.remove(ck);
            }
        }
        else {
            // We don't have enough feedback yet---just store it and move on.
            entry->feedback.push_back(autoFeedback.release());
        }

        return Status::OK();
    }
Example #2
0
    Status PlanCache::add(const CanonicalQuery& query,
                          const std::vector<QuerySolution*>& solns,
                          PlanRankingDecision* why) {
        invariant(why);

        if (solns.empty()) {
            return Status(ErrorCodes::BadValue, "no solutions provided");
        }

        if (why->stats.size() != solns.size()) {
            return Status(ErrorCodes::BadValue,
                          "number of stats in decision must match solutions");
        }

        if (why->scores.size() != solns.size()) {
            return Status(ErrorCodes::BadValue,
                          "number of scores in decision must match solutions");
        }

        if (why->candidateOrder.size() != solns.size()) {
            return Status(ErrorCodes::BadValue,
                          "candidate ordering entries in decision must match solutions");
        }

        PlanCacheEntry* entry = new PlanCacheEntry(solns, why);
        const LiteParsedQuery& pq = query.getParsed();
        entry->query = pq.getFilter().getOwned();
        entry->sort = pq.getSort().getOwned();
        entry->projection = pq.getProj().getOwned();

        // If the winning solution uses a blocking stage, then try and
        // find a fallback solution that has no blocking stage.
        if (solns[0]->hasBlockingStage) {
            for (size_t i = 1; i < solns.size(); ++i) {
                if (!solns[i]->hasBlockingStage) {
                    entry->backupSoln.reset(i);
                    break;
                }
            }
        }

        boost::lock_guard<boost::mutex> cacheLock(_cacheMutex);
        std::auto_ptr<PlanCacheEntry> evictedEntry = _cache.add(query.getPlanCacheKey(), entry);

        if (NULL != evictedEntry.get()) {
            LOG(1) << _ns << ": plan cache maximum size exceeded - "
                   << "removed least recently used entry "
                   << evictedEntry->toString();
        }

        return Status::OK();
    }
Example #3
0
void QuerySettings::removeAllowedIndices(const CanonicalQuery& canonicalQuery) {
    const PlanCacheKey& key = canonicalQuery.getPlanCacheKey();
    boost::lock_guard<boost::mutex> cacheLock(_mutex);
    AllowedIndexEntryMap::iterator i = _allowedIndexEntryMap.find(key);

    // Nothing to do if key does not exist in query settings.
    if (i == _allowedIndexEntryMap.end()) {
        return;
    }

    // Free up resources and delete entry.
    AllowedIndexEntry* entry = i->second;
    _allowedIndexEntryMap.erase(i);
    delete entry;
}
Example #4
0
    Status PlanCache::getEntry(const CanonicalQuery& query, PlanCacheEntry** entryOut) const {
        const PlanCacheKey& key = query.getPlanCacheKey();
        verify(entryOut);

        boost::lock_guard<boost::mutex> cacheLock(_cacheMutex);
        PlanCacheEntry* entry;
        Status cacheStatus = _cache.get(key, &entry);
        if (!cacheStatus.isOK()) {
            return cacheStatus;
        }
        invariant(entry);

        *entryOut = entry->clone();

        return Status::OK();
    }
Example #5
0
    Status PlanCache::get(const CanonicalQuery& query, CachedSolution** crOut) const {
        const PlanCacheKey& key = query.getPlanCacheKey();
        verify(crOut);

        boost::lock_guard<boost::mutex> cacheLock(_cacheMutex);
        PlanCacheEntry* entry;
        Status cacheStatus = _cache.get(key, &entry);
        if (!cacheStatus.isOK()) {
            return cacheStatus;
        }
        invariant(entry);

        *crOut = new CachedSolution(key, *entry);

        return Status::OK();
    }
Example #6
0
void QuerySettings::setAllowedIndices(const CanonicalQuery& canonicalQuery,
                                      const std::vector<BSONObj>& indexes) {
    const LiteParsedQuery& lpq = canonicalQuery.getParsed();
    const BSONObj& query = lpq.getFilter();
    const BSONObj& sort = lpq.getSort();
    const BSONObj& projection = lpq.getProj();
    AllowedIndexEntry* entry = new AllowedIndexEntry(query, sort, projection, indexes);

    const PlanCacheKey& key = canonicalQuery.getPlanCacheKey();
    boost::lock_guard<boost::mutex> cacheLock(_mutex);
    AllowedIndexEntryMap::iterator i = _allowedIndexEntryMap.find(key);
    // Replace existing entry.
    if (i != _allowedIndexEntryMap.end()) {
        AllowedIndexEntry* entry = i->second;
        delete entry;
    }
    _allowedIndexEntryMap[key] = entry;
}
Example #7
0
bool QuerySettings::getAllowedIndices(const CanonicalQuery& query,
                                      AllowedIndices** allowedIndicesOut) const {
    invariant(allowedIndicesOut);

    const PlanCacheKey& key = query.getPlanCacheKey();

    boost::lock_guard<boost::mutex> cacheLock(_mutex);
    AllowedIndexEntryMap::const_iterator cacheIter = _allowedIndexEntryMap.find(key);

    // Nothing to do if key does not exist in query settings.
    if (cacheIter == _allowedIndexEntryMap.end()) {
        *allowedIndicesOut = NULL;
        return false;
    }

    AllowedIndexEntry* entry = cacheIter->second;

    // Create a AllowedIndices from entry.
    *allowedIndicesOut = new AllowedIndices(entry->indexKeyPatterns);

    return true;
}
Example #8
0
 bool PlanCache::contains(const CanonicalQuery& cq) const {
     boost::lock_guard<boost::mutex> cacheLock(_cacheMutex);
     return _cache.hasKey(cq.getPlanCacheKey());
 }
Example #9
0
 Status PlanCache::remove(const CanonicalQuery& canonicalQuery) {
     boost::lock_guard<boost::mutex> cacheLock(_cacheMutex);
     return _cache.remove(canonicalQuery.getPlanCacheKey());
 }