// SERVER-2326 - make sure that sharding only works with unique indices (function() { var s = new ShardingTest({ name: "shard_index", shards: 2, mongos: 1 }); // Regenerate fully because of SERVER-2782 for ( var i = 0; i < 22; i++ ) { var coll = s.admin._mongo.getDB( "test" ).getCollection( "foo" + i ); coll.drop(); var bulk = coll.initializeUnorderedBulkOp(); for ( var j = 0; j < 300; j++ ) { bulk.insert({ num: j, x: 1 }); } assert.writeOK(bulk.execute()); if (i == 0) { s.adminCommand({ enablesharding: "" + coll._db }); s.ensurePrimaryShard(coll.getDB().getName(), 'shard0001'); } print("\n\n\n\n\nTest # " + i); if ( i == 0 ) { // Unique index exists, but not the right one. coll.ensureIndex( { num : 1 }, { unique : true } ); coll.ensureIndex( { x : 1 } ); passed = false; try { s.adminCommand( { shardcollection : "" + coll, key : { x : 1 } } ); passed = true; } catch (e) { print( e ); } assert( !passed, "Should not shard collection when another unique index exists!"); } if ( i == 1 ) { // Unique index exists as prefix, also index exists coll.ensureIndex( { x : 1 } ); coll.ensureIndex( { x : 1, num : 1 }, { unique : true } ); try{ s.adminCommand({ shardcollection : "" + coll, key : { x : 1 } }); } catch(e){ print(e); assert( false, "Should be able to shard non-unique index without unique option."); } } if ( i == 2 ) { // Non-unique index exists as prefix, also index exists. No unique index. coll.ensureIndex( { x : 1 } ); coll.ensureIndex( { x : 1, num : 1 } ); passed = false; try{ s.adminCommand({ shardcollection : "" + coll, key : { x : 1 } }); passed = true; } catch( e ){ print(e); assert( !passed, "Should be able to shard collection with no unique index if unique not specified."); } } if ( i == 3 ) { // Unique index exists as prefix, also unique index exists coll.ensureIndex( { num : 1 }, { unique : true }); coll.ensureIndex( { num : 1 , x : 1 }, { unique : true } ); try{ s.adminCommand({ shardcollection : "" + coll, key : { num : 1 }, unique : true }); } catch( e ){ print(e); assert( false, "Should be able to shard collection with unique prefix index."); } } if ( i == 4 ) { // Unique index exists as id, also unique prefix index exists coll.ensureIndex( { _id : 1, num : 1 }, { unique : true } ); try{ s.adminCommand({ shardcollection : "" + coll, key : { _id : 1 }, unique : true }); } catch( e ){ print(e); assert( false, "Should be able to shard collection with unique id index."); } } if ( i == 5 ) { // Unique index exists as id, also unique prefix index exists coll.ensureIndex( { _id : 1, num : 1 }, { unique : true } ); try{ s.adminCommand({ shardcollection : "" + coll, key : { _id : 1, num : 1 }, unique : true }); } catch( e ){ print(e); assert( false, "Should be able to shard collection with unique combination id index."); } } if ( i == 6 ) { coll.remove({}); // Unique index does not exist, also unique prefix index exists coll.ensureIndex( { num : 1, _id : 1 }, { unique : true } ); try{ s.adminCommand({ shardcollection : "" + coll, key : { num : 1 }, unique : true }); } catch( e ){ print(e); assert( false, "Should be able to shard collection with no unique index but with a unique prefix index."); } printjson( coll.getIndexes() ); // Make sure the index created is unique! assert.eq( 1, coll.getIndexes().filter( function(z) { return friendlyEqual( z.key, { num : 1 } ) && z.unique; } ).length ); } if ( i == 7 ) { coll.remove({}); // No index exists try{ assert.eq( coll.find().itcount(), 0 ); s.adminCommand({ shardcollection : "" + coll, key : { num : 1 } }); } catch( e ){ print(e); assert( false, "Should be able to shard collection with no index on shard key."); } } if ( i == 8 ) { coll.remove({}); // No index exists passed = false; try{ assert.eq( coll.find().itcount(), 0 ); s.adminCommand({ shardcollection : "" + coll, key : { num : 1 }, unique : true }); passed = true; } catch( e ){ print(e); } assert( passed, "Should be able to shard collection with unique flag but with no unique index on shard key, if coll empty."); printjson( coll.getIndexes() ); // Make sure the index created is unique! assert.eq( 1, coll.getIndexes().filter( function(z) { return friendlyEqual( z.key, { num : 1 } ) && z.unique; } ).length ); } if ( i == 9 ) { // Unique index exists on a different field as well coll.ensureIndex( { num : 1 }, { unique : true } ); coll.ensureIndex( { x : 1 } ); passed = false; try { s.adminCommand( { shardcollection : "" + coll, key : { x : 1 } } ); passed = true; } catch (e) { print( e ); } assert( !passed, "Should not shard collection when another unique index exists!" ); } if ( i == 10 ){ //try sharding non-empty collection without any index passed = false; try{ s.adminCommand( { shardcollection : "" + coll, key : { num : 1 } } ); passed = true; } catch( e ){ print(e); } assert( !passed , "Should not be able to shard without index"); //now add containing index and try sharding by prefix coll.ensureIndex( {num : 1, x : 1} ); try{ s.adminCommand( { shardcollection : "" + coll, key : { num : 1 } } ); passed = true; } catch( e ){ print(e); } assert( passed , "Should be able to shard collection with prefix of existing index"); printjson( coll.getIndexes() ); //make sure no extra index is created assert.eq( 2, coll.getIndexes().length ); } if ( i == 11 ){ coll.remove({}); //empty collection with useful index. check new index not created coll.ensureIndex( {num : 1, x : 1} ); try{ s.adminCommand( { shardcollection : "" + coll, key : { num : 1 } } ); passed = true; } catch( e ){ print(e); } assert( passed , "Should be able to shard collection with prefix of existing index"); printjson( coll.getIndexes() ); //make sure no extra index is created assert.eq( 2, coll.getIndexes().length ); } if ( i == 12 ){ //check multikey values for x make index unusable for shard key coll.save({num : 100 , x : [2,3] }); coll.ensureIndex( {num : 1, x : 1} ); passed = false; try{ s.adminCommand( { shardcollection : "" + coll, key : { num : 1 } } ); passed = true; } catch( e ){ print(e); } assert( !passed , "Should not be able to shard collection with mulikey index"); } if ( i == 13 ){ coll.save({ num : [100, 200], x : 10}); coll.ensureIndex( { num : 1, x : 1} ); passed = false; try{ s.adminCommand( { shardcollection : "" + coll, key : { num : 1 } } ); passed = true; } catch( e ){ print(e); } assert( !passed , "Should not be able to shard collection with mulikey index"); } if ( i == 14 ){ coll.save({ num : 100, x : 10, y : [1,2]}); coll.ensureIndex( { num : 1, x : 1, y : 1} ); passed = false; try{ s.adminCommand( { shardcollection : "" + coll, key : { num : 1 } } ); passed = true; } catch( e ){ print(e); } assert( !passed , "Should not be able to shard collection with mulikey index"); } if ( i == 15 ) { // try sharding with a hashed index coll.ensureIndex( { num : "hashed"} ); try{ s.adminCommand( { shardcollection : "" + coll, key : { num : "hashed" } } ); } catch( e ){ print(e); assert( false, "Should be able to shard collection with hashed index."); } } if ( i == 16 ) { // create hashed index, but try to declare it unique when sharding coll.ensureIndex( { num : "hashed"} ); passed = false; try{ s.adminCommand({ shardcollection : "" + coll, key : { num : "hashed" }, unique : true}); passed = true; } catch( e ){ print(e); } assert( !passed , "Should not be able to declare hashed shard key unique."); } if ( i == 17 ) { // create hashed index, but unrelated unique index present coll.ensureIndex( { x : "hashed" } ); coll.ensureIndex( { num : 1 }, { unique : true} ); passed = false; try { s.adminCommand( { shardcollection : "" + coll, key : { x : "hashed" } } ); passed = true; } catch (e) { print( e ); } assert( !passed, "Should not be able to shard on hashed index with another unique index" ); } if ( i == 18 ) { // create hashed index, and a regular unique index exists on same field coll.ensureIndex( { num : "hashed" } ); coll.ensureIndex( { num : 1 }, { unique : true } ); try{ s.adminCommand({ shardcollection : "" + coll, key : { num : "hashed" } } ); } catch( e ){ print(e); assert( false, "Should be able to shard coll with hashed and regular unique index"); } } if ( i == 19 ) { // Create sparse index. coll.ensureIndex( { x : 1 }, { sparse : true } ); passed = false; try { s.adminCommand( { shardcollection : "" + coll, key : { x : 1 } } ); passed = true; } catch ( e ) { print( e ); } assert( !passed, "Should not be able to shard coll with sparse index" ); } if ( i == 20 ) { // Create partial index. coll.ensureIndex( { x : 1 }, { filter: { num : { $gt : 1 } } } ); passed = false; try { s.adminCommand( { shardcollection : "" + coll, key : { x : 1 } } ); passed = true; } catch ( e ) { print( e ); } assert( !passed, "Should not be able to shard coll with partial index" ); } if ( i == 21 ) { // Ensure that a collection with a normal index and a partial index can be sharded, where // both are prefixed by the shard key. coll.ensureIndex( { x : 1, num : 1 }, { filter: { num : { $gt : 1 } } } ); coll.ensureIndex( { x : 1, num : -1 } ); try { s.adminCommand( { shardcollection : "" + coll, key : { x : 1 } } ); } catch ( e ) { print( e ); assert( false, "Should be able to shard coll with regular and partial index"); } } } s.stop(); })();