/// <summary>
        /// Handles the shardlet move request from tje request queue.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <param name="queue">The queue.</param>
        /// <param name="uniqueProcessID">A unique process identifier that can be set to maintain state between moves.</param>
        public static void HandleShardletMoveRequest(ShardletMoveRequest request, IShardSetActionQueue queue,
                                                     Guid uniqueProcessID)
        {
            Action <ShardletMoveRequest> process =
                x =>
            {
                var shardlet         = Load(x.ShardSetName, x.ShardingKey);
                var destinationShard =
                    new RangeShard
                {
                    Catalog            = x.DestinationCatalog,
                    ServerInstanceName = x.DestinationServerInstanceName
                };

                shardlet.MoveToShard(destinationShard, x.Pin, x.DeleteOnMove, uniqueProcessID);
            };

            Action <ShardletMoveRequest> complete =
                x =>
            {
                var message = GetCompletionMessage("ShardletMoveRequest", x);
                queue.SendQueueProcessingEvent(message);
            };

            Action <ShardletMoveRequest> error =
                x =>
            {
                var message = GetErrorMessage("ShardletMoveRequest", x);
                queue.SendQueueProcessingEvent(message);
            };

            request.Process(process, complete, error);
        }
        private static void ProcessShardMapPublishingRequest(ShardMapPublishingRequest shardMapPublishingRequest,
                                                             ShardSetConfig shardSetConfig)
        {
            var shardSetName             = shardMapPublishingRequest.ShardSetName;
            var shardSetConnectionDriver = GetShardSetConnectionDriver(shardSetName);

            // to do - may need to page
            var shardlets = shardSetConnectionDriver.GetShardlets(shardSetName);

            foreach (var shardlet in shardlets)
            {
                // skip if shardlet is pinned
                if (shardlet.Pinned)
                {
                    continue;
                }

                // get the matching range shard for this shardlet based on the range map
                var rangeShard =
                    shardSetConfig.ShardMap.Shards
                    .FirstOrDefault(rs => rs.HighDistributionKey > shardlet.DistributionKey);

                // skip if we cannot find a range.
                if (rangeShard == null)
                {
                    continue;
                }

                // determine if the shardlet needs to be moved
                if (rangeShard.ServerInstanceName == shardlet.ServerInstanceName &&
                    rangeShard.Catalog == shardlet.Catalog)
                {
                    continue;
                }

                var request =
                    new ShardletMoveRequest
                {
                    DestinationCatalog            = rangeShard.Catalog,
                    DestinationServerInstanceName = shardlet.ServerInstanceName,
                    SourceCatalog            = shardlet.Catalog,
                    SourceServerInstanceName = shardlet.ServerInstanceName,
                    DistributionKey          = shardlet.DistributionKey,
                    ShardingKey  = shardlet.ShardingKey,
                    ShardSetName = shardlet.ShardSetName,
                    DeleteOnMove = true,
                    Pin          = false
                };

                request.Save();
            }

            // todo: do this save in parallel
            //var parallelOptions = GetParallelOptions();

            //Parallel.ForEach(shardletMoveRequests, parallelOptions,
            //    shardletMoveRequest => shardletMoveRequest.Save());
        }
        /// <summary>
        /// Moves to shard.
        /// </summary>
        /// <param name="shard">The shard to move the ShardLet data to.</param>
        /// <param name="pin">if set to <c>true</c> add the shard to the pinned shard list.</param>
        /// <param name="deleteOnMove">if set to <c>true</c> delete the Shardlet data from the existing Shard after move.</param>
        /// <param name="uniqueProcessID">A unique process identifier that can be set to maintain state between moves.</param>
        /// <param name="queueRequest">if set to <c>true</c> queue the shard move rather than executing it immediately.</param>
        public void MoveToShard(ShardBase shard, bool pin, bool deleteOnMove, Guid uniqueProcessID,
                                bool queueRequest = false)
        {
            if (queueRequest)
            {
                var request =
                    new ShardletMoveRequest
                {
                    DestinationCatalog            = shard.Catalog,
                    DestinationServerInstanceName = shard.ServerInstanceName,
                    SourceCatalog            = Catalog,
                    SourceServerInstanceName = ServerInstanceName,
                    DistributionKey          = DistributionKey,
                    ShardingKey     = ShardingKey,
                    ShardSetName    = ShardSetName,
                    DeleteOnMove    = deleteOnMove,
                    UniqueProcessID = uniqueProcessID,
                    Pin             = pin
                };

                request.Save();

                return;
            }

            var shardSetConnectionDriver = ScaleOutShardletManager.GetManager().GetShardletConnectionDriver(ShardSetName);

            try
            {
                // change the state to read only in the map and update th epin status
                Status = ShardletStatus.Moving;
                Pinned = pin;
                shardSetConnectionDriver.PublishShardlet(this);

                // terminate all existing connections
                shardSetConnectionDriver.TerminateConnections(this);

                // copy the shardlet data
                var shardSetConfig = ShardSetConfig.LoadCurrent(ShardSetName);

                var currentShard =
                    new RangeShard
                {
                    Catalog            = Catalog,
                    ServerInstanceName = ServerInstanceName,
                };

                shardSetConfig.CopyShardlet(currentShard, shard, ShardingKey, uniqueProcessID);

                // update the status and set the new catalog and instance in the shard map
                Catalog            = shard.Catalog;
                ServerInstanceName = shard.ServerInstanceName;
                Status             = ShardletStatus.Active;

                shardSetConnectionDriver.PublishShardlet(this);

                if (deleteOnMove)
                {
                    shardSetConfig.DeleteShardlet(currentShard, ShardingKey);
                }
            }
            catch (Exception)
            {
                Status = ShardletStatus.Active;
                shardSetConnectionDriver.PublishShardlet(this);

                throw;
            }
        }