/// <summary>
        /// Performs binary search on the cached mappings and returns the
        /// index of mapping object which contains the given key.
        /// </summary>
        /// <param name="key">Input key.</param>
        /// <returns>Index of range in the cache which contains the given key.</returns>
        private int GetIndexOfMappingContainingShardKey(ShardKey key)
        {
            IList <ShardRange> rangeKeys = _mappingsByRange.Keys;

            int lb = 0;
            int ub = rangeKeys.Count - 1;

            while (lb <= ub)
            {
                int mid = lb + (ub - lb) / 2;

                ShardRange current = rangeKeys[mid];

                if (current.Contains(key))
                {
                    return(mid);
                }
                else if (key < current.Low)
                {
                    ub = mid - 1;
                }
                else
                {
                    lb = mid + 1;
                }
            }

            return(-1);
        }
        /// <summary>
        /// Add or update a mapping in cache.
        /// </summary>
        /// <param name="sm">Storage mapping object.</param>
        /// <param name="policy">Policy to use for preexisting cache entries during update.</param>
        internal override void AddOrUpdate(IStoreMapping sm, CacheStoreMappingUpdatePolicy policy)
        {
            ShardKey min = ShardKey.FromRawValue(this.KeyType, sm.MinValue);

            // Make range out of mapping key ranges.
            ShardRange range = new ShardRange(
                min,
                ShardKey.FromRawValue(this.KeyType, sm.MaxValue));

            CacheMapping       cm;
            ICacheStoreMapping csm;

            IStoreMapping smDummy;

            // We need to update TTL and update entry if:
            // a) We are in update TTL mode
            // b) Mapping exists and same as the one we already have
            // c) Entry is beyond the TTL limit
            if (policy == CacheStoreMappingUpdatePolicy.UpdateTimeToLive &&
                (csm = this.LookupByKey(min, out smDummy)) != null &&
                csm.Mapping.Id == sm.Id /*&&
                                         * TimerUtils.ElapsedMillisecondsSince(csm.CreationTime) >= csm.TimeToLiveMilliseconds */)
            {
                cm = new CacheMapping(sm, CacheMapper.CalculateNewTimeToLiveMilliseconds(csm));
            }
            else
            {
                cm = new CacheMapping(sm);
            }

            this.Remove(sm);

            // Add the entry to lookup table by Range.
            _mappingsByRange.Add(range, cm);
        }
        /// <summary>
        /// Performs binary search on the cached mappings and returns the
        /// index of mapping object whose min-value is less than and closest
        /// to given key value.
        /// </summary>
        /// <param name="key">Input key.</param>
        /// <returns>Index of range in the cache which contains the given key.</returns>
        private int GetIndexOfMappingWithClosestMaxGreaterThanOrEqualToMaxKey(ShardKey key)
        {
            IList <ShardRange> rangeKeys = _mappingsByRange.Keys;

            int lb = 0;
            int ub = rangeKeys.Count - 1;

            while (lb <= ub)
            {
                int mid = lb + (ub - lb) / 2;

                ShardRange current = rangeKeys[mid];

                if (current.High > key)
                {
                    if (current.Low <= key)
                    {
                        return(mid);
                    }
                    else
                    {
                        ub = mid - 1;
                    }
                }
                else
                {
                    lb = mid + 1;
                }
            }

            return(lb);
        }
        /// <summary>
        /// Asynchronously opens a regular <see cref="SqlConnection"/> to the shard
        /// to which the specified key value is mapped.
        /// </summary>
        /// <typeparam name="TKey">Type of the key.</typeparam>
        /// <param name="key">Input key value.</param>
        /// <param name="connectionString">
        /// Connection string with credential information such as SQL Server credentials or Integrated Security settings.
        /// The hostname of the server and the database name for the shard are obtained from the lookup operation for key.
        /// </param>
        /// <param name="options">Options for validation operations to perform on opened connection.</param>
        /// <returns>A Task encapsulating an opened SqlConnection.</returns>
        /// <remarks>
        /// Note that the <see cref="SqlConnection"/> object returned by this call is not protected against transient faults.
        /// Callers should follow best practices to protect the connection against transient faults
        /// in their application code, e.g., by using the transient fault handling
        /// functionality in the Enterprise Library from Microsoft Patterns and Practices team.
        /// This call only works if there is a single default mapping.
        /// </remarks>
        public Task <SqlConnection> OpenConnectionForKeyAsync <TKey>(
            TKey key,
            string connectionString,
            ConnectionOptions options)
        {
            ExceptionUtils.DisallowNullArgument(connectionString, "connectionString");

            Debug.Assert(this.StoreShardMap.KeyType != ShardKeyType.None);

            using (ActivityIdScope activityIdScope = new ActivityIdScope(Guid.NewGuid()))
            {
                IShardMapper <TKey> mapper = this.GetMapper <TKey>();

                if (mapper == null)
                {
                    throw new ArgumentException(
                              StringUtils.FormatInvariant(
                                  Errors._ShardMap_OpenConnectionForKey_KeyTypeNotSupported,
                                  typeof(TKey),
                                  this.StoreShardMap.Name,
                                  ShardKey.TypeFromShardKeyType(this.StoreShardMap.KeyType)),
                              "key");
                }

                Debug.Assert(mapper != null);

                return(mapper.OpenConnectionForKeyAsync(key, connectionString, options));
            }
        }
