From fba714c58325b4670f9fd3ca76db0268d55d7f0f Mon Sep 17 00:00:00 2001 From: Dwight Date: Thu, 13 Mar 2008 15:39:09 -0400 Subject: [PATCH] new dup key implementation --- db/btree.cpp | 187 +++++++++++++++++++++----------------------------- db/btree.h | 26 ++++--- db/db.cpp | 2 +- db/jsobj.h | 2 +- db/pdfile.cpp | 25 ++++--- db/pdfile.h | 4 ++ db/query.cpp | 14 +++- db/storage.h | 10 +++ db/testdb.js | 70 +++++++++++++++++-- stdafx.h | 8 +-- 10 files changed, 207 insertions(+), 141 deletions(-) diff --git a/db/btree.cpp b/db/btree.cpp index 7364413b613..0f424431fbe 100644 --- a/db/btree.cpp +++ b/db/btree.cpp @@ -12,10 +12,12 @@ int ninserts = 0; extern int otherTraceLevel; int split_debug = 0; int insert_debug = 0; +DiskLoc maxDiskLoc(0x7fffffff, 0x7fffffff); +DiskLoc minDiskLoc(0, 1); inline KeyNode::KeyNode(BucketBasics& bb, _KeyNode &k) : prevChildBucket(k.prevChildBucket), - recordLoc(k.recordLoc), key(bb.data+k.keyDataOfs) + recordLoc(k.recordLoc), key(bb.data+k.keyDataOfs()) { } /* BucketBasics --------------------------------------------------- */ @@ -36,36 +38,48 @@ void BucketBasics::_shape(int level, stringstream& ss) { int bt_fv=0; int bt_dmp=0; -void BucketBasics::fullValidate(const DiskLoc& thisLoc) { - assertValid(); - if( bt_fv==0 ) - return; +void BucketBasics::dumpTree(DiskLoc thisLoc) { + bt_dmp=1; + fullValidate(thisLoc); + bt_dmp=0; +} -// cout << "fullValidate() [slow]" << endl; +int BucketBasics::fullValidate(const DiskLoc& thisLoc) { + assertValid(true); +// if( bt_fv==0 ) +// return; - if( bt_dmp ) + if( bt_dmp ) { + cout << thisLoc.toString() << ' '; ((BtreeBucket *) this)->dump(); + } + + // keycount + int kc = 0; for( int i = 0; i < n; i++ ) { _KeyNode& kn = k(i); + if( kn.isUsed() ) kc++; if( !kn.prevChildBucket.isNull() ) { DiskLoc left = kn.prevChildBucket; BtreeBucket *b = left.btree(); wassert( b->parent == thisLoc ); - b->fullValidate(kn.prevChildBucket); + kc += b->fullValidate(kn.prevChildBucket); } } if( !nextChild.isNull() ) { BtreeBucket *b = nextChild.btree(); wassert( b->parent == thisLoc ); - b->fullValidate(nextChild); + kc += b->fullValidate(nextChild); } + + return kc; } int nDumped = 0; -void BucketBasics::assertValid() { - if( !debug ) +void BucketBasics::assertValid(bool force) { + if( !debug && !force ) return; wassert( n >= 0 && n < BucketSize ); wassert( emptySize >= 0 && emptySize < BucketSize ); @@ -76,7 +90,7 @@ void BucketBasics::assertValid() { for( int i = 0; i < n-1; i++ ) { JSObj k1 = keyNode(i).key; JSObj k2 = keyNode(i+1).key; - int z = k1.woCompare(k2); + int z = k1.woCompare(k2); //OK if( z > 0 ) { cout << "ERROR: btree key order corrupt. Keys:" << endl; if( ++nDumped < 5 ) { @@ -88,6 +102,9 @@ void BucketBasics::assertValid() { wassert(false); break; } + else if( z == 0 ) { + wassert( k(i).recordLoc < k(i+1).recordLoc ); + } } } else { @@ -151,7 +168,7 @@ void BucketBasics::pushBack(const DiskLoc& recordLoc, JSObj& key, DiskLoc prevCh kn.prevChildBucket = prevChild; kn.recordLoc = recordLoc; kn.setKeyDataOfs( (short) _alloc(key.objsize()) ); - char *p = dataAt(kn.keyDataOfs); + char *p = dataAt(kn.keyDataOfs()); memcpy(p, key.objdata(), key.objsize()); } @@ -171,7 +188,7 @@ bool BucketBasics::basicInsert(int keypos, const DiskLoc& recordLoc, JSObj& key) kn.prevChildBucket.Null(); kn.recordLoc = recordLoc; kn.setKeyDataOfs((short) _alloc(key.objsize()) ); - char *p = dataAt(kn.keyDataOfs); + char *p = dataAt(kn.keyDataOfs()); memcpy(p, key.objdata(), key.objsize()); return true; } @@ -188,12 +205,12 @@ void BucketBasics::pack() { int ofs = tdz; topSize = 0; for( int j = 0; j < n; j++ ) { - short ofsold = k(j).keyDataOfs; + short ofsold = k(j).keyDataOfs(); int sz = keyNode(j).key.objsize(); ofs -= sz; topSize += sz; memcpy(temp+ofs, dataAt(ofsold), sz); - k(j).setKeyDataOfs( ofs ); + k(j).setKeyDataOfsSavingUse( ofs ); } int dataUsed = tdz - ofs; memcpy(data + ofs, temp + ofs, dataUsed); @@ -236,13 +253,15 @@ void BtreeBucket::findLargestKey(const DiskLoc& thisLoc, DiskLoc& largestLoc, in returns n if it goes after the last existing key. note result might be Unused! */ -bool BtreeBucket::find(JSObj& key, int& pos) { +bool BtreeBucket::find(JSObj& key, DiskLoc recordLoc, int& pos) { /* binary search for this key */ int l=0; int h=n-1; while( l <= h ) { int m = (l+h)/2; KeyNode M = keyNode(m); int x = key.woCompare(M.key); + if( x == 0 ) + x = recordLoc.compare(M.recordLoc); if( x < 0 ) // key < M.key h = m-1; else if( x > 0 ) @@ -250,8 +269,10 @@ bool BtreeBucket::find(JSObj& key, int& pos) { else { // found it. however, if dup keys are here, be careful we might have // found one in the middle. we want find() to return the leftmost instance. +/* while( m >= 1 && keyNode(m-1).key.woEqual(key) ) m--; +*/ pos = m; @@ -271,7 +292,7 @@ bool BtreeBucket::find(JSObj& key, int& pos) { return true; } - x = key.woCompare(M.key); +//? x = key.woCompare(M.key); } // not found pos = l; @@ -341,31 +362,13 @@ int verbose = 0; int qqq = 0; bool BtreeBucket::unindex(const DiskLoc& thisLoc, const char *ns, JSObj& key, const DiskLoc& recordLoc ) { -// cout << "unindex " << key.toString() << endl; - - if( qqq ) { - fullValidate(thisLoc); + int pos; + bool found; + DiskLoc loc = locate(thisLoc, key, pos, found, recordLoc, 1); + if( found ) { + loc.btree()->delKeyAtPos(loc, ns, pos); + return true; } - - BtreeCursor c(thisLoc, key, 1, true); - - while( c.ok() ) { - KeyNode kn = c.currKeyNode(); - if( !kn.key.woEqual(key) ) - break; - if( recordLoc == kn.recordLoc ) { - if( verbose ) - c.bucket.btree()->dump(); - c.bucket.btree()->delKeyAtPos(c.bucket, ns, c.keyOfs); - return true; - } - c.advance(); - } - - if( qqq ) { - fullValidate(thisLoc); - } - return false; } @@ -631,26 +634,10 @@ DiskLoc BtreeBucket::advance(const DiskLoc& thisLoc, int& keyOfs, int direction, return DiskLoc(); } -DiskLoc BtreeBucket::locate(const DiskLoc& thisLoc, JSObj& key, int& pos, bool& found, int direction) { +DiskLoc BtreeBucket::locate(const DiskLoc& thisLoc, JSObj& key, int& pos, bool& found, DiskLoc recordLoc, int direction) { int p; - found = find(key, p); -// dump(); + found = find(key, recordLoc, p); if( found ) { - /* todo: slow? this can be avoided for indexes that don't allow dup keys. add support for that. */ - { - // todo: fix for direction==-1! -// dmtodo - DiskLoc lchild = k(p).prevChildBucket; - if( !lchild.isNull() ) { - // if dup keys, might be dups to the left. - DiskLoc largestLoc; - int largestKey; - lchild.btree()->findLargestKey(lchild, largestLoc, largestKey); - if( !largestLoc.isNull() && largestLoc.btree()->keyAt(largestKey).woEqual(key) ) - return lchild.btree()->locate(lchild, key, pos, found, direction); - } - } - pos = p; return thisLoc; } @@ -658,7 +645,7 @@ DiskLoc BtreeBucket::locate(const DiskLoc& thisLoc, JSObj& key, int& pos, bool& DiskLoc child = childForPos(p); if( !child.isNull() ) { - DiskLoc l = child.btree()->locate(child, key, pos, found, direction); + DiskLoc l = child.btree()->locate(child, key, pos, found, recordLoc, direction); if( !l.isNull() ) return l; } @@ -680,9 +667,9 @@ int BtreeBucket::_insert(DiskLoc thisLoc, const char *ns, DiskLoc recordLoc, return 2; } assert( key.objsize() > 0 ); -//dump(); + int pos; - bool found = find(key, pos); + bool found = find(key, recordLoc, pos); if( insert_debug ) { cout << " " << thisLoc.toString() << '.' << "_insert " << key.toString() << '/' << recordLoc.toString() << @@ -691,8 +678,21 @@ int BtreeBucket::_insert(DiskLoc thisLoc, const char *ns, DiskLoc recordLoc, } if( found ) { + if( k(pos).isUnused() ) { + cout << "an unused already occupying keyslot, write more code.\n"; + cout << " index may be corrupt (missing data) now.\n"; + } + + cout << "_insert(): key already exists in index\n"; + cout << " " << ns << " thisLoc:" << thisLoc.toString() << '\n'; + cout << " " << key.toString() << '\n'; + cout << " " << "recordLoc:" << recordLoc.toString() << " pos:" << pos << endl; + cout << " old l r: " << childForPos(pos).toString() << ' ' << childForPos(pos+1).toString() << endl; + cout << " new l r: " << lChild.toString() << ' ' << rChild.toString() << endl; + assert(false); + // on a dup key always insert on the right or else you will be broken. - pos++; +// pos++; // on a promotion, find the right point to update if dup keys. /* not needed: we always insert right after the first key so we are ok with just pos++... if( !rChild.isNull() ) { @@ -755,17 +755,6 @@ int BtreeBucket::insert(DiskLoc thisLoc, const char *ns, DiskLoc recordLoc, { if( toplevel ) { assert( key.objsize() < BucketSize / 10 ); -/* if( key.toString() == "{ _searchIndex: \"music\" }" ) { - if( music == 0 ) { - music = new JSObj(key.copy()); - cout << music->toString() << endl; - } - tempMusic(thisLoc); - if( recordLoc.getOfs() == 0x4c8d7c0 ) { - cout << "About to add it!" << endl; - } - } -*/ ++ninserts; if( /*ninserts > 127250 || */ninserts % 1000 == 0 ) { cout << "ninserts: " << ninserts << endl; @@ -773,17 +762,7 @@ int BtreeBucket::insert(DiskLoc thisLoc, const char *ns, DiskLoc recordLoc, cout << "debug?" << endl; split_debug = 1; } - //bt_fv = 1; - //idx.head.btree()->fullValidate(idx.head); } -/* if( 0 && ninserts >= 127287 ) { - cout << "---------------------------------------------------------------- " << ninserts << endl; - cout << "insert() top level " << key.toString() << ' ' << recordLoc.toString() << endl; - bt_fv = 1; - split_debug = 1; - insert_debug = 1; - idx.head.btree()->fullValidate(idx.head); - }*/ } bool chk = false; @@ -824,7 +803,7 @@ BtreeCursor::BtreeCursor(DiskLoc head, JSObj& k, int _direction, bool sm) : head.btree()->dump(); } } - bucket = head.btree()->locate(head, k, keyOfs, found, direction); + bucket = head.btree()->locate(head, k, keyOfs, found, direction > 0 ? minDiskLoc : maxDiskLoc, direction); checkUnused(); } @@ -866,6 +845,7 @@ void BtreeCursor::noteLocation() { if( !eof() ) { JSObj o = bucket.btree()->keyAt(keyOfs).copy(); keyAtKeyOfs = o; + locAtKeyOfs = bucket.btree()->k(keyOfs).recordLoc; } } @@ -878,9 +858,11 @@ void BtreeCursor::checkLocation() { return; BtreeBucket *b = bucket.btree(); if( b->keyAt(keyOfs).woEqual(keyAtKeyOfs) && - b->k(keyOfs).isUsed() - ) + b->k(keyOfs).recordLoc == locAtKeyOfs ) { + if( !b->k(keyOfs).isUsed() ) + checkUnused(); return; + } } catch( AssertionException ) { cout << "Caught exception in checkLocation(), that's maybe ok" << endl; @@ -888,32 +870,21 @@ void BtreeCursor::checkLocation() { bool found; DiskLoc bold = bucket; - /* probably just moved in our node, so to be fast start from here rather than the head */ -// bucket = bucket.btree()->locate(bucket, keyAtKeyOfs, keyOfs, found, direction); -/// if( found || bucket.btree()->isHead() ) { -// cout << " key seems to have moved in the index, refinding. found:" << found << endl; -// checkUnused(); -/* - if( found && !bucket.btree()->k(keyOfs).isUsed() ) { - cout << " " << keyAtKeyOfs.toString() << endl; - cout << " " << keyOfs << endl; - cout << " " << bucket.btree()->keyNode(keyOfs).key.toString() << endl; - cout << " " << bucket.btree()->keyNode(keyOfs).recordLoc.toString() << endl; - bucket.btree()->dump(); - assert(false); - } -*/ -// return; -// } /* TODO: Switch to keep indexdetails and do idx.head! */ /* didn't find, check from the top */ DiskLoc head = bold.btree()->getHead(bold); - bucket = head.btree()->locate(head, keyAtKeyOfs, keyOfs, found, direction); -// head.btree()->locate(head, keyAtKeyOfs, keyOfs, found); + bucket = head.btree()->locate(head, keyAtKeyOfs, keyOfs, found, locAtKeyOfs, direction); if( clctr++ % 128 == 0 ) cout << " key seems to have moved in the index, refinding. found:" << found << endl; if( found ) checkUnused(); - // assert( !found || bucket.btree()->k(keyOfs).isUsed() ); } + +/* ----------------------------------------------------------------------------- */ + +struct BtreeUnitTest { + BtreeUnitTest() { + assert( minDiskLoc.compare(maxDiskLoc) < 0 ); + } +} btut; diff --git a/db/btree.h b/db/btree.h index bdde56ec0c7..a2b7c43cf9d 100644 --- a/db/btree.h +++ b/db/btree.h @@ -13,11 +13,14 @@ struct _KeyNode { DiskLoc prevChildBucket; DiskLoc recordLoc; - short keyDataOfs; - void setKeyDataOfs(short s) { keyDataOfs = s; } - void setUnused() { recordLoc.Null(); } - bool isUnused() { return recordLoc.isNull(); } - bool isUsed() { return !isUnused(); } + short keyDataOfs() { return (short) _kdo; } + unsigned short _kdo; + void setKeyDataOfs(short s) { _kdo = s; assert(s>=0); } + void setKeyDataOfsSavingUse(short s) { _kdo = s; assert(s>=0); } + void setUnused() { recordLoc.GETOFS() |= 1; } +// void setUsed() { _kdo &= 0x7fff; } + int isUnused() { return (recordLoc.getOfs() & 1); } + int isUsed() { return !isUnused(); } }; #pragma pack(pop) @@ -40,9 +43,10 @@ public: class BucketBasics { friend class KeyNode; public: + void dumpTree(DiskLoc thisLoc); bool isHead() { return parent.isNull(); } - void assertValid(); - void fullValidate(const DiskLoc& thisLoc); /* traverses everything */ + void assertValid(bool force = false); + int fullValidate(const DiskLoc& thisLoc); /* traverses everything */ protected: DiskLoc& getChild(int pos) { assert( pos >= 0 && pos <= n ); @@ -114,12 +118,13 @@ public: static DiskLoc addHead(const char *ns); /* start a new index off, empty */ int insert(DiskLoc thisLoc, const char *ns, DiskLoc recordLoc, JSObj& key, bool dupsAllowed, IndexDetails& idx, bool toplevel); - void update(const DiskLoc& recordLoc, JSObj& key); +// void update(const DiskLoc& recordLoc, JSObj& key); bool unindex(const DiskLoc& thisLoc, const char *ns, JSObj& key, const DiskLoc& recordLoc); /* locate may return an "unused" key that is just a marker. so be careful. + looks for a key:recordloc pair. */ - DiskLoc locate(const DiskLoc& thisLoc, JSObj& key, int& pos, bool& found, int direction=1); + DiskLoc locate(const DiskLoc& thisLoc, JSObj& key, int& pos, bool& found, DiskLoc recordLoc, int direction=1); /* advance one key position in the index: */ DiskLoc advance(const DiskLoc& thisLoc, int& keyOfs, int direction, const char *caller); @@ -139,7 +144,7 @@ private: int _insert(DiskLoc thisLoc, const char *ns, DiskLoc recordLoc, JSObj& key, bool dupsAllowed, DiskLoc lChild, DiskLoc rChild, IndexDetails&); - bool find(JSObj& key, int& pos); + bool find(JSObj& key, DiskLoc recordLoc, int& pos); static void findLargestKey(const DiskLoc& thisLoc, DiskLoc& largestLoc, int& largestKey); }; @@ -177,6 +182,7 @@ private: int direction; // 1=fwd,-1=reverse bool stopmiss; JSObj keyAtKeyOfs; // so we can tell if things moved around on us between the query and the getMore call + DiskLoc locAtKeyOfs; }; #pragma pack(pop) diff --git a/db/db.cpp b/db/db.cpp index 5126230d826..205833296fc 100644 --- a/db/db.cpp +++ b/db/db.cpp @@ -263,7 +263,7 @@ public: }; void listen(int port) { - cout << "db version: 08mar2008 capped collections.3 rno" << endl; + cout << "db version: mar2008 new dup key handling" << endl; pdfileInit(); testTheDb(); cout << curTimeMillis() % 10000 << " waiting for connections...\n" << endl; diff --git a/db/jsobj.h b/db/jsobj.h index 6b09043a8b9..a93ee47277d 100644 --- a/db/jsobj.h +++ b/db/jsobj.h @@ -298,7 +298,7 @@ public: JSObj doneAndDecouple() { int l; - return JSObj(decouple(l)); + return JSObj(decouple(l), true); } JSObj done() { return JSObj(_done()); diff --git a/db/pdfile.cpp b/db/pdfile.cpp index fbd4ddbd8b4..ca3987d95ef 100644 --- a/db/pdfile.cpp +++ b/db/pdfile.cpp @@ -117,11 +117,15 @@ DiskLoc NamespaceDetails::__alloc(int len) { int extra = 5; // look for a better fit, a little. int chain = 0; while( 1 ) { - int a = cur.a(); - if( a < -1 || a >= 100000 ) { - cout << "Assertion failure - a() out of range in _alloc() " << a << endl; - sayDbContext(); - cur.Null(); + { + int a = cur.a(); + if( a < -1 || a >= 100000 ) { + cout << "Assertion failure - a() out of range in _alloc() " << a << endl; + sayDbContext(); + if( cur == *prev ) + prev->Null(); + cur.Null(); + } } if( cur.isNull() ) { // move to next bucket. if we were doing "extra", just break @@ -548,7 +552,7 @@ void _unindexRecord(const char *ns, IndexDetails& id, JSObj& obj, const DiskLoc& id.getKeysFromObject(obj, keys); for( set::iterator i=keys.begin(); i != keys.end(); i++ ) { JSObj j = *i; -// cout << "TEMP: j:" << j.toString() << endl; +// cout << "UNINDEX: j:" << j.toString() << " head:" << id.head.toString() << dl.toString() << endl; if( otherTraceLevel >= 5 ) { cout << "_unindexRecord() " << obj.toString(); cout << "\n unindex:" << j.toString() << endl; @@ -562,14 +566,12 @@ void _unindexRecord(const char *ns, IndexDetails& id, JSObj& obj, const DiskLoc& cout << " caught assertion _unindexRecord " << id.indexNamespace() << '\n'; } -#if defined(_WIN32) - id.head.btree()->fullValidate(id.head); -#endif if( !ok ) { cout << "Assertion failure: _unindex failed" << '\n'; cout << " obj:" << obj.toString() << '\n'; cout << " key:" << j.toString() << '\n'; cout << " dl:" << dl.toString() << endl; + sayDbContext(); } } } @@ -720,14 +722,17 @@ int followupExtentSize(int len, int lastExtentLen) { return sz; } +int deb=0; + /* add keys to indexes for a new record */ void _indexRecord(IndexDetails& idx, JSObj& obj, DiskLoc newRecordLoc) { + set keys; idx.getKeysFromObject(obj, keys); for( set::iterator i=keys.begin(); i != keys.end(); i++ ) { - // cout << "temp: _indexRecord " << i->toString() << endl; assert( !newRecordLoc.isNull() ); try { +// cout << "TEMP index: " << newRecordLoc.toString() << obj.toString() << endl; idx.head.btree()->insert(idx.head, idx.indexNamespace().c_str(), newRecordLoc, (JSObj&) *i, false, idx, true); } diff --git a/db/pdfile.h b/db/pdfile.h index 49c7f162ca1..46db0a0f9d2 100644 --- a/db/pdfile.h +++ b/db/pdfile.h @@ -327,6 +327,10 @@ inline BtreeBucket* DiskLoc::btree() const { return (BtreeBucket*) rec()->data; } +inline Bucket* DiskLoc::bucket() const { + return (Bucket*) rec()->data; +} + /*---------------------------------------------------------------------*/ // customer, or rather a customer's database -- i guess down the line diff --git a/db/query.cpp b/db/query.cpp index 6046589a8fa..16dd1e3703b 100644 --- a/db/query.cpp +++ b/db/query.cpp @@ -346,6 +346,18 @@ string validateNS(const char *ns, NamespaceDetails *d) { } ss << " deleted: n: " << ndel << " size: " << delSize << endl; + int idxn = 0; + try { + ss << " nIndexes:" << d->nIndexes << endl; + for( ; idxn < d->nIndexes; idxn++ ) { + ss << " " << d->indexes[idxn].indexNamespace() << " keys:" << + d->indexes[idxn].head.btree()->fullValidate(d->indexes[idxn].head) << endl; + } + } + catch(...) { + ss << "\n exception during index validate idxn:" << idxn << endl; + } + } catch(AssertionException) { ss << "\n exception during validate\n" << endl; @@ -730,4 +742,4 @@ done: b.decouple(); return qr; -} \ No newline at end of file +} diff --git a/db/storage.h b/db/storage.h index ab42f504796..78d1dbf1a5e 100644 --- a/db/storage.h +++ b/db/storage.h @@ -15,6 +15,7 @@ class Extent; class BtreeBucket; class JSObj; class PhysicalDataFile; +class Bucket; class DiskLoc { int fileNo; /* this will be volume, file #, etc. */ @@ -41,6 +42,7 @@ public: return ss.str(); } + int& GETOFS() { return ofs; } int getOfs() const { return ofs; } void set(int a, int b) { fileNo=a; ofs=b; } void setOfs(int _fileNo, int _ofs) { @@ -62,6 +64,13 @@ public: assert(ofs!=0); return *this; } + int compare(const DiskLoc& b) const { + int x = fileNo - b.fileNo; + if( x ) + return x; + if( ofs == b.ofs ) return 0; + return ofs < b.ofs ? -1 : 1; + } bool operator<(const DiskLoc& b) const { if( fileNo == b.fileNo ) return ofs < b.ofs; @@ -73,6 +82,7 @@ public: DeletedRecord* drec() const; Extent* ext() const; BtreeBucket* btree() const; + Bucket* bucket() const; PhysicalDataFile& pdf() const; }; diff --git a/db/testdb.js b/db/testdb.js index f3486de235e..ebc09199b9e 100644 --- a/db/testdb.js +++ b/db/testdb.js @@ -58,6 +58,58 @@ function index2() { t.z.remove({}); } +function giantIndexTest() { + print("giantIndexTest"); + drop("giant"); + db.giant.save({moe:1,foo:[33],bar:"aaaaa"}); + + var z = 0; + var prime = 127; + for( var i = 0; i < 20000; i++ ) { + var ar = []; + for( var j = 0; j < 100; j++ ) { + z += prime; + ar.push( z % 100 ); + } + db.giant.save({foo:ar, bar:"bbbbb"}); + if( i % 1000 == 0 ) print(i); + if( i == 10000 ) + db.giant.ensureIndex({foo:1}); + } + + + assert( db.giant.findOne({foo:33}) ); + print("giantIndexTest end"); +} + +function giant2() { + print("giant2"); + drop("giant"); + db.giant.save({moe:1,foo:[33],bar:"aaaaa",q:-1}); + + var z = 0; + var prime = 127; + for( var i = 0; i < 20000; i++ ) { + var ar = []; + for( var j = 0; j < 100; j++ ) { + z += prime; + ar.push( z % 100 ); + } + db.giant.save({foo:ar, bar:"bbbbb", q:i}); + if( i % 1000 == 0 ) print(i); + if( 0 && i == 10000 ) + db.giant.ensureIndex({foo:1}); + } + + + assert( db.giant.findOne({foo:33}) ); + print("giant2 end"); +} + +// mx=-3; +// db.giant.find().forEach( function(x) { +// if( x.q % 100 == 0 ) print(x.q); if( x.q > mx ) { x.name = "john smith"; db.giant.save(x); mx = x.q; } } );} } ); + function bigIndexTest() { t.big.remove({}); t.big.save( { name: "Dwight" } ); @@ -154,19 +206,23 @@ function testgetmore() { function testdups() { print("testdups"); - for( pass=0;pass<2;pass++ ) { + K = 2000; + for( pass=0;pass<1;pass++ ) { print(" pass:" + pass); - if( pass < 2 ) + if( pass < 2 ) { + print("removing keys"); t.td.remove({}); - for( var x=0;x<2000;x++ ) + } + print("add keys"); + for( var x=0;x #include -//#if defined(_WIN32) -//#include -//#else typedef char _TCHAR; -//#endif #include #include