コード例 #1
0
        /// <summary>
        /// Initialize a HashPartitionResolver.
        /// </summary>
        /// <param name="partitionKeyPropertyName">The property name to be used as the partition Key.</param>
        /// <param name="client">The DocumentDB client instance to use.</param>
        /// <param name="database">The database to run the samples on.</param>
        /// <param name="collectionNames">The names of collections used.</param>
        /// <returns>The created HashPartitionResolver.</returns>
        public static async Task <HashPartitionResolver> InitializeHashResolver(string partitionKeyPropertyName, DocumentClient client, Database database, string[] collectionNames)
        {
            // Set local to input.
            string[] CollectionNames    = collectionNames;
            int      numCollectionNames = CollectionNames.Length;

            // Create array of DocumentCollections.
            DocumentCollection[] collections = new DocumentCollection[numCollectionNames];

            // Create string array of Self Links to Collections.
            string[] selfLinks = new string[numCollectionNames];

            //Create some collections to partition data.
            for (int i = 0; i < numCollectionNames; i++)
            {
                collections[i] = await DocumentClientHelper.GetCollectionAsync(client, database, CollectionNames[i]);

                selfLinks[i] = collections[i].SelfLink;
            }

            // Join Self Link Array into a comma separated string.
            string selfLinkString = String.Join(", ", selfLinks);

            //Initialize a partition resolver that users hashing, and register with DocumentClient.
            //Uses User Id for PartitionKeyPropertyName, could also be TenantId, or any other variable.
            HashPartitionResolver hashResolver = new HashPartitionResolver(partitionKeyPropertyName, new[] { selfLinkString });

            client.PartitionResolvers[database.SelfLink] = hashResolver;

            return(hashResolver);
        }
コード例 #2
0
        /// <summary>
        /// Initialize a HashPartitionResolver that uses a custom function to extract the partition key.
        /// </summary>
        /// <param name="partitionKeyExtractor">The partition key extractor function.</param>
        /// <param name="client">The DocumentDB client instance to use.</param>
        /// <param name="database">The database to run the samples on.</param>
        /// <param name="collectionNames">The names of collections used.</param>
        /// <returns>The created HashPartitionResolver.</returns>
        public static async Task <HashPartitionResolver> InitializeCustomHashResolver(Func <object, string> partitionKeyExtractor, DocumentClient client, Database database, string[] collectionNames)
        {
            // Set local to input.
            string[] CollectionNames    = collectionNames;
            int      numCollectionNames = CollectionNames.Length;

            // Create array of DocumentCollections.
            DocumentCollection[] collections = new DocumentCollection[numCollectionNames];

            // Create string array of Self Links to Collections.
            string[] selfLinks = new string[numCollectionNames];

            //Create some collections to partition data.
            for (int i = 0; i < numCollectionNames; i++)
            {
                collections[i] = await DocumentClientHelper.GetCollectionAsync(client, database, CollectionNames[i]);

                selfLinks[i] = collections[i].SelfLink;
            }

            // Join Self Link Array into a comma separated string.
            string selfLinkString = String.Join(", ", selfLinks);

            var hashResolver = new HashPartitionResolver(
                partitionKeyExtractor,
                new[] { selfLinkString });

            client.PartitionResolvers[database.SelfLink] = hashResolver;
            return(hashResolver);
        }
