0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-11-30 17:10:48 +01:00

npe fix and defensive code

This commit is contained in:
Dwight 2008-07-16 14:36:10 -04:00
parent f164a412fc
commit 4bfd28fa48
5 changed files with 45 additions and 32 deletions

View File

@ -866,34 +866,48 @@ void BtreeCursor::noteLocation() {
} }
} }
int clctr = 0; /* Since the last noteLocation(), our key may have moved around, and that old cached
information may thus be stale and wrong (although often it is right). We check
that here; if we have moved, we have to search back for where we were at.
/* see if things moved around (deletes, splits, inserts) */ i.e., after operations on the index, the BtreeCursor's cached location info may
be invalid. This function ensures validity, so you should call it before using
the cursor if other writers have used the database since the last noteLocation
call.
*/
void BtreeCursor::checkLocation() { void BtreeCursor::checkLocation() {
try { {
if( eof() ) if( eof() )
return; return;
BtreeBucket *b = bucket.btree(); BtreeBucket *b = bucket.btree();
assert( !keyAtKeyOfs.isEmpty() );
// Note keyAt() returns an empty JSObj if keyOfs is now out of range,
// which is possible as keys may have been deleted.
if( b->keyAt(keyOfs).woEqual(keyAtKeyOfs) && if( b->keyAt(keyOfs).woEqual(keyAtKeyOfs) &&
b->k(keyOfs).recordLoc == locAtKeyOfs ) { b->k(keyOfs).recordLoc == locAtKeyOfs ) {
if( !b->k(keyOfs).isUsed() ) if( !b->k(keyOfs).isUsed() ) {
checkUnused(); /* we were deleted but still exist as an unused
return; marker key. advance.
*/
checkUnused();
}
return;
} }
} }
catch( AssertionException ) {
cout << "Caught exception in checkLocation(), that's maybe ok" << endl; /* normally we don't get to here. when we do, old position is no longer
} valid and we must refind where we left off (which is expensive)
*/
bool found; bool found;
DiskLoc bold = bucket; DiskLoc bold = bucket;
/* TODO: Switch to keep indexdetails and do idx.head! */ /* TODO: Switch to keep indexdetails and do idx.head! */
/* didn't find, check from the top */
DiskLoc head = bold.btree()->getHead(bold); DiskLoc head = bold.btree()->getHead(bold);
bucket = head.btree()->locate(head, keyAtKeyOfs, keyOfs, found, locAtKeyOfs, direction); bucket = head.btree()->locate(head, keyAtKeyOfs, keyOfs, found, locAtKeyOfs, direction);
if( clctr++ % 128 == 0 ) RARELY cout << " key seems to have moved in the index, refinding. found:" << found << endl;
cout << " key seems to have moved in the index, refinding. found:" << found << endl;
if( found ) if( found )
checkUnused(); checkUnused();
} }

View File

@ -17,8 +17,16 @@ struct _KeyNode {
unsigned short _kdo; unsigned short _kdo;
void setKeyDataOfs(short s) { _kdo = s; assert(s>=0); } void setKeyDataOfs(short s) { _kdo = s; assert(s>=0); }
void setKeyDataOfsSavingUse(short s) { _kdo = s; assert(s>=0); } void setKeyDataOfsSavingUse(short s) { _kdo = s; assert(s>=0); }
void setUnused() { recordLoc.GETOFS() |= 1; } void setUnused() {
// void setUsed() { _kdo &= 0x7fff; } /* setting ofs to 1 is the sentinel. setInvalid sets the
fileno, that is defensive code.
*/
recordLoc.setInvalid();
recordLoc.GETOFS() = 1;
}
/* & 1 for backward compatibility. can be made "== 1" later when we increment
the db data version
*/
int isUnused() { return (recordLoc.getOfs() & 1); } int isUnused() { return (recordLoc.getOfs() & 1); }
int isUsed() { return !isUnused(); } int isUsed() { return !isUnused(); }
}; };

View File

@ -170,16 +170,7 @@ class JSObj {
friend class JSElemIter; friend class JSElemIter;
class Details { class Details {
public: public:
~Details() { ~Details() { _objdata = 0; }
assert(refCount <= 0);
// note that the assert above protects owned() from lying to us. If the assert() goes, fix this
if (owned()) {
free((void *)_objdata);
}
_objdata = 0;
}
const char *_objdata; const char *_objdata;
int _objsize; int _objsize;
int refCount; // -1 == don't free int refCount; // -1 == don't free
@ -233,8 +224,8 @@ public:
JSObj extractFields(JSObj pattern, JSObjBuilder& b); JSObj extractFields(JSObj pattern, JSObjBuilder& b);
const char *objdata() const { return details->_objdata; } const char *objdata() const { return details->_objdata; }
int objsize() const { return details->_objsize; } // includes the embedded size field int objsize() const { return details ? details->_objsize : 0; } // includes the embedded size field
bool isEmpty() const { return details == 0 || objsize() <= 5; } bool isEmpty() const { return objsize() <= 5; }
/* this is broken if elements aren't in the same order. */ /* this is broken if elements aren't in the same order. */
bool operator<(const JSObj& r) const { return woCompare(r) < 0; } bool operator<(const JSObj& r) const { return woCompare(r) < 0; }
@ -244,7 +235,9 @@ public:
*/ */
int woCompare(const JSObj& r) const; int woCompare(const JSObj& r) const;
bool woEqual(const JSObj& r) const { bool woEqual(const JSObj& r) const {
return objsize()==r.objsize() && memcmp(objdata(),r.objdata(),objsize())==0; int os = objsize();
return os == r.objsize() &&
(os == 0 || memcmp(objdata(),r.objdata(),os)==0);
} }
bool operator==(const JSObj& r) const { bool operator==(const JSObj& r) const {
return this->woEqual(r); return this->woEqual(r);

View File

@ -717,8 +717,6 @@ void DataFileMgr::deleteRecord(const char *ns, Record *todelete, const DiskLoc&
{ {
dassert( todelete == dl.rec() ); dassert( todelete == dl.rec() );
int tempextofs = todelete->extentOfs;
NamespaceDetails* d = nsdetails(ns); NamespaceDetails* d = nsdetails(ns);
if( d->capped && !cappedOK ) { if( d->capped && !cappedOK ) {
cout << "failing remove on a capped ns " << ns << endl; cout << "failing remove on a capped ns " << ns << endl;

View File

@ -150,7 +150,7 @@ auto_ptr<Cursor> getIndexCursor(const char *ns, JSObj& query, JSObj& order, bool
} }
fail: fail:
DEV cout << "getIndexCursor fail" << endl; DEV cout << "getIndexCursor fail " << ns << '\n';
return auto_ptr<Cursor>(); return auto_ptr<Cursor>();
} }