Beispiel #5
0
        /// <summary>
        /// Converts IStoreShardMap to ShardMap.
        /// </summary>
        /// <param name="manager">Reference to shard map manager.</param>
        /// <param name="ssm">Storage representation for ShardMap.</param>
        /// <returns>ShardMap object corresponding to storange representation.</returns>
        internal static ShardMap CreateShardMapFromStoreShardMap(
            ShardMapManager manager,
            IStoreShardMap ssm)
        {
            switch (ssm.MapType)
            {
            case ShardMapType.List:
                // Create ListShardMap<TKey>
                return((ShardMap)Activator.CreateInstance(
                           typeof(ListShardMap <>).MakeGenericType(
                               ShardKey.TypeFromShardKeyType(ssm.KeyType)),
                           BindingFlags.NonPublic | BindingFlags.Instance,
                           null,
                           new object[] { manager, ssm },
                           CultureInfo.InvariantCulture));

            default:
                Debug.Assert(ssm.MapType == ShardMapType.Range);
                // Create RangeShardMap<TKey>
                return((ShardMap)Activator.CreateInstance(
                           typeof(RangeShardMap <>).MakeGenericType(
                               ShardKey.TypeFromShardKeyType(ssm.KeyType)),
                           BindingFlags.NonPublic | BindingFlags.Instance,
                           null,
                           new object[] { manager, ssm },
                           CultureInfo.InvariantCulture));
            }
        }
        /// <summary>
        /// Add or update a mapping in cache.
        /// </summary>
        /// <param name="sm">Storage mapping object.</param>
        /// <param name="policy">Policy to use for preexisting cache entries during update.</param>
        internal override void AddOrUpdate(IStoreMapping sm, CacheStoreMappingUpdatePolicy policy)
        {
            // Make key out of mapping key.
            ShardKey key = ShardKey.FromRawValue(this.KeyType, sm.MinValue);

            CacheMapping cm;

            // We need to update TTL and update entry if:
            // a) We are in update TTL mode
            // b) Mapping exists and same as the one we already have
            // c) Entry is beyond the TTL limit
            if (policy == CacheStoreMappingUpdatePolicy.UpdateTimeToLive &&
                _mappingsByKey.TryGetValue(key, out cm) &&
                cm.Mapping.Id == sm.Id /*&&
                                        * TimerUtils.ElapsedMillisecondsSince(cm.CreationTime) >= cm.TimeToLiveMilliseconds */)
            {
                cm = new CacheMapping(sm, CacheMapper.CalculateNewTimeToLiveMilliseconds(cm));
            }
            else
            {
                cm = new CacheMapping(sm);
            }

            // Remove existing entry.
            this.Remove(sm);

            // Add the entry to lookup table by Key.
            _mappingsByKey.Add(key, cm);
        }
        /// <summary>
        /// Looks up a mapping by key.
        /// </summary>
        /// <param name="key">Key value.</param>
        /// <param name="sm">Storage mapping object.</param>
        /// <returns>Mapping object which has the key value.</returns>
        internal override ICacheStoreMapping LookupByKey(ShardKey key, out IStoreMapping sm)
        {
            CacheMapping cm;

            // Performs a binary search in the ranges for key value and
            // then return the result.
            int rangeIndex = this.GetIndexOfMappingContainingShardKey(key);

            if (rangeIndex != -1)
            {
                ShardRange range = _mappingsByRange.Keys[rangeIndex];

                cm = _mappingsByRange[range];

                // DEVNOTE(wbasheer): We should clone the mapping.
                sm = cm.Mapping;
            }
            else
            {
                cm = null;
                sm = null;
            }

            return(cm);
        }
        /// <summary>
        /// Arguments used to create a point mapping.
        /// </summary>
        /// <param name="point">Point value being mapped.</param>
        /// <param name="shard">Shard used as the mapping target.</param>
        /// <param name="status">Status of the mapping.</param>
        public PointMappingCreationInfo(TKey point, Shard shard, MappingStatus status)
        {
            ExceptionUtils.DisallowNullArgument(shard, "shard");
            this.Value  = point;
            this.Shard  = shard;
            this.Status = status;

            this.Key = new ShardKey(ShardKey.ShardKeyTypeFromType(typeof(TKey)), point);
        }
        /// <summary>
        /// Looks up the key value and returns the corresponding mapping.
        /// </summary>
        /// <typeparam name="TMapping">Mapping type.</typeparam>
        /// <typeparam name="TKey">Key type.</typeparam>
        /// <param name="key">Input key value.</param>
        /// <param name="useCache">Whether to use cache for lookups.</param>
        /// <param name="constructMapping">Delegate to construct a mapping object.</param>
        /// <param name="errorCategory">Category under which errors must be thrown.</param>
        /// <returns>Mapping that contains the key value.</returns>
        protected TMapping Lookup <TMapping, TKey>(
            TKey key,
            bool useCache,
            Func <ShardMapManager, ShardMap, IStoreMapping, TMapping> constructMapping,
            ShardManagementErrorCategory errorCategory)
            where TMapping : class, IShardProvider
        {
            ShardKey sk = new ShardKey(ShardKey.ShardKeyTypeFromType(typeof(TKey)), key);

            if (useCache)
            {
                ICacheStoreMapping cachedMapping = this.Manager.Cache.LookupMappingByKey(this.ShardMap.StoreShardMap, sk);

                if (cachedMapping != null)
                {
                    return(constructMapping(this.Manager, this.ShardMap, cachedMapping.Mapping));
                }
            }

            // Cache-miss, find mapping for given key in GSM.
            TMapping m = null;

            IStoreResults gsmResult;

            Stopwatch stopwatch = Stopwatch.StartNew();

            using (IStoreOperationGlobal op = this.Manager.StoreOperationFactory.CreateFindMappingByKeyGlobalOperation(
                       this.Manager,
                       "Lookup",
                       this.ShardMap.StoreShardMap,
                       sk,
                       CacheStoreMappingUpdatePolicy.OverwriteExisting,
                       errorCategory,
                       true,
                       false))
            {
                gsmResult = op.Do();
            }

            stopwatch.Stop();

            Tracer.TraceVerbose(
                TraceSourceConstants.ComponentNames.BaseShardMapper,
                "Lookup",
                "Lookup key from GSM complete; Key type : {0}; Result: {1}; Duration: {2}",
                typeof(TKey),
                gsmResult.Result,
                stopwatch.Elapsed);

            // If we could not locate the mapping, we return null and do nothing here.
            if (gsmResult.Result != StoreResult.MappingNotFoundForKey)
            {
                return(gsmResult.StoreMappings.Select(sm => constructMapping(this.Manager, this.ShardMap, sm)).Single());
            }

            return(m);
        }
