// Enter a new shard - i.e. an empty database - to the shard map, allocate a first tenant to it // and kick off EF intialization of the database to deploy schema // public void RegisterNewShard(string server, string database, string user, string pwd, string appname, int key) public void RegisterNewShard(string server, string database, string connstr, int key) { Shard shard; ShardLocation shardLocation = new ShardLocation(server, database); if (!this.ShardMap.TryGetShard(shardLocation, out shard)) { shard = this.ShardMap.CreateShard(shardLocation); } SqlConnectionStringBuilder connStrBldr = new SqlConnectionStringBuilder(connstr); connStrBldr.DataSource = server; connStrBldr.InitialCatalog = database; // Go into a DbContext to trigger migrations and schema deployment for the new shard. // This requires an un-opened connection. using (var db = new ElasticScaleContext<int>(connStrBldr.ConnectionString)) { // Run a query to engage EF migrations (from b in db.Blogs select b).Count(); } // Register the mapping of the tenant to the shard in the shard map. // After this step, DDR on the shard map can be used PointMapping<int> mapping; if (!this.ShardMap.TryGetMappingForKey(key, out mapping)) { this.ShardMap.CreatePointMapping(key, shard); } }
/// <summary> /// 建立 new shard, 或取得現有空的 shard (i.e. a shard 可能還沒 mapper ). /// 空的 shard 可能存在的原因是因為,創建和初始化的時候,我們無法 mapping 他 /// </summary> private static Shard CreateOrGetEmptyShard(RangeShardMap<int> shardMap) { // 假如已經有了,則取得空的 shard Shard shard = FindEmptyShard(shardMap); if (shard == null) { // 為 Null,表示沒有空的,所以要建立 // 更改 shard name string databaseName = string.Format(ShardNameFormat, shardMap.GetShards().Count()); // 假如資料庫不存在,則建立資料庫 // 假如存在,則會返回 if (!SqlDatabaseUtils.DatabaseExists(Configuration.ShardMapManagerServerName, databaseName)) { SqlDatabaseUtils.CreateDatabase(Configuration.ShardMapManagerServerName, databaseName); } // 建立 schema 和相關的資料到 db // 並使用初始化腳本初始化,如果資料庫已經存在,會發生問題 // SqlDatabaseUtils.ExecuteSqlScript( Configuration.ShardMapManagerServerName, databaseName, InitializeShardScriptFile); // 產生shard Location , 並取得 Shard ShardLocation shardLocation = new ShardLocation(Configuration.ShardMapManagerServerName, databaseName); shard = ShardManagementUtils.CreateOrGetShard(shardMap, shardLocation); } return shard; }
/// <summary> /// Creates a new shard, or gets an existing empty shard (i.e. a shard that has no mappings). /// The reason why an empty shard might exist is that it was created and initialized but we /// failed to create a mapping to it. /// </summary> private static Shard CreateOrGetEmptyShard(RangeShardMap<int> shardMap) { // Get an empty shard if one already exists, otherwise create a new one Shard shard = FindEmptyShard(shardMap); if (shard == null) { // No empty shard exists, so create one // Choose the shard name string databaseName = string.Format(ShardNameFormat, shardMap.GetShards().Count()); // Only create the database if it doesn't already exist. It might already exist if // we tried to create it previously but hit a transient fault. if (!SqlDatabaseUtils.DatabaseExists(Configuration.ShardMapManagerServerName, databaseName)) { SqlDatabaseUtils.CreateDatabase(Configuration.ShardMapManagerServerName, databaseName); } // Create schema and populate reference data on that database // The initialize script must be idempotent, in case it was already run on this database // and we failed to add it to the shard map previously SqlDatabaseUtils.ExecuteSqlScript( Configuration.ShardMapManagerServerName, databaseName, InitializeShardScriptFile); // Add it to the shard map ShardLocation shardLocation = new ShardLocation(Configuration.ShardMapManagerServerName, databaseName); shard = ShardManagementUtils.CreateOrGetShard(shardMap, shardLocation); } return shard; }
/// <summary> /// Constructs request to get shard with specific location for given shard map from GSM. /// </summary> /// <param name="shardMapManager">Shard map manager object.</param> /// <param name="operationName">Operation name, useful for diagnostics.</param> /// <param name="shardMap">Shard map for which shard is being requested.</param> /// <param name="location">Location of shard being searched.</param> internal FindShardByLocationGlobalOperation(ShardMapManager shardMapManager, string operationName, IStoreShardMap shardMap, ShardLocation location) : base(shardMapManager.Credentials, shardMapManager.RetryPolicy, operationName) { _shardMapManager = shardMapManager; _shardMap = shardMap; _location = location; }
/// <summary> /// Constructs request for obtaining all the shard maps and shards from an LSM. /// </summary> /// <param name="operationName">Operation name.</param> /// <param name="shardMapManager">Shard map manager.</param> /// <param name="location">Location of the LSM.</param> internal CheckShardLocalOperation( string operationName, ShardMapManager shardMapManager, ShardLocation location) : base(shardMapManager.Credentials, shardMapManager.RetryPolicy, location, operationName) { }
/// <summary> /// Constructs request to upgrade store hosting LSM. /// </summary> /// <param name="shardMapManager">Shard map manager object.</param> /// <param name="location">Store location to upgrade.</param> /// <param name="operationName">Operation name, useful for diagnostics.</param> /// <param name="targetVersion">Target version to upgrade.</param> internal UpgradeStoreLocalOperation( ShardMapManager shardMapManager, ShardLocation location, string operationName, Version targetVersion) : base(shardMapManager.Credentials, shardMapManager.RetryPolicy, location, operationName) { _targetVersion = targetVersion; }
/// <summary> /// Simple constructor to set up an immutable LabeledDbDataReader object. /// </summary> /// <param name="reader">The DbDataReader to keep track of.</param> /// <param name="shardLocation">The Shard this reader belongs to</param> /// <param name="cmd">The command object that produced ther reader.</param> /// <exception cref="ArgumentNullException"> /// If either of the arguments is null. /// </exception> internal LabeledDbDataReader(DbDataReader reader, ShardLocation shardLocation, DbCommand cmd) : this(shardLocation, cmd) { if (null == reader) { throw new ArgumentNullException("reader"); } this.DbDataReader = reader; }
/// <summary> /// Initializes a new instance of the <see cref="MultiShardException"/> class with /// the specified shard location, error message and exception encountered. /// </summary> /// <param name="shardLocation"> specifies the location of the shard where the exception occurred.</param> /// <param name="message"> specifices the message that explains the reason for the exception.</param> /// <param name="inner"> specifies the exception encountered at the shard.</param> /// <exception cref="T:System.ArgumentNullException">The <paramref name="shardLocation"/> is null </exception> public MultiShardException(ShardLocation shardLocation, string message, Exception inner) : base(message, inner) { if (null == shardLocation) { throw new ArgumentNullException("shardLocation"); } _shardLocation = shardLocation; }
internal LabeledDbDataReader(MultiShardException exception, ShardLocation shardLocation, DbCommand cmd) : this(shardLocation, cmd) { if (null == exception) { throw new ArgumentNullException("exception"); } this.Exception = exception; }
/// <summary> /// Constructs an instance of SqlOperationLocal. /// </summary> /// <param name="credentials">Credentials for connecting to SMM databases.</param> /// <param name="retryPolicy">Retry policy for requests.</param> /// <param name="location">Shard location where the operation is to be performed.</param> /// <param name="operationName">Operation name.</param> internal StoreOperationLocal( SqlShardMapManagerCredentials credentials, TransientFaultHandling.RetryPolicy retryPolicy, ShardLocation location, string operationName) { _credentials = credentials; _retryPolicy = retryPolicy; this.OperationName = operationName; this.Location = location; }
/// <summary> /// Constructs request for Detaching the given shard and mapping information to the GSM database. /// </summary> /// <param name="shardMapManager">Shard map manager object.</param> /// <param name="operationName">Operation name.</param> /// <param name="location">Location to be detached.</param> /// <param name="shardMapName">Shard map from which shard is being detached.</param> /// <returns>The store operation.</returns> public virtual IStoreOperationGlobal CreateDetachShardGlobalOperation( ShardMapManager shardMapManager, string operationName, ShardLocation location, string shardMapName) { return new DetachShardGlobalOperation( shardMapManager, operationName, location, shardMapName); }
/// <summary> /// Constructs the storage representation from client side objects. /// </summary> /// <param name="id">Shard Id.</param> /// <param name="version">Shard version.</param> /// <param name="shardMapId">Identify of shard map.</param> /// <param name="location">Data source location.</param> /// <param name="status">Status of the shard.</param> internal DefaultStoreShard( Guid id, Guid version, Guid shardMapId, ShardLocation location, int status) { this.Id = id; this.Version = version; this.ShardMapId = shardMapId; this.Location = location; this.Status = status; }
/// <summary> /// Constructs request for replacing the LSM mappings for given shard map with the input mappings. /// </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="rangesToRemove">Optional list of ranges to minimize amount of deletions.</param> /// <param name="mappingsToAdd">List of mappings to add.</param> internal ReplaceMappingsLocalOperation( ShardMapManager shardMapManager, ShardLocation location, string operationName, IStoreShardMap shardMap, IStoreShard shard, IEnumerable<ShardRange> rangesToRemove, IEnumerable<IStoreMapping> mappingsToAdd) : base(shardMapManager.Credentials, shardMapManager.RetryPolicy, location, operationName) { _shardMap = shardMap; _shard = shard; _rangesToRemove = rangesToRemove; _mappingsToAdd = mappingsToAdd; }
private LabeledDbDataReader(ShardLocation shardLocation, DbCommand cmd) { if (null == shardLocation) { throw new ArgumentNullException("shardLocation"); } if (null == cmd) { throw new ArgumentNullException("cmd"); } this.ShardLocation = shardLocation; this.ShardLabel = ShardLocation.ToString(); this.Command = cmd; }
/// <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; }
// Enter a new shard - i.e. an empty database - to the shard map, allocate a first tenant to it public void RegisterNewShard(string server, string database, string connstr, int key) { Shard shard; ShardLocation shardLocation = new ShardLocation(server, database); if (!this.ShardMap.TryGetShard(shardLocation, out shard)) { shard = this.ShardMap.CreateShard(shardLocation); } // Register the mapping of the tenant to the shard in the shard map. // After this step, DDR on the shard map can be used PointMapping<int> mapping; if (!this.ShardMap.TryGetMappingForKey(key, out mapping)) { this.ShardMap.CreatePointMapping(key, shard); } }
public void FailsValidationWhenAnyShardLocationsAreNull() { var sut = new AddInt32RangeMapShardsArgs { ConnectionString = @"Server = (localdb)\mssqllocaldb; Initial Catalog = SomeTestDb; Integrated Security = true; Application Name = Galen.CI.Azure.Sql.Sharding.App.Tests;", MapName = "MyTestIntRangeMapName", ShardLocations = new ShardLocations() }; var validShardLocation = new ShardLocation { ServerName = @"(localdb)\.\SharedLocalDb", DatabaseName = "MyTestShardDb001" }; sut.ShardLocations.Locations = new [] {validShardLocation, null}; sut.Validate(); }
/// <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">Operatio name.</param> public virtual IStoreOperationLocal CreateGetShardsLocalOperation( ShardMapManager shardMapManager, ShardLocation location, string operationName) { return new GetShardsLocalOperation( shardMapManager, location, operationName); }
/// <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 shard maps and shards from an LSM. /// </summary> /// <param name="operationName">Operation name.</param> /// <param name="shardMapManager">Shard map manager.</param> /// <param name="location">Location of the LSM.</param> public virtual IStoreOperationLocal CreateCheckShardLocalOperation( string operationName, ShardMapManager shardMapManager, ShardLocation location) { return new CheckShardLocalOperation( operationName, shardMapManager, location); }
/// <summary> /// Returns the proper ShardManagementException corresponding to given error code in /// <paramref name="result"/> for ShardMap operations. /// </summary> /// <param name="result">Operation result object.</param> /// <param name="shardMap">Shard map object.</param> /// <param name="location">Location of LSM operation.</param> /// <param name="operationName">Operation being performed.</param> /// <param name="storedProcName">Stored procedure being executed.</param> /// <returns>ShardManagementException to be raised.</returns> internal static ShardManagementException OnValidationErrorLocal( IStoreResults result, IStoreShardMap shardMap, ShardLocation location, string operationName, string storedProcName) { switch (result.Result) { case StoreResult.ShardMapDoesNotExist: return new ShardManagementException( ShardManagementErrorCategory.Validation, ShardManagementErrorCode.ShardMapDoesNotExist, Errors._Store_Validate_ShardMapDoesNotExist, shardMap.Name, location, operationName, storedProcName); case StoreResult.ShardDoesNotExist: return new ShardManagementException( ShardManagementErrorCategory.Validation, ShardManagementErrorCode.ShardDoesNotExist, Errors._Store_Validate_ShardDoesNotExist, location, shardMap.Name, operationName, storedProcName); case StoreResult.ShardVersionMismatch: return new ShardManagementException( ShardManagementErrorCategory.Validation, ShardManagementErrorCode.ShardVersionMismatch, Errors._Store_Validate_ShardVersionMismatch, location, shardMap.Name, operationName, storedProcName); case StoreResult.MappingDoesNotExist: return new ShardManagementException( ShardManagementErrorCategory.Validation, ShardManagementErrorCode.MappingDoesNotExist, Errors._Store_Validate_MappingDoesNotExist, location, shardMap.Name, operationName, storedProcName); case StoreResult.MappingIsOffline: return new ShardManagementException( ShardManagementErrorCategory.Validation, ShardManagementErrorCode.MappingIsOffline, Errors._Store_Validate_MappingIsOffline, location, shardMap.Name, operationName, storedProcName); case StoreResult.StoreVersionMismatch: case StoreResult.MissingParametersForStoredProcedure: default: return StoreOperationErrorHandler.OnCommonErrorLocal( result, location, operationName, storedProcName); } }
public void CreateShardAbortGSM() { int retryCount = 0; EventHandler <RetryingEventArgs> eventHandler = (sender, arg) => { retryCount++; }; ShardMapManager smm = new ShardMapManager( new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString), new SqlStoreConnectionFactory(), new StubStoreOperationFactory() { CallBase = true, CreateAddShardOperationShardMapManagerIStoreShardMapIStoreShard = (_smm, _sm, _s) => new NTimeFailingAddShardOperation(10, _smm, _sm, _s) }, new CacheStore(), ShardMapManagerLoadPolicy.Lazy, new RetryPolicy(5, TimeSpan.Zero, TimeSpan.Zero, TimeSpan.Zero), RetryBehavior.DefaultRetryBehavior); ShardMap sm = smm.GetShardMap(ShardMapTests.s_defaultShardMapName); Assert.IsNotNull(sm); ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapTests.s_shardedDBs[0]); bool storeOperationFailed = false; smm.ShardMapManagerRetrying += eventHandler; try { Shard sNew = sm.CreateShard(sl); Assert.IsNotNull(sNew); } catch (ShardManagementException sme) { Assert.AreEqual(ShardManagementErrorCategory.ShardMap, sme.ErrorCategory); Assert.AreEqual(ShardManagementErrorCode.StorageOperationFailure, sme.ErrorCode); storeOperationFailed = true; } smm.ShardMapManagerRetrying -= eventHandler; Assert.AreEqual(5, retryCount); Assert.IsTrue(storeOperationFailed); // verify that shard map does not have any shards. int count = 0; IEnumerable <Shard> sList = sm.GetShards(); using (IEnumerator <Shard> sEnum = sList.GetEnumerator()) { while (sEnum.MoveNext()) { count++; } } Assert.AreEqual(0, count); }
/// <summary> /// Detaches the given shard from the shard map manager. Mappings pointing to the /// shard to be deleted will automatically be removed by this method. /// </summary> /// <param name="location">Location of the shard being detached.</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 DetachShard(ShardLocation location) { this.DetachShard(location, null); }
public void RebuildMappingsOnShard(RecoveryToken token, IEnumerable <ShardRange> ranges) { ExceptionUtils.DisallowNullArgument(token, "token"); ExceptionUtils.DisallowNullArgument(ranges, "ranges"); ShardLocation location = this.GetShardLocation(token); if (!this.Inconsistencies.ContainsKey(token)) { throw new ArgumentException( StringUtils.FormatInvariant( Errors._Recovery_InvalidRecoveryToken, token), "token"); } IStoreShardMap ssmLocal; DefaultStoreShard dss = this.GetStoreShardFromToken("RebuildMappingsOnShard", token, out ssmLocal); IList <IStoreMapping> mappingsToAdd = new List <IStoreMapping>(); // Determine the ranges we want to keep based on input keeps list. foreach (ShardRange range in ranges) { MappingDifference difference; if (!this.Inconsistencies[token].TryGetValue(range, out difference)) { throw new ArgumentException( StringUtils.FormatInvariant( Errors._Recovery_InvalidRebuildShardSpecification, range, location), "ranges"); } // The storeMapping we will use as a template. IStoreMapping storeMappingTemplate = difference.Location == MappingLocation.MappingInShardMapOnly ? difference.MappingForShardMap : difference.MappingForShard; IStoreMapping storeMappingToAdd = new DefaultStoreMapping( Guid.NewGuid(), storeMappingTemplate.ShardMapId, dss, range.Low.RawValue, range.High.RawValue, storeMappingTemplate.Status, default(Guid) ); mappingsToAdd.Add(storeMappingToAdd); } using (IStoreOperationLocal op = this.Manager.StoreOperationFactory.CreateReplaceMappingsLocalOperation( this.Manager, location, "RebuildMappingsOnShard", ssmLocal, dss, this.Inconsistencies[token].Keys, mappingsToAdd)) { op.Do(); } this.StoreShardMaps.Remove(token); this.Locations.Remove(token); this.Inconsistencies.Remove(token); }
/// <summary> /// Serializes shard location to xml. /// </summary> /// <param name="name">Element name for shard location.</param> /// <param name="location">Shard location to serialize.</param> /// <returns>XElement representing shard location.</returns> internal static XElement WriteShardLocation(string name, ShardLocation location) { Debug.Assert(location != null); return new XElement(name, new XElement("Protocol", (int)location.Protocol), new XElement("ServerName", location.Server), new XElement("Port", location.Port), new XElement("DatabaseName", location.Database)); }
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> /// Attaches a shard to the shard map manager. Earlier versions /// of mappings for the same shard map will automatically be updated /// if more recent versions are found on the shard to be attached. /// After attaching a shard, <see cref="DetectMappingDifferences(ShardLocation, string)"/> /// should be called to check for any inconsistencies that warrant /// manual conflict resolution. /// </summary> /// <param name="location">Location of the shard being attached.</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 AttachShard(ShardLocation location) { this.AttachShard(location, null); }
internal MultiShardPartialReadException(ShardLocation shardLocation, string message, Exception inner) : base(shardLocation, message, inner) { }
/// <summary> /// Returns the proper ShardManagementException corresponding to given error code in /// <paramref name="result"/> for ShardMap operations. /// </summary> /// <param name="result">Operation result object.</param> /// <param name="shardMap">Shard map object.</param> /// <param name="location">Location of operation.</param> /// <param name="errorCategory">Error category to use for raised errors.</param> /// <param name="operationName">Operation being performed.</param> /// <param name="storedProcName">Stored procedure being executed.</param> /// <returns>ShardManagementException to be raised.</returns> internal static ShardManagementException OnRecoveryErrorLocal( IStoreResults result, IStoreShardMap shardMap, ShardLocation location, ShardManagementErrorCategory errorCategory, string operationName, string storedProcName) { switch (result.Result) { case StoreResult.ShardMapDoesNotExist: return new ShardManagementException( errorCategory, ShardManagementErrorCode.ShardMapDoesNotExist, Errors._Store_ShardMap_DoesNotExistLocal, shardMap.Name, location, storedProcName, operationName); case StoreResult.StoreVersionMismatch: case StoreResult.MissingParametersForStoredProcedure: default: return StoreOperationErrorHandler.OnCommonErrorLocal( result, location, operationName, storedProcName); } }
/// <summary> /// Constructs request for replacing the LSM mappings for given shard map with the input mappings. /// </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="rangesToRemove">Optional list of ranges to minimize amount of deletions.</param> /// <param name="mappingsToAdd">List of mappings to add.</param> public virtual IStoreOperationLocal CreateReplaceMappingsLocalOperation( ShardMapManager shardMapManager, ShardLocation location, string operationName, IStoreShardMap shardMap, IStoreShard shard, IEnumerable<ShardRange> rangesToRemove, IEnumerable<IStoreMapping> mappingsToAdd) { return new ReplaceMappingsLocalOperation( shardMapManager, location, operationName, shardMap, shard, rangesToRemove, mappingsToAdd); }
/// <summary> /// Request to get shard with specified location for a shard map from GSM. /// </summary> /// <param name="shardMap">Shard map for which to get shard.</param> /// <param name="location">Location for which to find shard.</param> /// <returns>Xml formatted request.</returns> internal static XElement FindShardByLocationGlobal( IStoreShardMap shardMap, ShardLocation location) { return new XElement( @"FindShardByLocationGlobal", StoreOperationRequestBuilder.s_gsmVersion, StoreObjectFormatterXml.WriteIStoreShardMap("ShardMap", shardMap), StoreObjectFormatterXml.WriteShardLocation("Location", location)); }
/// <summary> /// Constructs a request to upgrade store location. /// </summary> /// <param name="shardMapManager">Shard map manager object.</param> /// <param name="location">Location to upgrade.</param> /// <param name="operationName">Operation name, useful for diagnostics.</param> /// <param name="targetVersion">Target version of store to deploy.</param> /// <returns>The store operation.</returns> public virtual IStoreOperationLocal CreateUpgradeStoreLocalOperation( ShardMapManager shardMapManager, ShardLocation location, string operationName, Version targetVersion) { return new UpgradeStoreLocalOperation( shardMapManager, location, operationName, targetVersion); }
/// <summary> /// Request to detach shard to GSM. /// </summary> /// <param name="shardMapName">Optional shard map name to detach.</param> /// <param name="location">Location to detach.</param> /// <returns>Xml formatted request.</returns> internal static XElement DetachShardGlobal(string shardMapName, ShardLocation location) { return new XElement( @"DetachShardGlobal", StoreOperationRequestBuilder.s_gsmVersion, shardMapName == null ? new XElement("ShardMap", new XAttribute("Null", 1)) : new XElement("ShardMap", new XAttribute("Null", 0), new XElement("Name", shardMapName)), StoreObjectFormatterXml.WriteShardLocation("Location", location)); }
public void GetShardInfo(RecoveryToken token, out ShardMapType mapType, out string shardMapName, out ShardLocation shardLocation) { ExceptionUtils.DisallowNullArgument(token, "token"); Tuple <IStoreShardMap, IStoreShard> shardInfoLocal; if (!this.StoreShardMaps.TryGetValue(token, out shardInfoLocal)) { throw new ArgumentException( StringUtils.FormatInvariant( Errors._Recovery_InvalidRecoveryToken, token), "token"); } mapType = shardInfoLocal.Item1.MapType; shardMapName = shardInfoLocal.Item1.Name; if (!this.Locations.TryGetValue(token, out shardLocation)) { throw new ArgumentException( StringUtils.FormatInvariant( Errors._Recovery_InvalidRecoveryToken, token), "token"); } }
/// <summary> /// Enumerates differences in the mappings between the global shard map manager database and the local shard /// database in the specified shard location. /// </summary> /// <param name="location">Location of shard for which to detect inconsistencies.</param> /// <returns>Collection of tokens to be used for further resolution tasks (see <see cref="ResolveMappingDifferences"/>).</returns> public IEnumerable <RecoveryToken> DetectMappingDifferences(ShardLocation location) { return(this.DetectMappingDifferences(location, null)); }
public void DeleteShardAbortGSMDoAndLSMUndo() { bool shouldThrow = true; IStoreOperationFactory sof = new StubStoreOperationFactory() { CallBase = true, CreateRemoveShardOperationShardMapManagerIStoreShardMapIStoreShard = (_smm, _sm, _s) => { StubRemoveShardOperation op = new StubRemoveShardOperation(_smm, _sm, _s); op.CallBase = true; op.DoGlobalPostLocalExecuteIStoreTransactionScope = (ts) => { if (shouldThrow) { throw new StoreException("", ShardMapFaultHandlingTests.TransientSqlException); } else { // Call the base function, hack for this behavior is to save current operation, set current to null, restore current operation. var original = op.DoGlobalPostLocalExecuteIStoreTransactionScope; op.DoGlobalPostLocalExecuteIStoreTransactionScope = null; try { return(op.DoGlobalPostLocalExecute(ts)); } finally { op.DoGlobalPostLocalExecuteIStoreTransactionScope = original; } } }; op.UndoLocalSourceExecuteIStoreTransactionScope = (ts) => { if (shouldThrow) { throw new StoreException("", ShardMapFaultHandlingTests.TransientSqlException); } else { // Call the base function, hack for this behavior is to save current operation, set current to null, restore current operation. var original = op.UndoLocalSourceExecuteIStoreTransactionScope; op.UndoLocalSourceExecuteIStoreTransactionScope = null; try { return(op.UndoLocalSourceExecute(ts)); } finally { op.UndoLocalSourceExecuteIStoreTransactionScope = original; } } }; return(op); } }; ShardMapManager smm = new ShardMapManager( new SqlShardMapManagerCredentials(Globals.ShardMapManagerConnectionString), new SqlStoreConnectionFactory(), sof, new CacheStore(), ShardMapManagerLoadPolicy.Lazy, new RetryPolicy(1, TimeSpan.Zero, TimeSpan.Zero, TimeSpan.Zero), RetryBehavior.DefaultRetryBehavior); ShardMap sm = smm.GetShardMap(ShardMapTests.s_defaultShardMapName); Assert.IsNotNull(sm); ShardLocation sl = new ShardLocation(Globals.ShardMapManagerTestsDatasourceName, ShardMapTests.s_shardedDBs[0]); Shard sNew = sm.CreateShard(sl); Assert.IsNotNull(sNew); bool storeOperationFailed = false; try { sm.DeleteShard(sNew); } catch (ShardManagementException sme) { Assert.AreEqual(ShardManagementErrorCategory.ShardMap, sme.ErrorCategory); Assert.AreEqual(ShardManagementErrorCode.StorageOperationFailure, sme.ErrorCode); storeOperationFailed = true; } Assert.IsTrue(storeOperationFailed); // verify that the shard exists in store. Shard sValidate = sm.GetShard(sl); Assert.IsNotNull(sValidate); // Obtain the pending operations. var pendingOperations = ShardMapperTests.GetPendingStoreOperations(); Assert.AreEqual(pendingOperations.Count(), 1); shouldThrow = false; storeOperationFailed = false; try { sm.DeleteShard(sNew); } catch (ShardManagementException) { storeOperationFailed = true; } Assert.IsFalse(storeOperationFailed); Assert.AreEqual(0, sm.GetShards().Count()); }
/// <summary> /// Constructs request to get shard with specific location for given shard map from GSM. /// </summary> /// <param name="shardMapManager">Shard map manager object.</param> /// <param name="operationName">Operation name, useful for diagnostics.</param> /// <param name="shardMap">Shard map for which shard is being requested.</param> /// <param name="location">Location of shard being searched.</param> /// <returns>The store operation.</returns> public virtual IStoreOperationGlobal CreateFindShardByLocationGlobalOperation( ShardMapManager shardMapManager, string operationName, IStoreShardMap shardMap, ShardLocation location) { return new FindShardByLocationGlobalOperation( shardMapManager, operationName, shardMap, location); }
/// <summary> /// Returns the proper ShardManagementException corresponding to given common error code /// in <paramref name="result"/>. /// </summary> /// <param name="result">Operation result object.</param> /// <param name="location">Location of LSM.</param> /// <param name="operationName">Operation being performed.</param> /// <param name="storedProcName">Stored procedure being executed.</param> /// <returns>ShardManagementException to be raised.</returns> private static ShardManagementException OnCommonErrorLocal( IStoreResults result, ShardLocation location, string operationName, string storedProcName) { switch (result.Result) { case StoreResult.StoreVersionMismatch: return new ShardManagementException( ShardManagementErrorCategory.Validation, ShardManagementErrorCode.LocalStoreVersionMismatch, Errors._Store_UnsupportedLibraryVersionLocal, (result.StoreVersion != null) ? result.StoreVersion.Version.ToString() : "", location, GlobalConstants.LsmVersionClient, (result.StoreVersion != null) ? (result.StoreVersion.Version > GlobalConstants.LsmVersionClient ? "library" : "store") : "store"); case StoreResult.MissingParametersForStoredProcedure: return new ShardManagementException( ShardManagementErrorCategory.Validation, ShardManagementErrorCode.LocalStoreOperationInsufficientParameters, Errors._Store_MissingSprocParametersLocal, operationName, location, storedProcName); default: Debug.Fail("Unexpected error code found."); return new ShardManagementException( ShardManagementErrorCategory.General, ShardManagementErrorCode.UnexpectedError, Errors._Store_UnexpectedErrorLocal, location); } }
/// <summary> /// Returns the proper ShardManagementException corresponding to given error code in /// <paramref name="result"/> for ShardMapper operations. /// </summary> /// <param name="result">Operation result object.</param> /// <param name="location">Location of LSM operation.</param> /// <param name="operationName">Operation being performed.</param> /// <param name="storedProcName">Stored procedure being executed.</param> /// <returns>ShardManagementException to be raised.</returns> internal static ShardManagementException OnShardMapperErrorLocal( IStoreResults result, ShardLocation location, string operationName, string storedProcName) { switch (result.Result) { case StoreResult.StoreVersionMismatch: case StoreResult.MissingParametersForStoredProcedure: default: return StoreOperationErrorHandler.OnCommonErrorLocal( result, location, operationName, storedProcName); } }