summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/mongo/db/matcher.cpp181
-rw-r--r--src/mongo/db/matcher.h23
-rwxr-xr-xsrc/mongo/db/pipeline/document_source.cpp3
-rwxr-xr-xsrc/mongo/db/pipeline/document_source.h2
-rwxr-xr-xsrc/mongo/db/pipeline/document_source_match.cpp6
-rwxr-xr-xsrc/mongo/util/trace.cpp87
-rwxr-xr-xsrc/mongo/util/trace.h84
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;
+ }
+
+}