Beispiel #10
0
        /// <summary>
        /// Calculates the hash code for the object.
        /// </summary>
        /// <returns>Hash code for the object.</returns>
        private int CalculateHashCode()
        {
            int h;

            h = ShardKey.QPHash(this.Protocol.GetHashCode(), this.DataSource.ToUpperInvariant().GetHashCode());
            h = ShardKey.QPHash(h, this.Port.GetHashCode());
            h = ShardKey.QPHash(h, this.Database.ToUpperInvariant().GetHashCode());

            return(h);
        }
Beispiel #11
0
        /// <summary>
        /// Constructs range based on its low boundary value. The low boundary value is
        /// set to the one specified in <paramref name="low"/> while the
        /// high boundary value is set to maximum possible value i.e. +infinity.
        /// </summary>
        /// <param name="low">Low boundary value (inclusive).</param>
        public Range(TKey low)
        {
            ShardKeyType k = ShardKey.ShardKeyTypeFromType(typeof(TKey));

            _r = new ShardRange(
                new ShardKey(k, low),
                new ShardKey(k, null));

            this.Low       = low;
            this.HighIsMax = true;
        }
        /// <summary>
        /// Remove a mapping object from cache.
        /// </summary>
        /// <param name="sm">Storage maping object.</param>
        internal override void Remove(IStoreMapping sm)
        {
            // Make key value out of mapping key.
            ShardKey key = ShardKey.FromRawValue(this.KeyType, sm.MinValue);

            // Remove existing entry.
            if (_mappingsByKey.ContainsKey(key))
            {
                _mappingsByKey.Remove(key);
            }
        }
