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);
        }
Exemple #18
0
        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]);
        }
Exemple #30
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);
            }
        }