コード例 #3
0
        /// <summary>
        /// Initialize a HashPartitionResolver.
        /// </summary>
        /// <param name="partitionKeyPropertyName">The property name to be used as the partition Key.</param>
        /// <param name="client">The DocumentDB client instance to use.</param>
        /// <param name="database">The database to run the samples on.</param>
        /// <param name="collectionNames">The names of collections used.</param>
        /// <returns>The created HashPartitionResolver.</returns>
        public static async Task<HashPartitionResolver> InitializeHashResolver(string partitionKeyPropertyName, DocumentClient client, Database database, string[] collectionNames)
        {
            // Set local to input.
            string[] CollectionNames = collectionNames;
            int numCollectionNames = CollectionNames.Length;

            // Create array of DocumentCollections.
            DocumentCollection[] collections = new DocumentCollection[numCollectionNames];

            // Create string array of Self Links to Collections.
            string[] selfLinks = new string[numCollectionNames];

            //Create some collections to partition data.
            for (int i = 0; i < numCollectionNames; i++)
            {
                collections[i] = await DocumentClientHelper.GetCollectionAsync(client, database, CollectionNames[i]);
                selfLinks[i] = collections[i].SelfLink;
            }

            // Join Self Link Array into a comma separated string.
            string selfLinkString = String.Join(", ", selfLinks);

            //Initialize a partition resolver that users hashing, and register with DocumentClient. 
            //Uses User Id for PartitionKeyPropertyName, could also be TenantId, or any other variable.
            HashPartitionResolver hashResolver = new HashPartitionResolver(partitionKeyPropertyName, new[] { selfLinkString });
            client.PartitionResolvers[database.SelfLink] = hashResolver;

            return hashResolver;
        }
コード例 #4
0
        /// <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;
            }
        }
コード例 #5
0
        public static IPartitionResolver CreateHashPartitionResolver(IReliableReadWriteDocumentClient client, Database db,
                                                                     Func <object, string> partitionKeyExtractor, IEnumerable <string> partitionCollectionsSelfLinks)
        {
            //note that the partition key property must be present for all documents
            HashPartitionResolver hashResolver = new HashPartitionResolver((Func <object, string>)partitionKeyExtractor, partitionCollectionsSelfLinks);

            client.UnderlyingClient.PartitionResolvers[db.SelfLink] = hashResolver;
            return(hashResolver);
        }
コード例 #6
0
        public async Task <IHttpActionResult> HashPartitionResolver()
        {
            string[] collections = AppSettingsConfig.MainCollection.Split(',');
            var      database    = await DocumentClientHelper.GetNewDatabaseAsync(_client, AppSettingsConfig.Db);

            HashPartitionResolver hashResolver = await PartitionInitializers.InitializeHashResolver("UserId", _client, database, collections);

            return(Ok());
        }
コード例 #7
0
        /// <summary>
        /// Initialize a HashPartitionResolver that uses a custom function to extract the partition key.
        /// </summary>
        /// <param name="database">The database to run the samples on.</param>
        /// <returns>The created HashPartitionResolver.</returns>
        private async Task <HashPartitionResolver> InitializeCustomHashResolver(Database database)
        {
            DocumentCollection collection1 = await DocumentClientHelper.GetCollectionAsync(this.client, database, "Collection.HashBucket0");

            DocumentCollection collection2 = await DocumentClientHelper.GetCollectionAsync(this.client, database, "Collection.HashBucket1");

            var hashResolver = new HashPartitionResolver(
                u => ((UserProfile)u).UserId,
                new[] { collection1.SelfLink, collection2.SelfLink });

            this.client.PartitionResolvers[database.SelfLink] = hashResolver;
            return(hashResolver);
        }
コード例 #8
0
        /// <summary>
        /// Initialize a HashPartitionResolver.
        /// </summary>
        /// <param name="database">The database to run the samples on.</param>
        /// <returns>The created HashPartitionResolver.</returns>
        private async Task <HashPartitionResolver> InitializeHashResolver(Database database)
        {
            // Create some collections to partition data.
            DocumentCollection collection1 = await DocumentClientHelper.GetCollectionAsync(this.client, database, "Collection.HashBucket0");

            DocumentCollection collection2 = await DocumentClientHelper.GetCollectionAsync(this.client, database, "Collection.HashBucket1");

            // Initialize a partition resolver that users hashing, and register with DocumentClient.
            HashPartitionResolver hashResolver = new HashPartitionResolver("UserId", new[] { collection1.SelfLink, collection2.SelfLink });

            this.client.PartitionResolvers[database.SelfLink] = hashResolver;

            return(hashResolver);
        }