Beispiel #13
0
        /// <summary>
        /// Constructs range based on its low and high boundary values.
        /// </summary>
        /// <param name="low">Low boundary value (inclusive).</param>
        /// <param name="high">High boundary value (exclusive).</param>
        public Range(TKey low, TKey high)
        {
            ShardKeyType k = ShardKey.ShardKeyTypeFromType(typeof(TKey));

            _r = new ShardRange(
                new ShardKey(k, low),
                new ShardKey(k, high));

            this.Low  = low;
            this.High = high;
        }
        public RangeMappingCreationInfo(Range <TKey> value, Shard shard, MappingStatus status)
        {
            ExceptionUtils.DisallowNullArgument(value, "value");
            ExceptionUtils.DisallowNullArgument(shard, "shard");
            this.Value  = value;
            this.Shard  = shard;
            this.Status = status;

            this.Range = new ShardRange(
                new ShardKey(ShardKey.ShardKeyTypeFromType(typeof(TKey)), value.Low),
                new ShardKey(ShardKey.ShardKeyTypeFromType(typeof(TKey)), value.HighIsMax ? null : (object)value.High));
        }
Beispiel #15
0
 /// <summary>
 /// Raise conversion exception.
 /// </summary>
 /// <typeparam name="TKey">Key type.</typeparam>
 /// <param name="ssm">Shard map whose conversion failed.</param>
 /// <param name="targetKind">Requested type of shard map.</param>
 private static ShardManagementException GetConversionException <TKey>(IStoreShardMap ssm, string targetKind)
 {
     return(new ShardManagementException(
                ShardManagementErrorCategory.ShardMapManager,
                ShardManagementErrorCode.ShardMapTypeConversionError,
                Errors._ShardMapExtensions_AsTypedShardMap_ConversionFailure,
                ssm.Name,
                targetKind,
                typeof(TKey).Name,
                ssm.MapType.ToString(),
                ssm.KeyType == ShardKeyType.None ? string.Empty : ShardKey.TypeFromShardKeyType(ssm.KeyType).Name));
 }
