Beispiel #1
0
 /// <summary>
 /// Performs undo of the storage operation that is pending.
 /// </summary>
 /// <param name="logEntry">Log entry for the pending operation.</param>
 protected override void UndoPendingStoreOperations(IStoreLogEntry logEntry)
 {
     using (IStoreOperation op = _shardMapManager.StoreOperationFactory.FromLogEntry(_shardMapManager, logEntry))
     {
         op.Undo();
     }
 }
Beispiel #2
0
        /// <summary>
        /// Adds a mapping to shard map.
        /// </summary>
        /// <typeparam name="TMapping">Mapping type.</typeparam>
        /// <param name="mapping">Mapping being added.</param>
        /// <param name="constructMapping">Delegate to construct a mapping object.</param>
        /// <returns>The added mapping object.</returns>
        protected TMapping Add <TMapping>(
            TMapping mapping,
            Func <ShardMapManager, ShardMap, IStoreMapping, TMapping> constructMapping)
            where TMapping : class, IShardProvider, IMappingInfoProvider
        {
            ExceptionUtils.EnsureShardBelongsToShardMap(
                this.Manager,
                this.ShardMap,
                mapping.ShardInfo,
                "CreateMapping",
                mapping.Kind == MappingKind.PointMapping ? "PointMapping" : "RangeMapping");

            this.EnsureMappingBelongsToShardMap(mapping, "Add", "mapping");

            TMapping newMapping = constructMapping(
                this.Manager,
                this.ShardMap,
                new DefaultStoreMapping(
                    mapping.StoreMapping.Id,
                    mapping.StoreMapping.ShardMapId,
                    new DefaultStoreShard(
                        mapping.ShardInfo.StoreShard.Id,
                        Guid.NewGuid(),
                        mapping.ShardInfo.StoreShard.ShardMapId,
                        mapping.ShardInfo.StoreShard.Location,
                        mapping.ShardInfo.StoreShard.Status),
                    mapping.StoreMapping.MinValue,
                    mapping.StoreMapping.MaxValue,
                    mapping.StoreMapping.Status,
                    mapping.StoreMapping.LockOwnerId));

            using (IStoreOperation op = this.Manager.StoreOperationFactory.CreateAddMappingOperation(
                       this.Manager,
                       mapping.Kind == MappingKind.RangeMapping ?
                       StoreOperationCode.AddRangeMapping :
                       StoreOperationCode.AddPointMapping,
                       this.ShardMap.StoreShardMap,
                       newMapping.StoreMapping))
            {
                op.Do();
            }

            return(newMapping);
        }
        public void Remove(Shard shard, Guid lockOwnerId = default(Guid))
        {
            Debug.Assert(shard != null);

            ExceptionUtils.EnsureShardBelongsToShardMap(
                this.Manager,
                this.ShardMap,
                shard,
                "DeleteShard",
                "Shard");

            using (IStoreOperation op = this.Manager.StoreOperationFactory.CreateRemoveShardOperation(
                       this.Manager,
                       this.ShardMap.StoreShardMap,
                       shard.StoreShard))
            {
                op.Do();
            }
        }
Beispiel #4
0
        public void AttachShard(ShardLocation location, string shardMapName)
        {
            ExceptionUtils.DisallowNullArgument(location, "location");

            IStoreResults result;

            using (IStoreOperationLocal op = this.Manager.StoreOperationFactory.CreateGetShardsLocalOperation(
                       this.Manager,
                       location,
                       "AttachShard"))
            {
                result = op.Do();
            }

            Debug.Assert(result.Result == StoreResult.Success);

            IEnumerable <IStoreShardMap> shardMaps =
                shardMapName == null ?
                result.StoreShardMaps :
                result.StoreShardMaps.Where(s => s.Name == shardMapName);

            shardMaps.ToList <IStoreShardMap>().ForEach((sm) =>
            {
                IStoreShard shard = result.StoreShards.SingleOrDefault(s => s.ShardMapId == sm.Id);

                // construct a new store shard with correct location
                DefaultStoreShard sNew = new DefaultStoreShard(
                    shard.Id,
                    shard.Version,
                    shard.ShardMapId,
                    location,
                    shard.Status);

                using (IStoreOperation op = this.Manager.StoreOperationFactory.CreateAttachShardOperation(
                           this.Manager,
                           sm,
                           sNew))
                {
                    op.Do();
                }
            });
        }
        public Shard Add(Shard shard)
        {
            Debug.Assert(shard != null);

            ExceptionUtils.EnsureShardBelongsToShardMap(
                this.Manager,
                this.ShardMap,
                shard,
                "CreateShard",
                "Shard");

            using (IStoreOperation op = this.Manager.StoreOperationFactory.CreateAddShardOperation(
                       this.Manager,
                       this.ShardMap.StoreShardMap,
                       shard.StoreShard))
            {
                op.Do();
            }

            return(shard);
        }
