/// <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> /// 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; }
/// <summary> /// Instantiates a new instance of range mapping comparison result. /// </summary> /// <param name="ssm">Store representation of shard map.</param> /// <param name="range">Range being considered.</param> /// <param name="mappingLocation">Location of mapping.</param> /// <param name="gsmMapping">Storage representation of GSM mapping.</param> /// <param name="lsmMapping">Storange representation of LSM mapping.</param> internal MappingComparisonResult( IStoreShardMap ssm, ShardRange range, MappingLocation mappingLocation, IStoreMapping gsmMapping, IStoreMapping lsmMapping) { this.ShardMap = ssm; this.Range = range; this.MappingLocation = mappingLocation; this.ShardMapManagerMapping = gsmMapping; this.ShardMapping = lsmMapping; }
/// <summary> /// Helper function to advance mapping iterators. /// </summary> /// <param name="iterator">The iterator to advance.</param> /// <param name="keyType">The data type of the map key.</param> /// <param name="nextMapping">Output value that will contain next mapping.</param> /// <param name="nextRange">Output value that will contain next range.</param> /// <param name="nextMinKey">Output value that will contain next min key.</param> private static void MoveToNextMapping( IEnumerator <IStoreMapping> iterator, ShardKeyType keyType, out IStoreMapping nextMapping, out ShardRange nextRange, out ShardKey nextMinKey) { nextMapping = iterator.MoveNext() ? iterator.Current : null; nextRange = nextMapping != null ? new ShardRange( ShardKey.FromRawValue(keyType, nextMapping.MinValue), ShardKey.FromRawValue(keyType, nextMapping.MaxValue)) : null; nextMinKey = nextRange != null ? nextRange.Low : null; }
/// <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; }
public void CheckValidity() { if (!ShardRange.IsValid()) { throw new InvalidConfigurationException("Shard range is invalid."); } if (ShardRange.Min < 0) { throw new InvalidConfigurationException("Shard range minimum is below zero."); } if (ShardRange.Max > TotalShards) { throw new InvalidConfigurationException("Shard range max is above total shard count."); } if (string.IsNullOrWhiteSpace(Token)) { throw new InvalidConfigurationException("Configuration contains no token."); } }
/// <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; }
/// <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> /// Request to get all shard mappings from LSM for a particular shard map /// and optional shard and range. /// </summary> /// <param name="shardMap">Shard map whose mappings are being requested.</param> /// <param name="shard">Optional shard for which mappings are being requested.</param> /// <param name="range">Optional range for which mappings are being requested.</param> /// <returns>Xml formatted request.</returns> internal static XElement GetAllShardMappingsLocal( IStoreShardMap shardMap, IStoreShard shard, ShardRange range) { return new XElement( @"GetAllShardMappingsLocal", StoreOperationRequestBuilder.s_lsmVersion, StoreObjectFormatterXml.WriteIStoreShardMap("ShardMap", shardMap), StoreObjectFormatterXml.WriteIStoreShard("Shard", shard), StoreObjectFormatterXml.WriteShardRange(range)); }
/// <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> /// Helper function to advance mapping iterators. /// </summary> /// <param name="iterator">The iterator to advance.</param> /// <param name="keyType">The data type of the map key.</param> /// <param name="nextMapping">Output value that will contain next mapping.</param> /// <param name="nextRange">Output value that will contain next range.</param> /// <param name="nextMinKey">Output value that will contain next min key.</param> private static void MoveToNextMapping( IEnumerator<IStoreMapping> iterator, ShardKeyType keyType, out IStoreMapping nextMapping, out ShardRange nextRange, out ShardKey nextMinKey) { nextMapping = iterator.MoveNext() ? iterator.Current : null; nextRange = nextMapping != null ? new ShardRange( ShardKey.FromRawValue(keyType, nextMapping.MinValue), ShardKey.FromRawValue(keyType, nextMapping.MaxValue)) : null; nextMinKey = nextRange != null ? nextRange.Low : null; }
/// <summary> /// Sets the stub of StoreOperationFactory.CreateGetMappingsByRangeLocalOperation(ShardMapManager shardMapManager, ShardLocation location, String operationName, IStoreShardMap shardMap, IStoreShard shard, ShardRange range, Boolean ignoreFailure) /// </summary> public override IStoreOperationLocal CreateGetMappingsByRangeLocalOperation(ShardMapManager shardMapManager, ShardLocation location, string operationName, IStoreShardMap shardMap, IStoreShard shard, ShardRange range, bool ignoreFailure) { Func<ShardMapManager, ShardLocation, string, IStoreShardMap, IStoreShard, ShardRange, bool, IStoreOperationLocal> func1 = this.CreateGetMappingsByRangeLocalOperationShardMapManagerShardLocationStringIStoreShardMapIStoreShardShardRangeBoolean; if (func1 != null) return func1(shardMapManager, location, operationName, shardMap, shard, range, ignoreFailure); if (this.___callBase) return base.CreateGetMappingsByRangeLocalOperation(shardMapManager, location, operationName, shardMap, shard, range, ignoreFailure); return this.InstanceBehavior.Result<StubStoreOperationFactory, IStoreOperationLocal>(this, "CreateGetMappingsByRangeLocalOperation"); }
/// <summary> /// Sets the stub of StoreOperationFactory.CreateGetMappingsByRangeGlobalOperation(ShardMapManager shardMapManager, String operationName, IStoreShardMap shardMap, IStoreShard shard, ShardRange range, ShardManagementErrorCategory errorCategory, Boolean cacheResults, Boolean ignoreFailure) /// </summary> public override IStoreOperationGlobal CreateGetMappingsByRangeGlobalOperation(ShardMapManager shardMapManager, string operationName, IStoreShardMap shardMap, IStoreShard shard, ShardRange range, ShardManagementErrorCategory errorCategory, bool cacheResults, bool ignoreFailure) { Func<ShardMapManager, string, IStoreShardMap, IStoreShard, ShardRange, ShardManagementErrorCategory, bool, bool, IStoreOperationGlobal> func1 = this.CreateGetMappingsByRangeGlobalOperationShardMapManagerStringIStoreShardMapIStoreShardShardRangeShardManagementErrorCategoryBooleanBoolean; if (func1 != null) return func1(shardMapManager, operationName, shardMap, shard, range, errorCategory, cacheResults, ignoreFailure); if (this.___callBase) return base.CreateGetMappingsByRangeGlobalOperation(shardMapManager, operationName, shardMap, shard, range, errorCategory, cacheResults, ignoreFailure); return this.InstanceBehavior.Result<StubStoreOperationFactory, IStoreOperationGlobal>(this, "CreateGetMappingsByRangeGlobalOperation"); }
/// <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); } } }
/// <summary> /// Finds range mapping which contain the given range for the shard map. /// If range is not given: /// If shard is given, finds all mappings for the shard. /// If shard is also not given, finds all the mappings. /// If range is given: /// If shard is given, finds all mappings for the shard in the range. /// If shard is not given, finds all the mappings in the range. /// </summary> /// <param name="ssm">Shard map to find mappings in.</param> /// <param name="range">Optional range to find mappings in.</param> /// <param name="shard">Shard to find mappings in.</param> /// <returns>Storage operation result.</returns> public virtual IStoreResults FindRangeMappingByRangeLocal(IStoreShardMap ssm, ShardRange range, IStoreShard shard) { try { return SqlStore.FindMappingByRangeLocalHelper(ssm, range, shard, @"__ShardManagement.smm_getAllRangeShardMappingsLocal"); } catch (SqlException se) { throw new StoreException( Errors.SqlStore_ShardMap_AddRemoveUpdateFindMappingLocal_SqlException, se, "FindMappingsForRange", "Range", shard.Location); } }
/// <summary> /// Removes range mapping within existing range mapping. /// </summary> /// <param name="ssm">Shard map to remove range mapping to.</param> /// <param name="sm">Shard mapping to remove range from.</param> /// <param name="range">Range to remove.</param> /// <param name="lockOwnerId">Lock owner id of this mapping</param> /// <returns>Storage operation result.</returns> public virtual IStoreResults RemoveRangeWithinRangeMappingGlobal(IStoreShardMap ssm, IStoreMapping sm, ShardRange range, Guid lockOwnerId) { try { SqlResults result = new SqlResults(); using (SqlCommand cmd = SqlTransactionScopeGlobal.CreateSqlCommand()) { cmd.CommandText = @"__ShardManagement.smm_removeRangeShardMappingWithinRangeGlobal"; cmd.CommandType = CommandType.StoredProcedure; XElement input = new XElement(cmd.CommandText, new XElement("gsm_version", SqlStoreGsmVersion.ToString()), new XElement("sm_id", sm.ShardMapId.ToString()), new XElement("lo_id", lockOwnerId.ToString()), new XElement("sm_version", ssm.Version.ToString()), new XElement("m_id", sm.Id.ToString()), new XElement("m_min_value", StringUtils.ByteArrayToString(range.Low.RawValue)), new XElement("m_max_value", (range.High == null) ? null : StringUtils.ByteArrayToString(range.High.RawValue), new XAttribute("is_null", (range.High == null) ? "true" : "false") ), new XElement("m_version", sm.Version.ToString()) ); SqlStore.AddCommandParameter(cmd, "@input", SqlDbType.Xml, ParameterDirection.Input, 0, input.ToString()); SqlParameter resultParam = SqlStore.AddCommandParameter(cmd, "@result", SqlDbType.Int, ParameterDirection.Output, 0, 0); using (SqlDataReader reader = cmd.ExecuteReader()) { result.Fetch(reader); } // Output parameter will be used to specify the outcome. result.Result = (StoreResult)resultParam.Value; } return result; } catch (SqlException se) { throw new StoreException( Errors.SqlStore_RangeShardMap_AddRemoveRange_SqlException, se, "RemoveRange", ssm.Name); } }
public IEnumerable <RecoveryToken> DetectMappingDifferences(ShardLocation location, string shardMapName) { ExceptionUtils.DisallowNullArgument(location, "location"); IList <RecoveryToken> listOfTokens = new List <RecoveryToken>(); IStoreResults getShardsLocalResult; using (IStoreOperationLocal op = this.Manager.StoreOperationFactory.CreateGetShardsLocalOperation( this.Manager, location, "DetectMappingDifferences")) { getShardsLocalResult = op.Do(); } Debug.Assert(getShardsLocalResult.Result == StoreResult.Success); IEnumerable <IStoreShardMap> shardMaps = shardMapName == null ? getShardsLocalResult.StoreShardMaps : getShardsLocalResult.StoreShardMaps.Where(s => s.Name == shardMapName); IEnumerable <Tuple <IStoreShardMap, IStoreShard> > shardInfos = shardMaps .Select(sm => new Tuple <IStoreShardMap, IStoreShard>( sm, getShardsLocalResult.StoreShards.SingleOrDefault(s => s.ShardMapId == sm.Id))); foreach (Tuple <IStoreShardMap, IStoreShard> shardInfo in shardInfos) { IStoreShardMap ssmLocal = shardInfo.Item1; IStoreShard ssLocal = shardInfo.Item2; RecoveryToken token = new RecoveryToken(); listOfTokens.Add(token); this.StoreShardMaps[token] = shardInfo; this.Locations[token] = location; this.Inconsistencies[token] = new Dictionary <ShardRange, MappingDifference>(); DefaultStoreShard dss = new DefaultStoreShard( ssLocal.Id, ssLocal.Version, ssLocal.ShardMapId, ssLocal.Location, ssLocal.Status); // First get all local mappings. IStoreResults lsmMappings; using (IStoreOperationLocal op = this.Manager.StoreOperationFactory.CreateGetMappingsByRangeLocalOperation( this.Manager, location, "DetectMappingDifferences", ssmLocal, dss, null, true)) { lsmMappings = op.Do(); if (lsmMappings.Result == StoreResult.ShardMapDoesNotExist) { // The shard needs to be re-attached. We are ignoring these errors in // DetectMappingDifferences, since corruption is more profound than // just inconsistent mappings. // Alternatively, this shard belongs to a different shard map manager. // Either way, we can't do anything about it here. continue; } } // Next build up a set of relevant global mappings. // This is the union of those mappings that are associated with this local shard // and those mappings which intersect with mappings found in the local shard. // We will partition these mappings based on ranges. IDictionary <ShardRange, IStoreMapping> relevantGsmMappings = new Dictionary <ShardRange, IStoreMapping>(); IStoreResults gsmMappingsByMap; using (IStoreOperationGlobal op = this.Manager.StoreOperationFactory.CreateGetMappingsByRangeGlobalOperation( this.Manager, "DetectMappingDifferences", ssmLocal, dss, null, ShardManagementErrorCategory.Recovery, false, true /* ignore failures */)) { gsmMappingsByMap = op.Do(); } if (gsmMappingsByMap.Result == StoreResult.ShardMapDoesNotExist) { // The shard map is not properly attached to this GSM. // This is beyond what we can handle resolving mappings. continue; } foreach (IStoreMapping gsmMapping in gsmMappingsByMap.StoreMappings) { ShardKey min = ShardKey.FromRawValue(ssmLocal.KeyType, gsmMapping.MinValue); ShardKey max = null; switch (ssmLocal.MapType) { case ShardMapType.Range: max = ShardKey.FromRawValue(ssmLocal.KeyType, gsmMapping.MaxValue); break; default: Debug.Assert(ssmLocal.MapType == ShardMapType.List); max = ShardKey.FromRawValue(ssmLocal.KeyType, gsmMapping.MinValue).GetNextKey(); break; } ShardRange range = new ShardRange(min, max); relevantGsmMappings[range] = gsmMapping; } // Next, for each of the mappings in lsmMappings, we need to augment // the gsmMappingsByMap by intersecting ranges. foreach (IStoreMapping lsmMapping in lsmMappings.StoreMappings) { ShardKey min = ShardKey.FromRawValue(ssmLocal.KeyType, lsmMapping.MinValue); IStoreResults gsmMappingsByRange; if (ssmLocal.MapType == ShardMapType.Range) { ShardKey max = ShardKey.FromRawValue(ssmLocal.KeyType, lsmMapping.MaxValue); ShardRange range = new ShardRange(min, max); using (IStoreOperationGlobal op = this.Manager.StoreOperationFactory.CreateGetMappingsByRangeGlobalOperation( this.Manager, "DetectMappingDifferences", ssmLocal, null, range, ShardManagementErrorCategory.Recovery, false, true /* ignore failures */)) { gsmMappingsByRange = op.Do(); } if (gsmMappingsByRange.Result == StoreResult.ShardMapDoesNotExist) { // The shard was not properly attached. // This is more than we can deal with in mapping resolution. continue; } } else { Debug.Assert(ssmLocal.MapType == ShardMapType.List); using (IStoreOperationGlobal op = this.Manager.StoreOperationFactory.CreateFindMappingByKeyGlobalOperation( this.Manager, "DetectMappingDifferences", ssmLocal, min, CacheStoreMappingUpdatePolicy.OverwriteExisting, ShardManagementErrorCategory.Recovery, false, true /* ignore failures */)) { gsmMappingsByRange = op.Do(); if (gsmMappingsByRange.Result == StoreResult.MappingNotFoundForKey || gsmMappingsByRange.Result == StoreResult.ShardMapDoesNotExist) { // * No intersections being found is fine. Skip to the next mapping. // * The shard was not properly attached. // This is more than we can deal with in mapping resolution. continue; } } } foreach (IStoreMapping gsmMapping in gsmMappingsByRange.StoreMappings) { ShardKey retrievedMin = ShardKey.FromRawValue(ssmLocal.KeyType, gsmMapping.MinValue); ShardRange retrievedRange = null; switch (ssmLocal.MapType) { case ShardMapType.Range: ShardKey retrievedMax = ShardKey.FromRawValue(ssmLocal.KeyType, gsmMapping.MaxValue); retrievedRange = new ShardRange(retrievedMin, retrievedMax); break; default: Debug.Assert(ssmLocal.MapType == ShardMapType.List); retrievedMax = ShardKey.FromRawValue(ssmLocal.KeyType, gsmMapping.MinValue).GetNextKey(); retrievedRange = new ShardRange(retrievedMin, retrievedMax); break; } relevantGsmMappings[retrievedRange] = gsmMapping; } } IList <MappingComparisonResult> comparisonResults = null; switch (ssmLocal.MapType) { case ShardMapType.Range: comparisonResults = MappingComparisonUtils.CompareRangeMappings( ssmLocal, relevantGsmMappings.Values, lsmMappings.StoreMappings); break; default: Debug.Assert(ssmLocal.MapType == ShardMapType.List); comparisonResults = MappingComparisonUtils.ComparePointMappings( ssmLocal, relevantGsmMappings.Values, lsmMappings.StoreMappings); break; } // Now we have 2 sets of mappings. Each submapping generated from this function is // 1.) in the GSM only: report. // 2.) in the LSM only: report. // 3.) in both but with different version number: report. // 4.) in both with the same version number: skip. foreach (MappingComparisonResult r in comparisonResults) { switch (r.MappingLocation) { case MappingLocation.MappingInShardMapOnly: case MappingLocation.MappingInShardOnly: break; default: Debug.Assert(r.MappingLocation == MappingLocation.MappingInShardMapAndShard); if (r.ShardMapManagerMapping.Id == r.ShardMapping.Id) { // No conflict found, skip to the next range. continue; } break; } // Store the inconsistency for later reporting. this.Inconsistencies[token][r.Range] = new MappingDifference( type: MappingDifferenceType.Range, location: r.MappingLocation, shardMap: r.ShardMap, mappingForShard: r.ShardMapping, mappingForShardMap: r.ShardMapManagerMapping); } } return(listOfTokens); }
private static IStoreResults FindMappingByRangeLocalHelper(IStoreShardMap ssm, ShardRange range, IStoreShard shard, string storedProcName) { SqlResults result = new SqlResults(); using (SqlCommand cmd = SqlTransactionScopeLocal.CreateSqlCommand(shard.Location)) { cmd.CommandText = storedProcName; cmd.CommandType = CommandType.StoredProcedure; XElement input = new XElement(storedProcName, new XElement("lsm_version", SqlStoreLsmVersion.ToString()), new XElement("sm_id", ssm.Id.ToString()), new XElement("s_id", shard == null ? null : shard.Id.ToString(), new XAttribute("is_null", (shard == null) ? "true" : "false") ), new XElement("m_min_value", range == null ? null : StringUtils.ByteArrayToString(range.Low.RawValue), new XAttribute("is_null", (range == null) ? "true" : "false") ), new XElement("m_max_value", (range == null) ? null : StringUtils.ByteArrayToString(range.High.RawValue), new XAttribute("is_null", (range == null) ? "true" : "false") ) ); SqlStore.AddCommandParameter(cmd, "@input", SqlDbType.Xml, ParameterDirection.Input, 0, input.ToString()); SqlParameter resultParam = SqlStore.AddCommandParameter(cmd, "@result", SqlDbType.Int, ParameterDirection.Output, 0, 0); using (SqlDataReader reader = cmd.ExecuteReader()) { result.Fetch(reader); } // Output parameter will be used to specify the outcome. result.Result = (StoreResult)resultParam.Value; } return result; }
public IEnumerable<RecoveryToken> DetectMappingDifferences(ShardLocation location, string shardMapName) { ExceptionUtils.DisallowNullArgument(location, "location"); IList<RecoveryToken> listOfTokens = new List<RecoveryToken>(); IStoreResults getShardsLocalResult; using (IStoreOperationLocal op = this.Manager.StoreOperationFactory.CreateGetShardsLocalOperation( this.Manager, location, "DetectMappingDifferences")) { getShardsLocalResult = op.Do(); } Debug.Assert(getShardsLocalResult.Result == StoreResult.Success); IEnumerable<IStoreShardMap> shardMaps = shardMapName == null ? getShardsLocalResult.StoreShardMaps : getShardsLocalResult.StoreShardMaps.Where(s => s.Name == shardMapName); IEnumerable<Tuple<IStoreShardMap, IStoreShard>> shardInfos = shardMaps .Select(sm => new Tuple<IStoreShardMap, IStoreShard>( sm, getShardsLocalResult.StoreShards.SingleOrDefault(s => s.ShardMapId == sm.Id))); foreach (Tuple<IStoreShardMap, IStoreShard> shardInfo in shardInfos) { IStoreShardMap ssmLocal = shardInfo.Item1; IStoreShard ssLocal = shardInfo.Item2; RecoveryToken token = new RecoveryToken(); listOfTokens.Add(token); this.StoreShardMaps[token] = shardInfo; this.Locations[token] = location; this.Inconsistencies[token] = new Dictionary<ShardRange, MappingDifference>(); DefaultStoreShard dss = new DefaultStoreShard( ssLocal.Id, ssLocal.Version, ssLocal.ShardMapId, ssLocal.Location, ssLocal.Status); // First get all local mappings. IStoreResults lsmMappings; using (IStoreOperationLocal op = this.Manager.StoreOperationFactory.CreateGetMappingsByRangeLocalOperation( this.Manager, location, "DetectMappingDifferences", ssmLocal, dss, null, true)) { lsmMappings = op.Do(); if (lsmMappings.Result == StoreResult.ShardMapDoesNotExist) { // The shard needs to be re-attached. We are ignoring these errors in // DetectMappingDifferences, since corruption is more profound than // just inconsistent mappings. // Alternatively, this shard belongs to a different shard map manager. // Either way, we can't do anything about it here. continue; } } // Next build up a set of relevant global mappings. // This is the union of those mappings that are associated with this local shard // and those mappings which intersect with mappings found in the local shard. // We will partition these mappings based on ranges. IDictionary<ShardRange, IStoreMapping> relevantGsmMappings = new Dictionary<ShardRange, IStoreMapping>(); IStoreResults gsmMappingsByMap; using (IStoreOperationGlobal op = this.Manager.StoreOperationFactory.CreateGetMappingsByRangeGlobalOperation( this.Manager, "DetectMappingDifferences", ssmLocal, dss, null, ShardManagementErrorCategory.Recovery, false, true/* ignore failures */)) { gsmMappingsByMap = op.Do(); } if (gsmMappingsByMap.Result == StoreResult.ShardMapDoesNotExist) { // The shard map is not properly attached to this GSM. // This is beyond what we can handle resolving mappings. continue; } foreach (IStoreMapping gsmMapping in gsmMappingsByMap.StoreMappings) { ShardKey min = ShardKey.FromRawValue(ssmLocal.KeyType, gsmMapping.MinValue); ShardKey max = null; switch (ssmLocal.MapType) { case ShardMapType.Range: max = ShardKey.FromRawValue(ssmLocal.KeyType, gsmMapping.MaxValue); break; default: Debug.Assert(ssmLocal.MapType == ShardMapType.List); max = ShardKey.FromRawValue(ssmLocal.KeyType, gsmMapping.MinValue).GetNextKey(); break; } ShardRange range = new ShardRange(min, max); relevantGsmMappings[range] = gsmMapping; } // Next, for each of the mappings in lsmMappings, we need to augment // the gsmMappingsByMap by intersecting ranges. foreach (IStoreMapping lsmMapping in lsmMappings.StoreMappings) { ShardKey min = ShardKey.FromRawValue(ssmLocal.KeyType, lsmMapping.MinValue); IStoreResults gsmMappingsByRange; if (ssmLocal.MapType == ShardMapType.Range) { ShardKey max = ShardKey.FromRawValue(ssmLocal.KeyType, lsmMapping.MaxValue); ShardRange range = new ShardRange(min, max); using (IStoreOperationGlobal op = this.Manager.StoreOperationFactory.CreateGetMappingsByRangeGlobalOperation( this.Manager, "DetectMappingDifferences", ssmLocal, null, range, ShardManagementErrorCategory.Recovery, false, true/* ignore failures */)) { gsmMappingsByRange = op.Do(); } if (gsmMappingsByRange.Result == StoreResult.ShardMapDoesNotExist) { // The shard was not properly attached. // This is more than we can deal with in mapping resolution. continue; } } else { Debug.Assert(ssmLocal.MapType == ShardMapType.List); using (IStoreOperationGlobal op = this.Manager.StoreOperationFactory.CreateFindMappingByKeyGlobalOperation( this.Manager, "DetectMappingDifferences", ssmLocal, min, CacheStoreMappingUpdatePolicy.OverwriteExisting, ShardManagementErrorCategory.Recovery, false, true/* ignore failures */)) { gsmMappingsByRange = op.Do(); if (gsmMappingsByRange.Result == StoreResult.MappingNotFoundForKey || gsmMappingsByRange.Result == StoreResult.ShardMapDoesNotExist) { // * No intersections being found is fine. Skip to the next mapping. // * The shard was not properly attached. // This is more than we can deal with in mapping resolution. continue; } } } foreach (IStoreMapping gsmMapping in gsmMappingsByRange.StoreMappings) { ShardKey retrievedMin = ShardKey.FromRawValue(ssmLocal.KeyType, gsmMapping.MinValue); ShardRange retrievedRange = null; switch (ssmLocal.MapType) { case ShardMapType.Range: ShardKey retrievedMax = ShardKey.FromRawValue(ssmLocal.KeyType, gsmMapping.MaxValue); retrievedRange = new ShardRange(retrievedMin, retrievedMax); break; default: Debug.Assert(ssmLocal.MapType == ShardMapType.List); retrievedMax = ShardKey.FromRawValue(ssmLocal.KeyType, gsmMapping.MinValue).GetNextKey(); retrievedRange = new ShardRange(retrievedMin, retrievedMax); break; } relevantGsmMappings[retrievedRange] = gsmMapping; } } IList<MappingComparisonResult> comparisonResults = null; switch (ssmLocal.MapType) { case ShardMapType.Range: comparisonResults = MappingComparisonUtils.CompareRangeMappings( ssmLocal, relevantGsmMappings.Values, lsmMappings.StoreMappings); break; default: Debug.Assert(ssmLocal.MapType == ShardMapType.List); comparisonResults = MappingComparisonUtils.ComparePointMappings( ssmLocal, relevantGsmMappings.Values, lsmMappings.StoreMappings); break; } // Now we have 2 sets of mappings. Each submapping generated from this function is // 1.) in the GSM only: report. // 2.) in the LSM only: report. // 3.) in both but with different version number: report. // 4.) in both with the same version number: skip. foreach (MappingComparisonResult r in comparisonResults) { switch (r.MappingLocation) { case MappingLocation.MappingInShardMapOnly: case MappingLocation.MappingInShardOnly: break; default: Debug.Assert(r.MappingLocation == MappingLocation.MappingInShardMapAndShard); if (r.ShardMapManagerMapping.Id == r.ShardMapping.Id) { // No conflict found, skip to the next range. continue; } break; } // Store the inconsistency for later reporting. this.Inconsistencies[token][r.Range] = new MappingDifference( type: MappingDifferenceType.Range, location: r.MappingLocation, shardMap: r.ShardMap, mappingForShard: r.ShardMapping, mappingForShardMap: r.ShardMapManagerMapping); } } return listOfTokens; }
/// <summary> /// Finds point mapping which contain the given range for the shard map. /// If range is not given: /// If shard is given, finds all mappings for the shard. /// If shard is also not given, finds all the mappings. /// If range is given: /// If shard is given, finds all mappings for the shard in the range. /// If shard is not given, finds all the mappings in the range. /// </summary> /// <param name="ssm">Shard map to find mappings in.</param> /// <param name="range">Optional range to find mappings in.</param> /// <param name="shard">Option shard to find mappings in.</param> /// <returns>Storage operation result.</returns> public virtual IStoreResults FindPointMappingByRangeGlobal(IStoreShardMap ssm, ShardRange range, IStoreShard shard) { try { return SqlStore.FindMappingByRangeGlobalHelper(ssm, range, shard, @"__ShardManagement.smm_getAllPointShardMappingsGlobal"); } catch (SqlException se) { throw new StoreException( Errors.SqlStore_ShardMap_AddRemoveUpdateFindMappingGlobal_SqlException, se, "FindMappingsForRange", "Point", ssm.Name); } }