Beispiel #16
0
        /// <summary>Returns the intersection of two ranges.</summary>
        /// <param name="range">Range to intersect with.</param>
        /// <returns>
        /// The intersection of the current range and the specified range, null if ranges dont intersect.
        /// </returns>
        internal ShardRange Intersect(ShardRange range)
        {
            ExceptionUtils.DisallowNullArgument(range, "range");

            ShardKey intersectLow  = ShardKey.Max(Low, range.Low);
            ShardKey intersectHigh = ShardKey.Min(High, range.High);

            if (intersectLow >= intersectHigh)
            {
                return(null);
            }

            return(new ShardRange(intersectLow, intersectHigh));
        }
        /// <summary>
        /// Asynchronously finds the mapping in store for OpenConnectionForKey operation.
        /// </summary>
        /// <param name="sk">Key to find.</param>
        /// <param name="policy">Cache update policy.</param>
        /// <param name="errorCategory">Error category.</param>
        /// <returns>Task with the Mapping corresponding to the given key if found as the result.</returns>
        private async Task <IStoreMapping> LookupMappingForOpenConnectionForKeyAsync(
            ShardKey sk,
            CacheStoreMappingUpdatePolicy policy,
            ShardManagementErrorCategory errorCategory)
        {
            IStoreResults gsmResult;

            Stopwatch stopwatch = Stopwatch.StartNew();

            using (IStoreOperationGlobal op = this.Manager.StoreOperationFactory.CreateFindMappingByKeyGlobalOperation(
                       this.Manager,
                       "Lookup",
                       this.ShardMap.StoreShardMap,
                       sk,
                       policy,
                       errorCategory,
                       true,
                       false))
            {
                gsmResult = await op.DoAsync().ConfigureAwait(false);
            }

            stopwatch.Stop();

            Tracer.TraceVerbose(
                TraceSourceConstants.ComponentNames.BaseShardMapper,
                "LookupMappingForOpenConnectionForKeyAsync",
                "Lookup key from GSM complete; Key type : {0}; Result: {1}; Duration: {2}",
                sk.DataType,
                gsmResult.Result,
                stopwatch.Elapsed);

            // If we could not locate the mapping, we throw.
            if (gsmResult.Result == StoreResult.MappingNotFoundForKey)
            {
                throw new ShardManagementException(
                          errorCategory,
                          ShardManagementErrorCode.MappingNotFoundForKey,
                          Errors._Store_ShardMapper_MappingNotFoundForKeyGlobal,
                          this.ShardMap.Name,
                          StoreOperationRequestBuilder.SpFindShardMappingByKeyGlobal,
                          "LookupMappingForOpenConnectionForKeyAsync");
            }
            else
            {
                return(gsmResult.StoreMappings.Single());
            }
        }
        /// <summary>
        /// Gets all the mappings that exist within given range.
        /// </summary>
        /// <param name="range">Optional range value, if null, we cover everything.</param>
        /// <param name="shard">Optional shard parameter, if null, we cover all shards.</param>
        /// <param name="constructMapping">Delegate to construct a mapping object.</param>
        /// <param name="errorCategory">Category under which errors will be posted.</param>
        /// <param name="mappingType">Name of mapping type.</param>
        /// <returns>Read-only collection of mappings that overlap with given range.</returns>
        protected IReadOnlyList <TMapping> GetMappingsForRange <TMapping, TKey>(
            Range <TKey> range,
            Shard shard,
            Func <ShardMapManager, ShardMap, IStoreMapping, TMapping> constructMapping,
            ShardManagementErrorCategory errorCategory,
            string mappingType)
            where TMapping : class
        {
            ShardRange sr = null;

            if (shard != null)
            {
                ExceptionUtils.EnsureShardBelongsToShardMap(
                    this.Manager,
                    this.ShardMap,
                    shard,
                    "GetMappings",
                    mappingType);
            }

            if (range != null)
            {
                sr = new ShardRange(
                    new ShardKey(ShardKey.ShardKeyTypeFromType(typeof(TKey)), range.Low),
                    new ShardKey(ShardKey.ShardKeyTypeFromType(typeof(TKey)), range.HighIsMax ? null : (object)range.High));
            }

            IStoreResults result;

            using (IStoreOperationGlobal op = this.Manager.StoreOperationFactory.CreateGetMappingsByRangeGlobalOperation(
                       this.Manager,
                       "GetMappingsForRange",
                       this.ShardMap.StoreShardMap,
                       shard != null ? shard.StoreShard : null,
                       sr,
                       errorCategory,
                       true, // Always cache.
                       false))
            {
                result = op.Do();
            }

            return(result.StoreMappings
                   .Select(sm => constructMapping(this.Manager, this.ShardMap, sm))
                   .ToList()
                   .AsReadOnly());
        }
        /// <summary>
        /// Looks up a mapping by key.
        /// </summary>
        /// <param name="key">Key value.</param>
        /// <param name="sm">Storage mapping object.</param>
        /// <returns>Mapping object which has the key value.</returns>
        internal override ICacheStoreMapping LookupByKey(ShardKey key, out IStoreMapping sm)
        {
            CacheMapping cm;

            _mappingsByKey.TryGetValue(key, out cm);

            if (cm != null)
            {
                sm = cm.Mapping;
            }
            else
            {
                sm = null;
            }

            return(cm);
        }
        /// <summary>
        /// Internal constructor used for deserialization from store representation of
        /// the mapping object.
        /// </summary>
        /// <param name="manager">Owning ShardMapManager.</param>
        /// <param name="shardMap">Owning shard map.</param>
        /// <param name="mapping">Storage representation of the mapping.</param>
        internal PointMapping(
            ShardMapManager manager,
            ShardMap shardMap,
            IStoreMapping mapping)
        {
            Debug.Assert(manager != null);
            this.Manager = manager;

            Debug.Assert(mapping != null);
            Debug.Assert(mapping.ShardMapId != default(Guid));
            Debug.Assert(mapping.StoreShard.ShardMapId != default(Guid));
            this.StoreMapping = mapping;

            _shard = new Shard(this.Manager, shardMap, mapping.StoreShard);

            this.Key   = ShardKey.FromRawValue(ShardKey.ShardKeyTypeFromType(typeof(TKey)), mapping.MinValue);
            this.Value = (TKey)this.Key.Value;
        }
        /// <summary>
        /// Creates a list based <see cref="ListShardMap{TKey}"/>.
        /// </summary>
        /// <typeparam name="TKey">Type of keys.</typeparam>
        /// <param name="shardMapName">Name of shard map.</param>
        /// <returns>List shard map with the specified name.</returns>
        public ListShardMap <TKey> CreateListShardMap <TKey>(string shardMapName)
        {
            ShardMapManager.ValidateShardMapName(shardMapName);

            using (ActivityIdScope activityIdScope = new ActivityIdScope(Guid.NewGuid()))
            {
                DefaultStoreShardMap dssm = new DefaultStoreShardMap(
                    Guid.NewGuid(),
                    shardMapName,
                    ShardMapType.List,
                    ShardKey.ShardKeyTypeFromType(typeof(TKey)));

                ListShardMap <TKey> listShardMap = new ListShardMap <TKey>(this, dssm);

                Tracer.TraceInfo(
                    TraceSourceConstants.ComponentNames.ShardMapManager,
                    "CreateListShardMap",
                    "Start; ShardMap: {0}",
                    shardMapName);

                Stopwatch stopwatch = Stopwatch.StartNew();

                this.AddShardMapToStore("CreateListShardMap", dssm);

                stopwatch.Stop();

                Tracer.TraceInfo(
                    TraceSourceConstants.ComponentNames.ShardMapManager,
                    "CreateListShardMap",
                    "Added ShardMap to Store; ShardMap: {0} Duration: {1}",
                    shardMapName,
                    stopwatch.Elapsed);

                Tracer.TraceInfo(
                    TraceSourceConstants.ComponentNames.ShardMapManager,
                    "CreateListShardMap",
                    "Complete; ShardMap: {0} Duration: {1}",
                    shardMapName,
                    stopwatch.Elapsed);

                return(listShardMap);
            }
        }