Beispiel #6
0
        /// <summary>
        /// Removes a mapping from shard map.
        /// </summary>
        /// <typeparam name="TMapping">Mapping type.</typeparam>
        /// <param name="mapping">Mapping being removed.</param>
        /// <param name="constructMapping">Delegate to construct a mapping object.</param>
        /// <param name="lockOwnerId">Lock owner id of this mapping</param>
        protected void Remove <TMapping>(
            TMapping mapping,
            Func <ShardMapManager, ShardMap, IStoreMapping, TMapping> constructMapping,
            Guid lockOwnerId)
            where TMapping : class, IShardProvider, IMappingInfoProvider
        {
            this.EnsureMappingBelongsToShardMap <TMapping>(mapping, "Remove", "mapping");

            TMapping newMapping = constructMapping(
                this.Manager,
                this.ShardMap,
                new DefaultStoreMapping(
                    mapping.StoreMapping.Id,
                    mapping.StoreMapping.ShardMapId,
                    new DefaultStoreShard(
                        mapping.ShardInfo.Id,
                        Guid.NewGuid(),
                        mapping.ShardInfo.StoreShard.ShardMapId,
                        mapping.ShardInfo.StoreShard.Location,
                        mapping.ShardInfo.StoreShard.Status),
                    mapping.StoreMapping.MinValue,
                    mapping.StoreMapping.MaxValue,
                    mapping.StoreMapping.Status,
                    mapping.StoreMapping.LockOwnerId));

            using (IStoreOperation op = this.Manager.StoreOperationFactory.CreateRemoveMappingOperation(
                       this.Manager,
                       mapping.Kind == MappingKind.RangeMapping ?
                       StoreOperationCode.RemoveRangeMapping :
                       StoreOperationCode.RemovePointMapping,
                       this.ShardMap.StoreShardMap,
                       newMapping.StoreMapping,
                       lockOwnerId))
            {
                op.Do();
            }
        }
        /// <summary>
        /// Allows for update to a shard with the updates provided in the <paramref name="update"/> parameter.
        /// </summary>
        /// <param name="currentShard">Shard to be updated.</param>
        /// <param name="update">Updated properties of the Shard.</param>
        /// <returns>New Shard instance with updated information.</returns>
        internal Shard UpdateShard(Shard currentShard, ShardUpdate update)
        {
            Debug.Assert(currentShard != null);
            Debug.Assert(update != null);

            ExceptionUtils.EnsureShardBelongsToShardMap(
                this.Manager,
                this.ShardMap,
                currentShard,
                "UpdateShard",
                "Shard");

            // CONSIDER(wbasheer): Have refresh semantics for trivial case when nothing is modified.
            if (!update.IsAnyPropertySet(ShardUpdatedProperties.All))
            {
                return(currentShard);
            }

            DefaultStoreShard sNew = new DefaultStoreShard(
                currentShard.Id,
                Guid.NewGuid(),
                currentShard.ShardMapId,
                currentShard.Location,
                update.IsAnyPropertySet(ShardUpdatedProperties.Status) ? (int)update.Status : currentShard.StoreShard.Status);

            using (IStoreOperation op = this.Manager.StoreOperationFactory.CreateUpdateShardOperation(
                       this.Manager,
                       this.ShardMap.StoreShardMap,
                       currentShard.StoreShard,
                       sNew))
            {
                op.Do();
            }

            return(new Shard(this.Manager, this.ShardMap, sNew));
        }
