public void TestCopyLSMToGSM() { ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerLoadPolicy.Lazy); RangeShardMap<int> rsm = smm.GetRangeShardMap<int>(RecoveryManagerTests.s_rangeShardMapName); Assert.IsNotNull(rsm); ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, RecoveryManagerTests.s_shardedDBs[0]); Shard s = rsm.CreateShard(sl); Assert.IsNotNull(s); RangeMapping<int> r1 = rsm.CreateRangeMapping(new Range<int>(1, 10), s); // Add a range to the gsm RangeMapping<int> r2 = rsm.CreateRangeMapping(new Range<int>(11, 20), s); Assert.IsNotNull(r1); // Delete everything from GSM (yes, this is overkill.) using (SqlConnection conn = new SqlConnection(Globals.ShardMapManagerTestConnectionString)) { conn.Open(); using (SqlCommand cmd = new SqlCommand(String.Format("delete from {0}.__ShardManagement.ShardMappingsGlobal", Globals.ShardMapManagerDatabaseName), conn)) { cmd.ExecuteNonQuery(); } } RecoveryManager rm = new RecoveryManager(smm); // Briefly validate that there are, in fact, the two ranges of inconsistency we are expecting. IEnumerable<RecoveryToken> gs = rm.DetectMappingDifferences(sl); Assert.AreEqual(1, gs.Count(), "The test environment was not expecting more than one local shardmap."); // Briefly validate that foreach (RecoveryToken g in gs) { var kvps = rm.GetMappingDifferences(g); Assert.AreEqual(2, kvps.Keys.Count, "The count of differences does not match the expected."); foreach (var kvp in kvps) { ShardRange range = kvp.Key; MappingLocation mappingLocation = kvp.Value; Assert.AreEqual(MappingLocation.MappingInShardOnly, mappingLocation, "An unexpected difference between global and local shardmaps was detected. This is likely a false positive and implies a bug in the detection code."); } // Recover the GSM from the LSM rm.ResolveMappingDifferences(g, MappingDifferenceResolution.KeepShardMapping); } // Validate that there are no more differences. IEnumerable<RecoveryToken> gsAfterFix = rm.DetectMappingDifferences(sl); foreach (RecoveryToken g in gsAfterFix) { var kvps = rm.GetMappingDifferences(g); Assert.AreEqual(0, kvps.Keys.Count, "There were still differences after resolution."); } }
public void TestGeoFailoverAttach() { ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerLoadPolicy.Lazy); ListShardMap<int> listsm = smm.GetListShardMap<int>(RecoveryManagerTests.s_listShardMapName); Assert.IsNotNull(listsm); ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, RecoveryManagerTests.s_shardedDBs[0]); ShardLocation slNew = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, RecoveryManagerTests.s_shardedDBs[0] + "_new"); // deploy LSM version 1.1 at location 'sl' before calling CreateShard() so that createshard will not deploy latest LSM version smm.UpgradeLocalStore(sl, new Version(1, 1)); Shard s = listsm.CreateShard(sl); Assert.IsNotNull(s); for (int i = 0; i < 5; i++) { PointMapping<int> r = listsm.CreatePointMapping(creationInfo: new PointMappingCreationInfo<int>(i, s, MappingStatus.Online)); Assert.IsNotNull(r); } // rename shard1 as shard1_new using (SqlConnection conn = new SqlConnection(Globals.ShardMapManagerTestConnectionString)) { conn.Open(); using (SqlCommand cmd = new SqlCommand("alter database shard1 set single_user with rollback immediate", conn)) { cmd.ExecuteNonQuery(); } using (SqlCommand cmd = new SqlCommand("alter database shard1 modify name = shard1_new", conn)) { cmd.ExecuteNonQuery(); } using (SqlCommand cmd = new SqlCommand("alter database shard1_new set multi_user with rollback immediate", conn)) { cmd.ExecuteNonQuery(); } } RecoveryManager rm = new RecoveryManager(smm); rm.DetachShard(sl); rm.AttachShard(slNew); // Verify that shard location in LSM is updated to show databasename as 'shard1_new' IStoreResults result; using (IStoreOperationLocal op = smm.StoreOperationFactory.CreateGetShardsLocalOperation( smm, slNew, "RecoveryTest")) { result = op.Do(); } Assert.AreEqual("shard1_new", result.StoreShards.First().Location.Database); // detect mapping differences and add local mappings to GSM var gs = rm.DetectMappingDifferences(slNew); foreach (RecoveryToken g in gs) { var kvps = rm.GetMappingDifferences(g); Assert.AreEqual(5, kvps.Keys.Count, "Count of Mapping differences for shard1_new does not match expected value."); rm.ResolveMappingDifferences(g, MappingDifferenceResolution.KeepShardMapping); } gs = rm.DetectMappingDifferences(slNew); foreach (RecoveryToken g in gs) { var kvps = rm.GetMappingDifferences(g); Assert.AreEqual(0, kvps.Keys.Count, "GSM and LSM at shard1_new do not have consistent mappings"); } // rename shard1_new back to shard1 so that test cleanup operations will succeed using (SqlConnection conn = new SqlConnection(Globals.ShardMapManagerTestConnectionString)) { conn.Open(); using (SqlCommand cmd = new SqlCommand("alter database shard1_new set single_user with rollback immediate", conn)) { cmd.ExecuteNonQuery(); } using (SqlCommand cmd = new SqlCommand("alter database shard1_new modify name = shard1", conn)) { cmd.ExecuteNonQuery(); } using (SqlCommand cmd = new SqlCommand("alter database shard1 set multi_user with rollback immediate", conn)) { cmd.ExecuteNonQuery(); } } }
public void TestPointMappingRecoverFromLSM() { ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerLoadPolicy.Lazy); ListShardMap<int> listsm = smm.GetListShardMap<int>(RecoveryManagerTests.s_listShardMapName); Assert.IsNotNull(listsm); ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, RecoveryManagerTests.s_shardedDBs[0]); Shard s = listsm.CreateShard(sl); Assert.IsNotNull(s); for (int i = 0; i < 5; i++) { PointMapping<int> r = listsm.CreatePointMapping(creationInfo: new PointMappingCreationInfo<int>(i, s, MappingStatus.Online)); Assert.IsNotNull(r); } // Delete all the ranges and shardmaps from the shardlocation. using (SqlConnection conn = new SqlConnection(Globals.ShardMapManagerTestConnectionString)) { conn.Open(); using (SqlCommand cmd = new SqlCommand("delete from shard1.__ShardManagement.ShardMappingsLocal", conn)) { cmd.ExecuteNonQuery(); } } RecoveryManager rm = new RecoveryManager(smm); var gs = rm.DetectMappingDifferences(sl); // Validate that all the shard locations are in fact missing from the LSM. foreach (RecoveryToken g in gs) { var kvps = rm.GetMappingDifferences(g); Assert.AreEqual(5, kvps.Keys.Count, "The count of differences does not match the expected."); foreach (var kvp in kvps) { ShardRange range = kvp.Key; MappingLocation mappingLocation = kvp.Value; Assert.AreEqual(MappingLocation.MappingInShardMapOnly, mappingLocation, "An unexpected difference between global and local shardmaps was detected. This is likely a false positive and implies a bug in the detection code."); } rm.RebuildMappingsOnShard(g, kvps.Keys.Take(3)); } gs = rm.DetectMappingDifferences(sl); foreach (RecoveryToken g in gs) { var kvps = rm.GetMappingDifferences(g); Assert.AreEqual(2, kvps.Values.Where(loc => loc != MappingLocation.MappingInShardMapAndShard).Count(), "The count of differences does not match the expected."); // We expect that the last two ranges only are missing from the shards. var expectedLocations = new List<MappingLocation>() { MappingLocation.MappingInShardMapAndShard, MappingLocation.MappingInShardMapAndShard, MappingLocation.MappingInShardMapAndShard, MappingLocation.MappingInShardMapOnly, MappingLocation.MappingInShardMapOnly, }; Assert.IsTrue(expectedLocations.Zip(kvps.Values, (x, y) => x == y).Aggregate((x, y) => x && y), "RebuildRangeShardMap rebuilt the shards out of order with respect to its keeplist."); // Rebuild the range, leaving 1 inconsistency rm.RebuildMappingsOnShard(g, kvps.Keys.Skip(1)); } gs = rm.DetectMappingDifferences(sl); foreach (RecoveryToken g in gs) { var kvps = rm.GetMappingDifferences(g); Assert.AreEqual(1, kvps.Values.Where(loc => loc != MappingLocation.MappingInShardMapAndShard).Count(), "The count of differences does not match the expected."); // Rebuild the range, leaving no inconsistencies rm.RebuildMappingsOnShard(g, kvps.Keys); } gs = rm.DetectMappingDifferences(sl); // Everything should be semantically consistent now. foreach (RecoveryToken g in gs) { var kvps = rm.GetMappingDifferences(g); Assert.AreEqual(0, kvps.Values.Where(loc => loc != MappingLocation.MappingInShardMapAndShard).Count(), "The count of differences does not match the expected."); // As a sanity check, make sure the root is restorable from this LSM. rm.ResolveMappingDifferences(g, MappingDifferenceResolution.KeepShardMapping); } gs = rm.DetectMappingDifferences(sl); foreach (RecoveryToken g in gs) { var kvps = rm.GetMappingDifferences(g); Assert.AreEqual(0, kvps.Keys.Count, "The GSM is not restorable from a rebuilt local shard."); } }
public void TestPointMappingRecoverFromGSM() { ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerLoadPolicy.Lazy); ListShardMap<int> listsm = smm.GetListShardMap<int>(RecoveryManagerTests.s_listShardMapName); Assert.IsNotNull(listsm); ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, RecoveryManagerTests.s_shardedDBs[0]); Shard s = listsm.CreateShard(sl); Assert.IsNotNull(s); for (int i = 0; i < 5; i++) { PointMapping<int> r = listsm.CreatePointMapping(creationInfo: new PointMappingCreationInfo<int>(i, s, MappingStatus.Online)); Assert.IsNotNull(r); } // Delete all the ranges and shardmaps from the shardlocation. using (SqlConnection conn = new SqlConnection(Globals.ShardMapManagerTestConnectionString)) { conn.Open(); using (SqlCommand cmd = new SqlCommand("delete from shard1.__ShardManagement.ShardMappingsLocal", conn)) { cmd.ExecuteNonQuery(); } } RecoveryManager rm = new RecoveryManager(smm); var gs = rm.DetectMappingDifferences(sl); // Validate that all the shard locations are in fact missing from the LSM. foreach (RecoveryToken g in gs) { var kvps = rm.GetMappingDifferences(g); Assert.AreEqual(5, kvps.Keys.Count, "The count of differences does not match the expected."); foreach (var kvp in kvps) { ShardRange range = kvp.Key; MappingLocation mappingLocation = kvp.Value; Assert.AreEqual(MappingLocation.MappingInShardMapOnly, mappingLocation, "An unexpected difference between global and local shardmaps was detected. This is likely a false positive and implies a bug in the detection code."); } // Recover the LSM from the GSM rm.ResolveMappingDifferences(g, MappingDifferenceResolution.KeepShardMapMapping); } gs = rm.DetectMappingDifferences(sl); foreach (RecoveryToken g in gs) { var kvps = rm.GetMappingDifferences(g); Assert.AreEqual(0, kvps.Values.Count(), "The count of differences does not match the expected."); } }
public void TestRebuildShardFromGSMRangeKeepNonconflicts() { ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerLoadPolicy.Lazy); RangeShardMap<int> rsm = smm.GetRangeShardMap<int>(RecoveryManagerTests.s_rangeShardMapName); Assert.IsNotNull(rsm); ShardLocation sl1 = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, RecoveryManagerTests.s_shardedDBs[0]); Shard s1 = rsm.CreateShard(sl1); // set initial ranges as non-intersecting. RangeMapping<int> r1 = rsm.CreateRangeMapping(new Range<int>(1, 6), s1); RangeMapping<int> r2 = rsm.CreateRangeMapping(new Range<int>(6, 10), s1); // Only mess up the range on the right. using (SqlConnection conn = new SqlConnection(Globals.ShardMapManagerTestConnectionString)) { conn.Open(); using (SqlCommand cmd = new SqlCommand("update shard1.__ShardManagement.ShardMappingsLocal set MaxValue = 0x8000000B, MappingId = newid() where MaxValue = 0x8000000A", conn)) { cmd.ExecuteNonQuery(); } using (SqlCommand cmd = new SqlCommand("update shard1.__ShardManagement.ShardMappingsLocal set MinValue = 0x8000000B where MinValue = 0x8000000A", conn)) { cmd.ExecuteNonQuery(); } } RecoveryManager rm = new RecoveryManager(smm); var gs = rm.DetectMappingDifferences(sl1); foreach (RecoveryToken g in gs) { var kvps = rm.GetMappingDifferences(g); Assert.AreEqual(2, kvps.Keys.Count, "The count of differences does not match the expected."); // Let's make sure that rebuild does not unintuitively delete ranges 1-6. rm.RebuildMappingsOnShard(g, new List<ShardRange>()); } gs = rm.DetectMappingDifferences(sl1); foreach (RecoveryToken g in gs) { // Take local. rm.ResolveMappingDifferences(g, MappingDifferenceResolution.KeepShardMapping); } var resultingMappings = rsm.GetMappings(new Range<int>(1, 11), s1); // Make sure the mapping [1-6) is still around. Assert.AreEqual(1, resultingMappings.Count(), "RebuildShard unexpectedly removed a non-conflicting range."); }