Beispiel #22
0
 /// <summary>
 /// Constructs request for obtaining mapping from GSM based on given key.
 /// </summary>
 /// <param name="shardMapManager">Shard map manager.</param>
 /// <param name="operationName">Operation being executed.</param>
 /// <param name="shardMap">Local shard map.</param>
 /// <param name="key">Key for lookup operation.</param>
 /// <param name="policy">Policy for cache update.</param>
 /// <param name="errorCategory">Error category.</param>
 /// <param name="cacheResults">Whether to cache the results of the operation.</param>
 /// <param name="ignoreFailure">Ignore shard map not found error.</param>
 protected internal FindMappingByKeyGlobalOperation(
     ShardMapManager shardMapManager,
     string operationName,
     IStoreShardMap shardMap,
     ShardKey key,
     CacheStoreMappingUpdatePolicy policy,
     ShardManagementErrorCategory errorCategory,
     bool cacheResults,
     bool ignoreFailure) :
     base(shardMapManager.Credentials, shardMapManager.RetryPolicy, operationName)
 {
     _manager       = shardMapManager;
     _shardMap      = shardMap;
     _key           = key;
     _policy        = policy;
     _errorCategory = errorCategory;
     _cacheResults  = cacheResults;
     _ignoreFailure = ignoreFailure;
 }
 /// <summary>
 /// Constructs request for obtaining mapping from GSM based on given key.
 /// </summary>
 /// <param name="shardMapManager">Shard map manager.</param>
 /// <param name="operationName">Operation being executed.</param>
 /// <param name="shardMap">Local shard map.</param>
 /// <param name="key">Key for lookup operation.</param>
 /// <param name="policy">Policy for cache update.</param>
 /// <param name="errorCategory">Error category.</param>
 /// <param name="cacheResults">Whether to cache the results of the operation.</param>
 /// <param name="ignoreFailure">Ignore shard map not found error.</param>
 /// <returns>The store operation.</returns>
 public virtual IStoreOperationGlobal CreateFindMappingByKeyGlobalOperation(
     ShardMapManager shardMapManager,
     string operationName,
     IStoreShardMap shardMap,
     ShardKey key,
     CacheStoreMappingUpdatePolicy policy,
     ShardManagementErrorCategory errorCategory,
     bool cacheResults,
     bool ignoreFailure)
 {
     return(new FindMappingByKeyGlobalOperation(
                shardMapManager,
                operationName,
                shardMap,
                key,
                policy,
                errorCategory,
                cacheResults,
                ignoreFailure));
 }
