/// <summary> /// Initializes the partition resolver to be used with Item repository. /// </summary> /// <param name="resolverService"></param> public async void getResolver(int resolverService) { switch (resolverService) { case Hash: HashPartitionResolver hashResolver = await PartitionInitializers.InitializeHashResolver("tenantId", Client, Database, collections); break; case ManagedHash: ManagedHashPartitionResolver managedHashResolver = PartitionInitializers.InitializeManagedHashResolver(i => ((Item)i).tenantId, Client, Database, 3, null); break; case Spillover: SpilloverPartitionResolver spilloverResolver = new SpilloverPartitionResolver(Client, Database); Client.PartitionResolvers[Database.SelfLink] = spilloverResolver; break; case Range: RangePartitionResolver <string> rangeResolver = await PartitionInitializers.InitializeRangeResolver("tenantId", Client, Database, collections); break; case Lookup: LookupPartitionResolver <string> lookupResolver = await PartitionInitializers.InitializeLookupPartitionResolver("tenantId", Client, Database, collections); break; default: goto case Hash; } }
/// <summary> /// Removes a partition (collection) from the consistent hash ring. /// </summary> /// <returns>The Task object for the asynchronous execution.</returns> public async Task <int> RemovePartition() { ManagedHashPartitionResolver currentResolver = (ManagedHashPartitionResolver)this.Client.PartitionResolvers[this.Database.SelfLink]; int numberOfMovedDocuments = await this.RepartitionData(currentResolver.PartitionCount - 1); await this.Client.DeleteDocumentCollectionAsync(currentResolver.CollectionLinks.Last()); return(numberOfMovedDocuments); }
/// <summary> /// Initialize a "managed" HashPartitionResolver that also takes care of creating collections, and cloning collection properties like /// stored procedures, offer type and indexing policy. /// </summary> /// <param name="database">The database to run the samples on.</param> /// <returns>The created HashPartitionResolver.</returns> private ManagedHashPartitionResolver InitializeManagedHashResolver(Database database) { var hashResolver = new ManagedHashPartitionResolver(u => ((UserProfile)u).UserId, this.client, database, 3, null, new DocumentCollectionSpec { OfferType = "S2" }); this.client.PartitionResolvers[database.SelfLink] = hashResolver; return(hashResolver); }
public async Task <IHttpActionResult> ManagedHashPartitionResolver() { string[] collections = AppSettingsConfig.MainCollection.Split(','); var database = await DocumentClientHelper.GetNewDatabaseAsync(_client, AppSettingsConfig.Db); ManagedHashPartitionResolver managedHashResolver = PartitionInitializers.InitializeManagedHashResolver(u => ((UserProfile)u).UserId, _client, database, 3, null); return(Ok()); }
/// <summary> /// Internal method to rebalance data across a different number of partitions. /// </summary> /// <param name="newPartitionCount">The target number of partitions.</param> /// <returns>The Task object for the asynchronous execution.</returns> private async Task <int> RepartitionData(int newPartitionCount) { // No-op, just delete the last collection. if (newPartitionCount == 0) { return(0); } ManagedHashPartitionResolver currentResolver = (ManagedHashPartitionResolver)this.Client.PartitionResolvers[this.Database.SelfLink]; var nextPartitionResolver = new ManagedHashPartitionResolver( currentResolver.PartitionKeyExtractor, this.Client, this.Database, newPartitionCount); TransitionHashPartitionResolver transitionaryResolver = new TransitionHashPartitionResolver( currentResolver, nextPartitionResolver, this.ReadMode); this.Client.PartitionResolvers[this.Database.SelfLink] = transitionaryResolver; // Move data between partitions. Here it's one by one, but you can change this to implement inserts // in bulk using stored procedures (bulkImport and bulkDelete), or run them in parallel. Another // improvement to this would be push down the check for partitioning function down to the individual // collections as a LINQ/SQL query. int numberOfMovedDocuments = 0; foreach (string collectionLink in currentResolver.CollectionLinks) { ResourceFeedReader <Document> feedReader = this.Client.CreateDocumentFeedReader(collectionLink); while (feedReader.HasMoreResults) { foreach (Document document in await feedReader.ExecuteNextAsync()) { object partitionKey = nextPartitionResolver.GetPartitionKey(document); string newCollectionLink = nextPartitionResolver.ResolveForCreate(partitionKey); if (newCollectionLink != collectionLink) { numberOfMovedDocuments++; await this.Client.DeleteDocumentAsync(document.SelfLink); await this.Client.CreateDocumentAsync(newCollectionLink, document); } } } } this.Client.PartitionResolvers[this.Database.SelfLink] = nextPartitionResolver; return(numberOfMovedDocuments); }
/// <summary> /// Initializes the partition resolver to be used with Item repository. /// </summary> /// <param name="resolverService"></param> public async void getResolver(int resolverService) { switch (resolverService) { case Hash: HashPartitionResolver hashResolver = await PartitionInitializers.InitializeHashResolver("docType", Client, Database, collections); break; case ManagedHash: ManagedHashPartitionResolver managedHashResolver = PartitionInitializers.InitializeManagedHashResolver(i => ((ItemBase)i).docType, Client, Database, 3, null); break; default: goto case Hash; } }
/// <summary> /// Initialize a "managed" HashPartitionResolver that also takes care of creating collections, and cloning collection properties like /// stored procedures, offer type and indexing policy. /// </summary> /// <param name="partitionKeyExtractor">The partition key extractor function. (Ex: "u => ((UserProfile)u).UserId")</param> /// <param name="client">The DocumentDB client instance to use.</param> /// <param name="database">The database to run the samples on.</param> /// <param name="numCollections">The number of collections to be used.</param> /// <param name="collectionSpec">The DocumentCollectionSpec to be used for each collection created. If null returns Spec with defaultOfferType as set in config.</param> /// <returns>The created HashPartitionResolver.</returns> public static ManagedHashPartitionResolver InitializeManagedHashResolver(Func <object, string> partitionKeyExtractor, DocumentClient client, Database database, int numCollections, DocumentCollectionSpec collectionSpec) { // If no collectionSpec used, use a default spec with the offerType (ie: S1, S2, S3) that is specified in config. if (collectionSpec == null) { var hashResolver = new ManagedHashPartitionResolver(partitionKeyExtractor, client, database, numCollections, null, new DocumentCollectionSpec { OfferType = defaultOfferType }); client.PartitionResolvers[database.SelfLink] = hashResolver; return(hashResolver); } // If there is a collectionSpec passed as a parameter, use that instead of default. else { var hashResolver = new ManagedHashPartitionResolver(partitionKeyExtractor, client, database, numCollections, null, collectionSpec); client.PartitionResolvers[database.SelfLink] = hashResolver; return(hashResolver); } }
/// <summary> /// Add a partition (collection) to the consistent hash ring. /// </summary> /// <returns>The Task object for the asynchronous execution.</returns> public async Task <int> AddPartition() { ManagedHashPartitionResolver currentResolver = (ManagedHashPartitionResolver)this.Client.PartitionResolvers[this.Database.SelfLink]; return(await this.RepartitionData(currentResolver.PartitionCount + 1)); }
/// <summary> /// Run samples for Database create, read, update and delete. /// </summary> /// <returns>a Task object.</returns> private async Task RunAsync() { // Let's see how a to use a HashPartitionResolver. Console.WriteLine("Running samples with the default hash partition resolver ..."); Database database = await DocumentClientHelper.GetNewDatabaseAsync(this.client, DatabaseId); HashPartitionResolver hashResolver = await this.InitializeHashResolver(database); await this.RunCrudAndQuerySample(database, hashResolver); // Let's see how to use a RangePartitionResolver. Console.WriteLine("Running samples with the default range partition resolver ..."); database = await DocumentClientHelper.GetNewDatabaseAsync(this.client, DatabaseId); RangePartitionResolver <string> rangeResolver = await this.InitializeRangeResolver(database); await this.RunCrudAndQuerySample(database, rangeResolver); // Now let's take a look at an example of how to derive from one of the supported partition resolvers. // Here we implement a generic hash resolver that takes an arbirary lambda to extract partition keys. database = await DocumentClientHelper.GetNewDatabaseAsync(this.client, DatabaseId); HashPartitionResolver customHashResolver = await this.InitializeCustomHashResolver(database); await this.RunCrudAndQuerySample(database, customHashResolver); // Let's take a look at a example of a LookupPartitionResolver, i.e., use a simple lookup table. Console.WriteLine("Running samples with a lookup partition resolver ..."); database = await DocumentClientHelper.GetNewDatabaseAsync(this.client, DatabaseId); LookupPartitionResolver <string> lookupResolver = await this.InitializeLookupPartitionResolver(database); await this.RunCrudAndQuerySample(database, lookupResolver); // Now, a "managed" HashPartitionResolver that creates collections, while cloning their attributes like // IndexingPolicy and OfferType. Console.WriteLine("Running samples with a custom hash partition resolver that automates creating collections ..."); database = await DocumentClientHelper.GetNewDatabaseAsync(this.client, DatabaseId); ManagedHashPartitionResolver managedHashResolver = this.InitializeManagedHashResolver(database); await this.RunCrudAndQuerySample(database, managedHashResolver); // Now, a PartitionResolver that starts with one collection and spills over to new ones as the collections // get filled up. Console.WriteLine("Running samples with a custom \"spillover\" partition resolver"); database = await DocumentClientHelper.GetNewDatabaseAsync(this.client, DatabaseId); SpilloverPartitionResolver spilloverResolver = new SpilloverPartitionResolver(this.client, database); this.client.PartitionResolvers[database.SelfLink] = spilloverResolver; await this.RunCrudAndQuerySample(database, spilloverResolver); // Now let's see how to persist the settings for a PartitionResolver, and how to bootstrap from those settings. this.RunSerializeDeserializeSample(hashResolver); // Now let's take a look at how to add and remove partitions to a HashPartitionResolver. database = await DocumentClientHelper.GetNewDatabaseAsync(this.client, DatabaseId); await this.RepartitionDataSample(database); }