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:
parent
f164a412fc
commit
4bfd28fa48
42
db/btree.cpp
42
db/btree.cpp
@ -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();
|
||||||
}
|
}
|
||||||
|
12
db/btree.h
12
db/btree.h
@ -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(); }
|
||||||
};
|
};
|
||||||
|
19
db/jsobj.h
19
db/jsobj.h
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user