public void LoadTestMarkAllShardsAsOnlineInRangeShardMap() { try { ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerLoadPolicy.Lazy); RangeShardMap <int> rsm = smm.GetRangeShardMap <int>(ShardMapManagerLoadTests.s_rangeShardMapName); Assert.IsNotNull(rsm); foreach (Shard s in rsm.GetShards()) { if (s.Status == ShardStatus.Offline) { rsm.UpdateShard(s, new ShardUpdate { Status = ShardStatus.Online }); } } } catch (ShardManagementException sme) { Debug.WriteLine("Exception caught: {0}", sme.Message); } }
public void LoadTestDeleteRangeMapping() { try { ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerLoadPolicy.Lazy); RangeShardMap <int> rsm = smm.GetRangeShardMap <int>(ShardMapManagerLoadTests.s_rangeShardMapName); Assert.IsNotNull(rsm); RangeMapping <int> r1 = this.GetRandomRangeMapping(rsm); if (r1 != null) { Debug.WriteLine("Trying to delete mapping for range with low value = {0}", r1.Range.Low); RangeMappingUpdate ru = new RangeMappingUpdate(); ru.Status = MappingStatus.Offline; RangeMapping <int> mappingToDelete = rsm.UpdateMapping(r1, ru); rsm.DeleteMapping(mappingToDelete); } } catch (ShardManagementException sme) { Debug.WriteLine("Exception caught: {0}", sme.Message); } }
public void LoadTestRangeMappingDDR() { try { ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerLoadPolicy.Lazy); RangeShardMap <int> rsm = smm.GetRangeShardMap <int>(ShardMapManagerLoadTests.s_rangeShardMapName); Assert.IsNotNull(rsm); RangeMapping <int> r1 = this.GetRandomRangeMapping(rsm); if (r1 != null) { int keyToValidate = _r.Next((int)(r1.Range.Low.Value), (int)(r1.Range.High.Value)); Debug.WriteLine("Trying to validate mapping for key {0}", keyToValidate); // Validate mapping by trying to connect s_retryPolicy.ExecuteAction( () => ValidateImpl( (ShardMap)rsm, keyToValidate)); } } catch (ShardManagementException sme) { Debug.WriteLine("Exception caught: {0}", sme.Message); } }
public void LoadTestSplitRangeNoLock() { try { ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerLoadPolicy.Lazy); RangeShardMap <int> rsm = smm.GetRangeShardMap <int>(ShardMapManagerLoadTests.s_rangeShardMapName); Assert.IsNotNull(rsm); RangeMapping <int> r1 = this.GetRandomRangeMapping(rsm, 2); if (r1 != null) { int splitPoint = _r.Next((int)(r1.Range.Low.Value) + 1, (int)(r1.Range.High.Value) - 1); Debug.WriteLine("Trying to split range mapping for key range ({0} - {1}) at {2}", r1.Range.Low.Value, r1.Range.High.Value, splitPoint); IReadOnlyList <RangeMapping <int> > rList = rsm.SplitMapping(r1, splitPoint); Assert.AreEqual(2, rList.Count); } } catch (ShardManagementException sme) { Debug.WriteLine("Exception caught: {0}", sme.Message); } }
public void LoadTestRemoveShardFromRangeShardMap() { try { ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerLoadPolicy.Lazy); RangeShardMap <int> rsm = smm.GetRangeShardMap <int>(ShardMapManagerLoadTests.s_rangeShardMapName); Assert.IsNotNull(rsm); List <Shard> existingShards = rsm.GetShards().ToList(); if (existingShards.Count == 0) { return; } // If there is already a shard marked as offline, chose that one to delete. // This can happend if earlier remove operation was terminated for some reason - ex. killing connections. Shard offlineShard = existingShards.Find(e => e.Status == ShardStatus.Offline); if (offlineShard == null) { offlineShard = existingShards[_r.Next(existingShards.Count)]; // First mark shard as offline so that other test threads will not add new mappings to it. offlineShard = rsm.UpdateShard(offlineShard, new ShardUpdate { Status = ShardStatus.Offline }); } Debug.WriteLine("Trying to remove shard at location {0}", offlineShard.Location); RangeMappingUpdate ru = new RangeMappingUpdate(); ru.Status = MappingStatus.Offline; // Remove all mappings from this shard for given shard map. foreach (RangeMapping <int> rm in rsm.GetMappings(offlineShard)) { RangeMapping <int> mappingToDelete = rsm.UpdateMapping(rm, ru); rsm.DeleteMapping(mappingToDelete); } // get shard object again. Shard deleteShard = rsm.GetShard(offlineShard.Location); // now remove shard. rsm.DeleteShard(deleteShard); Debug.WriteLine("Removed shard at location {0} from shard map {1}", deleteShard.Location, rsm); } catch (ShardManagementException sme) { Debug.WriteLine("Exception caught: {0}", sme.Message); } }
public void LoadTestMergeRangesWithLock() { try { ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerLoadPolicy.Lazy); RangeShardMap <int> rsm = smm.GetRangeShardMap <int>(ShardMapManagerLoadTests.s_rangeShardMapName); Assert.IsNotNull(rsm); IEnumerable <RangeMapping <int> > existingMappings = rsm.GetMappings(new Range <int>(MinMappingPoint, MaxMappingPoint)); IQueryable <RangeMapping <int> > qr = Queryable.AsQueryable(existingMappings); // Find pair of adjacent mappings. var test = from a in qr join b in qr on new { a.Range.High.Value, a.StoreMapping.StoreShard.Id, a.StoreMapping.Status } equals new { b.Range.Low.Value, b.StoreMapping.StoreShard.Id, b.StoreMapping.Status } select new { a, b }; if (test.Count() > 0) { var t = test.First(); Debug.WriteLine("Trying to merge range mapping for key range ({0} - {1}) and ({2} - {3})", t.a.Range.Low.Value, t.a.Range.High.Value, t.b.Range.Low.Value, t.b.Range.High.Value); MappingLockToken mappingLockTokenLeft = MappingLockToken.Create(); rsm.LockMapping(t.a, mappingLockTokenLeft); MappingLockToken mappingLockTokenRight = MappingLockToken.Create(); rsm.LockMapping(t.b, mappingLockTokenLeft); RangeMapping <int> rMerged = rsm.MergeMappings(t.a, t.b, mappingLockTokenLeft, mappingLockTokenRight); Assert.IsNotNull(rMerged); MappingLockToken storeMappingLockToken = rsm.GetMappingLockOwner(rMerged); Assert.AreEqual(storeMappingLockToken, mappingLockTokenLeft, "Expected merged mapping lock id to equal left mapping id!"); rsm.UnlockMapping(rMerged, storeMappingLockToken); storeMappingLockToken = rsm.GetMappingLockOwner(rMerged); Assert.AreEqual(storeMappingLockToken, MappingLockToken.NoLock, "Expected merged mapping lock id to equal default mapping id after unlock!"); } } catch (ShardManagementException sme) { Debug.WriteLine("Exception caught: {0}", sme.Message); } }
public void LoadTestAddRangeMapping() { try { ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerLoadPolicy.Lazy); RangeShardMap <int> rsm = smm.GetRangeShardMap <int>(ShardMapManagerLoadTests.s_rangeShardMapName); Assert.IsNotNull(rsm); do { // Chose a random shard to add mapping. Shard s = GetRandomOnlineShardFromShardMap((ShardMap)rsm); if (s == null) { continue; } // generate a random range to add a new range mapping and verify that its not already mapped. int minKey = _r.Next(MinMappingPoint, MaxMappingPoint); int maxKey = minKey + _r.Next(1, MaxRangeMappingSize); maxKey = (maxKey <= MaxMappingPoint) ? maxKey : MaxMappingPoint; IReadOnlyList <RangeMapping <int> > existingMapping = rsm.GetMappings(new Range <int>(minKey, maxKey)); if (existingMapping.Count > 0) { continue; } Debug.WriteLine("Trying to add range mapping for key range ({0} - {1}) to shard location {2}", minKey, maxKey, s.Location); RangeMapping <int> r1 = rsm.CreateRangeMapping(new Range <int>(minKey, maxKey), s); Assert.IsNotNull(r1); // Validate mapping by trying to connect s_retryPolicy.ExecuteAction( () => ValidateImpl( (ShardMap)rsm, minKey)); }while (false); } catch (ShardManagementException sme) { Debug.WriteLine("Exception caught: {0}", sme.Message); } }
public void LoadTestSplitRangeWithLock() { try { ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerLoadPolicy.Lazy); RangeShardMap <int> rsm = smm.GetRangeShardMap <int>(ShardMapManagerLoadTests.s_rangeShardMapName); Assert.IsNotNull(rsm); RangeMapping <int> r1 = this.GetRandomRangeMapping(rsm, 2); if (r1 != null) { int splitPoint = _r.Next((int)(r1.Range.Low.Value) + 1, (int)(r1.Range.High.Value) - 1); Debug.WriteLine("Trying to split range mapping for key range ({0} - {1}) at {2}", r1.Range.Low.Value, r1.Range.High.Value, splitPoint); // Lock the mapping MappingLockToken mappingLockToken = MappingLockToken.Create(); rsm.LockMapping(r1, mappingLockToken); IReadOnlyList <RangeMapping <int> > rList = rsm.SplitMapping(r1, splitPoint, mappingLockToken); Assert.AreEqual(2, rList.Count); foreach (RangeMapping <int> r2 in rList) { Assert.IsNotNull(r2); Assert.AreEqual(mappingLockToken, rsm.GetMappingLockOwner(r2), String.Format("LockOwnerId of mapping: {0} does not match id in store!", r2)); // Unlock each mapping and verify rsm.UnlockMapping(r2, mappingLockToken); Assert.AreEqual(MappingLockToken.NoLock, rsm.GetMappingLockOwner(r2), String.Format("Mapping: {0} not unlocked as expected!", r2)); } } } catch (ShardManagementException sme) { Debug.WriteLine("Exception caught: {0}", sme.Message); } }
public void LoadTestAddShardToRangeShardMap() { try { ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerLoadPolicy.Lazy); RangeShardMap <int> rsm = smm.GetRangeShardMap <int>(ShardMapManagerLoadTests.s_rangeShardMapName); Assert.IsNotNull(rsm); AddShardToShardMap((ShardMap)rsm); } catch (ShardManagementException sme) { Debug.WriteLine("Exception caught: {0}", sme.Message); } }
public void LoadTestMergeRangesNoLock() { try { ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerLoadPolicy.Lazy); RangeShardMap <int> rsm = smm.GetRangeShardMap <int>(ShardMapManagerLoadTests.s_rangeShardMapName); Assert.IsNotNull(rsm); IEnumerable <RangeMapping <int> > existingMappings = rsm.GetMappings(new Range <int>(MinMappingPoint, MaxMappingPoint)); IQueryable <RangeMapping <int> > qr = Queryable.AsQueryable(existingMappings); // find pair of adjacent mappings. var test = from a in qr join b in qr on new { a.Range.High.Value, a.StoreMapping.StoreShard.Id, a.StoreMapping.Status } equals new { b.Range.Low.Value, b.StoreMapping.StoreShard.Id, b.StoreMapping.Status } select new { a, b }; if (test.Count() > 0) { var t = test.First(); Debug.WriteLine("Trying to merge range mapping for key range ({0} - {1}) and ({2} - {3})", t.a.Range.Low.Value, t.a.Range.High.Value, t.b.Range.Low.Value, t.b.Range.High.Value); RangeMapping <int> rMerged = rsm.MergeMappings(t.a, t.b); Assert.IsNotNull(rMerged); } } catch (ShardManagementException sme) { Debug.WriteLine("Exception caught: {0}", sme.Message); } }
public void UpdateRangeMappingOfflineAbortGSMDoAndGSMUndoPostLocal() { bool shouldThrow = true; IStoreOperationFactory sof = new StubStoreOperationFactory() { CallBase = true, CreateUpdateMappingOperationShardMapManagerStoreOperationCodeIStoreShardMapIStoreMappingIStoreMappingStringGuid = (_smm, _opcode, _ssm, _sms, _smt, _p, _loid) => { StubUpdateMappingOperation op = new StubUpdateMappingOperation(_smm, _opcode, _ssm, _sms, _smt, _p, _loid); op.CallBase = true; op.DoGlobalPostLocalExecuteIStoreTransactionScope = (ts) => { if (shouldThrow) { throw new StoreException("", ShardMapFaultHandlingTests.TransientSqlException); } else { // Call the base function, hack for this behavior is to save current operation, set current to null, restore current operation. var original = op.DoGlobalPostLocalExecuteIStoreTransactionScope; op.DoGlobalPostLocalExecuteIStoreTransactionScope = null; try { return op.DoGlobalPostLocalExecute(ts); } finally { op.DoGlobalPostLocalExecuteIStoreTransactionScope = original; } } }; op.UndoLocalSourceExecuteIStoreTransactionScope = (ts) => { if (shouldThrow) { throw new StoreException("", ShardMapFaultHandlingTests.TransientSqlException); } else { // Call the base function, hack for this behavior is to save current operation, set current to null, restore current operation. var original = op.UndoLocalSourceExecuteIStoreTransactionScope; op.UndoLocalSourceExecuteIStoreTransactionScope = null; try { return op.UndoLocalSourceExecute(ts); } finally { op.UndoLocalSourceExecuteIStoreTransactionScope = original; } } }; return op; } }; ShardMapManager smm = new ShardMapManager( new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString), new SqlStoreConnectionFactory(), sof, new CacheStore(), ShardMapManagerLoadPolicy.Lazy, new RetryPolicy(1, TimeSpan.Zero, TimeSpan.Zero, TimeSpan.Zero), RetryBehavior.DefaultRetryBehavior); RangeShardMap<int> rsm = smm.GetRangeShardMap<int>(ShardMapperTests.s_rangeShardMapName); Assert.IsNotNull(rsm); ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapperTests.s_shardedDBs[0]); Shard s = rsm.CreateShard(sl); Assert.IsNotNull(s); RangeMapping<int> r1 = rsm.CreateRangeMapping(new Range<int>(1, 20), s); RangeMappingUpdate ru = new RangeMappingUpdate() { Status = MappingStatus.Offline }; RangeMapping<int> rNew; bool storeOperationFailed = false; try { rNew = rsm.UpdateMapping(r1, ru); } catch (ShardManagementException sme) { Assert.AreEqual(ShardManagementErrorCategory.RangeShardMap, sme.ErrorCategory); Assert.AreEqual(ShardManagementErrorCode.StorageOperationFailure, sme.ErrorCode); storeOperationFailed = true; } Assert.IsTrue(storeOperationFailed); // Validation: check that custom is unchanged. RangeMapping<int> rValidate = rsm.GetMappingForKey(1); Assert.AreEqual(r1.Status, rValidate.Status); shouldThrow = false; rNew = rsm.UpdateMapping(r1, ru); Assert.IsNotNull(rNew); Assert.AreEqual(rNew.Status, ru.Status); }
public void KillConnectionOnOfflineRangeMapping() { ShardMapManager smm = new ShardMapManager( new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString), new SqlStoreConnectionFactory(), new StoreOperationFactory(), new CacheStore(), ShardMapManagerLoadPolicy.Lazy, new RetryPolicy(1, TimeSpan.Zero, TimeSpan.Zero, TimeSpan.Zero), RetryBehavior.DefaultRetryBehavior); RangeShardMap<int> rsm = smm.GetRangeShardMap<int>(ShardMapperTests.s_rangeShardMapName); Assert.IsNotNull(rsm); ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapperTests.s_shardedDBs[0]); Shard s = rsm.CreateShard(sl); Assert.IsNotNull(s); RangeMapping<int> r1 = rsm.CreateRangeMapping(new Range<int>(1, 20), s); using (SqlConnection conn = rsm.OpenConnectionForKeyAsync(1, Globals.ShardUserConnectionString).Result) { Assert.AreEqual(ConnectionState.Open, conn.State); RangeMappingUpdate ru = new RangeMappingUpdate(); ru.Status = MappingStatus.Offline; RangeMapping<int> rNew = rsm.UpdateMapping(r1, ru); Assert.IsNotNull(rNew); bool failed = false; try { using (SqlCommand cmd = conn.CreateCommand()) { cmd.CommandText = "select 1"; cmd.CommandType = CommandType.Text; using (SqlDataReader rdr = cmd.ExecuteReader()) { } } } catch (SqlException) { failed = true; } Assert.AreEqual(true, failed); Assert.AreEqual(ConnectionState.Closed, conn.State); failed = false; // Open 2nd connection. try { using (SqlConnection conn2 = rsm.OpenConnectionForKeyAsync(1, Globals.ShardUserConnectionString).Result) { } } catch (AggregateException ex) { var sme = ex.InnerException as ShardManagementException; if (sme != null) { failed = true; Assert.AreEqual(ShardManagementErrorCode.MappingIsOffline, sme.ErrorCode); } } Assert.AreEqual(true, failed); // Mark the mapping online again so that it will be cleaned up ru.Status = MappingStatus.Online; RangeMapping<int> rUpdated = rsm.UpdateMapping(rNew, ru); Assert.IsNotNull(rUpdated); failed = false; // Open 3rd connection. This should succeed. try { using (SqlConnection conn3 = rsm.OpenConnectionForKey(1, Globals.ShardUserConnectionString)) { } } catch (ShardManagementException) { failed = true; } Assert.AreEqual(false, failed); } }
public void UpdateRangeMappingDefault() { CountingCacheStore countingCache = new CountingCacheStore(new CacheStore()); ShardMapManager smm = new ShardMapManager( new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString), new SqlStoreConnectionFactory(), new StoreOperationFactory(), countingCache, ShardMapManagerLoadPolicy.Lazy, new RetryPolicy(1, TimeSpan.Zero, TimeSpan.Zero, TimeSpan.Zero), RetryBehavior.DefaultRetryBehavior); RangeShardMap<int> rsm = smm.GetRangeShardMap<int>(ShardMapperTests.s_rangeShardMapName); Assert.IsNotNull(rsm); ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapperTests.s_shardedDBs[0]); Shard s = rsm.CreateShard(sl); Assert.IsNotNull(s); RangeMapping<int> r1 = rsm.CreateRangeMapping(new Range<int>(1, 20), s); // Lock the mapping MappingLockToken mappingLockToken = MappingLockToken.Create(); rsm.LockMapping(r1, mappingLockToken); RangeMappingUpdate ru = new RangeMappingUpdate() { Status = MappingStatus.Offline }; RangeMapping<int> rNew = rsm.UpdateMapping(r1, ru, mappingLockToken); Assert.IsNotNull(rNew); MappingLockToken storeMappingLockToken = rsm.GetMappingLockOwner(rNew); Assert.AreEqual(storeMappingLockToken, mappingLockToken, "LockownerId does not match that in store!"); rsm.UnlockMapping(rNew, mappingLockToken); RangeMapping<int> r2 = rsm.GetMappingForKey(1); Assert.AreEqual(0, countingCache.LookupMappingHitCount); Assert.AreNotEqual(r1.Id, r2.Id); }
public void UpdateRangeMappingIdempotency() { ShardMapManager smm = new ShardMapManager( new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString), new SqlStoreConnectionFactory(), new StoreOperationFactory(), new CacheStore(), ShardMapManagerLoadPolicy.Lazy, new RetryPolicy(1, TimeSpan.Zero, TimeSpan.Zero, TimeSpan.Zero), RetryBehavior.DefaultRetryBehavior); RangeShardMap<int> rsm = smm.GetRangeShardMap<int>(ShardMapperTests.s_rangeShardMapName); Assert.IsNotNull(rsm); Shard s1 = rsm.CreateShard(new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapperTests.s_shardedDBs[0])); Assert.IsNotNull(s1); Shard s2 = rsm.CreateShard(new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapperTests.s_shardedDBs[1])); Assert.IsNotNull(s2); RangeMapping<int> r1 = rsm.CreateRangeMapping(new Range<int>(1, 20), s1); // Online -> Offline - No Location Change RangeMappingUpdate pu = new RangeMappingUpdate { Status = MappingStatus.Offline }; RangeMapping<int> presult = rsm.UpdateMapping(r1, pu); Assert.IsNotNull(presult); Assert.IsTrue(presult.Status == MappingStatus.Offline); // Offline -> Offline - No Location Change pu = new RangeMappingUpdate { Status = MappingStatus.Offline }; presult = rsm.UpdateMapping(presult, pu); Assert.IsNotNull(presult); Assert.IsTrue(presult.Status == MappingStatus.Offline); // Offline -> Offline - Location Change pu = new RangeMappingUpdate { Shard = s2 }; presult = rsm.UpdateMapping(presult, pu); Assert.IsNotNull(presult); Assert.IsTrue(presult.Status == MappingStatus.Offline); Assert.AreEqual(s2.Location, presult.Shard.Location); // Offline -> Online - No Location Change pu = new RangeMappingUpdate { Status = MappingStatus.Online }; presult = rsm.UpdateMapping(presult, pu); Assert.IsNotNull(presult); Assert.IsTrue(presult.Status == MappingStatus.Online); // Online -> Offline - Location Change pu = new RangeMappingUpdate { Status = MappingStatus.Offline, Shard = s1 }; presult = rsm.UpdateMapping(presult, pu); Assert.IsNotNull(presult); Assert.IsTrue(presult.Status == MappingStatus.Offline); Assert.AreEqual(s1.Location, presult.Shard.Location); // Offline -> Online - Location Change pu = new RangeMappingUpdate { Status = MappingStatus.Online, Shard = s2 }; presult = rsm.UpdateMapping(presult, pu); Assert.IsNotNull(presult); Assert.IsTrue(presult.Status == MappingStatus.Online); Assert.AreEqual(s2.Location, presult.Shard.Location); // Online -> Online - No Location Change pu = new RangeMappingUpdate { Status = MappingStatus.Online }; presult = rsm.UpdateMapping(presult, pu); Assert.IsNotNull(presult); Assert.IsTrue(presult.Status == MappingStatus.Online); // Online -> Online - Location Change pu = new RangeMappingUpdate { Shard = s1 }; bool failed = false; try { presult = rsm.UpdateMapping(presult, pu); } catch (ShardManagementException sme) { failed = true; Assert.AreEqual(ShardManagementErrorCategory.RangeShardMap, sme.ErrorCategory); Assert.AreEqual(ShardManagementErrorCode.MappingIsNotOffline, sme.ErrorCode); } Assert.IsTrue(failed); }
public void UpdateRangeMappingLocation() { CountingCacheStore countingCache = new CountingCacheStore(new CacheStore()); ShardMapManager smm = new ShardMapManager( new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString), new SqlStoreConnectionFactory(), new StoreOperationFactory(), countingCache, ShardMapManagerLoadPolicy.Lazy, new RetryPolicy(1, TimeSpan.Zero, TimeSpan.Zero, TimeSpan.Zero), RetryBehavior.DefaultRetryBehavior); RangeShardMap<int> rsm = smm.GetRangeShardMap<int>(ShardMapperTests.s_rangeShardMapName); Assert.IsNotNull(rsm); ShardLocation sl1 = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapperTests.s_shardedDBs[0]); Shard s1 = rsm.CreateShard(sl1); Assert.IsNotNull(s1); ShardLocation sl2 = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapperTests.s_shardedDBs[1]); Shard s2 = rsm.CreateShard(sl2); Assert.IsNotNull(s2); RangeMapping<int> r1 = rsm.CreateRangeMapping(new Range<int>(1, 20), s1); RangeMappingUpdate ru = new RangeMappingUpdate(); // Shard location in a mapping cannot be updated when online. ru.Status = MappingStatus.Offline; RangeMapping<int> rOffline = rsm.UpdateMapping(r1, ru); Assert.IsNotNull(rOffline); Assert.AreEqual(ru.Status, rOffline.Status); ru.Shard = s2; RangeMapping<int> rNew = rsm.UpdateMapping(rOffline, ru); Assert.IsNotNull(rNew); // Bring the mapping back online. ru.Status = MappingStatus.Online; rNew = rsm.UpdateMapping(rNew, ru); Assert.IsNotNull(rNew); RangeMapping<int> r2 = rsm.GetMappingForKey(1); Assert.IsNotNull(r2); Assert.AreEqual(0, countingCache.LookupMappingHitCount); Assert.AreEqual(s2.Id, r2.Shard.Id); }
public void AddRangeMappingNoCacheUpdate() { // Create a cache store that never inserts. CountingCacheStore cacheStore = new CountingCacheStore( new StubCacheStore() { CallBase = true, AddOrUpdateMappingIStoreMappingCacheStoreMappingUpdatePolicy = (ssm, p) => { } }); ShardMapManager smm = new ShardMapManager( new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString), new SqlStoreConnectionFactory(), new StoreOperationFactory(), cacheStore, ShardMapManagerLoadPolicy.Lazy, RetryPolicy.DefaultRetryPolicy, RetryBehavior.DefaultRetryBehavior); RangeShardMap<int> rsm = smm.GetRangeShardMap<int>(ShardMapperTests.s_rangeShardMapName); Assert.IsNotNull(rsm); ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapperTests.s_shardedDBs[0]); Shard s = rsm.CreateShard(sl); Assert.IsNotNull(s); RangeMapping<int> r1 = rsm.CreateRangeMapping(new Range<int>(1, 10), s); Assert.IsNotNull(r1); RangeMapping<int> r2 = rsm.GetMappingForKey(2); Assert.IsNotNull(r2); Assert.AreEqual(0, cacheStore.LookupMappingMissCount); }
/// <summary> /// OpenConnectionForKey for unavailable server using RangeShardMap. /// </summary> /// <param name="openConnectionAsync">Whether the connection should be opened asynchronously</param> private void UnavailableServerOpenConnectionForKeyRangeShardMapInternal(bool openConnectionAsync = false) { StubSqlStoreConnectionFactory scf = null; bool shouldThrow = false; scf = new StubSqlStoreConnectionFactory() { CallBase = true, GetUserConnectionString = (cstr) => { if (shouldThrow) { throw ShardMapFaultHandlingTests.TransientSqlException; } else { var original = scf.GetUserConnectionString; scf.GetUserConnectionString = null; try { return scf.GetUserConnection(cstr); } finally { scf.GetUserConnectionString = original; } } } }; int callCount = 0; // Counting implementation of FindMappingByKey IStoreOperationFactory sof = new StubStoreOperationFactory() { CallBase = true, CreateFindMappingByKeyGlobalOperationShardMapManagerStringIStoreShardMapShardKeyCacheStoreMappingUpdatePolicyShardManagementErrorCategoryBooleanBoolean = (_smm, _opname, _ssm, _sk, _pol, _ec, _cr, _if) => { StubFindMappingByKeyGlobalOperation op = new StubFindMappingByKeyGlobalOperation(_smm, _opname, _ssm, _sk, _pol, _ec, _cr, _if); op.CallBase = true; op.DoGlobalExecuteIStoreTransactionScope = (ts) => { callCount++; // Call the base function, hack for this behavior is to save current operation, set current to null, restore current operation. var original = op.DoGlobalExecuteIStoreTransactionScope; op.DoGlobalExecuteIStoreTransactionScope = null; try { return op.DoGlobalExecute(ts); } finally { op.DoGlobalExecuteIStoreTransactionScope = original; } }; op.DoGlobalExecuteAsyncIStoreTransactionScope = (ts) => Task.FromResult<IStoreResults>(op.DoGlobalExecuteIStoreTransactionScope(ts)); return op; } }; StubCacheStore scs = null; ICacheStoreMapping currentMapping = null; StubICacheStoreMapping sics = new StubICacheStoreMapping { MappingGet = () => currentMapping.Mapping, CreationTimeGet = () => currentMapping.CreationTime, TimeToLiveMillisecondsGet = () => currentMapping.TimeToLiveMilliseconds, ResetTimeToLive = () => currentMapping.ResetTimeToLive(), HasTimeToLiveExpired = () => currentMapping.HasTimeToLiveExpired() }; scs = new StubCacheStore() { CallBase = true, LookupMappingByKeyIStoreShardMapShardKey = (_ssm, _sk) => { var original = scs.LookupMappingByKeyIStoreShardMapShardKey; scs.LookupMappingByKeyIStoreShardMapShardKey = null; try { currentMapping = scs.LookupMappingByKey(_ssm, _sk); return sics; } finally { scs.LookupMappingByKeyIStoreShardMapShardKey = original; } } }; ShardMapManager smm = new ShardMapManager( new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString), scf, sof, scs, ShardMapManagerLoadPolicy.Lazy, RetryPolicy.DefaultRetryPolicy, RetryBehavior.DefaultRetryBehavior); RangeShardMap<int> rsm = smm.GetRangeShardMap<int>(ShardMapperTests.s_rangeShardMapName); Assert.IsNotNull(rsm); ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapperTests.s_shardedDBs[0]); Shard s = rsm.CreateShard(sl); Assert.IsNotNull(s); RangeMapping<int> r1 = rsm.CreateRangeMapping(new Range<int>(5, 20), s); Assert.IsNotNull(r1); // Mapping is there, now let's try to abort the OpenConnectionForKey shouldThrow = true; bool failed = false; for (int i = 1; i <= 10; i++) { failed = false; try { if (openConnectionAsync) { rsm.OpenConnectionForKeyAsync(10, Globals.ShardUserConnectionString).Wait(); } else { rsm.OpenConnectionForKey(10, Globals.ShardUserConnectionString); } } catch (Exception ex) { if (ex is AggregateException) { ex = ex.InnerException as SqlException; } if (ex is SqlException) { failed = true; } } Assert.IsTrue(failed); } Assert.AreEqual(1, callCount); long currentTtl = ((ICacheStoreMapping)sics).TimeToLiveMilliseconds; Assert.IsTrue(currentTtl > 0); // Let's fake the TTL to be 0, to force another call to store. sics.TimeToLiveMillisecondsGet = () => 0; sics.HasTimeToLiveExpired = () => true; failed = false; try { if (openConnectionAsync) { rsm.OpenConnectionForKeyAsync(12, Globals.ShardUserConnectionString).Wait(); } else { rsm.OpenConnectionForKey(12, Globals.ShardUserConnectionString); } } catch (Exception ex) { if (ex is AggregateException) { ex = ex.InnerException as SqlException; } if (ex is SqlException) { failed = true; } } Assert.IsTrue(failed); Assert.AreEqual(2, callCount); sics.TimeToLiveMillisecondsGet = () => currentMapping.TimeToLiveMilliseconds; sics.HasTimeToLiveExpired = () => currentMapping.HasTimeToLiveExpired(); failed = false; try { if (openConnectionAsync) { rsm.OpenConnectionForKeyAsync(15, Globals.ShardUserConnectionString).Wait(); } else { rsm.OpenConnectionForKey(15, Globals.ShardUserConnectionString); } } catch (Exception ex) { if (ex is AggregateException) { ex = ex.InnerException as SqlException; } if (ex is SqlException) { failed = true; } } Assert.IsTrue(failed); Assert.IsTrue(((ICacheStoreMapping)sics).TimeToLiveMilliseconds > currentTtl); shouldThrow = false; failed = false; try { if (openConnectionAsync) { rsm.OpenConnectionForKeyAsync(7, Globals.ShardUserConnectionString).Wait(); } else { rsm.OpenConnectionForKey(7, Globals.ShardUserConnectionString); } } catch (Exception ex) { if (ex is AggregateException) { ex = ex.InnerException as SqlException; } if (ex is SqlException) { failed = true; } } Assert.IsFalse(failed); Assert.AreEqual(0, ((ICacheStoreMapping)sics).TimeToLiveMilliseconds); }
public void BasicScenarioRangeShardMaps() { bool success = true; string rangeShardMapName = "MultiTenantShardMap"; try { #region DeployShardMapManager // Deploy shard map manager. ShardMapManagerFactory.CreateSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerCreateMode.ReplaceExisting); #endregion DeployShardMapManager #region GetShardMapManager // Obtain shard map manager. ShardMapManager shardMapManager = ShardMapManagerFactory.GetSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerLoadPolicy.Lazy); #endregion GetShardMapManager #region CreateRangeShardMap // Create a single user per-tenant shard map. RangeShardMap <int> multiTenantShardMap = shardMapManager.CreateRangeShardMap <int>(rangeShardMapName); #endregion CreateRangeShardMap #region CreateShardAndRangeMapping for (int i = 0; i < ScenarioTests.s_multiTenantDBs.Length; i++) { // Create the shard. Shard s = multiTenantShardMap.CreateShard( new ShardLocation( Globals.ShardMapManagerTestsDatasourceName, ScenarioTests.s_multiTenantDBs[i])); // Create the mapping. RangeMapping <int> r = multiTenantShardMap.CreateRangeMapping( new Range <int>(i * 10, (i + 1) * 10), s); } #endregion CreateShardAndRangeMapping #region UpdateMapping // Let's add [50, 60) and map it to same shard as 23 i.e. MultiTenantDB3. RangeMapping <int> mappingFor23 = multiTenantShardMap.GetMappingForKey(23); RangeMapping <int> mappingFor50To60 = multiTenantShardMap.CreateRangeMapping( new Range <int>(50, 60), mappingFor23.Shard); Assert.IsTrue(mappingFor23.Shard.Location.Equals(mappingFor50To60.Shard.Location)); // Move [10, 20) from MultiTenantDB2 to MultiTenantDB1 RangeMapping <int> mappingToUpdate = multiTenantShardMap.GetMappingForKey(10); RangeMapping <int> mappingFor5 = multiTenantShardMap.GetMappingForKey(5); bool updateFailed = false; // Try updating that shard in the mapping without taking it offline first. try { multiTenantShardMap.UpdateMapping( mappingToUpdate, new RangeMappingUpdate { Shard = mappingFor5.Shard }); } catch (ShardManagementException smme) { Assert.AreEqual(smme.ErrorCode, ShardManagementErrorCode.MappingIsNotOffline); updateFailed = true; } Trace.Assert(updateFailed); // Mark mapping offline, update shard location. RangeMapping <int> newMappingFor10To20Offline = MarkMappingOfflineAndUpdateShard <int>( multiTenantShardMap, mappingToUpdate, mappingFor5.Shard); // Verify that update succeeded. Assert.IsTrue(newMappingFor10To20Offline.Shard.Location.Equals(mappingFor5.Shard.Location)); Assert.IsTrue(newMappingFor10To20Offline.Status == MappingStatus.Offline); // Bring the mapping back online. RangeMapping <int> newMappingFor10To20Online = multiTenantShardMap.UpdateMapping( newMappingFor10To20Offline, new RangeMappingUpdate { Status = MappingStatus.Online, }); // Verify that update succeeded. Assert.IsTrue(newMappingFor10To20Online.Status == MappingStatus.Online); #endregion UpdateMapping #region DeleteMapping // Find mapping for [0, 10). RangeMapping <int> mappingToDelete = multiTenantShardMap.GetMappingForKey(5); bool operationFailed = false; // Try to delete mapping while it is online, the delete should fail. try { multiTenantShardMap.DeleteMapping(mappingToDelete); } catch (ShardManagementException smme) { operationFailed = true; Assert.AreEqual(smme.ErrorCode, ShardManagementErrorCode.MappingIsNotOffline); } Trace.Assert(operationFailed); // The mapping must be made offline first before it can be deleted. RangeMappingUpdate ru = new RangeMappingUpdate(); ru.Status = MappingStatus.Offline; mappingToDelete = multiTenantShardMap.UpdateMapping(mappingToDelete, ru); Trace.Assert(mappingToDelete.Status == MappingStatus.Offline); multiTenantShardMap.DeleteMapping(mappingToDelete); // Verify that delete succeeded. try { RangeMapping <int> deletedMapping = multiTenantShardMap.GetMappingForKey(5); } catch (ShardManagementException smme) { Assert.AreEqual(smme.ErrorCode, ShardManagementErrorCode.MappingNotFoundForKey); } #endregion DeleteMapping #region OpenConnection without Validation using (SqlConnection conn = multiTenantShardMap.OpenConnectionForKey( 20, Globals.ShardUserConnectionString, ConnectionOptions.None)) { } #endregion OpenConnection without Validation #region OpenConnection with Validation // Use the stale state of "shardToUpdate" shard & see if validation works. bool validationFailed = false; try { using (SqlConnection conn = multiTenantShardMap.OpenConnection( mappingToDelete, Globals.ShardUserConnectionString, ConnectionOptions.Validate)) { } } catch (ShardManagementException smme) { validationFailed = true; Assert.AreEqual(smme.ErrorCode, ShardManagementErrorCode.MappingDoesNotExist); } Assert.AreEqual(validationFailed, true); #endregion OpenConnection with Validation #region OpenConnection without Validation and Empty Cache // Obtain new shard map manager instance ShardMapManager newShardMapManager = ShardMapManagerFactory.GetSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerLoadPolicy.Lazy); // Get the Range Shard Map RangeShardMap <int> newMultiTenantShardMap = newShardMapManager.GetRangeShardMap <int>(rangeShardMapName); using (SqlConnection conn = newMultiTenantShardMap.OpenConnectionForKey( 20, Globals.ShardUserConnectionString, ConnectionOptions.None)) { } #endregion #region OpenConnection with Validation and Empty Cache // Obtain new shard map manager instance newShardMapManager = ShardMapManagerFactory.GetSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerLoadPolicy.Lazy); // Get the Range Shard Map newMultiTenantShardMap = newShardMapManager.GetRangeShardMap <int>(rangeShardMapName); // Create a new mapping RangeMapping <int> newMappingToDelete = newMultiTenantShardMap.CreateRangeMapping( new Range <int>(70, 80), newMultiTenantShardMap.GetMappingForKey(23).Shard); // Delete the mapping newMappingToDelete = newMultiTenantShardMap.UpdateMapping( newMappingToDelete, new RangeMappingUpdate { Status = MappingStatus.Offline, }); newMultiTenantShardMap.DeleteMapping(newMappingToDelete); // Use the stale state of "shardToUpdate" shard & see if validation works. validationFailed = false; try { using (SqlConnection conn = newMultiTenantShardMap.OpenConnection( newMappingToDelete, Globals.ShardUserConnectionString, ConnectionOptions.Validate)) { } } catch (ShardManagementException smme) { validationFailed = true; Assert.AreEqual(smme.ErrorCode, ShardManagementErrorCode.MappingDoesNotExist); } Assert.AreEqual(validationFailed, true); #endregion #region OpenConnectionAsync without Validation using (SqlConnection conn = multiTenantShardMap.OpenConnectionForKeyAsync( 20, Globals.ShardUserConnectionString, ConnectionOptions.None).Result) { } #endregion #region OpenConnectionAsync with Validation // Use the stale state of "shardToUpdate" shard & see if validation works. validationFailed = false; try { using (SqlConnection conn = multiTenantShardMap.OpenConnectionAsync( mappingToDelete, Globals.ShardUserConnectionString, ConnectionOptions.Validate).Result) { } } catch (AggregateException ex) { ShardManagementException smme = ex.InnerException as ShardManagementException; if (smme != null) { validationFailed = true; Assert.AreEqual(smme.ErrorCode, ShardManagementErrorCode.MappingDoesNotExist); } } Assert.AreEqual(validationFailed, true); #endregion #region OpenConnectionAsync without Validation and Empty Cache // Obtain new shard map manager instance newShardMapManager = ShardMapManagerFactory.GetSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerLoadPolicy.Lazy); // Get the Range Shard Map newMultiTenantShardMap = newShardMapManager.GetRangeShardMap <int>(rangeShardMapName); using (SqlConnection conn = newMultiTenantShardMap.OpenConnectionForKeyAsync( 20, Globals.ShardUserConnectionString, ConnectionOptions.None).Result) { } #endregion #region OpenConnectionAsync with Validation and Empty Cache // Obtain new shard map manager instance newShardMapManager = ShardMapManagerFactory.GetSqlShardMapManager( Globals.ShardMapManagerConnectionString, ShardMapManagerLoadPolicy.Lazy); // Get the Range Shard Map newMultiTenantShardMap = newShardMapManager.GetRangeShardMap <int>(rangeShardMapName); // Create a new mapping newMappingToDelete = newMultiTenantShardMap.CreateRangeMapping( new Range <int>(70, 80), newMultiTenantShardMap.GetMappingForKey(23).Shard); // Delete the mapping newMappingToDelete = newMultiTenantShardMap.UpdateMapping( newMappingToDelete, new RangeMappingUpdate { Status = MappingStatus.Offline, }); newMultiTenantShardMap.DeleteMapping(newMappingToDelete); // Use the stale state of "shardToUpdate" shard & see if validation works. validationFailed = false; try { using (SqlConnection conn = newMultiTenantShardMap.OpenConnectionAsync( newMappingToDelete, Globals.ShardUserConnectionString, ConnectionOptions.Validate).Result) { } } catch (AggregateException ex) { ShardManagementException smme = ex.InnerException as ShardManagementException; if (smme != null) { validationFailed = true; Assert.AreEqual(smme.ErrorCode, ShardManagementErrorCode.MappingDoesNotExist); } } Assert.AreEqual(validationFailed, true); #endregion #region GetMapping // Perform tenant lookup. This will populate the cache. for (int i = 0; i < ScenarioTests.s_multiTenantDBs.Length; i++) { RangeMapping <int> result = shardMapManager .GetRangeShardMap <int>("MultiTenantShardMap") .GetMappingForKey((i + 1) * 10); Trace.WriteLine(result.Shard.Location); if (i == 0) { // Since we moved [10,20) to database 1 earlier. Assert.IsTrue(result.Shard.Location.Database == ScenarioTests.s_multiTenantDBs[0]); } else if (i < 4) { Assert.IsTrue(result.Shard.Location.Database == ScenarioTests.s_multiTenantDBs[i + 1]); } else { Assert.IsTrue(result.Shard.Location.Database == ScenarioTests.s_multiTenantDBs[2]); } } // Perform tenant lookup. This will read from the cache. for (int i = 0; i < ScenarioTests.s_multiTenantDBs.Length; i++) { RangeMapping <int> result = shardMapManager .GetRangeShardMap <int>("MultiTenantShardMap") .GetMappingForKey((i + 1) * 10); Trace.WriteLine(result.Shard.Location); if (i == 0) { // Since we moved [10,20) to database 1 earlier. Assert.IsTrue(result.Shard.Location.Database == ScenarioTests.s_multiTenantDBs[0]); } else if (i < 4) { Assert.IsTrue(result.Shard.Location.Database == ScenarioTests.s_multiTenantDBs[i + 1]); } else { Assert.IsTrue(result.Shard.Location.Database == ScenarioTests.s_multiTenantDBs[2]); } } #endregion GetMapping #region Split/Merge int splitPoint = 55; // Split [50, 60) into [50, 55) and [55, 60) RangeMapping <int> mappingToSplit = multiTenantShardMap.GetMappingForKey(splitPoint); IReadOnlyList <RangeMapping <int> > rangesAfterSplit = multiTenantShardMap.SplitMapping(mappingToSplit, splitPoint); rangesAfterSplit = rangesAfterSplit.OrderBy(nr => nr.Value.Low).ToArray(); // We should get 2 ranges back. Assert.AreEqual(2, rangesAfterSplit.Count); Assert.AreEqual(rangesAfterSplit[0].Value.Low, new Range <int>(50, 55).Low); Assert.AreEqual(rangesAfterSplit[0].Value.High, new Range <int>(50, 55).High); Assert.AreEqual(rangesAfterSplit[1].Value.Low, new Range <int>(55, 60).Low); Assert.AreEqual(rangesAfterSplit[1].Value.High, new Range <int>(55, 60).High); // Split [50, 55) into [50, 52) and [52, 55) IReadOnlyList <RangeMapping <int> > newRangesAfterAdd = multiTenantShardMap.SplitMapping(rangesAfterSplit[0], 52); newRangesAfterAdd = newRangesAfterAdd.OrderBy(nr => nr.Value.Low).ToArray(); // We should get 2 ranges back. Assert.AreEqual(2, newRangesAfterAdd.Count); Assert.AreEqual(newRangesAfterAdd[0].Value.Low, new Range <int>(50, 52).Low); Assert.AreEqual(newRangesAfterAdd[0].Value.High, new Range <int>(50, 52).High); Assert.AreEqual(newRangesAfterAdd[1].Value.Low, new Range <int>(52, 55).Low); Assert.AreEqual(newRangesAfterAdd[1].Value.High, new Range <int>(52, 55).High); // Move [50, 52) to MultiTenantDB1 Shard targetShard = multiTenantShardMap.GetShard(new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ScenarioTests.s_multiTenantDBs[0])); // Mark mapping offline, update shard location. RangeMapping <int> movedMapping1 = MarkMappingOfflineAndUpdateShard <int>( multiTenantShardMap, newRangesAfterAdd[0], targetShard); // Bring the mapping back online. movedMapping1 = multiTenantShardMap.UpdateMapping( movedMapping1, new RangeMappingUpdate { Status = MappingStatus.Online, }); // Mark mapping offline, update shard location. RangeMapping <int> movedMapping2 = MarkMappingOfflineAndUpdateShard <int>( multiTenantShardMap, newRangesAfterAdd[1], targetShard); // Bring the mapping back online. movedMapping2 = multiTenantShardMap.UpdateMapping( movedMapping2, new RangeMappingUpdate { Status = MappingStatus.Online, }); // Obtain the final moved mapping. RangeMapping <int> finalMovedMapping = multiTenantShardMap.MergeMappings(movedMapping1, movedMapping2); Assert.AreEqual(finalMovedMapping.Value.Low, new Range <int>(50, 55).Low); Assert.AreEqual(finalMovedMapping.Value.High, new Range <int>(50, 55).High); #endregion Split/Merge } catch (ShardManagementException smme) { success = false; Trace.WriteLine(String.Format("Error Category: {0}", smme.ErrorCategory)); Trace.WriteLine(String.Format("Error Code : {0}", smme.ErrorCode)); Trace.WriteLine(String.Format("Error Message : {0}", smme.Message)); if (smme.InnerException != null) { Trace.WriteLine(String.Format("Storage Error Message : {0}", smme.InnerException.Message)); if (smme.InnerException.InnerException != null) { Trace.WriteLine(String.Format("SqlClient Error Message : {0}", smme.InnerException.InnerException.Message)); } } } Assert.IsTrue(success); }
public void AddRangeMappingAbortLSM() { bool shouldThrow = true; IStoreOperationFactory sof = new StubStoreOperationFactory() { CallBase = true, CreateAddMappingOperationShardMapManagerStoreOperationCodeIStoreShardMapIStoreMapping = (_smm, _opcode, _ssm, _sm) => { StubAddMappingOperation op = new StubAddMappingOperation(_smm, _opcode, _ssm, _sm); op.CallBase = true; op.DoLocalSourceExecuteIStoreTransactionScope = (ts) => { if (shouldThrow) { throw new StoreException("", ShardMapFaultHandlingTests.TransientSqlException); } else { // Call the base function, hack for this behavior is to save current operation, set current to null, restore current operation. var original = op.DoLocalSourceExecuteIStoreTransactionScope; op.DoLocalSourceExecuteIStoreTransactionScope = null; try { return op.DoLocalSourceExecute(ts); } finally { op.DoLocalSourceExecuteIStoreTransactionScope = original; } } }; return op; } }; ShardMapManager smm = new ShardMapManager( new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString), new SqlStoreConnectionFactory(), sof, new CacheStore(), ShardMapManagerLoadPolicy.Lazy, new RetryPolicy(1, TimeSpan.Zero, TimeSpan.Zero, TimeSpan.Zero), RetryBehavior.DefaultRetryBehavior); RangeShardMap<int> rsm = smm.GetRangeShardMap<int>(ShardMapperTests.s_rangeShardMapName); Assert.IsNotNull(rsm); ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapperTests.s_shardedDBs[0]); Shard s = rsm.CreateShard(sl); Assert.IsNotNull(s); bool storeOperationFailed = false; try { RangeMapping<int> r1 = rsm.CreateRangeMapping(new Range<int>(1, 10), s); Assert.IsNotNull(r1); } catch (ShardManagementException sme) { Assert.AreEqual(ShardManagementErrorCategory.RangeShardMap, sme.ErrorCategory); Assert.AreEqual(ShardManagementErrorCode.StorageOperationFailure, sme.ErrorCode); storeOperationFailed = true; } Assert.IsTrue(storeOperationFailed); shouldThrow = false; // validation: adding same range mapping again will succeed. RangeMapping<int> rValidate = rsm.CreateRangeMapping(new Range<int>(1, 10), s); Assert.IsNotNull(rValidate); }
public void DeleteRangeMappingDefault() { CountingCacheStore countingCache = new CountingCacheStore(new CacheStore()); ShardMapManager smm = new ShardMapManager( new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString), new SqlStoreConnectionFactory(), new StoreOperationFactory(), countingCache, ShardMapManagerLoadPolicy.Lazy, new RetryPolicy(1, TimeSpan.Zero, TimeSpan.Zero, TimeSpan.Zero), RetryBehavior.DefaultRetryBehavior); RangeShardMap<int> rsm = smm.GetRangeShardMap<int>(ShardMapperTests.s_rangeShardMapName); Assert.IsNotNull(rsm); ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapperTests.s_shardedDBs[0]); Shard s = rsm.CreateShard(sl); Assert.IsNotNull(s); RangeMapping<int> r1 = rsm.CreateRangeMapping(new Range<int>(1, 10), s); Assert.IsNotNull(r1); MappingLockToken mappingLockToken = MappingLockToken.Create(); rsm.LockMapping(r1, mappingLockToken); RangeMapping<int> rLookup = rsm.GetMappingForKey(1); Assert.IsNotNull(rLookup); Assert.AreEqual(0, countingCache.LookupMappingHitCount); // The mapping must be made offline first before it can be deleted. RangeMappingUpdate ru = new RangeMappingUpdate(); ru.Status = MappingStatus.Offline; // Should throw if the correct lock owner id isn't passed ShardManagementException exception = AssertExtensions.AssertThrows<ShardManagementException> (() => rsm.UpdateMapping(r1, ru)); Assert.IsTrue( exception.ErrorCode == ShardManagementErrorCode.MappingLockOwnerIdDoesNotMatch && exception.ErrorCategory == ShardManagementErrorCategory.RangeShardMap); RangeMapping<int> mappingToDelete = rsm.UpdateMapping(r1, ru, mappingLockToken); exception = AssertExtensions.AssertThrows<ShardManagementException> (() => rsm.DeleteMapping(mappingToDelete)); Assert.IsTrue( exception.ErrorCode == ShardManagementErrorCode.MappingLockOwnerIdDoesNotMatch && exception.ErrorCategory == ShardManagementErrorCategory.RangeShardMap); rsm.DeleteMapping(mappingToDelete, mappingLockToken); exception = AssertExtensions.AssertThrows<ShardManagementException> (() => rsm.GetMappingForKey(1)); Assert.IsTrue( exception.ErrorCode == ShardManagementErrorCode.MappingNotFoundForKey && exception.ErrorCategory == ShardManagementErrorCategory.RangeShardMap); Assert.AreEqual(0, countingCache.LookupMappingMissCount); }
public void AddRangeMappingDefault() { CountingCacheStore countingCache = new CountingCacheStore(new CacheStore()); ShardMapManager smm = new ShardMapManager( new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString), new SqlStoreConnectionFactory(), new StoreOperationFactory(), countingCache, ShardMapManagerLoadPolicy.Lazy, new RetryPolicy(1, TimeSpan.Zero, TimeSpan.Zero, TimeSpan.Zero), RetryBehavior.DefaultRetryBehavior); RangeShardMap<int> rsm = smm.GetRangeShardMap<int>(ShardMapperTests.s_rangeShardMapName); Assert.IsNotNull(rsm); ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapperTests.s_shardedDBs[0]); Shard s = rsm.CreateShard(sl); Assert.IsNotNull(s); RangeMapping<int> r1 = rsm.CreateRangeMapping(new Range<int>(1, 10), s); Assert.IsNotNull(r1); RangeMapping<int> rLookup = rsm.GetMappingForKey(1); Assert.AreEqual(ShardKeyType.Int32, rLookup.Range.KeyType); Assert.IsNotNull(rLookup); Assert.AreEqual(0, countingCache.LookupMappingHitCount); }
public void AddRangeMappingFailGSMAfterSuccessLSMSingleRetry() { ShardMapManager smm = new ShardMapManager( new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString), new SqlStoreConnectionFactory(), new StubStoreOperationFactory() { CallBase = true, CreateAddMappingOperationShardMapManagerStoreOperationCodeIStoreShardMapIStoreMapping = (_smm, _opcode, _ssm, _sm) => new NTimeFailingAddMappingOperation(1, _smm, _opcode, _ssm, _sm) }, new CacheStore(), ShardMapManagerLoadPolicy.Lazy, new RetryPolicy(1, TimeSpan.Zero, TimeSpan.Zero, TimeSpan.Zero), RetryBehavior.DefaultRetryBehavior); RangeShardMap<int> rsm = smm.GetRangeShardMap<int>(ShardMapFaultHandlingTests.s_rangeShardMapName); Assert.IsNotNull(rsm); Shard s = rsm.CreateShard(new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapFaultHandlingTests.s_shardedDBs[0])); Assert.IsNotNull(s); bool failed = false; try { // Inject GSM transaction failure at GSM commit time. RangeMapping<int> r1 = rsm.CreateRangeMapping(new Range<int>(1, 10), s); } catch (ShardManagementException) { failed = true; } Assert.IsFalse(failed); }
public void DeleteRangeMappingAbortLSM() { IStoreOperationFactory sof = new StubStoreOperationFactory() { CallBase = true, CreateRemoveMappingOperationShardMapManagerStoreOperationCodeIStoreShardMapIStoreMappingGuid = (_smm, _opcode, _ssm, _sm, _loid) => { StubRemoveMappingOperation op = new StubRemoveMappingOperation(_smm, _opcode, _ssm, _sm, _loid); op.CallBase = true; op.DoLocalSourceExecuteIStoreTransactionScope = (ts) => { throw new StoreException("", ShardMapFaultHandlingTests.TransientSqlException); }; return op; } }; ShardMapManager smm = new ShardMapManager( new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString), new SqlStoreConnectionFactory(), sof, new CacheStore(), ShardMapManagerLoadPolicy.Lazy, new RetryPolicy(1, TimeSpan.Zero, TimeSpan.Zero, TimeSpan.Zero), RetryBehavior.DefaultRetryBehavior); RangeShardMap<int> rsm = smm.GetRangeShardMap<int>(ShardMapperTests.s_rangeShardMapName); Assert.IsNotNull(rsm); ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapperTests.s_shardedDBs[0]); Shard s = rsm.CreateShard(sl); Assert.IsNotNull(s); RangeMapping<int> r1 = rsm.CreateRangeMapping(new Range<int>(1, 10), s); Assert.IsNotNull(r1); RangeMappingUpdate ru = new RangeMappingUpdate(); ru.Status = MappingStatus.Offline; // The mapping must be made offline before it can be deleted. r1 = rsm.UpdateMapping(r1, ru); Assert.AreEqual(MappingStatus.Offline, r1.Status); bool storeOperationFailed = false; try { rsm.DeleteMapping(r1); } catch (ShardManagementException sme) { Assert.AreEqual(ShardManagementErrorCategory.RangeShardMap, sme.ErrorCategory); Assert.AreEqual(ShardManagementErrorCode.StorageOperationFailure, sme.ErrorCode); storeOperationFailed = true; } Assert.IsTrue(storeOperationFailed); // Validation: lookup for 5 returns a valid mapping. RangeMapping<int> rValidate = rsm.GetMappingForKey(5); Assert.IsNotNull(rValidate); }
public void DeleteRangeMappingAbortLSMDoAndGSMUndo() { bool shouldThrow = true; IStoreOperationFactory sof = new StubStoreOperationFactory() { CallBase = true, CreateRemoveMappingOperationShardMapManagerStoreOperationCodeIStoreShardMapIStoreMappingGuid = (_smm, _opcode, _ssm, _sm, _loid) => { StubRemoveMappingOperation op = new StubRemoveMappingOperation(_smm, _opcode, _ssm, _sm, _loid); op.CallBase = true; op.DoLocalSourceExecuteIStoreTransactionScope = (ts) => { if (shouldThrow) { throw new StoreException("", ShardMapFaultHandlingTests.TransientSqlException); } else { // Call the base function, hack for this behavior is to save current operation, set current to null, restore current operation. var original = op.DoLocalSourceExecuteIStoreTransactionScope; op.DoLocalSourceExecuteIStoreTransactionScope = null; try { return op.DoLocalSourceExecute(ts); } finally { op.DoLocalSourceExecuteIStoreTransactionScope = original; } } }; op.UndoGlobalPostLocalExecuteIStoreTransactionScope = (ts) => { if (shouldThrow) { throw new StoreException("", ShardMapFaultHandlingTests.TransientSqlException); } else { // Call the base function, hack for this behavior is to save current operation, set current to null, restore current operation. var original = op.UndoGlobalPostLocalExecuteIStoreTransactionScope; op.UndoGlobalPostLocalExecuteIStoreTransactionScope = null; try { return op.UndoGlobalPostLocalExecute(ts); } finally { op.UndoGlobalPostLocalExecuteIStoreTransactionScope = original; } } }; return op; } }; ShardMapManager smm = new ShardMapManager( new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString), new SqlStoreConnectionFactory(), sof, new CacheStore(), ShardMapManagerLoadPolicy.Lazy, new RetryPolicy(1, TimeSpan.Zero, TimeSpan.Zero, TimeSpan.Zero), RetryBehavior.DefaultRetryBehavior); RangeShardMap<int> rsm = smm.GetRangeShardMap<int>(ShardMapperTests.s_rangeShardMapName); Assert.IsNotNull(rsm); ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapperTests.s_shardedDBs[0]); Shard s = rsm.CreateShard(sl); Assert.IsNotNull(s); RangeMapping<int> r1 = rsm.CreateRangeMapping(new Range<int>(1, 10), s); Assert.IsNotNull(r1); RangeMappingUpdate ru = new RangeMappingUpdate(); ru.Status = MappingStatus.Offline; // The mapping must be made offline before it can be deleted. r1 = rsm.UpdateMapping(r1, ru); Assert.AreEqual(MappingStatus.Offline, r1.Status); bool storeOperationFailed = false; try { rsm.DeleteMapping(r1); } catch (ShardManagementException sme) { Assert.AreEqual(ShardManagementErrorCategory.RangeShardMap, sme.ErrorCategory); Assert.AreEqual(ShardManagementErrorCode.StorageOperationFailure, sme.ErrorCode); storeOperationFailed = true; } Assert.IsTrue(storeOperationFailed); // Obtain the pending operations. var pendingOperations = ShardMapperTests.GetPendingStoreOperations(); Assert.AreEqual(pendingOperations.Count(), 1); // Validation: lookup for 5 still returns a valid mapping since we never committed the remove. RangeMapping<int> rValidate = rsm.GetMappingForKey(5); Assert.IsNotNull(rValidate); Assert.AreEqual(rValidate.Range, r1.Range); #region OpenConnection with Validation // Validation should fail with mapping is offline error since local mapping was not deleted. bool validationFailed = false; try { using (SqlConnection conn = rsm.OpenConnection( rValidate, Globals.ShardUserConnectionString, ConnectionOptions.Validate)) { } } catch (ShardManagementException smme) { validationFailed = true; Assert.AreEqual(smme.ErrorCode, ShardManagementErrorCode.MappingIsOffline); } Assert.AreEqual(true, validationFailed); #endregion OpenConnection with Validation shouldThrow = false; // Now we try an AddOperation, which should fail since we still have the mapping. ShardManagementException exception = AssertExtensions.AssertThrows<ShardManagementException> (() => rsm.CreateRangeMapping(new Range<int>(1, 10), s)); Assert.IsTrue( exception.ErrorCode == ShardManagementErrorCode.MappingRangeAlreadyMapped && exception.ErrorCategory == ShardManagementErrorCategory.RangeShardMap, "Expected MappingRangeAlreadyMapped error!"); // No pending operation should be left now since the previous operation took care of it. pendingOperations = ShardMapperTests.GetPendingStoreOperations(); Assert.AreEqual(pendingOperations.Count(), 0); // Removal should succeed now. storeOperationFailed = false; try { rsm.DeleteMapping(r1); } catch (ShardManagementException) { storeOperationFailed = true; } Assert.IsFalse(storeOperationFailed); }
public void MergeRangeMappingsAbortLSM() { IStoreOperationFactory sof = new StubStoreOperationFactory() { CallBase = true, CreateReplaceMappingsOperationShardMapManagerStoreOperationCodeIStoreShardMapTupleOfIStoreMappingGuidArrayTupleOfIStoreMappingGuidArray = (_smm, _opcode, _ssm, _smo, _smn) => { StubReplaceMappingsOperation op = new StubReplaceMappingsOperation(_smm, _opcode, _ssm, _smo, _smn); op.CallBase = true; op.DoLocalSourceExecuteIStoreTransactionScope = (ts) => { throw new StoreException("", ShardMapFaultHandlingTests.TransientSqlException); }; return op; } }; ShardMapManager smm = new ShardMapManager( new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString), new SqlStoreConnectionFactory(), sof, new CacheStore(), ShardMapManagerLoadPolicy.Lazy, new RetryPolicy(1, TimeSpan.Zero, TimeSpan.Zero, TimeSpan.Zero), RetryBehavior.DefaultRetryBehavior); RangeShardMap<int> rsm = smm.GetRangeShardMap<int>(ShardMapperTests.s_rangeShardMapName); Assert.IsNotNull(rsm); Shard s1 = rsm.CreateShard(new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapperTests.s_shardedDBs[0])); Assert.IsNotNull(s1); RangeMapping<int> r1 = rsm.CreateRangeMapping(new Range<int>(1, 10), s1); RangeMapping<int> r2 = rsm.CreateRangeMapping(new Range<int>(10, 20), s1); bool storeOperationFailed = false; try { RangeMapping<int> rMerged = rsm.MergeMappings(r1, r2); Assert.IsNotNull(rMerged); } catch (ShardManagementException sme) { Assert.AreEqual(ShardManagementErrorCategory.RangeShardMap, sme.ErrorCategory); Assert.AreEqual(ShardManagementErrorCode.StorageOperationFailure, sme.ErrorCode); storeOperationFailed = true; } Assert.IsTrue(storeOperationFailed); // Validation: get all mappings for [1,20) should return 2 mappings. Assert.AreEqual(2, rsm.GetMappings().Count()); }
public void UpdateRangeMappingLocationAbortLSM() { bool shouldThrow = false; IStoreOperationFactory sof = new StubStoreOperationFactory() { CallBase = true, CreateUpdateMappingOperationShardMapManagerStoreOperationCodeIStoreShardMapIStoreMappingIStoreMappingStringGuid = (_smm, _opcode, _ssm, _sms, _smt, _p, _loid) => { StubUpdateMappingOperation op = new StubUpdateMappingOperation(_smm, _opcode, _ssm, _sms, _smt, _p, _loid); op.CallBase = true; if (shouldThrow) { // Abort on source. op.DoLocalSourceExecuteIStoreTransactionScope = (ts) => { throw new StoreException("", ShardMapFaultHandlingTests.TransientSqlException); }; } return op; } }; ShardMapManager smm = new ShardMapManager( new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString), new SqlStoreConnectionFactory(), sof, new CacheStore(), ShardMapManagerLoadPolicy.Lazy, new RetryPolicy(1, TimeSpan.Zero, TimeSpan.Zero, TimeSpan.Zero), RetryBehavior.DefaultRetryBehavior); RangeShardMap<int> rsm = smm.GetRangeShardMap<int>(ShardMapperTests.s_rangeShardMapName); Assert.IsNotNull(rsm); ShardLocation sl1 = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapperTests.s_shardedDBs[0]); Shard s1 = rsm.CreateShard(sl1); Assert.IsNotNull(s1); ShardLocation sl2 = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapperTests.s_shardedDBs[1]); Shard s2 = rsm.CreateShard(sl2); Assert.IsNotNull(s2); RangeMapping<int> r1 = rsm.CreateRangeMapping(new Range<int>(1, 20), s1); RangeMappingUpdate ru1 = new RangeMappingUpdate(); // Take the mapping offline first. ru1.Status = MappingStatus.Offline; RangeMapping<int> rNew = rsm.UpdateMapping(r1, ru1); Assert.IsNotNull(rNew); RangeMappingUpdate ru2 = new RangeMappingUpdate(); ru2.Shard = s2; shouldThrow = true; bool storeOperationFailed = false; try { rNew = rsm.UpdateMapping(rNew, ru2); Assert.IsNotNull(rNew); } catch (ShardManagementException sme) { Assert.AreEqual(ShardManagementErrorCategory.RangeShardMap, sme.ErrorCategory); Assert.AreEqual(ShardManagementErrorCode.StorageOperationFailure, sme.ErrorCode); storeOperationFailed = true; } Assert.IsTrue(storeOperationFailed); // validation: validate location of the mapping. RangeMapping<int> rValidate = rsm.GetMappingForKey(1); Assert.AreEqual(s1.Id, rValidate.Shard.Id); }
public void UpdateRangeMappingLocationAbortGSMPostLocalDoAndLSMTargetUndo() { bool shouldThrow = false; IStoreOperationFactory sof = new StubStoreOperationFactory() { CallBase = true, CreateUpdateMappingOperationShardMapManagerStoreOperationCodeIStoreShardMapIStoreMappingIStoreMappingStringGuid = (_smm, _opcode, _ssm, _sms, _smt, _p, _loid) => { StubUpdateMappingOperation op = new StubUpdateMappingOperation(_smm, _opcode, _ssm, _sms, _smt, _p, _loid); op.CallBase = true; op.DoGlobalPostLocalExecuteIStoreTransactionScope = (ts) => { if (shouldThrow) { throw new StoreException("", ShardMapFaultHandlingTests.TransientSqlException); } else { // Call the base function, hack for this behavior is to save current operation, set current to null, restore current operation. var original = op.DoGlobalPostLocalExecuteIStoreTransactionScope; op.DoGlobalPostLocalExecuteIStoreTransactionScope = null; try { return op.DoGlobalPostLocalExecute(ts); } finally { op.DoGlobalPostLocalExecuteIStoreTransactionScope = original; } } }; op.UndoLocalTargetExecuteIStoreTransactionScope = (ts) => { if (shouldThrow) { throw new StoreException("", ShardMapFaultHandlingTests.TransientSqlException); } else { // Call the base function, hack for this behavior is to save current operation, set current to null, restore current operation. var original = op.UndoLocalTargetExecuteIStoreTransactionScope; op.UndoLocalTargetExecuteIStoreTransactionScope = null; try { return op.UndoLocalTargetExecute(ts); } finally { op.UndoLocalTargetExecuteIStoreTransactionScope = original; } } }; return op; } }; ShardMapManager smm = new ShardMapManager( new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString), new SqlStoreConnectionFactory(), sof, new CacheStore(), ShardMapManagerLoadPolicy.Lazy, new RetryPolicy(1, TimeSpan.Zero, TimeSpan.Zero, TimeSpan.Zero), RetryBehavior.DefaultRetryBehavior); RangeShardMap<int> rsm = smm.GetRangeShardMap<int>(ShardMapperTests.s_rangeShardMapName); Assert.IsNotNull(rsm); ShardLocation sl1 = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapperTests.s_shardedDBs[0]); Shard s1 = rsm.CreateShard(sl1); Assert.IsNotNull(s1); ShardLocation sl2 = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapperTests.s_shardedDBs[1]); Shard s2 = rsm.CreateShard(sl2); Assert.IsNotNull(s2); RangeMapping<int> r1 = rsm.CreateRangeMapping(new Range<int>(1, 20), s1); RangeMappingUpdate ru1 = new RangeMappingUpdate(); // Take the mapping offline first. ru1.Status = MappingStatus.Offline; RangeMapping<int> rNew = rsm.UpdateMapping(r1, ru1); Assert.IsNotNull(rNew); RangeMappingUpdate ru2 = new RangeMappingUpdate(); ru2.Shard = s2; shouldThrow = true; bool storeOperationFailed = false; try { rNew = rsm.UpdateMapping(rNew, ru2); Assert.IsNotNull(rNew); } catch (ShardManagementException sme) { Assert.AreEqual(ShardManagementErrorCategory.RangeShardMap, sme.ErrorCategory); Assert.AreEqual(ShardManagementErrorCode.StorageOperationFailure, sme.ErrorCode); storeOperationFailed = true; } Assert.IsTrue(storeOperationFailed); // Obtain the pending operations. var pendingOperations = ShardMapperTests.GetPendingStoreOperations(); Assert.AreEqual(pendingOperations.Count(), 1); // validation: validate location of the mapping. RangeMapping<int> rValidate = rsm.GetMappingForKey(1); Assert.AreEqual(s1.Id, rValidate.Shard.Id); #region OpenConnection with Validation // Validation should fail with mapping does not exist since source mapping was deleted. bool validationFailed = false; try { using (SqlConnection conn = rsm.OpenConnection( rValidate, Globals.ShardUserConnectionString, ConnectionOptions.Validate)) { } } catch (ShardManagementException smme) { validationFailed = true; Assert.AreEqual(smme.ErrorCode, ShardManagementErrorCode.MappingDoesNotExist); } Assert.AreEqual(true, validationFailed); #endregion OpenConnection with Validation shouldThrow = false; // Removal should succeed now. storeOperationFailed = false; try { rsm.DeleteMapping(rNew); } catch (ShardManagementException) { storeOperationFailed = true; } Assert.IsFalse(storeOperationFailed); }
public void MergeRangeMappingAbortSourceLocalDoAndGSMPostLocalUndo() { bool shouldThrow = true; IStoreOperationFactory sof = new StubStoreOperationFactory() { CallBase = true, CreateReplaceMappingsOperationShardMapManagerStoreOperationCodeIStoreShardMapTupleOfIStoreMappingGuidArrayTupleOfIStoreMappingGuidArray = (_smm, _opcode, _ssm, _smo, _smn) => { StubReplaceMappingsOperation op = new StubReplaceMappingsOperation(_smm, _opcode, _ssm, _smo, _smn); op.CallBase = true; op.DoLocalSourceExecuteIStoreTransactionScope = (ts) => { if (shouldThrow) { throw new StoreException("", ShardMapFaultHandlingTests.TransientSqlException); } else { // Call the base function, hack for this behavior is to save current operation, set current to null, restore current operation. var original = op.DoLocalSourceExecuteIStoreTransactionScope; op.DoLocalSourceExecuteIStoreTransactionScope = null; try { return op.DoLocalSourceExecute(ts); } finally { op.DoLocalSourceExecuteIStoreTransactionScope = original; } } }; op.UndoGlobalPostLocalExecuteIStoreTransactionScope = (ts) => { if (shouldThrow) { throw new StoreException("", ShardMapFaultHandlingTests.TransientSqlException); } else { // Call the base function, hack for this behavior is to save current operation, set current to null, restore current operation. var original = op.UndoGlobalPostLocalExecuteIStoreTransactionScope; op.UndoGlobalPostLocalExecuteIStoreTransactionScope = null; try { return op.UndoGlobalPostLocalExecute(ts); } finally { op.UndoGlobalPostLocalExecuteIStoreTransactionScope = original; } } }; return op; } }; ShardMapManager smm = new ShardMapManager( new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString), new SqlStoreConnectionFactory(), sof, new CacheStore(), ShardMapManagerLoadPolicy.Lazy, new RetryPolicy(1, TimeSpan.Zero, TimeSpan.Zero, TimeSpan.Zero), RetryBehavior.DefaultRetryBehavior); RangeShardMap<int> rsm = smm.GetRangeShardMap<int>(ShardMapperTests.s_rangeShardMapName); Assert.IsNotNull(rsm); ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapperTests.s_shardedDBs[0]); Shard s = rsm.CreateShard(sl); Assert.IsNotNull(s); RangeMapping<int> r1 = rsm.CreateRangeMapping(new Range<int>(1, 20), s); RangeMapping<int> r2 = rsm.CreateRangeMapping(new Range<int>(20, 40), s); bool storeOperationFailed = false; try { RangeMapping<int> rMerged = rsm.MergeMappings(r1, r2); } catch (ShardManagementException sme) { Assert.AreEqual(ShardManagementErrorCategory.RangeShardMap, sme.ErrorCategory); Assert.AreEqual(ShardManagementErrorCode.StorageOperationFailure, sme.ErrorCode); storeOperationFailed = true; } Assert.IsTrue(storeOperationFailed); // Obtain the pending operations. var pendingOperations = ShardMapperTests.GetPendingStoreOperations(); Assert.AreEqual(pendingOperations.Count(), 1); // Validation: Mapping range is not updated - lookup for point 10 returns mapping with version 0. RangeMapping<int> rValidateLeft = rsm.GetMappingForKey(5); RangeMapping<int> rValidateRight = rsm.GetMappingForKey(25); Assert.AreEqual(r1.Range, rValidateLeft.Range); Assert.AreEqual(r2.Range, rValidateRight.Range); #region OpenConnection with Validation // Validation should succeed since source mapping was never deleted. bool validationFailed = false; try { using (SqlConnection conn = rsm.OpenConnection( rValidateLeft, Globals.ShardUserConnectionString, ConnectionOptions.Validate)) { } using (SqlConnection conn = rsm.OpenConnection( rValidateRight, Globals.ShardUserConnectionString, ConnectionOptions.Validate)) { } } catch (ShardManagementException) { validationFailed = true; } Assert.AreEqual(false, validationFailed); #endregion OpenConnection with Validation shouldThrow = false; // Split the range mapping on the left. storeOperationFailed = false; try { rsm.SplitMapping(r1, 10); } catch (ShardManagementException) { storeOperationFailed = true; } Assert.IsFalse(storeOperationFailed); }
public void ShardMapOperationsFailureAfterLocalTarget() { StubStoreOperationFactory ssof = new StubStoreOperationFactory() { CallBase = true, CreateAddShardOperationShardMapManagerIStoreShardMapIStoreShard = (_smm, _sm, _s) => new AddShardOperationFailAfterLocalTarget(_smm, _sm, _s), CreateRemoveShardOperationShardMapManagerIStoreShardMapIStoreShard = (_smm, _sm, _s) => new RemoveShardOperationFailAfterLocalTarget(_smm, _sm, _s), CreateUpdateShardOperationShardMapManagerIStoreShardMapIStoreShardIStoreShard = (_smm, _sm, _sold, _snew) => new UpdateShardOperationFailAfterLocalTarget(_smm, _sm, _sold, _snew), CreateAddMappingOperationShardMapManagerStoreOperationCodeIStoreShardMapIStoreMapping = (_smm, _opcode, _ssm, _sm) => new AddMappingOperationFailAfterLocalTarget(_smm, _opcode, _ssm, _sm), CreateRemoveMappingOperationShardMapManagerStoreOperationCodeIStoreShardMapIStoreMappingGuid = (_smm, _opcode, _sm, _mapping, _loid) => new RemoveMappingOperationFailAfterLocalTarget(_smm, _opcode, _sm, _mapping, _loid), CreateUpdateMappingOperationShardMapManagerStoreOperationCodeIStoreShardMapIStoreMappingIStoreMappingStringGuid = (_shardMapManager, _operationCode, _shardMap, _mappingSource, _mappingTarget, _patternForKill, _lockOwnerId) => new UpdateMappingOperationFailAfterLocalTarget(_shardMapManager, _operationCode, _shardMap, _mappingSource, _mappingTarget, _patternForKill, _lockOwnerId), CreateReplaceMappingsOperationShardMapManagerStoreOperationCodeIStoreShardMapTupleOfIStoreMappingGuidArrayTupleOfIStoreMappingGuidArray = (_smm, _opcode, _sm, _mappingsource, _mappingtarget) => new ReplaceMappingsOperationFailAfterLocalTarget(_smm, _opcode, _sm, _mappingsource, _mappingtarget) }; ShardMapManager smm = new ShardMapManager( new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString), new SqlStoreConnectionFactory(), ssof, new CacheStore(), ShardMapManagerLoadPolicy.Lazy, new RetryPolicy(1, TimeSpan.Zero, TimeSpan.Zero, TimeSpan.Zero), RetryBehavior.DefaultRetryBehavior); RangeShardMap<int> rsm = smm.GetRangeShardMap<int>(ShardMapFaultHandlingTests.s_rangeShardMapName); Assert.IsNotNull(rsm); // test undo operations on shard // global pre-local only create shard Shard stemp = rsm.CreateShard(new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapFaultHandlingTests.s_shardedDBs[0])); // now creating shard with GSM and LSM operations ssof.CreateAddShardOperationShardMapManagerIStoreShardMapIStoreShard = null; Shard s = rsm.CreateShard(new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapFaultHandlingTests.s_shardedDBs[0])); // global pre-local only update shard rsm.UpdateShard(s, new ShardUpdate { Status = ShardStatus.Offline }); // now update shard with GSM and LSM operations ssof.CreateUpdateShardOperationShardMapManagerIStoreShardMapIStoreShardIStoreShard = null; Shard sNew = rsm.UpdateShard(s, new ShardUpdate { Status = ShardStatus.Offline }); // global pre-local only remove shard rsm.DeleteShard(sNew); // now remove with GSM and LSM operations ssof.CreateRemoveShardOperationShardMapManagerIStoreShardMapIStoreShard = null; rsm.DeleteShard(sNew); // test undo operations for shard mapings Shard s1 = rsm.CreateShard(new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapFaultHandlingTests.s_shardedDBs[0])); Assert.IsNotNull(s1); Shard s2 = rsm.CreateShard(new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapFaultHandlingTests.s_shardedDBs[1])); Assert.IsNotNull(s2); // first add mapping will just execute global pre-local and add operation into pending operations log RangeMapping<int> rtemp = rsm.CreateRangeMapping(new Range<int>(1, 10), s1); ssof.CreateAddMappingOperationShardMapManagerStoreOperationCodeIStoreShardMapIStoreMapping = null; // now add mapping will succeed after undoing pending operation RangeMapping<int> r1 = rsm.CreateRangeMapping(new Range<int>(1, 10), s1); Assert.IsNotNull(r1); RangeMappingUpdate ru = new RangeMappingUpdate { Status = MappingStatus.Offline }; // below call will only execute global pre-local step to create operations log RangeMapping<int> r2 = rsm.UpdateMapping(r1, ru); ssof.CreateUpdateMappingOperationShardMapManagerStoreOperationCodeIStoreShardMapIStoreMappingIStoreMappingStringGuid = null; // now update same mapping again, this will undo previous pending operation and then add this mapping RangeMapping<int> r3 = rsm.UpdateMapping(r1, ru); // try mapping update failures with change in shard location // first reset CreateUpdateMappingOperation to just perform global pre-local ssof.CreateUpdateMappingOperationShardMapManagerStoreOperationCodeIStoreShardMapIStoreMappingIStoreMappingStringGuid = (_shardMapManager, _operationCode, _shardMap, _mappingSource, _mappingTarget, _patternForKill, _lockOwnerId) => new UpdateMappingOperationFailAfterLocalTarget(_shardMapManager, _operationCode, _shardMap, _mappingSource, _mappingTarget, _patternForKill, _lockOwnerId); RangeMapping<int> r4 = rsm.UpdateMapping(r3, new RangeMappingUpdate { Shard = s2 }); // now try with actual update mapping operation ssof.CreateUpdateMappingOperationShardMapManagerStoreOperationCodeIStoreShardMapIStoreMappingIStoreMappingStringGuid = null; RangeMapping<int> r5 = rsm.UpdateMapping(r3, new RangeMappingUpdate { Shard = s2 }); // split mapping toperform gsm-only pre-local operation IReadOnlyList<RangeMapping<int>> rlisttemp = rsm.SplitMapping(r5, 5); // try actual operation which will undo previous pending op ssof.CreateReplaceMappingsOperationShardMapManagerStoreOperationCodeIStoreShardMapTupleOfIStoreMappingGuidArrayTupleOfIStoreMappingGuidArray = null; IReadOnlyList<RangeMapping<int>> rlist = rsm.SplitMapping(r5, 5); // remove mapping to create operations log and then exit rsm.DeleteMapping(rlist[0]); ssof.CreateRemoveMappingOperationShardMapManagerStoreOperationCodeIStoreShardMapIStoreMappingGuid = null; // now actually remove the mapping rsm.DeleteMapping(rlist[0]); }
// スケールアウト実行メソッド private static void DoSplit <T>(string UserName, string Password, T splitValue) { string ShardMapManagerServerName = "."; // SQLサーバ名 string ShardMapManagerDatabaseName = "SplitMergeShardManagement"; // ShardMapManagerのDB名 string ShardServerName1 = ShardMapManagerServerName; // スケールアウト元のSQLサーバ名 string ShardDatabaseName1 = "ShardDb1"; // スケールアウト元のDB名 string ShardServerName2 = ShardMapManagerServerName; // スケールアウト先のSQLサーバ名 string ShardDatabaseName2 = "ShardDb2"; // スケールアウト先のDB名 string ShardMapName = "MyTestShardMap"; // SharMap名 string SplitMergeServerName = ShardMapManagerServerName; // スケールアウトの情報を登録するSQLサーバ名 string SplitMergeDatabaseName = ShardMapManagerDatabaseName; // スケールアウトの情報を登録するDB名 // Get shard map string smmConnStr = new SqlConnectionStringBuilder { UserID = UserName, Password = Password, DataSource = ShardMapManagerServerName, InitialCatalog = ShardMapManagerDatabaseName }.ToString(); string shardConnStr = new SqlConnectionStringBuilder { UserID = UserName, Password = Password, }.ToString(); ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager( smmConnStr, ShardMapManagerLoadPolicy.Lazy); RangeShardMap <T> rsm = smm.GetRangeShardMap <T>(ShardMapName); // スケールアウトしたデータを戻す場合 // Shard targetShard = rsm.GetShard(new ShardLocation(ShardServerName1, ShardDatabaseName1)); Shard targetShard = rsm.GetShard(new ShardLocation(ShardServerName2, ShardDatabaseName2)); // Split-merge worker config string certFile = "testCert.pfx"; string certFilePassword = "******"; X509Certificate2 encryptionCert = new X509Certificate2(); encryptionCert.Import(certFile, certFilePassword, X509KeyStorageFlags.DefaultKeySet); string splitMergeConnStr = new SqlConnectionStringBuilder { UserID = UserName, Password = Password, DataSource = SplitMergeServerName, InitialCatalog = SplitMergeDatabaseName }.ToString(); // スケールアウトの実行 using (SplitMergeWorker worker = SplitMergeWorkerFactory.CreateSplitMergeWorker(splitMergeConnStr, encryptionCert)) { SplitMergeOperation op = worker.Split( smmConnStr, shardConnStr, rsm, splitValue, targetShard, SplitMergePolicy.MoveLowerKeySegment); // 指定した日付以前のデータをスケールアウトする設定 worker.WaitForOperationToFinish(op); } }