Beispiel #24
0
        /// <summary>Constructs a shard range from low boundary (inclusive) to high high boundary (exclusive)</summary>
        /// <param name="low">Low boundary (inclusive)</param>
        /// <param name="high">High boundary (exclusive)</param>
        public ShardRange(ShardKey low, ShardKey high)
        {
            ExceptionUtils.DisallowNullArgument(low, "low");
            ExceptionUtils.DisallowNullArgument(high, "high");

            if (low >= high)
            {
                throw new ArgumentOutOfRangeException(
                          "low",
                          low,
                          string.Format(
                              Errors._ShardRange_LowGreaterThanOrEqualToHigh,
                              low,
                              high));
            }

            this.Low     = low;
            this.High    = high;
            this.KeyType = Low.KeyType;
            _hashCode    = this.CalculateHashCode();
        }
        /// <summary>
        /// Internal constructor used for deserialization from store representation of
        /// the mapping object.
        /// </summary>
        /// <param name="manager">Owning ShardMapManager.</param>
        /// <param name="shardMap">Owning shard map.</param>
        /// <param name="mapping">Storage representation of the mapping.</param>
        internal RangeMapping(
            ShardMapManager manager,
            ShardMap shardMap,
            IStoreMapping mapping)
        {
            Debug.Assert(manager != null);
            this.Manager = manager;

            Debug.Assert(mapping != null);
            Debug.Assert(mapping.ShardMapId != default(Guid));
            Debug.Assert(mapping.StoreShard.ShardMapId != default(Guid));
            this.StoreMapping = mapping;

            _shard = new Shard(this.Manager, shardMap, mapping.StoreShard);

            this.Range = new ShardRange(
                ShardKey.FromRawValue(ShardKey.ShardKeyTypeFromType(typeof(TKey)), mapping.MinValue),
                ShardKey.FromRawValue(ShardKey.ShardKeyTypeFromType(typeof(TKey)), mapping.MaxValue));

            this.Value = this.Range.High.IsMax ?
                         new Range <TKey>(this.Range.Low.GetValue <TKey>()) :
                         new Range <TKey>(this.Range.Low.GetValue <TKey>(), this.Range.High.GetValue <TKey>());
        }
 /// <summary>
 /// Looks up a mapping by key.
 /// </summary>
 /// <param name="key">Key value.</param>
 /// <param name="sm">Storage mapping object.</param>
 /// <returns>Mapping object which has the key value.</returns>
 internal abstract ICacheStoreMapping LookupByKey(ShardKey key, out IStoreMapping sm);
        /// <summary>
        /// Remove a mapping object from cache.
        /// </summary>
        /// <param name="sm">Storage maping object.</param>
        /// <remarks>
        /// Q: Do we ever need to remove multiple entries from the cache which cover the same range?
        /// A: Yes. Imagine that you have some stale mapping in the cache, user just simply performs
        /// an AddRangeMapping operation on a subset of stale mapping range, now you should remove the
        /// stale mapping.
        /// </remarks>
        internal override void Remove(IStoreMapping sm)
        {
            ShardKey minKey = ShardKey.FromRawValue(this.KeyType, sm.MinValue);
            ShardKey maxKey = ShardKey.FromRawValue(this.KeyType, sm.MaxValue);

            // Make range out of mapping key.
            ShardRange range = new ShardRange(minKey, maxKey);

            // Fast code path, where cache does contain the exact range.
            if (_mappingsByRange.ContainsKey(range))
            {
                _mappingsByRange.Remove(range);
            }
            else
            {
                int indexMin = this.GetIndexOfMappingWithClosestMinLessThanOrEqualToMinKey(minKey);
                int indexMax = this.GetIndexOfMappingWithClosestMaxGreaterThanOrEqualToMaxKey(maxKey);

                if (indexMin < 0)
                {
                    indexMin = 0;
                }

                if (indexMax >= _mappingsByRange.Keys.Count)
                {
                    indexMax = _mappingsByRange.Keys.Count - 1;
                }

                // Find first range with max greater than min key.
                for (; indexMin <= indexMax; indexMin++)
                {
                    ShardRange currentRange = _mappingsByRange.Keys[indexMin];
                    if (currentRange.High > minKey)
                    {
                        break;
                    }
                }

                // Find first range with min less than or equal to max key.
                for (; indexMax >= indexMin; indexMax--)
                {
                    ShardRange currentRange = _mappingsByRange.Keys[indexMax];
                    if (currentRange.Low <= maxKey)
                    {
                        break;
                    }
                }

                List <ShardRange> rangesToRemove = new List <ShardRange>();

                for (; indexMin <= indexMax; indexMin++)
                {
                    rangesToRemove.Add(_mappingsByRange.Keys[indexMin]);
                }

                foreach (ShardRange rangeToRemove in rangesToRemove)
                {
                    _mappingsByRange.Remove(rangeToRemove);
                }
            }
        }
