0
0
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:
Aaron 2009-03-02 13:42:31 -05:00
parent e6980f2e83
commit b5d11b9350
5 changed files with 90 additions and 49 deletions

View File

@ -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 {

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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_;