/// <summary> /// Selects one of the shard maps (either local or global) as a source of truth and brings /// mappings on both shard maps in sync. /// </summary> /// <param name="token">Recovery token returned from <see cref="DetectMappingDifferences(ShardLocation, string)"/>.</param> /// <param name="resolution">The resolution strategy to be used for resolution.</param> /// <remarks> /// Note that this method can cause unrecoverable data loss. Make sure you have taken backups or copies /// of your databases and only then proceed with great care. /// </remarks> public void ResolveMappingDifferences( RecoveryToken token, MappingDifferenceResolution resolution) { switch (resolution) { case MappingDifferenceResolution.KeepShardMapMapping: this.RestoreShardFromShardmap(token); break; case MappingDifferenceResolution.KeepShardMapping: this.RestoreShardMapFromShard(token); break; case MappingDifferenceResolution.Ignore: break; default: Debug.Fail("Unexpected value for MappingDifferenceResolution."); return; } this.StoreShardMaps.Remove(token); this.Locations.Remove(token); this.Inconsistencies.Remove(token); }
/// <summary> /// Given a collection of shard locations, reconstructs the shard map manager based on information /// stored in the individual shards. /// If the information in the individual shard maps is or becomes inconsistent, behavior is undefined. /// No cross shard locks are taken, so if any shards become inconsistent during the execution of this /// method, the final state of the global shard map may be corrupt. /// </summary> /// <param name="operationName">Operation name.</param> /// <param name="shardLocations">Collection of shard locations.</param> /// <param name="resolutionStrategy">Strategy for resolving the mapping differences.</param> /// <param name="shardMapName">Optional name of shard map. If omitted, will attempt to recover from all shard maps present on each shard.</param> private void RebuildMappingsHelper( string operationName, IEnumerable <ShardLocation> shardLocations, MappingDifferenceResolution resolutionStrategy, string shardMapName = null) { Debug.Assert(shardLocations != null); IList <RecoveryToken> idsToProcess = new List <RecoveryToken>(); // Collect the shard map-shard pairings to recover. Give each of these pairings a token. foreach (ShardLocation shardLocation in shardLocations) { IStoreResults getShardsLocalResult; using (IStoreOperationLocal op = this.Manager.StoreOperationFactory.CreateGetShardsLocalOperation( this.Manager, shardLocation, operationName)) { 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) { RecoveryToken token = new RecoveryToken(); idsToProcess.Add(token); this.StoreShardMaps[token] = shardInfo; this.Locations[token] = shardLocation; } } // Recover from the shard map-shard pairing corresponding to the collected token. foreach (RecoveryToken token in idsToProcess) { this.ResolveMappingDifferences(token, resolutionStrategy); this.StoreShardMaps.Remove(token); this.Locations.Remove(token); } }
/// <summary> /// Given a collection of shard locations, reconstructs the shard map manager based on information /// stored in the individual shards. /// If the information in the individual shard maps is or becomes inconsistent, behavior is undefined. /// No cross shard locks are taken, so if any shards become inconsistent during the execution of this /// method, the final state of the global shard map may be corrupt. /// </summary> /// <param name="operationName">Operation name.</param> /// <param name="shardLocations">Collection of shard locations.</param> /// <param name="resolutionStrategy">Strategy for resolving the mapping differences.</param> /// <param name="shardMapName">Optional name of shard map. If omitted, will attempt to recover from all shard maps present on each shard.</param> private void RebuildMappingsHelper( string operationName, IEnumerable<ShardLocation> shardLocations, MappingDifferenceResolution resolutionStrategy, string shardMapName = null) { Debug.Assert(shardLocations != null); IList<RecoveryToken> idsToProcess = new List<RecoveryToken>(); // Collect the shard map-shard pairings to recover. Give each of these pairings a token. foreach (ShardLocation shardLocation in shardLocations) { IStoreResults getShardsLocalResult; using (IStoreOperationLocal op = this.Manager.StoreOperationFactory.CreateGetShardsLocalOperation( this.Manager, shardLocation, operationName)) { 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) { RecoveryToken token = new RecoveryToken(); idsToProcess.Add(token); this.StoreShardMaps[token] = shardInfo; this.Locations[token] = shardLocation; } } // Recover from the shard map-shard pairing corresponding to the collected token. foreach (RecoveryToken token in idsToProcess) { this.ResolveMappingDifferences(token, resolutionStrategy); this.StoreShardMaps.Remove(token); this.Locations.Remove(token); } }