コード例 #9
0
        /// <summary>
        /// Illustrate how to load and save the serializer state. Uses HashPartitionResolver as example.
        /// </summary>
        private void RunSerializeDeserializeSample(HashPartitionResolver hashResolver)
        {
            // Store the partition resolver's configuration as JSON.
            string resolverStateAsString = JsonConvert.SerializeObject(hashResolver);

            // Read properties and extract individual values to clone the resolver.
            // ISSUE: fix deserialization of IHashGenerator
            dynamic       parsedResolver           = JsonConvert.DeserializeObject(resolverStateAsString);
            string        partitionKeyPropertyName = parsedResolver.PartitionKeyPropertyName;
            JArray        collections     = parsedResolver.CollectionLinks;
            List <string> collectionLinks = collections.Select(c => (string)c).ToList();

            HashPartitionResolver clonedHashResolver = new HashPartitionResolver(partitionKeyPropertyName, collectionLinks);
        }
コード例 #10
0
        private static async Task WriteCollectionSizes(HashPartitionResolver resolver)
        {
            foreach (var collectionLink in resolver.CollectionLinks)
            {
                var collection = await client.ReadDocumentCollectionAsync(collectionLink);

                var feed = await client.ReadDocumentFeedAsync(collectionLink, new FeedOptions
                {
                    MaxItemCount = 1000
                });

                Console.WriteLine("Collection '{0}', documents: {1}", collection.Resource.Id, feed.Count);
            }
        }
コード例 #11
0
        /// <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;
            }
        }
コード例 #12
0
        /// <summary>
        /// Initialize a HashPartitionResolver.
        /// </summary>
        /// <param name="database">The database to run the samples on.</param>
        /// <returns>The created HashPartitionResolver.</returns>
        private async Task<HashPartitionResolver> InitializeHashResolver(Database database)
        {
            // Create some collections to partition data.
            DocumentCollection collection1 = await DocumentClientHelper.GetOrCreateCollectionAsync(this.client, database.Id, "Collection.HashBucket0");
            DocumentCollection collection2 = await DocumentClientHelper.GetOrCreateCollectionAsync(this.client, database.Id, "Collection.HashBucket1");

            // Initialize a partition resolver that users hashing, and register with DocumentClient. 
            HashPartitionResolver hashResolver = new HashPartitionResolver("UserId", new[] { collection1.SelfLink, collection2.SelfLink });
            this.client.PartitionResolvers[database.SelfLink] = hashResolver;

            return hashResolver;
        }
コード例 #13
0
 public ItemRepository(DocumentClient client, string databaseId) : base(client, databaseId)
 {
     this.partitionResolver = new HashPartitionResolver(base.database.SelfLink);
     this.partitionResolver.Initialize(client);
 }
コード例 #14
0
        static int Main(string[] args)
        {
            Options options = new Options();
            if (!CommandLine.Parser.Default.ParseArguments(args, options))
            {
                Console.WriteLine("Invalid arguments");
                return 1;
            }

            using (DocumentClient client = new DocumentClient(
                new Uri(options.Endpoint), 
                options.AuthKey, 
                new ConnectionPolicy { ConnectionMode = ConnectionMode.Direct, ConnectionProtocol = Protocol.Tcp }))
            {
                Database database = client.CreateDatabaseQuery().Where(d => d.Id == options.Database).AsEnumerable().FirstOrDefault();
                if (database == null)
                {
                    Console.WriteLine("Cannot find database " + options.Database);
                    return 2;
                }
                
                List<DocumentCollection> collections = client.ReadDocumentCollectionFeedAsync(database.SelfLink).Result.ToList();
                int minimumRequiredCollections = Math.Max(options.NewCollections, options.CurrentCollections);

                if (collections.Count < minimumRequiredCollections)
                {
                    Console.WriteLine("At least {0} collections must be pre-created", minimumRequiredCollections);
                    return 3;
                }

                Console.WriteLine("Current distribution of documents across collections:");
                LogDocumentCountsPerCollection(client, database).Wait();
                Console.WriteLine();

                HashPartitionResolver currentPartitionResolver = new HashPartitionResolver(options.PartitionKeyName, collections.Take(options.CurrentCollections).Select(c => c.SelfLink));
                HashPartitionResolver nextPartitionResolver = new HashPartitionResolver(options.PartitionKeyName, collections.Take(options.NewCollections).Select(c => c.SelfLink));

                int numberOfMovedDocuments = 0;

                Parallel.ForEach(currentPartitionResolver.CollectionLinks, collectionLink =>                 
                {
                    ResourceFeedReader<Document> feedReader = client.CreateDocumentFeedReader(collectionLink, new FeedOptions { MaxItemCount = -1 });

                    while (feedReader.HasMoreResults)
                    {
                        foreach (Document document in DocumentClientHelper.ExecuteWithRetryAsync<FeedResponse<Document>>(() => feedReader.ExecuteNextAsync()).Result)
                        {
                            object partitionKey = nextPartitionResolver.GetPartitionKey(document);
                            string newCollectionLink = nextPartitionResolver.ResolveForCreate(partitionKey);

                            if (newCollectionLink != collectionLink)
                            {
                                int count = Interlocked.Increment(ref numberOfMovedDocuments);
                                DocumentClientHelper.ExecuteWithRetryAsync(() => client.DeleteDocumentAsync(document.SelfLink)).Wait();
                                DocumentClientHelper.ExecuteWithRetryAsync(() => client.CreateDocumentAsync(newCollectionLink, document)).Wait();

                                if (count % 100 == 0)
                                {
                                    Console.WriteLine("Moved {0} documents between partitions", numberOfMovedDocuments);
                                }
                            }
                        }
                    }
                });


                Console.WriteLine();
                Console.WriteLine("Moved {0} documents between partitions.", numberOfMovedDocuments);
                Console.WriteLine();

                Console.WriteLine("Current distribution of documents across collections:");
                LogDocumentCountsPerCollection(client, database).Wait();
                Console.WriteLine();           
            }

            return 0;
        }