Beispiel #28
0
        /// <summary>
        /// Finds all mappings to be purged based on the given input ranges.
        /// </summary>
        /// <param name="ts">LSM transaction scope.</param>
        /// <returns>Mappings which are to be removed.</returns>
        private IEnumerable <IStoreMapping> GetMappingsToPurge(IStoreTransactionScope ts)
        {
            IEnumerable <IStoreMapping> lsmMappings = null;

            IStoreResults result;

            if (_rangesToRemove == null)
            {
                // If no ranges are specified, get all the mappings for the shard.
                result = ts.ExecuteOperation(
                    StoreOperationRequestBuilder.SpGetAllShardMappingsLocal,
                    StoreOperationRequestBuilder.GetAllShardMappingsLocal(_shardMap, _shard, null));

                if (result.Result != StoreResult.Success)
                {
                    // Possible errors are:
                    // StoreResult.ShardMapDoesNotExist
                    // StoreResult.StoreVersionMismatch
                    // StoreResult.MissingParametersForStoredProcedure
                    throw StoreOperationErrorHandler.OnRecoveryErrorLocal(
                              result,
                              _shardMap,
                              this.Location,
                              ShardManagementErrorCategory.Recovery,
                              this.OperationName,
                              StoreOperationRequestBuilder.SpGetAllShardMappingsLocal);
                }

                lsmMappings = result.StoreMappings;
            }
            else
            {
                // If any ranges are specified, only delete intersected ranges.
                IDictionary <ShardRange, IStoreMapping> mappingsToPurge = new Dictionary <ShardRange, IStoreMapping>();

                foreach (ShardRange range in _rangesToRemove)
                {
                    switch (_shardMap.MapType)
                    {
                    case ShardMapType.Range:
                        result = ts.ExecuteOperation(
                            StoreOperationRequestBuilder.SpGetAllShardMappingsLocal,
                            StoreOperationRequestBuilder.GetAllShardMappingsLocal(
                                _shardMap,
                                _shard,
                                range));
                        break;

                    default:
                        Debug.Assert(_shardMap.MapType == ShardMapType.List);
                        result = ts.ExecuteOperation(
                            StoreOperationRequestBuilder.SpFindShardMappingByKeyLocal,
                            StoreOperationRequestBuilder.FindShardMappingByKeyLocal(
                                _shardMap,
                                ShardKey.FromRawValue(_shardMap.KeyType, range.Low.RawValue)));
                        break;
                    }

                    if (result.Result != StoreResult.Success)
                    {
                        if (result.Result != StoreResult.MappingNotFoundForKey)
                        {
                            // Possible errors are:
                            // StoreResult.ShardMapDoesNotExist
                            // StoreResult.StoreVersionMismatch
                            // StoreResult.MissingParametersForStoredProcedure
                            throw StoreOperationErrorHandler.OnRecoveryErrorLocal(
                                      result,
                                      _shardMap,
                                      this.Location,
                                      ShardManagementErrorCategory.Recovery,
                                      this.OperationName,
                                      _shardMap.MapType == ShardMapType.Range ?
                                      StoreOperationRequestBuilder.SpGetAllShardMappingsLocal :
                                      StoreOperationRequestBuilder.SpFindShardMappingByKeyLocal);
                        }
                        else
                        {
                            // No intersections being found is fine. Skip to the next mapping.
                            Debug.Assert(_shardMap.MapType == ShardMapType.List);
                        }
                    }
                    else
                    {
                        foreach (IStoreMapping mapping in result.StoreMappings)
                        {
                            ShardRange intersectedRange = new ShardRange(
                                ShardKey.FromRawValue(_shardMap.KeyType, mapping.MinValue),
                                ShardKey.FromRawValue(_shardMap.KeyType, mapping.MaxValue));

                            mappingsToPurge[intersectedRange] = mapping;
                        }
                    }
                }

                lsmMappings = mappingsToPurge.Values;
            }

            return(lsmMappings);
        }
Beispiel #29
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 #30
0
        /// <summary>
        /// Looks up a given key in given shard map.
        /// </summary>
        /// <param name="shardMap">Storage representation of shard map.</param>
        /// <param name="key">Key value.</param>
        /// <returns>Mapping corresponding to <paramref name="key"/> or null.</returns>
        public virtual ICacheStoreMapping LookupMappingByKey(IStoreShardMap shardMap, ShardKey key)
        {
            ICacheStoreMapping sm = null;

            using (ReadLockScope rls = _cacheRoot.GetReadLockScope(false))
            {
                CacheShardMap csm = _cacheRoot.LookupById(shardMap.Id);

                if (csm != null)
                {
                    using (ReadLockScope rlsShardMap = csm.GetReadLockScope(false))
                    {
                        IStoreMapping smDummy;
                        sm = csm.Mapper.LookupByKey(key, out smDummy);

                        /*
                         *          // perf counter can not be updated in csm.Mapper.LookupByKey() as this function is also called from csm.Mapper.AddOrUpdate()
                         *          // so updating perf counter value here instead.
                         *          csm.IncrementPerformanceCounter(sm == null ? PerformanceCounterName.MappingsLookupFailedPerSec : PerformanceCounterName.MappingsLookupSucceededPerSec);
                         */
                    }
                }
            }

            return(sm);
        }