mirror of
https://github.com/mongodb/mongo.git
synced 2024-12-01 09:32:32 +01:00
Use key matcher, keep real BSONObj in matcher, fix deleteObject bug
This commit is contained in:
parent
e6980f2e83
commit
b5d11b9350
@ -46,7 +46,7 @@ namespace mongo {
|
||||
const CursorId cursorid;
|
||||
string ns;
|
||||
//BSONObj pattern; // the query object
|
||||
auto_ptr<JSMatcher> matcher;
|
||||
auto_ptr<KeyValJSMatcher> matcher;
|
||||
auto_ptr<Cursor> c;
|
||||
int pos;
|
||||
DiskLoc lastLoc() const {
|
||||
|
@ -184,6 +184,7 @@ namespace mongo {
|
||||
friend class BSONObj;
|
||||
public:
|
||||
string toString() const;
|
||||
operator string() const { return toString(); }
|
||||
string jsonString( JsonStringFormat format, bool includeFieldNames = true ) const;
|
||||
|
||||
/** Returns the type of the element */
|
||||
@ -472,6 +473,8 @@ namespace mongo {
|
||||
details = new Details();
|
||||
details->_objdata = data;
|
||||
details->_objsize = *(reinterpret_cast<const int*>(data));
|
||||
if ( details->_objsize <= 0 )
|
||||
printStackTrace();
|
||||
massert( "BSONObj size spec too small", details->_objsize > 0 );
|
||||
massert( "BSONObj size spec too large", details->_objsize <= 1024 * 1024 * 16 );
|
||||
details->refCount = ifree ? 1 : -1;
|
||||
|
@ -115,20 +115,29 @@ namespace mongo {
|
||||
namespace mongo {
|
||||
|
||||
KeyValJSMatcher::KeyValJSMatcher(const BSONObj &_jsobj, const BSONObj &indexKeyPattern) :
|
||||
keyMatcher_(emptyObj),
|
||||
recordMatcher_(_jsobj) {
|
||||
keyMatcher_(_jsobj.filterFieldsUndotted(indexKeyPattern, true), indexKeyPattern),
|
||||
recordMatcher_(_jsobj.filterFieldsUndotted(indexKeyPattern, false)) {
|
||||
}
|
||||
|
||||
bool KeyValJSMatcher::matches(const BSONObj &key, const DiskLoc &recLoc, bool *deep) {
|
||||
return recordMatcher_.matches(recLoc.rec(), deep);
|
||||
// out() << "key: " << key << ", rec: " << BSONObj( recLoc.rec() ) << endl;
|
||||
// out() << "keyMatch: " << keyMatcher_.matches( key ) << endl;
|
||||
// out() << "recordMatch: " << recordMatcher_.matches( recLoc.rec() ) << endl;
|
||||
bool ret = //return
|
||||
keyMatcher_.matches(key, deep) ?
|
||||
recordMatcher_.matches(recLoc.rec(), deep) :
|
||||
false;
|
||||
// out() << "ret: " << ret << endl;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* _jsobj - the query pattern - This should not be destroyed before the matcher.
|
||||
/* _jsobj - the query pattern
|
||||
*/
|
||||
JSMatcher::JSMatcher(const BSONObj &_jsobj) :
|
||||
in(0), where(0), jsobj(_jsobj), nRegex(0)
|
||||
JSMatcher::JSMatcher(const BSONObj &_jsobj, const BSONObj &constrainIndexKey) :
|
||||
in(0), where(0), jsobj(_jsobj), constrainIndexKey_(constrainIndexKey), nRegex(0)
|
||||
{
|
||||
// out() << "query: " << jsobj << endl;
|
||||
nBuilders = 0;
|
||||
BSONObjIterator i(jsobj);
|
||||
n = 0;
|
||||
@ -267,6 +276,7 @@ namespace mongo {
|
||||
}
|
||||
|
||||
// normal, simple case e.g. { a : "foo" }
|
||||
// out() << "addBasic: " << e << endl;
|
||||
addBasic(e, Equality);
|
||||
}
|
||||
}
|
||||
@ -316,7 +326,36 @@ namespace mongo {
|
||||
1 match
|
||||
*/
|
||||
int JSMatcher::matchesDotted(const char *fieldName, const BSONElement& toMatch, const BSONObj& obj, int compareOp, bool *deep, bool isArr) {
|
||||
{
|
||||
BSONElement e;
|
||||
// out() << "fieldName: " << fieldName << endl;
|
||||
// out() << "constrain: " << constrainIndexKey_ << endl;
|
||||
// out() << "obj: " << obj << endl;
|
||||
if ( !constrainIndexKey_.isEmpty() ) {
|
||||
assert( e.eoo() );
|
||||
BSONObjIterator i( constrainIndexKey_ );
|
||||
int j = 0;
|
||||
while( i.more() ) {
|
||||
BSONElement f = i.next();
|
||||
if ( f.eoo() )
|
||||
break;
|
||||
if ( strcmp( f.fieldName(), fieldName ) == 0 )
|
||||
break;
|
||||
++j;
|
||||
}
|
||||
BSONObjIterator k( obj );
|
||||
while( k.more() ) {
|
||||
BSONElement g = k.next();
|
||||
if ( g.eoo() )
|
||||
break;
|
||||
if ( j == 0 ) {
|
||||
e = g;
|
||||
break;
|
||||
}
|
||||
--j;
|
||||
}
|
||||
assert( !e.eoo() );
|
||||
// out() << "idx e: " << e << endl;
|
||||
} else {
|
||||
const char *p = strchr(fieldName, '.');
|
||||
if ( p ) {
|
||||
string left(fieldName, p-fieldName);
|
||||
@ -329,11 +368,13 @@ namespace mongo {
|
||||
|
||||
BSONObj eo = e.embeddedObject();
|
||||
return matchesDotted(p+1, toMatch, eo, compareOp, deep, e.type() == Array);
|
||||
} else {
|
||||
e = obj.getField(fieldName);
|
||||
// out() << "getField: " << e << endl;
|
||||
}
|
||||
}
|
||||
|
||||
BSONElement e = obj.getField(fieldName);
|
||||
|
||||
// out() << "e: " << e << endl;
|
||||
|
||||
if ( valuesMatch(e, toMatch, compareOp) ) {
|
||||
return 1;
|
||||
}
|
||||
@ -419,7 +460,9 @@ namespace mongo {
|
||||
for ( int i = 0; i < n; i++ ) {
|
||||
BasicMatcher& bm = basics[i];
|
||||
BSONElement& m = bm.toMatch;
|
||||
// out() << "m: " << m << endl;
|
||||
// -1=mismatch. 0=missing element. 1=match
|
||||
// out() << "m.fieldName: " << m.fieldName() << endl;
|
||||
int cmp = matchesDotted(m.fieldName(), m, jsobj, bm.compareOp, deep);
|
||||
if ( cmp < 0 )
|
||||
return false;
|
||||
|
11
db/matcher.h
11
db/matcher.h
@ -93,7 +93,9 @@ namespace mongo {
|
||||
return op <= LTE ? -1 : 1;
|
||||
}
|
||||
|
||||
JSMatcher(const BSONObj& pattern);
|
||||
// Only specify constrainIndexKey if matches() will be called with
|
||||
// index keys having empty string field names.
|
||||
JSMatcher(const BSONObj &pattern, const BSONObj &constrainIndexKey = BSONObj());
|
||||
|
||||
~JSMatcher();
|
||||
|
||||
@ -107,7 +109,7 @@ namespace mongo {
|
||||
|
||||
private:
|
||||
void addBasic(BSONElement e, int c) {
|
||||
// TODO May want to selectively ignore these types based on op type.
|
||||
// TODO May want to selectively ignore these element types based on op type.
|
||||
if ( e.type() == MinKey || e.type() == MaxKey )
|
||||
return;
|
||||
BasicMatcher bm;
|
||||
@ -121,8 +123,9 @@ namespace mongo {
|
||||
|
||||
set<BSONElement,element_lt> *in; // set if query uses $in
|
||||
Where *where; // set if query uses $where
|
||||
const BSONObj& jsobj; // the query pattern. e.g., { name: "joe" }
|
||||
|
||||
BSONObj jsobj; // the query pattern. e.g., { name: "joe" }
|
||||
BSONObj constrainIndexKey_;
|
||||
|
||||
vector<BasicMatcher> basics;
|
||||
int n; // # of basicmatcher items
|
||||
|
||||
|
60
db/query.cpp
60
db/query.cpp
@ -58,7 +58,7 @@ namespace mongo {
|
||||
}
|
||||
virtual void init() {
|
||||
c_ = qp().newCursor();
|
||||
matcher_.reset( new JSMatcher( qp().query() ) );
|
||||
matcher_.reset( new KeyValJSMatcher( qp().query(), qp().indexKey() ) );
|
||||
}
|
||||
virtual void next() {
|
||||
if ( !c_->ok() ) {
|
||||
@ -66,12 +66,10 @@ namespace mongo {
|
||||
return;
|
||||
}
|
||||
|
||||
Record *r = c_->_current();
|
||||
DiskLoc rloc = c_->currLoc();
|
||||
BSONObj js(r);
|
||||
|
||||
bool deep;
|
||||
if ( matcher_->matches(js, &deep) ) {
|
||||
if ( matcher_->matches(c_->currKey(), rloc, &deep) ) {
|
||||
if ( !deep || !c_->getsetdup(rloc) )
|
||||
++count_;
|
||||
}
|
||||
@ -99,7 +97,7 @@ namespace mongo {
|
||||
int &bestCount_;
|
||||
int nScanned_;
|
||||
auto_ptr< Cursor > c_;
|
||||
auto_ptr< JSMatcher > matcher_;
|
||||
auto_ptr< KeyValJSMatcher > matcher_;
|
||||
};
|
||||
|
||||
/* ns: namespace, e.g. <database>.<collection>
|
||||
@ -130,15 +128,13 @@ namespace mongo {
|
||||
if( !c->ok() )
|
||||
return nDeleted;
|
||||
|
||||
JSMatcher matcher(pattern);
|
||||
KeyValJSMatcher matcher(pattern, c->indexKeyPattern());
|
||||
|
||||
do {
|
||||
Record *r = c->_current();
|
||||
DiskLoc rloc = c->currLoc();
|
||||
BSONObj js(r);
|
||||
|
||||
bool deep;
|
||||
if ( !matcher.matches(js, &deep) ) {
|
||||
if ( !matcher.matches(c->currKey(), rloc, &deep) ) {
|
||||
c->advance(); // advance must be after noMoreMatches() because it uses currKey()
|
||||
}
|
||||
else {
|
||||
@ -147,19 +143,18 @@ namespace mongo {
|
||||
if ( !justOne )
|
||||
c->noteLocation();
|
||||
|
||||
theDataFileMgr.deleteRecord(ns, r, rloc);
|
||||
nDeleted++;
|
||||
if ( justOne ) {
|
||||
if ( deletedId ) {
|
||||
BSONElement e;
|
||||
if( js.getObjectID( e ) ) {
|
||||
BSONObjBuilder b;
|
||||
b.append( e );
|
||||
*deletedId = b.obj();
|
||||
}
|
||||
}
|
||||
break;
|
||||
if ( justOne && deletedId ) {
|
||||
BSONElement e;
|
||||
if( BSONObj( rloc.rec() ).getObjectID( e ) ) {
|
||||
BSONObjBuilder b;
|
||||
b.append( e );
|
||||
*deletedId = b.obj();
|
||||
}
|
||||
}
|
||||
theDataFileMgr.deleteRecord(ns, rloc.rec(), rloc);
|
||||
nDeleted++;
|
||||
if ( justOne )
|
||||
break;
|
||||
c->checkLocation();
|
||||
}
|
||||
} while ( c->ok() );
|
||||
@ -268,17 +263,15 @@ namespace mongo {
|
||||
if ( !c_->ok() )
|
||||
setComplete();
|
||||
else
|
||||
matcher_.reset( new JSMatcher( pattern ) );
|
||||
matcher_.reset( new KeyValJSMatcher( pattern, qp().indexKey() ) );
|
||||
}
|
||||
virtual void next() {
|
||||
if ( !c_->ok() ) {
|
||||
setComplete();
|
||||
return;
|
||||
}
|
||||
Record *r = c_->_current();
|
||||
nscanned_++;
|
||||
BSONObj js(r);
|
||||
if ( matcher_->matches(js) ) {
|
||||
if ( matcher_->matches(c_->currKey(), c_->currLoc()) ) {
|
||||
setComplete();
|
||||
return;
|
||||
}
|
||||
@ -293,7 +286,7 @@ namespace mongo {
|
||||
private:
|
||||
auto_ptr< Cursor > c_;
|
||||
int nscanned_;
|
||||
auto_ptr< JSMatcher > matcher_;
|
||||
auto_ptr< KeyValJSMatcher > matcher_;
|
||||
};
|
||||
|
||||
int __updateObjects(const char *ns, BSONObj updateobj, BSONObj &pattern, bool upsert, stringstream& ss, bool logop=false) {
|
||||
@ -539,10 +532,8 @@ namespace mongo {
|
||||
cc = 0;
|
||||
break;
|
||||
}
|
||||
BSONObj js = c->current();
|
||||
|
||||
bool deep;
|
||||
if ( !cc->matcher->matches(js, &deep) ) {
|
||||
if ( !cc->matcher->matches(c->currKey(), c->currLoc(), &deep) ) {
|
||||
}
|
||||
else {
|
||||
//out() << "matches " << c->currLoc().toString() << ' ' << deep << '\n';
|
||||
@ -550,6 +541,7 @@ namespace mongo {
|
||||
//out() << " but it's a dup \n";
|
||||
}
|
||||
else {
|
||||
BSONObj js = c->current();
|
||||
bool ok = fillQueryResultFromObj(b, cc->filter.get(), js);
|
||||
if ( ok ) {
|
||||
n++;
|
||||
@ -702,7 +694,7 @@ namespace mongo {
|
||||
|
||||
c_ = qp().newCursor();
|
||||
|
||||
matcher_.reset(new JSMatcher(qp().query()));
|
||||
matcher_.reset(new KeyValJSMatcher(qp().query(), qp().indexKey()));
|
||||
|
||||
if ( qp().scanAndOrderRequired() ) {
|
||||
ordering_ = true;
|
||||
@ -716,12 +708,12 @@ namespace mongo {
|
||||
return;
|
||||
}
|
||||
|
||||
BSONObj js = c_->current();
|
||||
nscanned_++;
|
||||
bool deep;
|
||||
if ( !matcher_->matches(js, &deep) ) {
|
||||
if ( !matcher_->matches(c_->currKey(), c_->currLoc(), &deep) ) {
|
||||
}
|
||||
else if ( !deep || !c_->getsetdup(c_->currLoc()) ) { // i.e., check for dups on deep items only
|
||||
BSONObj js = c_->current();
|
||||
// got a match.
|
||||
assert( js.objsize() >= 0 ); //defensive for segfaults
|
||||
if ( ordering_ ) {
|
||||
@ -790,7 +782,7 @@ namespace mongo {
|
||||
BufBuilder &builder() { return b_; }
|
||||
bool scanAndOrderRequired() const { return ordering_; }
|
||||
auto_ptr< Cursor > cursor() { return c_; }
|
||||
auto_ptr< JSMatcher > matcher() { return matcher_; }
|
||||
auto_ptr< KeyValJSMatcher > matcher() { return matcher_; }
|
||||
int n() const { return n_; }
|
||||
int nscanned() const { return nscanned_; }
|
||||
bool saveClientCursor() const { return saveClientCursor_; }
|
||||
@ -806,7 +798,7 @@ namespace mongo {
|
||||
auto_ptr< Cursor > c_;
|
||||
int nscanned_;
|
||||
int queryOptions_;
|
||||
auto_ptr< JSMatcher > matcher_;
|
||||
auto_ptr< KeyValJSMatcher > matcher_;
|
||||
int n_;
|
||||
int soSize_;
|
||||
bool saveClientCursor_;
|
||||
|
Loading…
Reference in New Issue
Block a user