Beispiel #8
0
        internal RangeMapping <TKey> Merge(RangeMapping <TKey> left, RangeMapping <TKey> right, Guid leftLockOwnerId, Guid rightLockOwnerId)
        {
            this.EnsureMappingBelongsToShardMap <RangeMapping <TKey> >(left, "Merge", "left");
            this.EnsureMappingBelongsToShardMap <RangeMapping <TKey> >(right, "Merge", "right");

            if (!left.Shard.Location.Equals(right.Shard.Location))
            {
                throw new ArgumentException(
                          StringUtils.FormatInvariant(
                              Errors._ShardMapping_MergeDifferentShards,
                              this.ShardMap.Name,
                              left.Shard.Location,
                              right.Shard.Location),
                          "left");
            }

            if (left.Range.Intersects(right.Range) || left.Range.High != right.Range.Low)
            {
                throw new ArgumentOutOfRangeException(
                          "left",
                          Errors._ShardMapping_MergeNotAdjacent);
            }

            if (left.Status != right.Status)
            {
                throw new ArgumentException(
                          StringUtils.FormatInvariant(
                              Errors._ShardMapping_DifferentStatus,
                              this.ShardMap.Name),
                          "left");
            }

            IStoreShard newShard = new DefaultStoreShard(
                left.Shard.StoreShard.Id,
                Guid.NewGuid(),
                left.Shard.StoreShard.ShardMapId,
                left.Shard.StoreShard.Location,
                left.Shard.StoreShard.Status);

            IStoreMapping mappingToRemoveLeft = new DefaultStoreMapping(
                left.StoreMapping.Id,
                left.StoreMapping.ShardMapId,
                newShard,
                left.StoreMapping.MinValue,
                left.StoreMapping.MaxValue,
                left.StoreMapping.Status,
                left.StoreMapping.LockOwnerId);

            IStoreMapping mappingToRemoveRight = new DefaultStoreMapping(
                right.StoreMapping.Id,
                right.StoreMapping.ShardMapId,
                newShard,
                right.StoreMapping.MinValue,
                right.StoreMapping.MaxValue,
                right.StoreMapping.Status,
                right.StoreMapping.LockOwnerId);

            IStoreMapping mappingToAdd = new DefaultStoreMapping(
                Guid.NewGuid(),
                newShard.ShardMapId,
                newShard,
                left.Range.Low.RawValue,
                right.Range.High.RawValue,
                (int)left.Status,
                leftLockOwnerId);

            using (IStoreOperation op = this.Manager.StoreOperationFactory.CreateReplaceMappingsOperation(
                       this.Manager,
                       StoreOperationCode.MergeMappings,
                       this.ShardMap.StoreShardMap,
                       new[]
            {
                new Tuple <IStoreMapping, Guid> (mappingToRemoveLeft, leftLockOwnerId),
                new Tuple <IStoreMapping, Guid> (mappingToRemoveRight, rightLockOwnerId)
            },
                       new[]
            {
                new Tuple <IStoreMapping, Guid>(mappingToAdd, leftLockOwnerId)
            }))
            {
                op.Do();
            }

            return(new RangeMapping <TKey>(this.Manager, this.ShardMap, mappingToAdd));
        }
Beispiel #9
0
        /// <summary>
        /// Splits the given mapping into 2 at the given key. The new mappings point to the same shard
        /// as the existing mapping.
        /// </summary>
        /// <param name="existingMapping">Given existing mapping.</param>
        /// <param name="splitAt">Split point.</param>
        /// <param name="lockOwnerId">Lock owner id of this mapping</param>
        /// <returns>Read-only collection of 2 new mappings thus created.</returns>
        internal IReadOnlyList <RangeMapping <TKey> > Split(RangeMapping <TKey> existingMapping, TKey splitAt, Guid lockOwnerId)
        {
            this.EnsureMappingBelongsToShardMap <RangeMapping <TKey> >(
                existingMapping,
                "Split",
                "existingMapping");

            ShardKey shardKey = new ShardKey(ShardKey.ShardKeyTypeFromType(typeof(TKey)), splitAt);

            if (!existingMapping.Range.Contains(shardKey) ||
                existingMapping.Range.Low == shardKey ||
                existingMapping.Range.High == shardKey)
            {
                throw new ArgumentOutOfRangeException(
                          "splitAt",
                          Errors._ShardMapping_SplitPointOutOfRange);
            }

            IStoreShard newShard = new DefaultStoreShard(
                existingMapping.Shard.StoreShard.Id,
                Guid.NewGuid(),
                existingMapping.ShardMapId,
                existingMapping.Shard.StoreShard.Location,
                existingMapping.Shard.StoreShard.Status);

            IStoreMapping mappingToRemove = new DefaultStoreMapping(
                existingMapping.StoreMapping.Id,
                existingMapping.StoreMapping.ShardMapId,
                newShard,
                existingMapping.StoreMapping.MinValue,
                existingMapping.StoreMapping.MaxValue,
                existingMapping.StoreMapping.Status,
                existingMapping.StoreMapping.LockOwnerId);

            IStoreMapping[] mappingsToAdd = new IStoreMapping[2]
            {
                new DefaultStoreMapping(
                    Guid.NewGuid(),
                    newShard.ShardMapId,
                    newShard,
                    existingMapping.Range.Low.RawValue,
                    shardKey.RawValue,
                    (int)existingMapping.Status,
                    lockOwnerId),
                new DefaultStoreMapping(
                    Guid.NewGuid(),
                    newShard.ShardMapId,
                    newShard,
                    shardKey.RawValue,
                    existingMapping.Range.High.RawValue,
                    (int)existingMapping.Status,
                    lockOwnerId)
            };

            using (IStoreOperation op = this.Manager.StoreOperationFactory.CreateReplaceMappingsOperation(
                       this.Manager,
                       StoreOperationCode.SplitMapping,
                       this.ShardMap.StoreShardMap,
                       new[] { new Tuple <IStoreMapping, Guid>(mappingToRemove, lockOwnerId) },
                       mappingsToAdd.Select(mappingToAdd => new Tuple <IStoreMapping, Guid>(mappingToAdd, lockOwnerId)).ToArray()))
            {
                op.Do();
            }

            return(mappingsToAdd
                   .Select(m => new RangeMapping <TKey>(this.Manager, this.ShardMap, m))
                   .ToList()
                   .AsReadOnly());
        }
