/// <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 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>
        /// 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>
        /// 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>
 /// Constructs request for obtaining all the mappings from GSM based on given shard and mappings.
 /// </summary>
 /// <param name="shardMapManager">Shard map manager.</param>
 /// <param name="operationName">Operation being executed.</param>
 /// <param name="shardMap">Local shard map.</param>
 /// <param name="shard">Local shard.</param>
 /// <param name="range">Optional range to get mappings from.</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>
 internal GetMappingsByRangeGlobalOperation(ShardMapManager shardMapManager, string operationName, IStoreShardMap shardMap, IStoreShard shard, ShardRange range, ShardManagementErrorCategory errorCategory, bool cacheResults, bool ignoreFailure) :
     base(shardMapManager.Credentials, shardMapManager.RetryPolicy, operationName)
 {
     _manager       = shardMapManager;
     _shardMap      = shardMap;
     _shard         = shard;
     _range         = range;
     _errorCategory = errorCategory;
     _cacheResults  = cacheResults;
     _ignoreFailure = ignoreFailure;
 }
示例#6
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;
        }
示例#7
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;
        }
示例#8
0
 /// <summary>
 /// Converts a given shard range to xml.
 /// </summary>
 /// <param name="range">Input range.</param>
 /// <returns>XElement representing the given range.</returns>
 internal static XElement WriteShardRange(ShardRange range)
 {
     if (range == null)
     {
         return(new XElement("Range", new XAttribute("Null", 1)));
     }
     else
     {
         return(new XElement("Range", new XAttribute("Null", 0),
                             new XElement("MinValue", StringUtils.ByteArrayToString(range.Low.RawValue)),
                             new XElement("MaxValue",
                                          new XAttribute("Null", range.High.IsMax ? 1 : 0),
                                          range.High.IsMax ? null : StringUtils.ByteArrayToString(range.High.RawValue))));
     }
 }
        /// <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());
        }
示例#10
0
        /// <summary>
        /// Constructs request for obtaining all the shard maps and shards from an LSM.
        /// </summary>
        /// <param name="shardMapManager">Shard map manager.</param>
        /// <param name="location">Location of the LSM.</param>
        /// <param name="operationName">Operation name.</param>
        /// <param name="shardMap">Local shard map.</param>
        /// <param name="shard">Local shard.</param>
        /// <param name="range">Optional range to get mappings from.</param>
        /// <param name="ignoreFailure">Ignore shard map not found error.</param>
        internal GetMappingsByRangeLocalOperation(
            ShardMapManager shardMapManager,
            ShardLocation location,
            string operationName,
            IStoreShardMap shardMap,
            IStoreShard shard,
            ShardRange range,
            bool ignoreFailure) :
            base(shardMapManager.Credentials, shardMapManager.RetryPolicy, location, operationName)
        {
            Debug.Assert(shard != null);

            _shardMap      = shardMap;
            _shard         = shard;
            _range         = range;
            _ignoreFailure = ignoreFailure;
        }
 /// <summary>
 /// Constructs request for obtaining all the shard maps and shards from an LSM.
 /// </summary>
 /// <param name="shardMapManager">Shard map manager.</param>
 /// <param name="location">Location of the LSM.</param>
 /// <param name="operationName">Operation name.</param>
 /// <param name="shardMap">Local shard map.</param>
 /// <param name="shard">Local shard.</param>
 /// <param name="range">Optional range to get mappings from.</param>
 /// <param name="ignoreFailure">Ignore shard map not found error.</param>
 public virtual IStoreOperationLocal CreateGetMappingsByRangeLocalOperation(
     ShardMapManager shardMapManager,
     ShardLocation location,
     string operationName,
     IStoreShardMap shardMap,
     IStoreShard shard,
     ShardRange range,
     bool ignoreFailure)
 {
     return(new GetMappingsByRangeLocalOperation(
                shardMapManager,
                location,
                operationName,
                shardMap,
                shard,
                range,
                ignoreFailure));
 }
 /// <summary>
 /// Constructs request for obtaining all the mappings from GSM based on given shard and mappings.
 /// </summary>
 /// <param name="shardMapManager">Shard map manager.</param>
 /// <param name="operationName">Operation being executed.</param>
 /// <param name="shardMap">Local shard map.</param>
 /// <param name="shard">Local shard.</param>
 /// <param name="range">Optional range to get mappings from.</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 CreateGetMappingsByRangeGlobalOperation(
     ShardMapManager shardMapManager,
     string operationName,
     IStoreShardMap shardMap,
     IStoreShard shard,
     ShardRange range,
     ShardManagementErrorCategory errorCategory,
     bool cacheResults,
     bool ignoreFailure)
 {
     return(new GetMappingsByRangeGlobalOperation(
                shardMapManager,
                operationName,
                shardMap,
                shard,
                range,
                errorCategory,
                cacheResults,
                ignoreFailure));
 }
        /// <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);
                }
            }
        }
示例#14
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);
        }