コード例 #15
0
        /// <summary>
        /// Initialize a HashPartitionResolver that uses a custom function to extract the partition key.
        /// </summary>
        /// <param name="database">The database to run the samples on.</param>
        /// <returns>The created HashPartitionResolver.</returns>
        private async Task<HashPartitionResolver> InitializeCustomHashResolver(Database database)
        {
            DocumentCollection collection1 = await DocumentClientHelper.GetOrCreateCollectionAsync(this.client, database.Id, "Collection.HashBucket0");
            DocumentCollection collection2 = await DocumentClientHelper.GetOrCreateCollectionAsync(this.client, database.Id, "Collection.HashBucket1");

            var hashResolver = new HashPartitionResolver(
                u => ((UserProfile)u).UserId,
                new[] { collection1.SelfLink, collection2.SelfLink });

            this.client.PartitionResolvers[database.SelfLink] = hashResolver;
            return hashResolver;
        }
コード例 #16
0
        /// <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);
        }
コード例 #17
0
        /// <summary>
        /// Initialize a HashPartitionResolver that uses a custom function to extract the partition key.
        /// </summary>
        /// <param name="partitionKeyExtractor">The partition key extractor function.</param>
        /// <param name="client">The DocumentDB client instance to use.</param>
        /// <param name="database">The database to run the samples on.</param>
        /// <param name="collectionNames">The names of collections used.</param>
        /// <returns>The created HashPartitionResolver.</returns>
        public static async Task<HashPartitionResolver> InitializeCustomHashResolver(Func<object, string> partitionKeyExtractor, DocumentClient client, Database database, string[] collectionNames)
        {
            // Set local to input.
            string[] CollectionNames = collectionNames;
            int numCollectionNames = CollectionNames.Length;

            // Create array of DocumentCollections.
            DocumentCollection[] collections = new DocumentCollection[numCollectionNames];

            // Create string array of Self Links to Collections.
            string[] selfLinks = new string[numCollectionNames];

            //Create some collections to partition data.
            for (int i = 0; i < numCollectionNames; i++)
            {
                collections[i] = await DocumentClientHelper.GetCollectionAsync(client, database, CollectionNames[i]);
                selfLinks[i] = collections[i].SelfLink;
            }

            // Join Self Link Array into a comma separated string.
            string selfLinkString = String.Join(", ", selfLinks);

            var hashResolver = new HashPartitionResolver(
                partitionKeyExtractor,
                new[] { selfLinkString });

            client.PartitionResolvers[database.SelfLink] = hashResolver;
            return hashResolver;
        }