Beispiel #10
0
        /// <summary>
        /// Allows for update to a mapping with the updates provided in
        /// the <paramref name="update"/> parameter.
        /// </summary>
        /// <param name="currentMapping">Mapping being updated.</param>
        /// <param name="update">Updated properties of the Shard.</param>
        /// <param name="constructMapping">Delegate to construct a mapping object.</param>
        /// <param name="statusAsInt">Delegate to get the mapping status as an integer value.</param>
        /// <param name="intAsStatus">Delegate to get the mapping status from an integer value.</param>
        /// <param name="lockOwnerId">Lock owner id of this mapping</param>
        /// <param name="options">Options for validation operations to perform on opened connection to affected shard.</param>
        /// <returns>New instance of mapping with updated information.</returns>
        protected TMapping Update <TMapping, TUpdate, TStatus>(
            TMapping currentMapping,
            TUpdate update,
            Func <ShardMapManager, ShardMap, IStoreMapping, TMapping> constructMapping,
            Func <TStatus, int> statusAsInt,
            Func <int, TStatus> intAsStatus,
            Guid lockOwnerId       = default(Guid),
            MappingOptions options = MappingOptions.Validate)
            where TUpdate : class, IMappingUpdate <TStatus>
            where TMapping : class, IShardProvider, IMappingInfoProvider
            where TStatus : struct
        {
            Debug.Assert(currentMapping != null);
            Debug.Assert(update != null);

            this.EnsureMappingBelongsToShardMap <TMapping>(currentMapping, "Update", "currentMapping");

            IMappingUpdate <TStatus> mu = update as IMappingUpdate <TStatus>;

            // CONSIDER(wbasheer): Have refresh semantics for trivial case when nothing is modified.
            if (!mu.IsAnyPropertySet(MappingUpdatedProperties.All))
            {
                return(currentMapping);
            }

            bool shardChanged = mu.IsAnyPropertySet(MappingUpdatedProperties.Shard) && !mu.Shard.Equals(currentMapping.ShardInfo);

            // Ensure that shard belongs to current shard map.
            if (shardChanged)
            {
                ExceptionUtils.EnsureShardBelongsToShardMap(
                    this.Manager,
                    this.ShardMap,
                    mu.Shard,
                    "UpdateMapping",
                    currentMapping.Kind == MappingKind.PointMapping ? "PointMapping" : "RangeMapping");
            }

            IStoreShard originalShard = new DefaultStoreShard(
                currentMapping.ShardInfo.Id,
                Guid.NewGuid(),
                currentMapping.ShardInfo.StoreShard.ShardMapId,
                currentMapping.ShardInfo.StoreShard.Location,
                currentMapping.ShardInfo.StoreShard.Status);

            IStoreMapping originalMapping = new DefaultStoreMapping(
                currentMapping.StoreMapping.Id,
                currentMapping.ShardMapId,
                originalShard,
                currentMapping.StoreMapping.MinValue,
                currentMapping.StoreMapping.MaxValue,
                currentMapping.StoreMapping.Status,
                lockOwnerId);

            IStoreShard updatedShard;

            if (shardChanged)
            {
                updatedShard = new DefaultStoreShard(
                    update.Shard.ShardInfo.Id,
                    Guid.NewGuid(),
                    update.Shard.ShardInfo.StoreShard.ShardMapId,
                    update.Shard.ShardInfo.StoreShard.Location,
                    update.Shard.ShardInfo.StoreShard.Status);
            }
            else
            {
                updatedShard = originalShard;
            }

            IStoreMapping updatedMapping = new DefaultStoreMapping(
                Guid.NewGuid(),
                currentMapping.ShardMapId,
                updatedShard,
                currentMapping.StoreMapping.MinValue,
                currentMapping.StoreMapping.MaxValue,
                mu.IsAnyPropertySet(MappingUpdatedProperties.Status) ?
                statusAsInt(update.Status) :
                currentMapping.StoreMapping.Status,
                lockOwnerId);

            bool fromOnlineToOffline = mu.IsMappingBeingTakenOffline(intAsStatus(currentMapping.StoreMapping.Status));

            StoreOperationCode opCode;

            if (fromOnlineToOffline)
            {
                opCode = currentMapping.Kind == MappingKind.PointMapping ?
                         StoreOperationCode.UpdatePointMappingWithOffline :
                         StoreOperationCode.UpdateRangeMappingWithOffline;
            }
            else
            {
                opCode = currentMapping.Kind == MappingKind.PointMapping ?
                         StoreOperationCode.UpdatePointMapping :
                         StoreOperationCode.UpdateRangeMapping;
            }

            var killConnection = options == MappingOptions.Validate;

            using (IStoreOperation op = this.Manager.StoreOperationFactory.CreateUpdateMappingOperation(
                       this.Manager,
                       opCode,
                       this.ShardMap.StoreShardMap,
                       originalMapping,
                       updatedMapping,
                       this.ShardMap.ApplicationNameSuffix,
                       lockOwnerId,
                       killConnection))
            {
                op.Do();
            }

            return(constructMapping(this.Manager, this.ShardMap, updatedMapping));
        }
 internal StoreOperationDecorator(IStoreOperation inner)
 {
     this.inner = inner;
 }
