Browse files

support up to 64 indexes

  • Loading branch information...
1 parent 9aa407f commit 27f5790d110eed10b1cef77a176c945ccaab2159 @dwight dwight committed May 23, 2010
Showing with 163 additions and 83 deletions.
  1. +2 −0 db/db_10.sln
  2. +57 −9 db/namespace.cpp
  3. +46 −37 db/namespace.h
  4. +4 −3 jstests/capped3.js
  5. +49 −31 jstests/index_many.js
  6. +1 −1 jstests/indexapi.js
  7. +4 −2 jstests/objid5.js
View
2 db/db_10.sln
@@ -48,6 +48,8 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "jstests", "jstests", "{F5ABFB2C-A34F-48C1-9B5F-01D456AF6C57}"
ProjectSection(SolutionItems) = preProject
..\jstests\index_many.js = ..\jstests\index_many.js
+ ..\jstests\indexapi.js = ..\jstests\indexapi.js
+ ..\jstests\objid5.js = ..\jstests\objid5.js
EndProjectSection
EndProject
Global
View
66 db/namespace.cpp
@@ -568,28 +568,76 @@ namespace mongo {
return loc;
}
+ /* extra space for indexes when more than 10 */
+ NamespaceDetails::Extra* NamespaceIndex::newExtra(const char *ns, int i, NamespaceDetails *d) {
+ assert( i >= 0 && i <= 1 );
+ Namespace n(ns);
+ Namespace extra(n.extraName(i).c_str()); // throws userexception if ns name too long
+
+ massert( 10350 , "allocExtra: base ns missing?", d );
+ massert( 10351 , "allocExtra: extra already exists", ht->get(extra) == 0 );
+
+ NamespaceDetails::Extra temp;
+ temp.init();
+ uassert( 10082 , "allocExtra: too many namespaces/collections", ht->put(extra, (NamespaceDetails&) temp));
+ NamespaceDetails::Extra *e = (NamespaceDetails::Extra *) ht->get(extra);
+ return e;
+ }
+ NamespaceDetails::Extra* NamespaceDetails::allocExtra(const char *ns, int nindexessofar) {
+ NamespaceIndex *ni = nsindex(ns);
+ int i = (nindexessofar - NIndexesBase) / NIndexesExtra;
+ Extra *e = ni->newExtra(ns, i, this);
+ long ofs = e->ofsFrom(this);
+ if( i == 0 ) {
+ assert( extraOffset == 0 );
+ extraOffset = ofs;
+ assert( extra() == e );
+ }
+ else {
+ Extra *hd = extra();
+ assert( hd->next(this) == 0 );
+ hd->setNext(ofs);
+ }
+ return e;
+ }
+
/* you MUST call when adding an index. see pdfile.cpp */
IndexDetails& NamespaceDetails::addIndex(const char *thisns, bool resetTransient) {
assert( nsdetails(thisns) == this );
- if( nIndexes == NIndexesBase && extraOffset == 0 ) {
- nsindex(thisns)->allocExtra(thisns);
+ IndexDetails *id;
+ try {
+ id = &idx(nIndexes);
+ }
+ catch(DBException&) {
+ allocExtra(thisns, nIndexes);
+ id = &idx(nIndexes);
}
- IndexDetails& id = idx(nIndexes);
nIndexes++;
if ( resetTransient )
NamespaceDetailsTransient::get_w(thisns).addedIndex();
- return id;
+ return *id;
}
// must be called when renaming a NS to fix up extra
void NamespaceDetails::copyingFrom(const char *thisns, NamespaceDetails *src) {
- if( extraOffset ) {
- extraOffset = 0; // so allocExtra() doesn't assert.
- Extra *e = nsindex(thisns)->allocExtra(thisns);
- memcpy(e, src->extra(), sizeof(Extra));
- }
+ extraOffset = 0; // we are a copy -- the old value is wrong. fixing it up below.
+ Extra *se = src->extra();
+ int n = NIndexesBase;
+ if( se ) {
+ Extra *e = allocExtra(thisns, n);
+ while( 1 ) {
+ n += NIndexesExtra;
+ e->copy(this, *se);
+ se = se->next(src);
+ if( se == 0 ) break;
+ Extra *nxt = allocExtra(thisns, n);
+ e->setNext( nxt->ofsFrom(this) );
+ e = nxt;
+ }
+ assert( extraOffset );
+ }
}
/* returns index of the first index in which the field is present. -1 if not present.
View
83 db/namespace.h
@@ -178,23 +178,48 @@ namespace mongo {
enum { NIndexesExtra = 30,
NIndexesBase = 10
};
- struct Extra {
- // note we could use this field for more chaining later, so don't waste it:
- unsigned long long reserved1;
+ class Extra {
+ long _next;
+ unsigned long reserved4;
+ Extra(const Extra&) { assert(false); }
+ Extra& operator=(const Extra& r) { assert(false); }
+ public:
+ Extra() { }
+ long ofsFrom(NamespaceDetails *d) {
+ return ((char *) this) - ((char *) d);
+ }
IndexDetails details[NIndexesExtra];
+ void init() {
+ memset(this, 0, sizeof(Extra));
+ }
+ Extra* next(NamespaceDetails *d) {
+ if( _next == 0 ) return 0;
+ return (Extra*) (((char *) d) + _next);
+ }
+ void setNext(long ofs) { _next = ofs; }
+ void copy(NamespaceDetails *d, const Extra& e) {
+ memcpy(this, &e, sizeof(Extra));
+ _next = 0;
+ }
+ private:
unsigned reserved2;
unsigned reserved3;
};
Extra* extra() {
- assert( extraOffset );
+ if( extraOffset == 0 ) return 0;
return (Extra *) (((char *) this) + extraOffset);
}
+
public:
+ /* add extra space for indexes when more than 10 */
+ Extra* allocExtra(const char *ns, int nindexessofar);
+
void copyingFrom(const char *thisns, NamespaceDetails *src); // must be called when renaming a NS to fix up extra
- enum { NIndexesMax = 40 };
+ enum { NIndexesMax = 64 };
- BOOST_STATIC_ASSERT( NIndexesMax == NIndexesBase + NIndexesExtra );
+ BOOST_STATIC_ASSERT( NIndexesMax <= NIndexesBase + NIndexesExtra*2 );
+ BOOST_STATIC_ASSERT( NIndexesMax <= 64 ); // multiKey bits
/* called when loaded from disk */
void onLoad(const Namespace& k);
@@ -282,7 +307,15 @@ namespace mongo {
IndexDetails& idx(int idxNo) {
if( idxNo < NIndexesBase )
return _indexes[idxNo];
- return extra()->details[idxNo-NIndexesBase];
+ Extra *e = extra();
+ massert(13282, "missing Extra", e);
+ int i = idxNo - NIndexesBase;
+ if( i >= NIndexesExtra ) {
+ e = e->next(this);
+ massert(13283, "missing Extra", e);
+ i -= NIndexesExtra;
+ }
+ return e->details[i];
}
IndexDetails& backgroundIdx() {
DEV assert(backgroundIndexBuildInProgress);
@@ -294,22 +327,16 @@ namespace mongo {
int i;
int n;
NamespaceDetails *d;
- Extra *e;
IndexIterator(NamespaceDetails *_d) {
d = _d;
i = 0;
n = d->nIndexes;
- if( n > NIndexesBase )
- e = d->extra();
}
public:
int pos() { return i; } // note this is the next one to come
bool more() { return i < n; }
IndexDetails& next() {
- int k = i;
- i++;
- return k < NIndexesBase ? d->_indexes[k] :
- e->details[k-10];
+ return d->idx(i++);
}
};
@@ -581,23 +608,20 @@ namespace mongo {
class NamespaceIndex {
friend class NamespaceCursor;
BOOST_STATIC_ASSERT( sizeof(NamespaceDetails::Extra) <= sizeof(NamespaceDetails) );
- public:
+ public:
NamespaceIndex(const string &dir, const string &database) :
- ht( 0 ),
- dir_( dir ),
- database_( database ) {}
+ ht( 0 ), dir_( dir ), database_( database ) {}
/* returns true if new db will be created if we init lazily */
bool exists() const;
-
+
void init();
void add_ns(const char *ns, DiskLoc& loc, bool capped) {
NamespaceDetails details( loc, capped );
add_ns( ns, details );
}
-
void add_ns( const char *ns, const NamespaceDetails &details ) {
init();
Namespace n(ns);
@@ -611,23 +635,6 @@ namespace mongo {
return ((char *) d) - (char *) ht->nodes;
}*/
- /* extra space for indexes when more than 10 */
- NamespaceDetails::Extra* allocExtra(const char *ns) {
- Namespace n(ns);
- Namespace extra(n.extraName(0).c_str()); // throws userexception if ns name too long
- NamespaceDetails *d = details(ns);
- massert( 10350 , "allocExtra: base ns missing?", d );
- assert( d->extraOffset == 0 );
- massert( 10351 , "allocExtra: extra already exists", ht->get(extra) == 0 );
- NamespaceDetails::Extra temp;
- memset(&temp, 0, sizeof(temp));
- uassert( 10082 , "allocExtra: too many namespaces/collections", ht->put(extra, (NamespaceDetails&) temp));
- NamespaceDetails::Extra *e = (NamespaceDetails::Extra *) ht->get(extra);
- d->extraOffset = ((char *) e) - ((char *) d);
- assert( d->extra() == e );
- return e;
- }
-
NamespaceDetails* details(const char *ns) {
if ( !ht )
return 0;
@@ -668,6 +675,8 @@ namespace mongo {
void getNamespaces( list<string>& tofill , bool onlyCollections = true ) const;
+ NamespaceDetails::Extra* newExtra(const char *ns, int n, NamespaceDetails *d);
+
private:
boost::filesystem::path path() const;
void maybeMkdir() const;
View
7 jstests/capped3.js
@@ -23,9 +23,10 @@ c = t2.find().sort( {$natural:-1} );
i = 999;
while( c.hasNext() ) {
assert.eq( i--, c.next().i, "E" );
-}
-print( "i: " + i );
-print( "stats: " + tojson( t2.stats() ) );
+}
+//print( "i: " + i );
+var str = tojson( t2.stats() );
+//print( "stats: " + tojson( t2.stats() ) );
assert( i < 990, "F" );
t.drop();
View
80 jstests/index_many.js
@@ -1,33 +1,51 @@
/* test using lots of indexes on one collection */
-t = db.many;
-t.drop();
-db.many2.drop();
-
-t.save({x:9});
-t.save({x:19});
-
-x = 2;
-while( x < 70 ) {
- patt={};
- patt[x] = 1;
- if( x == 20 )
- patt = { x : 1 };
- t.ensureIndex(patt);
- x++;
-}
-
-// print( tojson(db.getLastErrorObj()) );
-assert( db.getLastError(), "should have got an error 'too many indexes'" );
-
-// 40 is the limit currently
-
-assert( t.getIndexes().length == 40, "40" );
-
-assert( t.find({x:9}).length() == 1, "b" );
-assert(t.find({ x: 9 }).explain().cursor.match(/Btree/), "not using index?");
-
-/* check that renamecollection remaps all the indexes right */
-t.renameCollection( "many2" );
-assert( t.find({x:9}).length() == 0, "many2a" ) ;
-assert( db.many2.find({x:9}).length() == 1, "many2b" ) ;
+t = db.many;
+
+function f() {
+
+ t.drop();
+ db.many2.drop();
+
+ t.save({ x: 9, y : 99 });
+ t.save({ x: 19, y : 99 });
+
+ x = 2;
+ while (x < 70) {
+ patt = {};
+ patt[x] = 1;
+ if (x == 20)
+ patt = { x: 1 };
+ if (x == 64)
+ patt = { y: 1 };
+ t.ensureIndex(patt);
+ x++;
+ }
+
+ // print( tojson(db.getLastErrorObj()) );
+ assert(db.getLastError(), "should have got an error 'too many indexes'");
+
+ // 40 is the limit currently
+ lim = t.getIndexes().length;
+ if (lim != 64) {
+ print("# of indexes should be 64 but is : " + lim);
+ return;
+ }
+ assert(lim == 64, "not 64 indexes");
+
+ assert(t.find({ x: 9 }).length() == 1, "b");
+ assert(t.find({ x: 9 }).explain().cursor.match(/Btree/), "not using index?");
+
+ assert(t.find({ y: 99 }).length() == 2, "y idx");
+ assert(t.find({ y: 99 }).explain().cursor.match(/Btree/), "not using y index?");
+
+ /* check that renamecollection remaps all the indexes right */
+ assert(t.renameCollection("many2").ok, "rename failed");
+ assert(t.find({ x: 9 }).length() == 0, "many2a");
+ assert(db.many2.find({ x: 9 }).length() == 1, "many2b");
+ assert(t.find({ y: 99 }).length() == 0, "many2c");
+ assert(db.many2.find({ y: 99 }).length() == 2, "many2d");
+
+}
+
+f();
View
2 jstests/indexapi.js
@@ -34,7 +34,7 @@ idx = t.getIndexes();
assert.eq( 2 , idx.length , "M1" );
assert.eq( key , idx[1].key , "M2" );
assert( idx[1].unique , "M3" );
-printjson( idx );
+//printjson( idx );
db.system.indexes.insert( { ns : "test" , key : { x : 1 } , name : "x" } );
assert( db.getLastError().indexOf( "invalid" ) >= 0 , "Z1" );
View
6 jstests/objid5.js
@@ -5,9 +5,11 @@ t.drop();
t.save( { _id : 5.5 } );
assert.eq( 18 , Object.bsonsize( t.findOne() ) , "A" );
-
x = db.runCommand( { features : 1 } )
-y = db.runCommand( { features : 1 , oidReset : 1 } )
+y = db.runCommand( { features : 1 , oidReset : 1 } )
+
+if( !x.ok )
+ print("x: " + tojson(x));
assert( x.oidMachine , "B1" )
assert.neq( x.oidMachine , y.oidMachine , "B2" )

0 comments on commit 27f5790

Please sign in to comment.