diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/mongo/db/matcher.cpp | 181 | ||||
-rw-r--r-- | src/mongo/db/matcher.h | 23 | ||||
-rwxr-xr-x | src/mongo/db/pipeline/document_source.cpp | 3 | ||||
-rwxr-xr-x | src/mongo/db/pipeline/document_source.h | 2 | ||||
-rwxr-xr-x | src/mongo/db/pipeline/document_source_match.cpp | 6 | ||||
-rwxr-xr-x | src/mongo/util/trace.cpp | 87 | ||||
-rwxr-xr-x | src/mongo/util/trace.h | 84 |
7 files changed, 367 insertions, 19 deletions
diff --git a/src/mongo/db/matcher.cpp b/src/mongo/db/matcher.cpp index cc00ad4b2b6..c49b5e84771 100755 --- a/src/mongo/db/matcher.cpp +++ b/src/mongo/db/matcher.cpp @@ -724,13 +724,13 @@ namespace mongo { if( strcmp(z.fieldName(),fieldName) == 0 ) { if ( compareOp == BSONObj::opEXISTS ) { - return retExistsFound( em ); + return retExistsFound( em ); } if (valuesMatch(z, toMatch, compareOp, em) ) { - // "field.<n>" array notation was used - if ( details ) - details->_elemMatchKey = z.fieldName(); - return 1; + // "field.<n>" array notation was used + if ( details ) + details->_elemMatchKey = z.fieldName(); + return 1; } } @@ -761,9 +761,9 @@ namespace mongo { if ( compareOp == BSONObj::opEXISTS ) { if( e.eoo() ) { - return 0; + return 0; } else { - return retExistsFound( em ); + return retExistsFound( em ); } } else if ( ( e.type() != Array || indexed || compareOp == BSONObj::opSIZE ) && @@ -807,7 +807,7 @@ namespace mongo { return 1; } if ( compareOp == BSONObj::opIN && valuesMatch( e, toMatch, compareOp, em ) ) { - return 1; + return 1; } } else if ( e.eoo() ) { @@ -821,6 +821,12 @@ namespace mongo { /* See if an object matches the query. */ bool Matcher::matches(const BSONObj& jsobj , MatchDetails * details ) const { + /* + NB: if any modifications are made to how this operates, make sure + they are reflected in visitReferences(), whose implementation + parallels this. + */ + LOG(5) << "Matcher::matches() " << jsobj.toString() << endl; /* assuming there is usually only one thing to match. if more this @@ -857,8 +863,8 @@ namespace mongo { } for (vector<RegexMatcher>::const_iterator it = _regexs.begin(); - it != _regexs.end(); - ++it) { + it != _regexs.end(); + ++it) { BSONElementSet s; if ( !_constrainIndexKey.isEmpty() ) { BSONElement e = jsobj.getFieldUsingIndexNames(it->_fieldName, _constrainIndexKey); @@ -866,10 +872,10 @@ namespace mongo { // Should only have keys nested one deep here, for geo-indices // TODO: future indices may nest deeper? if( e.type() == Array ){ - BSONObjIterator i( e.Obj() ); - while( i.more() ){ - s.insert( i.next() ); - } + BSONObjIterator i( e.Obj() ); + while( i.more() ){ + s.insert( i.next() ); + } } else if ( !e.eoo() ) s.insert( e ); @@ -964,13 +970,152 @@ namespace mongo { return true; } +#ifdef MONGO_LATER_SERVER_4644 + void Matcher::visitReferences(FieldSink *pSink) const { + // check normal non-regex cases: + for ( unsigned i = 0; i < _basics.size(); i++ ) { + const ElementMatcher& bm = _basics[i]; + const BSONElement& m = bm._toMatch; + // -1=mismatch. 0=missing element. 1=match + int cmp = matchesDotted(m.fieldName(), m, jsobj, bm._compareOp, bm , false , details ); + if ( cmp == 0 && bm._compareOp == BSONObj::opEXISTS ) { + // If missing, match cmp is opposite of $exists spec. + cmp = -retExistsFound(bm); + } + if ( bm._isNot ) + cmp = -cmp; + if ( cmp < 0 ) + return false; + if ( cmp == 0 ) { + /* missing is ok iff we were looking for null */ + if ( m.type() == jstNULL || m.type() == Undefined || + ( ( bm._compareOp == BSONObj::opIN || bm._compareOp == BSONObj::NIN ) && bm._myset->count( staticNull.firstElement() ) > 0 ) ) { + if ( bm.negativeCompareOp() ^ bm._isNot ) { + return false; + } + } + else { + if ( !bm._isNot ) { + return false; + } + } + } + } + + for (vector<RegexMatcher>::const_iterator it = _regexs.begin(); + it != _regexs.end(); + ++it) { + BSONElementSet s; + if ( !_constrainIndexKey.isEmpty() ) { + BSONElement e = jsobj.getFieldUsingIndexNames(it->_fieldName, _constrainIndexKey); + + // Should only have keys nested one deep here, for geo-indices + // TODO: future indices may nest deeper? + if( e.type() == Array ){ + BSONObjIterator i( e.Obj() ); + while( i.more() ){ + s.insert( i.next() ); + } + } + else if ( !e.eoo() ) + s.insert( e ); + + } + else { + jsobj.getFieldsDotted( it->_fieldName, s ); + } + bool match = false; + for( BSONElementSet::const_iterator i = s.begin(); i != s.end(); ++i ) + if ( regexMatches(*it, *i) ) + match = true; + if ( !match ^ it->_isNot ) + return false; + } + + if ( _orDedupConstraints.size() > 0 ) { + for( vector< shared_ptr< FieldRangeVector > >::const_iterator i = _orDedupConstraints.begin(); + i != _orDedupConstraints.end(); ++i ) { + if ( (*i)->matches( jsobj ) ) { + return false; + } + } + } + + if ( _andMatchers.size() > 0 ) { + for( list< shared_ptr< Matcher > >::const_iterator i = _andMatchers.begin(); + i != _andMatchers.end(); ++i ) { + // SERVER-3192 Track field matched using details the same as for + // top level fields, at least for now. + if ( !(*i)->matches( jsobj, details ) ) { + return false; + } + } + } + + if ( _orMatchers.size() > 0 ) { + bool match = false; + for( list< shared_ptr< Matcher > >::const_iterator i = _orMatchers.begin(); + i != _orMatchers.end(); ++i ) { + // SERVER-205 don't submit details - we don't want to track field + // matched within $or + if ( (*i)->matches( jsobj ) ) { + match = true; + break; + } + } + if ( !match ) { + return false; + } + } + + if ( _norMatchers.size() > 0 ) { + for( list< shared_ptr< Matcher > >::const_iterator i = _norMatchers.begin(); + i != _norMatchers.end(); ++i ) { + // SERVER-205 don't submit details - we don't want to track field + // matched within $nor + if ( (*i)->matches( jsobj ) ) { + return false; + } + } + } + + if ( _where ) { + if ( _where->func == 0 ) { + u_assert( 10070 , "$where compile error", false); + return false; // didn't compile + } + + if ( _where->jsScope ) { + _where->scope->init( _where->jsScope ); + } + _where->scope->setObject( "obj", const_cast< BSONObj & >( jsobj ) ); + _where->scope->setBoolean( "fullObject" , true ); // this is a hack b/c fullObject used to be relevant + + int err = _where->scope->invoke( _where->func , 0, &jsobj , 1000 * 60 , false ); + if ( err == -3 ) { // INVOKE_ERROR + stringstream ss; + ss << "error on invocation of $where function:\n" + << _where->scope->getError(); + u_assert( 10071 , ss.str(), false); + return false; + } + else if ( err != 0 ) { // ! INVOKE_SUCCESS + u_assert( 10072 , "unknown error in invocation of $where function", false); + return false; + } + return _where->scope->getBoolean( "return" ) != 0; + + } + } +#endif /* MONGO_LATER_SERVER_4644 */ + bool Matcher::keyMatch( const Matcher &docMatcher ) const { // Quick check certain non key match cases. if ( docMatcher._all - || docMatcher._haveSize - || docMatcher._hasArray // We can't match an array to its first indexed element using keymatch - || docMatcher._haveNeg ) { - return false; + || docMatcher._haveSize + || docMatcher._hasArray // We can't match an array to its first indexed element using keymatch + || docMatcher._haveNeg ) { + return false; } // Check that all match components are available in the index matcher. diff --git a/src/mongo/db/matcher.h b/src/mongo/db/matcher.h index b6994a79229..0678bb696ae 100644 --- a/src/mongo/db/matcher.h +++ b/src/mongo/db/matcher.h @@ -148,6 +148,27 @@ namespace mongo { bool matches(const BSONObj& j, MatchDetails * details = 0 ) const; +#ifdef MONGO_LATER_SERVER_4644 + class FieldSink { + public: + virtual ~FieldSink() {}; + virtual void referenceField(const string &fieldPath) = 0; + }; + + /** + Visit all of the fields that are referenced by this Matcher + (and any descendants). + + This can be used to gather a list of all the references made by + this matcher. The implementation of this parallels that of + matches() above. + + @param pSink a FieldSink that the caller will use to gather or + process the references + */ + void visitReferences(FieldSink *pSink) const; +#endif /* MONGO_LATER_SERVER_4644 */ + bool atomic() const { return _atomic; } string toString() const { @@ -176,7 +197,7 @@ namespace mongo { // return ( ( basics.size() + nRegex ) < 2 ) && !where && !_orMatchers.size() && !_norMatchers.size(); } - const BSONObj *getQuery() const { return &_jsobj; }; + const BSONObj *getQuery() const { return &_jsobj; }; private: /** diff --git a/src/mongo/db/pipeline/document_source.cpp b/src/mongo/db/pipeline/document_source.cpp index 89177f58767..3a496875b9d 100755 --- a/src/mongo/db/pipeline/document_source.cpp +++ b/src/mongo/db/pipeline/document_source.cpp @@ -48,6 +48,9 @@ namespace mongo { void DocumentSource::manageDependencies(
const intrusive_ptr<DependencyTracker> &pTracker) {
+#ifdef MONGO_LATER_SERVER_4644
+ assert(false); // identify any sources that need this but don't have it
+#endif /* MONGO_LATER_SERVER_4644 */
}
void DocumentSource::addToBsonArray(BSONArrayBuilder *pBuilder) const {
diff --git a/src/mongo/db/pipeline/document_source.h b/src/mongo/db/pipeline/document_source.h index 6b547032801..acca4b2f7af 100755 --- a/src/mongo/db/pipeline/document_source.h +++ b/src/mongo/db/pipeline/document_source.h @@ -590,6 +590,8 @@ namespace mongo { // virtuals from DocumentSource
virtual ~DocumentSourceMatch();
virtual const char *getSourceName() const;
+ virtual void manageDependencies(
+ const intrusive_ptr<DependencyTracker> &pTracker);
/**
Create a filter.
diff --git a/src/mongo/db/pipeline/document_source_match.cpp b/src/mongo/db/pipeline/document_source_match.cpp index c02490e92da..6fc1b0b9f52 100755 --- a/src/mongo/db/pipeline/document_source_match.cpp +++ b/src/mongo/db/pipeline/document_source_match.cpp @@ -82,4 +82,10 @@ namespace mongo { matcher(query) {
}
+ void DocumentSourceMatch::manageDependencies(
+ const intrusive_ptr<DependencyTracker> &pTracker) {
+#ifdef MONGO_LATER_SERVER_4644
+ assert(false); // $$$ implement dependencies on Matcher
+#endif /* MONGO_LATER_SERVER_4644 */
+ }
}
diff --git a/src/mongo/util/trace.cpp b/src/mongo/util/trace.cpp new file mode 100755 index 00000000000..db81952e9eb --- /dev/null +++ b/src/mongo/util/trace.cpp @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2012 10gen Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "util/trace.h" + +namespace mongo { + + /* the singleton static instance of this object */ + Trace::NameMap *Trace::pMap = NULL; + SimpleRWLock Trace::lock("Trace"); + Trace Trace::trace; + + Trace::NameMap::NameMap(): + traces() { + } + + Trace::Trace() { + /* + This static singleton is constructed at program load time, so the + lock should not be necessary here. + */ + Trace::pMap = new NameMap(); + } + + Trace::~Trace() { + delete Trace::pMap; + } + + void Trace::setTrace(const string &name, unsigned level) { + SimpleRWLock::Exclusive xlock(Trace::lock); // dtor unlocks + + /* if the new level is to be zero, we're going to remove the entry */ + if (level == 0) { + Trace::pMap->traces.erase(name); + return; + } + + /* try to insert the new trace */ + std::pair<MapType::iterator, bool> i( + Trace::pMap->traces.insert( + MapType::value_type(name, level))); + + /* + If the insert didn't take place, there was already an entry for + that name. Set it to have the new level. + */ + if (!i.second) { + (*i.first).second = level; + } + } + +#ifdef LATER + void Trace::setTraces(const string &names) { + /* create a new map, and replace the existing one */ + NameMap *pM; + assert(false); + } +#endif + + unsigned Trace::getTrace(const string &name) { + SimpleRWLock::Shared slock(Trace::lock); // dtor unlocks + + /* quickest check for no active traces */ + if (Trace::pMap->traces.empty()) + return 0; + + /* there are traces, so look up by name */ + MapType::const_iterator i(Trace::pMap->traces.find(name)); + if (i == Trace::pMap->traces.end()) + return 0; + + return (*i).second; + } +} diff --git a/src/mongo/util/trace.h b/src/mongo/util/trace.h new file mode 100755 index 00000000000..1bde95b9938 --- /dev/null +++ b/src/mongo/util/trace.h @@ -0,0 +1,84 @@ +/** + * Copyright (c) 2012 10gen Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "pch.h" + +#include <boost/unordered_map.hpp> +#include "util/concurrency/rwlock.h" + + +namespace mongo { + + class Trace : + public boost::noncopyable { + public: + +#ifdef LATER + /** + Set the traces with the given names. + + @param name comma separated trace names + */ + static void setTraces(const string &names); +#endif + + static void setTrace(const string &name, unsigned level); + + /** + Test to see if the given trace is on or off. + + @param name the name of the trace to check + @returns true if the trace is on, false otherwise + */ + static unsigned getTrace(const string &name); + + private: + Trace(); + ~Trace(); + + struct Hash : + unary_function<string, size_t> { + size_t operator()(const string &rS) const; + }; + + typedef boost::unordered_map<string, unsigned, Trace::Hash> MapType; + class NameMap { + public: + NameMap(); + + MapType traces; + }; + + static NameMap *pMap; /* used by Trace(), so precedes it */ + static SimpleRWLock lock; /* used by Trace(), so precedes it */ + static Trace trace; + }; + +} + +/* ======================= PRIVATE IMPLEMENTATIONS ========================== */ + +namespace mongo { + + inline size_t Trace::Hash::operator()(const string &rS) const { + size_t seed = 0xf0afbeef; + boost::hash_combine(seed, rS); + return seed; + } + +} |