Beispiel #12
0
        /// <summary>
        /// Performs the store operation.
        /// </summary>
        /// <returns>Results of the operation.</returns>
        public IStoreResults Do()
        {
            IStoreResults result;

            try
            {
                do
                {
                    result = this.Manager.RetryPolicy.ExecuteAction(() =>
                    {
                        IStoreResults r;

                        try
                        {
                            // Open connections & acquire the necessary app locks.
                            this.EstablishConnnections(false);

                            // Execute & commit the Global pre-Local operations.
                            r = this.DoGlobalPreLocal();

                            // If pending operation, we need to release the locks.
                            if (!r.StoreOperations.Any())
                            {
                                // Execute & commit the Local operations on source.
                                this.DoLocalSource();

                                // Execute & commit the Local operations on target.
                                this.DoLocalTarget();

                                // Execute & commit the Global post-Local operations.
                                r = this.DoGlobalPostLocal();

                                Debug.Assert(r != null);

                                _operationState = StoreOperationState.DoEnd;
                            }
                        }
                        finally
                        {
                            // Figure out the maximum of the progress made yet during Do operation.
                            if (_maxDoState < _operationState)
                            {
                                _maxDoState = _operationState;
                            }

                            // Close connections & release the necessary app locks.
                            this.TeardownConnections();
                        }

                        return(r);
                    });

                    // If pending operation, deserialize the pending operation and perform Undo.
                    if (result.StoreOperations.Any())
                    {
                        Debug.Assert(result.StoreOperations.Count() == 1);

                        using (IStoreOperation op = this.Manager.StoreOperationFactory.FromLogEntry(this.Manager, result.StoreOperations.Single()))
                        {
                            op.Undo();
                        }
                    }
                }while (result.StoreOperations.Any());
            }
            catch (StoreException se)
            {
                // If store exception was thrown, we will attempt to undo the current operation.
                this.AttemptUndo();

                throw this.OnStoreException(se, _operationState);
            }
            catch (ShardManagementException)
            {
                // If shard map manager exception was thrown, we will attempt to undo the operation.
                this.AttemptUndo();

                throw;
            }

            Debug.Assert(result != null);
            return(result);
        }
Beispiel #13
0
 internal StoreOperationDecorator(IStoreOperation inner)
 {
     this.inner = inner;
 }