コード例 #18
0
        /// <summary>
        /// Illustrate how to load and save the serializer state. Uses HashPartitionResolver as example.
        /// </summary>
        private void RunSerializeDeserializeSample(HashPartitionResolver hashResolver)
        {
            // Store the partition resolver's configuration as JSON.
            string resolverStateAsString = JsonConvert.SerializeObject(hashResolver);

            // Read properties and extract individual values to clone the resolver.
            // ISSUE: fix deserialization of IHashGenerator
            dynamic parsedResolver = JsonConvert.DeserializeObject(resolverStateAsString);
            string partitionKeyPropertyName = parsedResolver.PartitionKeyPropertyName;
            JArray collections = parsedResolver.CollectionLinks;
            List<string> collectionLinks = collections.Select(c => (string)c).ToList();

            HashPartitionResolver clonedHashResolver = new HashPartitionResolver(partitionKeyPropertyName, collectionLinks);
        }
コード例 #19
0
        static int Main(string[] args)
        {
            Options options = new Options();

            if (!CommandLine.Parser.Default.ParseArguments(args, options))
            {
                Console.WriteLine("Invalid arguments");
                return(1);
            }

            using (DocumentClient client = new DocumentClient(
                       new Uri(options.Endpoint),
                       options.AuthKey,
                       new ConnectionPolicy {
                ConnectionMode = ConnectionMode.Direct, ConnectionProtocol = Protocol.Tcp
            }))
            {
                Database database = client.CreateDatabaseQuery().Where(d => d.Id == options.Database).AsEnumerable().FirstOrDefault();
                if (database == null)
                {
                    Console.WriteLine("Cannot find database " + options.Database);
                    return(2);
                }

                List <DocumentCollection> collections = client.ReadDocumentCollectionFeedAsync(database.SelfLink).Result.ToList();
                int minimumRequiredCollections        = Math.Max(options.NewCollections, options.CurrentCollections);

                if (collections.Count < minimumRequiredCollections)
                {
                    Console.WriteLine("At least {0} collections must be pre-created", minimumRequiredCollections);
                    return(3);
                }

                Console.WriteLine("Current distribution of documents across collections:");
                LogDocumentCountsPerCollection(client, database).Wait();
                Console.WriteLine();

                HashPartitionResolver currentPartitionResolver = new HashPartitionResolver(options.PartitionKeyName, collections.Take(options.CurrentCollections).Select(c => c.SelfLink));
                HashPartitionResolver nextPartitionResolver    = new HashPartitionResolver(options.PartitionKeyName, collections.Take(options.NewCollections).Select(c => c.SelfLink));

                int numberOfMovedDocuments = 0;

                Parallel.ForEach(currentPartitionResolver.CollectionLinks, collectionLink =>
                {
                    ResourceFeedReader <Document> feedReader = client.CreateDocumentFeedReader(collectionLink, new FeedOptions {
                        MaxItemCount = -1
                    });

                    while (feedReader.HasMoreResults)
                    {
                        foreach (Document document in DocumentClientHelper.ExecuteWithRetryAsync <FeedResponse <Document> >(() => feedReader.ExecuteNextAsync()).Result)
                        {
                            object partitionKey      = nextPartitionResolver.GetPartitionKey(document);
                            string newCollectionLink = nextPartitionResolver.ResolveForCreate(partitionKey);

                            if (newCollectionLink != collectionLink)
                            {
                                int count = Interlocked.Increment(ref numberOfMovedDocuments);
                                DocumentClientHelper.ExecuteWithRetryAsync(() => client.DeleteDocumentAsync(document.SelfLink)).Wait();
                                DocumentClientHelper.ExecuteWithRetryAsync(() => client.CreateDocumentAsync(newCollectionLink, document)).Wait();

                                if (count % 100 == 0)
                                {
                                    Console.WriteLine("Moved {0} documents between partitions", numberOfMovedDocuments);
                                }
                            }
                        }
                    }
                });


                Console.WriteLine();
                Console.WriteLine("Moved {0} documents between partitions.", numberOfMovedDocuments);
                Console.WriteLine();

                Console.WriteLine("Current distribution of documents across collections:");
                LogDocumentCountsPerCollection(client, database).Wait();
                Console.WriteLine();
            }

            return(0);
        }