private void ResumeReplicas(string documentId)
        {
            ResourceId           documentRId          = ResourceId.Parse(documentId);
            string               collectionId         = documentRId.DocumentCollectionId.ToString();
            IEnumerable <string> indexFiles           = Directory.EnumerateFiles("c:\\wfroot\\", "*.bwdata", SearchOption.AllDirectories);
            List <string>        collectionIndexFiles = new List <string>();

            foreach (string indexFile in indexFiles)
            {
                if (indexFile.Contains(collectionId))
                {
                    collectionIndexFiles.Add(indexFile);
                }
            }

            foreach (string fileName in collectionIndexFiles)
            {
                string directoryName = Path.GetDirectoryName(fileName);
                string manualRecoveryFileFullName = Path.Combine(directoryName, MultiRegionStrongTests.repairInProgressFileName);
                try
                {
                    File.Delete(manualRecoveryFileFullName);
                }
                catch (FileNotFoundException)
                {
                }
            }
        }
Пример #2
0
        private static ConcurrentDictionary <string, ISessionToken> GetPartitionKeyRangeIdToTokenMap(SessionContainerState self, DocumentServiceRequest request)
        {
            ulong?maybeRID = null;

            if (request.IsNameBased)
            {
                string collectionName = PathsHelper.GetCollectionPath(request.ResourceAddress);

                if (self.collectionNameByResourceId.TryGetValue(collectionName, out ulong rid))
                {
                    maybeRID = rid;
                }
            }
            else
            {
                if (!string.IsNullOrEmpty(request.ResourceId))
                {
                    ResourceId resourceId = ResourceId.Parse(request.ResourceId);
                    if (resourceId.DocumentCollection != 0)
                    {
                        maybeRID = resourceId.UniqueDocumentCollectionId;
                    }
                }
            }

            ConcurrentDictionary <string, ISessionToken> partitionKeyRangeIdToTokenMap = null;

            if (maybeRID.HasValue)
            {
                self.sessionTokensRIDBased.TryGetValue(maybeRID.Value, out partitionKeyRangeIdToTokenMap);
            }

            return(partitionKeyRangeIdToTokenMap);
        }
        private Task <ContainerProperties> ResolveByRidAsync(
            string apiVersion,
            string resourceId,
            ITrace trace,
            IClientSideRequestStatistics clientSideRequestStatistics,
            CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            ResourceId    resourceIdParsed     = ResourceId.Parse(resourceId);
            string        collectionResourceId = resourceIdParsed.DocumentCollectionId.ToString();
            InternalCache cache = this.GetCache(apiVersion);

            return(cache.collectionInfoById.GetAsync(
                       collectionResourceId,
                       null,
                       async() =>
            {
                DateTime currentTime = DateTime.UtcNow;
                ContainerProperties collection = await this.GetByRidAsync(apiVersion, collectionResourceId, trace, clientSideRequestStatistics, cancellationToken);
                cache.collectionInfoByIdLastRefreshTime.AddOrUpdate(collectionResourceId, currentTime,
                                                                    (string currentKey, DateTime currentValue) => currentTime);
                return collection;
            },
                       cancellationToken));
        }
Пример #4
0
        public static IReadOnlyList <Record> GetRecords(this ReadFeedPage page)
        {
            using (MemoryStream memoryStream = new MemoryStream())
            {
                page.Content.CopyTo(memoryStream);
                CosmosObject responseEnvolope = CosmosObject.CreateFromBuffer(memoryStream.ToArray());
                if (!responseEnvolope.TryGetValue("Documents", out CosmosArray documents))
                {
                    throw new InvalidOperationException();
                }

                List <Record> records = new List <Record>();
                foreach (CosmosElement document in documents)
                {
                    CosmosObject documentObject = (CosmosObject)document;
                    ResourceId   rid            = ResourceId.Parse(((CosmosString)documentObject["_rid"]).Value);
                    long         ticks          = Number64.ToLong(((CosmosNumber)documentObject["_ts"]).Value);
                    string       id             = ((CosmosString)documentObject["id"]).Value;
                    CosmosObject payload        = documentObject;

                    Record record = new Record(rid, new DateTime(ticks: ticks, DateTimeKind.Utc), id, payload);
                    records.Add(record);
                }

                return(records);
            }
        }
        public string GetSessionToken(string collectionLink)
        {
            bool   isNameBased;
            bool   isFeed;
            string resourceTypeString;
            string resourceIdOrFullName;
            ConcurrentDictionary <string, ISessionToken> partitionKeyRangeIdToTokenMap = null;

            if (PathsHelper.TryParsePathSegments(collectionLink, out isFeed, out resourceTypeString, out resourceIdOrFullName, out isNameBased))
            {
                if (isNameBased)
                {
                    string collectionName = PathsHelper.GetCollectionPath(resourceIdOrFullName);
                    this.sessionTokensNameBased.TryGetValue(collectionName, out partitionKeyRangeIdToTokenMap);
                }
                else
                {
                    ResourceId resourceId = ResourceId.Parse(resourceIdOrFullName);
                    if (resourceId.DocumentCollection != 0)
                    {
                        this.sessionTokens.TryGetValue(resourceId.UniqueDocumentCollectionId, out partitionKeyRangeIdToTokenMap);
                    }
                }
            }

            if (partitionKeyRangeIdToTokenMap == null)
            {
                return(string.Empty);
            }

            return(SessionContainer.GetSessionTokenString(partitionKeyRangeIdToTokenMap));
        }
        public void ClearToken(DocumentServiceRequest request, INameValueCollection responseHeaders)
        {
            string ownerFullName  = responseHeaders[HttpConstants.HttpHeaders.OwnerFullName];
            string collectionName = PathsHelper.GetCollectionPath(ownerFullName);
            string resourceIdString;

            if (!request.IsNameBased)
            {
                resourceIdString = request.ResourceId;
            }
            else
            {
                resourceIdString = responseHeaders[HttpConstants.HttpHeaders.OwnerId];
            }

            if (!string.IsNullOrEmpty(resourceIdString))
            {
                ResourceId resourceId = ResourceId.Parse(resourceIdString);
                if (resourceId.DocumentCollection != 0 && collectionName != null)
                {
                    ConcurrentDictionary <string, ISessionToken> ignored;
                    this.sessionTokens.TryRemove(resourceId.UniqueDocumentCollectionId, out ignored);
                    this.sessionTokensNameBased.TryRemove(collectionName, out ignored);
                }
            }
        }
Пример #7
0
        private static void ClearTokenByResourceId(SessionContainerState self, string resourceId)
        {
            if (!string.IsNullOrEmpty(resourceId))
            {
                ResourceId resource = ResourceId.Parse(resourceId);
                if (resource.DocumentCollection != 0)
                {
                    ulong rid = resource.UniqueDocumentCollectionId;

                    self.rwlock.EnterWriteLock();
                    try
                    {
                        if (self.collectionResourceIdByName.ContainsKey(rid))
                        {
                            string collectionName = self.collectionResourceIdByName[rid];
                            _ = self.sessionTokensRIDBased.TryRemove(rid, out _);
                            _ = self.collectionResourceIdByName.TryRemove(rid, out _);
                            _ = self.collectionNameByResourceId.TryRemove(collectionName, out _);
                        }
                    }
                    finally
                    {
                        self.rwlock.ExitWriteLock();
                    }
                }
            }
        }
        public void ClearTokenByResourceId(string resourceId)
        {
            if (!string.IsNullOrEmpty(resourceId))
            {
                ResourceId resource = ResourceId.Parse(resourceId);
                if (resource.DocumentCollection != 0)
                {
                    ulong rid = resource.UniqueDocumentCollectionId;

                    this.rwlock.EnterWriteLock();
                    try
                    {
                        if (this.collectionResourceIdByName.ContainsKey(rid))
                        {
                            string ignoreString;
                            ulong  ignoreUlong;

                            string collectionName = this.collectionResourceIdByName[rid];
                            ConcurrentDictionary <string, ISessionToken> ignored;
                            this.sessionTokensRIDBased.TryRemove(rid, out ignored);
                            this.collectionResourceIdByName.TryRemove(rid, out ignoreString);
                            this.collectionNameByResourceId.TryRemove(collectionName, out ignoreUlong);
                        }
                    }
                    finally
                    {
                        this.rwlock.ExitWriteLock();
                    }
                }
            }
        }
Пример #9
0
        private static void SetSessionToken(SessionContainerState self, string collectionRid, string collectionFullname, INameValueCollection responseHeaders)
        {
            ResourceId resourceId     = ResourceId.Parse(collectionRid);
            string     collectionName = PathsHelper.GetCollectionPath(collectionFullname);
            string     token          = responseHeaders[HttpConstants.HttpHeaders.SessionToken];

            if (!string.IsNullOrEmpty(token))
            {
                SessionContainer.SetSessionToken(self, resourceId, collectionName, token);
            }
        }
        internal static string GetAuthorizationResourceIdOrFullName(string resourceType, string resourceIdOrFullName)
        {
            if (string.IsNullOrEmpty(resourceType) || string.IsNullOrEmpty(resourceIdOrFullName))
            {
                return(resourceIdOrFullName);
            }

            if (PathsHelper.IsNameBased(resourceIdOrFullName))
            {
                // resource fullname is always end with name (not type segment like docs/colls).
                return(resourceIdOrFullName);
            }

            if (resourceType.Equals(Paths.OffersPathSegment, StringComparison.OrdinalIgnoreCase) ||
                resourceType.Equals(Paths.PartitionsPathSegment, StringComparison.OrdinalIgnoreCase) ||
                resourceType.Equals(Paths.TopologyPathSegment, StringComparison.OrdinalIgnoreCase) ||
                resourceType.Equals(Paths.RidRangePathSegment, StringComparison.OrdinalIgnoreCase) ||
                resourceType.Equals(Paths.SnapshotsPathSegment, StringComparison.OrdinalIgnoreCase))
            {
                return(resourceIdOrFullName);
            }

            ResourceId parsedRId = ResourceId.Parse(resourceIdOrFullName);

            if (resourceType.Equals(Paths.DatabasesPathSegment, StringComparison.OrdinalIgnoreCase))
            {
                return(parsedRId.DatabaseId.ToString());
            }
            else if (resourceType.Equals(Paths.UsersPathSegment, StringComparison.OrdinalIgnoreCase))
            {
                return(parsedRId.UserId.ToString());
            }
            else if (resourceType.Equals(Paths.UserDefinedTypesPathSegment, StringComparison.OrdinalIgnoreCase))
            {
                return(parsedRId.UserDefinedTypeId.ToString());
            }
            else if (resourceType.Equals(Paths.CollectionsPathSegment, StringComparison.OrdinalIgnoreCase))
            {
                return(parsedRId.DocumentCollectionId.ToString());
            }
            else if (resourceType.Equals(Paths.ClientEncryptionKeysPathSegment, StringComparison.OrdinalIgnoreCase))
            {
                return(parsedRId.ClientEncryptionKeyId.ToString());
            }
            else if (resourceType.Equals(Paths.DocumentsPathSegment, StringComparison.OrdinalIgnoreCase))
            {
                return(parsedRId.DocumentId.ToString());
            }
            else
            {
                // leaf node
                return(resourceIdOrFullName);
            }
        }
Пример #11
0
        /// <summary> Load the data in the table </summary>
        public override void LoadData()
        {
            DataTable table = GetAllData();

            foreach (DataRow row in table.Rows)
            {
                long     resourceId = ResourceId.Parse(row);
                Resource resource   = TableManager.Resource.GetResource(resourceId);
                DateTime date       = Date.Parse(row);
                int      price      = Price.Parse(row);
                resource.AddPriceHistory(date, price);
            }
        }
Пример #12
0
        //Workaround
        //This method was removed from Direct
        private static ResourceId NewDocumentId(string collectionId, uint documentId)
        {
            ResourceId collectionResourceId = ResourceId.Parse(collectionId);

            ResourceId documentResourceId = ResourceId.Empty;

            //Properties have private setters
            documentResourceId.GetType().GetProperty(nameof(documentResourceId.Database)).SetValue(documentResourceId, collectionResourceId.Database);
            documentResourceId.GetType().GetProperty(nameof(documentResourceId.DocumentCollection)).SetValue(documentResourceId, collectionResourceId.DocumentCollection);
            documentResourceId.GetType().GetProperty(nameof(documentResourceId.Document)).SetValue(documentResourceId, documentId);

            return(documentResourceId);
        }
Пример #13
0
        /// <summary> Loads the data in this table </summary>
        public override void LoadData()
        {
            DataTable table = GetAllData();

            foreach (DataRow row in table.Rows)
            {
                Profession profession = TableManager.Profession.GetProfession(ProfessionId.Parse(row));
                int        grade      = Grade.Parse(row);
                Resource   resource   = TableManager.Resource.GetResource(ResourceId.Parse(row));
                int        amount     = Amount.Parse(row);
                profession.AddUpgradeCost(grade, resource, amount);
            }
        }
Пример #14
0
        /// <summary> Load all recipe costs from the database </summary>
        public override void LoadData()
        {
            DataTable table = GetAllData();

            foreach (DataRow row in table.Rows)
            {
                long     recipeId   = RecipeId.Parse(row);
                long     resourceId = ResourceId.Parse(row);
                int      amount     = Amount.Parse(row);
                Recipe   recipe     = TableManager.Recipe.GetRecipe(recipeId);
                Resource resource   = TableManager.Resource.GetResource(resourceId);
                recipe.AddConsumed(resource, amount);
            }
        }
        private static bool IsSameCollection(PartitionKeyRange initiallyResolved, PartitionKeyRange newlyResolved)
        {
            if (initiallyResolved == null)
            {
                throw new ArgumentException("parent");
            }

            if (newlyResolved == null)
            {
                return(false);
            }

            if (initiallyResolved.Id == PartitionKeyRange.MasterPartitionKeyRangeId &&
                newlyResolved.Id == PartitionKeyRange.MasterPartitionKeyRangeId)
            {
                return(true);
            }

            if (initiallyResolved.Id == PartitionKeyRange.MasterPartitionKeyRangeId ||
                newlyResolved.Id == PartitionKeyRange.MasterPartitionKeyRangeId)
            {
                string message =
                    "Request was resolved to master partition and then to server partition.";
                Debug.Assert(false, message);
                DefaultTrace.TraceCritical(message);
                return(false);
            }

            if (ResourceId.Parse(initiallyResolved.ResourceId).DocumentCollection
                != ResourceId.Parse(newlyResolved.ResourceId).DocumentCollection)
            {
                return(false);
            }

            if (initiallyResolved.Id != newlyResolved.Id && !(newlyResolved.Parents != null && newlyResolved.Parents.Contains(initiallyResolved.Id)))
            {
                // the above condition should be always false in current codebase.
                // We don't need to refresh any caches if we resolved to a range which is child of previously resolved range.
                // Quorum reads should be handled transparently as child partitions share LSNs with parent partitions which are gone.
                string message =
                    "Request is targeted at a partition key range which is not child of previously targeted range.";
                Debug.Assert(false, message);
                DefaultTrace.TraceCritical(message);

                return(false);
            }

            return(true);
        }
        private Task <CosmosContainerSettings> ResolveByRidAsync(
            string resourceId,
            CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            ResourceId resourceIdParsed     = ResourceId.Parse(resourceId);
            string     collectionResourceId = resourceIdParsed.DocumentCollectionId.ToString();

            return(this.collectionInfoByIdCache.GetAsync(
                       collectionResourceId,
                       null,
                       () => this.GetByRidAsync(collectionResourceId, cancellationToken),
                       cancellationToken));
        }
        public void ClearToken(string collectionRid, string collectionFullname, INameValueCollection responseHeader)
        {
            if (!string.IsNullOrEmpty(collectionFullname))
            {
                string collectionName = PathsHelper.GetCollectionPath(collectionFullname);
                ConcurrentDictionary <string, ISessionToken> ignored;
                this.sessionTokensNameBased.TryRemove(collectionName, out ignored);
            }

            if (!string.IsNullOrEmpty(collectionRid))
            {
                ResourceId resourceId = ResourceId.Parse(collectionRid);
                ConcurrentDictionary <string, ISessionToken> ignored;
                this.sessionTokens.TryRemove(resourceId.UniqueDocumentCollectionId, out ignored);
            }
        }
        /// <summary>
        /// Resolve the ContainerProperties object from the cache. If the collection was read before "refreshAfter" Timespan, force a cache refresh by reading from the backend.
        /// </summary>
        /// <param name="request">Request to resolve.</param>
        /// <param name="refreshAfter"> Time duration to refresh</param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <param name="trace">The trace.</param>
        /// <returns>Instance of <see cref="ContainerProperties"/>.</returns>
        public virtual Task <ContainerProperties> ResolveCollectionAsync(
            DocumentServiceRequest request,
            TimeSpan refreshAfter,
            CancellationToken cancellationToken,
            ITrace trace)
        {
            cancellationToken.ThrowIfCancellationRequested();
            InternalCache cache = this.GetCache(request.Headers[HttpConstants.HttpHeaders.Version]);

#if !NETSTANDARD16
            Debug.Assert(request.ForceNameCacheRefresh == false);
#endif
            DateTime currentTime     = DateTime.UtcNow;
            DateTime lastRefreshTime = DateTime.MinValue;
            if (request.IsNameBased)
            {
                string resourceFullName = PathsHelper.GetCollectionPath(request.ResourceAddress);

                if (cache.collectionInfoByNameLastRefreshTime.TryGetValue(resourceFullName, out lastRefreshTime))
                {
                    TimeSpan cachedItemStaleness = currentTime - lastRefreshTime;

                    if (cachedItemStaleness > refreshAfter)
                    {
                        cache.collectionInfoByName.TryRemoveIfCompleted(resourceFullName);
                    }
                }
            }
            else
            {
                ResourceId resourceIdParsed     = ResourceId.Parse(request.ResourceId);
                string     collectionResourceId = resourceIdParsed.DocumentCollectionId.ToString();

                if (cache.collectionInfoByIdLastRefreshTime.TryGetValue(collectionResourceId, out lastRefreshTime))
                {
                    TimeSpan cachedItemStaleness = currentTime - lastRefreshTime;

                    if (cachedItemStaleness > refreshAfter)
                    {
                        cache.collectionInfoById.TryRemoveIfCompleted(request.ResourceId);
                    }
                }
            }

            return(this.ResolveCollectionAsync(request, cancellationToken, trace));
        }
Пример #19
0
        private static string GetSessionToken(SessionContainerState self, string collectionLink)
        {
            bool arePathSegmentsParsed = PathsHelper.TryParsePathSegments(
                collectionLink,
                out _,
                out _,
                out string resourceIdOrFullName,
                out bool isNameBased);

            ConcurrentDictionary <string, ISessionToken> partitionKeyRangeIdToTokenMap = null;

            if (arePathSegmentsParsed)
            {
                ulong?maybeRID = null;

                if (isNameBased)
                {
                    string collectionName = PathsHelper.GetCollectionPath(resourceIdOrFullName);

                    if (self.collectionNameByResourceId.TryGetValue(collectionName, out ulong rid))
                    {
                        maybeRID = rid;
                    }
                }
                else
                {
                    ResourceId resourceId = ResourceId.Parse(resourceIdOrFullName);
                    if (resourceId.DocumentCollection != 0)
                    {
                        maybeRID = resourceId.UniqueDocumentCollectionId;
                    }
                }

                if (maybeRID.HasValue)
                {
                    self.sessionTokensRIDBased.TryGetValue(maybeRID.Value, out partitionKeyRangeIdToTokenMap);
                }
            }

            if (partitionKeyRangeIdToTokenMap == null)
            {
                return(string.Empty);
            }

            return(SessionContainer.GetSessionTokenString(partitionKeyRangeIdToTokenMap));
        }
Пример #20
0
        private static bool ShouldUpdateSessionToken(
            DocumentServiceRequest request,
            INameValueCollection responseHeaders,
            out ResourceId resourceId,
            out string collectionName)
        {
            resourceId = null;
            string ownerFullName = responseHeaders[HttpConstants.HttpHeaders.OwnerFullName];

            if (string.IsNullOrEmpty(ownerFullName))
            {
                ownerFullName = request.ResourceAddress;
            }

            collectionName = PathsHelper.GetCollectionPath(ownerFullName);
            string resourceIdString;

            if (request.IsNameBased)
            {
                resourceIdString = responseHeaders[HttpConstants.HttpHeaders.OwnerId];
                if (string.IsNullOrEmpty(resourceIdString))
                {
                    resourceIdString = request.ResourceId;
                }
            }
            else
            {
                resourceIdString = request.ResourceId;
            }

            if (!string.IsNullOrEmpty(resourceIdString))
            {
                resourceId = ResourceId.Parse(resourceIdString);

                if (resourceId.DocumentCollection != 0 &&
                    collectionName != null &&
                    !ReplicatedResourceClient.IsReadingFromMaster(request.ResourceType, request.OperationType))
                {
                    return(true);
                }
            }

            return(false);
        }
Пример #21
0
            public Record Add(int pkrangeid, CosmosObject payload)
            {
                // using pkrangeid for database since resource id doesnt serialize both document and pkrangeid.
                ResourceId currentResourceId;

                if (this.Count == 0)
                {
                    currentResourceId = ResourceId.Parse("AYIMAMmFOw8YAAAAAAAAAA==");

                    PropertyInfo documentProp = currentResourceId
                                                .GetType()
                                                .GetProperty("Document", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
                    documentProp.SetValue(currentResourceId, (ulong)1);

                    PropertyInfo databaseProp = currentResourceId
                                                .GetType()
                                                .GetProperty("Database", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
                    databaseProp.SetValue(currentResourceId, (uint)pkrangeid + 1);
                }
                else
                {
                    currentResourceId = this.storage[this.storage.Count - 1].ResourceIdentifier;
                }

                ResourceId nextResourceId = ResourceId.Parse("AYIMAMmFOw8YAAAAAAAAAA==");
                {
                    PropertyInfo documentProp = nextResourceId
                                                .GetType()
                                                .GetProperty("Document", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
                    documentProp.SetValue(nextResourceId, (ulong)(currentResourceId.Document + 1));

                    PropertyInfo databaseProp = nextResourceId
                                                .GetType()
                                                .GetProperty("Database", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
                    databaseProp.SetValue(nextResourceId, (uint)pkrangeid + 1);
                }

                Record record = new Record(nextResourceId, DateTime.UtcNow.Ticks, Guid.NewGuid().ToString(), payload);

                this.storage.Add(record);
                return(record);
            }
Пример #22
0
        private static IEnumerable <CosmosElement> ExecuteCrossPartitionOrdering(
            IEnumerable <CosmosElement> dataSource,
            IReadOnlyDictionary <string, PartitionKeyRange> ridToPartitionKeyRange)
        {
            // Grab from the left most partition first
            IOrderedEnumerable <CosmosElement> orderedDataSource = dataSource
                                                                   .OrderBy((element) =>
            {
                string rid = ((CosmosString)((CosmosObject)element)["_rid"]).Value;
                PartitionKeyRange partitionKeyRange = ridToPartitionKeyRange[rid];
                return(partitionKeyRange.MinInclusive);
            },
                                                                            StringComparer.Ordinal);

            // Break all final ties within partition by document id
            orderedDataSource = orderedDataSource
                                .ThenBy(element => ResourceId.Parse(((CosmosString)((CosmosObject)element)["_rid"]).Value).Document);

            return(orderedDataSource);
        }
        private ConcurrentDictionary <string, ISessionToken> GetPartitionKeyRangeIdToTokenMap(DocumentServiceRequest request)
        {
            ConcurrentDictionary <string, ISessionToken> partitionKeyRangeIdToTokenMap = null;

            if (!request.IsNameBased)
            {
                if (!string.IsNullOrEmpty(request.ResourceId))
                {
                    ResourceId resourceId = ResourceId.Parse(request.ResourceId);
                    if (resourceId.DocumentCollection != 0)
                    {
                        this.sessionTokens.TryGetValue(resourceId.UniqueDocumentCollectionId, out partitionKeyRangeIdToTokenMap);
                    }
                }
            }
            else
            {
                string collectionName = PathsHelper.GetCollectionPath(request.ResourceAddress);
                this.sessionTokensNameBased.TryGetValue(collectionName, out partitionKeyRangeIdToTokenMap);
            }

            return(partitionKeyRangeIdToTokenMap);
        }
        private static void SetupAccountAndCacheOperations(
            out string secondaryRegionNameForUri,
            out string globalEndpoint,
            out string secondaryRegionEndpiont,
            out string databaseName,
            out string containerName,
            out ResourceId containerResourceId,
            out Mock <IHttpHandler> mockHttpHandler,
            out IReadOnlyList <string> primaryRegionPartitionKeyRangeIds,
            out TransportAddressUri primaryRegionprimaryReplicaUri)
        {
            string accountName             = "testAccount";
            string primaryRegionNameForUri = "eastus";

            secondaryRegionNameForUri = "westus";
            globalEndpoint            = $"https://{accountName}.documents.azure.com:443/";
            Uri    globalEndpointUri     = new Uri(globalEndpoint);
            string primaryRegionEndpoint = $"https://{accountName}-{primaryRegionNameForUri}.documents.azure.com";

            secondaryRegionEndpiont = $"https://{accountName}-{secondaryRegionNameForUri}.documents.azure.com";
            databaseName            = "testDb";
            containerName           = "testContainer";
            string containerRid = "ccZ1ANCszwk=";

            containerResourceId = ResourceId.Parse(containerRid);

            List <AccountRegion> writeRegion = new List <AccountRegion>()
            {
                new AccountRegion()
                {
                    Name     = "East US",
                    Endpoint = $"{primaryRegionEndpoint}:443/"
                }
            };

            List <AccountRegion> readRegions = new List <AccountRegion>()
            {
                new AccountRegion()
                {
                    Name     = "East US",
                    Endpoint = $"{primaryRegionEndpoint}:443/"
                },
                new AccountRegion()
                {
                    Name     = "West US",
                    Endpoint = $"{secondaryRegionEndpiont}:443/"
                }
            };

            // Create a mock http handler to inject gateway responses.
            // MockBehavior.Strict ensures that only the mocked APIs get called
            mockHttpHandler = new Mock <IHttpHandler>(MockBehavior.Strict);
            MockSetupsHelper.SetupStrongAccountProperties(
                mockHttpClientHandler: mockHttpHandler,
                endpoint: globalEndpointUri.ToString(),
                accountName: accountName,
                writeRegions: writeRegion,
                readRegions: readRegions);

            MockSetupsHelper.SetupContainerProperties(
                mockHttpHandler: mockHttpHandler,
                regionEndpoint: primaryRegionEndpoint,
                databaseName: databaseName,
                containerName: containerName,
                containerRid: containerRid);

            MockSetupsHelper.SetupPartitionKeyRanges(
                mockHttpHandler: mockHttpHandler,
                regionEndpoint: primaryRegionEndpoint,
                containerResourceId: containerResourceId,
                partitionKeyRangeIds: out primaryRegionPartitionKeyRangeIds);

            MockSetupsHelper.SetupAddresses(
                mockHttpHandler: mockHttpHandler,
                partitionKeyRangeId: primaryRegionPartitionKeyRangeIds.First(),
                regionEndpoint: primaryRegionEndpoint,
                regionName: primaryRegionNameForUri,
                containerResourceId: containerResourceId,
                primaryReplicaUri: out primaryRegionprimaryReplicaUri);
        }
        public async Task TestHttpRequestExceptionScenarioAsync()
        {
            // testhost.dll.config sets it to 2 seconds which causes it to always expire before retrying. Remove the override.
            System.Configuration.ConfigurationManager.AppSettings["UnavailableLocationsExpirationTimeInSeconds"] = "500";

            string     accountName               = nameof(TestHttpRequestExceptionScenarioAsync);
            string     primaryRegionNameForUri   = "eastus";
            string     secondaryRegionNameForUri = "westus";
            string     globalEndpoint            = $"https://{accountName}.documents.azure.com:443/";
            Uri        globalEndpointUri         = new Uri(globalEndpoint);
            string     primaryRegionEndpoint     = $"https://{accountName}-{primaryRegionNameForUri}.documents.azure.com";
            string     secondaryRegionEndpiont   = $"https://{accountName}-{secondaryRegionNameForUri}.documents.azure.com";
            string     databaseName              = "testDb";
            string     containerName             = "testContainer";
            string     containerRid              = "ccZ1ANCszwk=";
            ResourceId containerResourceId       = ResourceId.Parse(containerRid);

            List <AccountRegion> writeRegion = new List <AccountRegion>()
            {
                new AccountRegion()
                {
                    Name     = "East US",
                    Endpoint = $"{primaryRegionEndpoint}:443/"
                }
            };

            List <AccountRegion> readRegions = new List <AccountRegion>()
            {
                new AccountRegion()
                {
                    Name     = "East US",
                    Endpoint = $"{primaryRegionEndpoint}:443/"
                },
                new AccountRegion()
                {
                    Name     = "West US",
                    Endpoint = $"{secondaryRegionEndpiont}:443/"
                }
            };

            List <AccountRegion> writeRegionFailedOver = new List <AccountRegion>()
            {
                new AccountRegion()
                {
                    Name     = "West US",
                    Endpoint = $"{secondaryRegionEndpiont}:443/"
                }
            };

            List <AccountRegion> readRegionsFailedOver = new List <AccountRegion>()
            {
                new AccountRegion()
                {
                    Name     = "West US",
                    Endpoint = $"{secondaryRegionEndpiont}:443/"
                },
                new AccountRegion()
                {
                    Name     = "East US",
                    Endpoint = $"{primaryRegionEndpoint}:443/"
                },
            };

            // Create a mock http handler to inject gateway responses.
            // MockBehavior.Strict ensures that only the mocked APIs get called
            Mock <IHttpHandler> mockHttpHandler = new Mock <IHttpHandler>(MockBehavior.Strict);


            mockHttpHandler.Setup(x => x.SendAsync(
                                      It.Is <HttpRequestMessage>(m => m.RequestUri == globalEndpointUri || m.RequestUri.ToString().Contains(primaryRegionNameForUri)),
                                      It.IsAny <CancellationToken>())).Throws(new HttpRequestException("Mock HttpRequestException to simulate region being down"));

            int count = 0;

            mockHttpHandler.Setup(x => x.SendAsync(
                                      It.Is <HttpRequestMessage>(x => x.RequestUri == new Uri(secondaryRegionEndpiont)),
                                      It.IsAny <CancellationToken>()))
            .Returns <HttpRequestMessage, CancellationToken>((request, cancellationToken) =>
            {
                // Simulate the legacy gateway being down. After 40 requests simulate the write region pointing to new location.
                count++;
                if (count < 2)
                {
                    return(Task.FromResult(MockSetupsHelper.CreateStrongAccount(accountName, writeRegion, readRegions)));
                }
                else
                {
                    return(Task.FromResult(MockSetupsHelper.CreateStrongAccount(accountName, writeRegionFailedOver, readRegionsFailedOver)));
                }
            });


            MockSetupsHelper.SetupContainerProperties(
                mockHttpHandler: mockHttpHandler,
                regionEndpoint: secondaryRegionEndpiont,
                databaseName: databaseName,
                containerName: containerName,
                containerRid: containerRid);

            MockSetupsHelper.SetupPartitionKeyRanges(
                mockHttpHandler: mockHttpHandler,
                regionEndpoint: secondaryRegionEndpiont,
                containerResourceId: containerResourceId,
                partitionKeyRangeIds: out IReadOnlyList <string> secondaryRegionPartitionKeyRangeIds);

            MockSetupsHelper.SetupAddresses(
                mockHttpHandler: mockHttpHandler,
                partitionKeyRangeId: secondaryRegionPartitionKeyRangeIds.First(),
                regionEndpoint: secondaryRegionEndpiont,
                regionName: secondaryRegionNameForUri,
                containerResourceId: containerResourceId,
                primaryReplicaUri: out TransportAddressUri secondaryRegionprimaryReplicaUri);

            Mock <TransportClient> mockTransport = new Mock <TransportClient>(MockBehavior.Strict);

            MockSetupsHelper.SetupRequestTimeoutException(
                mockTransport,
                secondaryRegionprimaryReplicaUri);

            // Partition key ranges are the same in both regions so the SDK
            // does not need to go the secondary to get the partition key ranges.
            // Only the addresses need to be mocked on the secondary
            MockSetupsHelper.SetupAddresses(
                mockHttpHandler: mockHttpHandler,
                partitionKeyRangeId: secondaryRegionPartitionKeyRangeIds.First(),
                regionEndpoint: secondaryRegionEndpiont,
                regionName: secondaryRegionNameForUri,
                containerResourceId: containerResourceId,
                primaryReplicaUri: out TransportAddressUri secondaryRegionPrimaryReplicaUri);

            MockSetupsHelper.SetupCreateItemResponse(
                mockTransport,
                secondaryRegionPrimaryReplicaUri);

            CosmosClientOptions cosmosClientOptions = new CosmosClientOptions()
            {
                EnablePartitionLevelFailover = true,
                ConsistencyLevel             = Cosmos.ConsistencyLevel.Strong,
                ApplicationPreferredRegions  = new List <string>()
                {
                    Regions.EastUS,
                    Regions.WestUS
                },
                HttpClientFactory             = () => new HttpClient(new HttpHandlerHelper(mockHttpHandler.Object)),
                TransportClientHandlerFactory = (original) => mockTransport.Object,
            };

            using (CosmosClient customClient = new CosmosClient(
                       globalEndpoint,
                       Convert.ToBase64String(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())),
                       cosmosClientOptions))
            {
                Container container = customClient.GetContainer(databaseName, containerName);

                ToDoActivity toDoActivity = new ToDoActivity()
                {
                    Id = "TestItem",
                    Pk = "TestPk"
                };

                ItemResponse <ToDoActivity> response = await container.CreateItemAsync(toDoActivity, new Cosmos.PartitionKey(toDoActivity.Pk));

                Assert.AreEqual(HttpStatusCode.Created, response.StatusCode);
                mockTransport.VerifyAll();
                mockHttpHandler.VerifyAll();

                // Clears all the setups. No network calls should be done on the next operation.
                mockHttpHandler.Reset();
                mockTransport.Reset();

                MockSetupsHelper.SetupCreateItemResponse(
                    mockTransport,
                    secondaryRegionPrimaryReplicaUri);

                ToDoActivity toDoActivity2 = new ToDoActivity()
                {
                    Id = "TestItem2",
                    Pk = "TestPk"
                };

                response = await container.CreateItemAsync(toDoActivity2, new Cosmos.PartitionKey(toDoActivity2.Pk));

                Assert.AreEqual(HttpStatusCode.Created, response.StatusCode);
                mockTransport.Setup(x => x.Dispose());

                // Reset it back to the override to avoid impacting other tests.
                System.Configuration.ConfigurationManager.AppSettings["UnavailableLocationsExpirationTimeInSeconds"] = "2";
            }

            await Task.Delay(TimeSpan.FromMinutes(2));
        }
Пример #26
0
        private static IEnumerable <CosmosElement> ExecuteOrderByClause(
            IEnumerable <CosmosElement> dataSource,
            SqlOrderByClause sqlOrderByClause,
            IReadOnlyDictionary <string, PartitionKeyRange> ridToPartitionKeyRange)
        {
            // Sort by the columns left to right
            SqlOrderByItem firstItem = sqlOrderByClause.OrderByItems[0];

            // Since we don't supply an explicit index on the policy undefined items don't show up in the sort order
            if (sqlOrderByClause.OrderByItems.Length == 1)
            {
                dataSource = dataSource.Where(element => firstItem.Expression.Accept(
                                                  ScalarExpressionEvaluator.Singleton,
                                                  element) != Undefined);
            }

            IOrderedEnumerable <CosmosElement> orderedDataSource;

            if (firstItem.IsDescending)
            {
                orderedDataSource = dataSource.OrderByDescending(
                    element => firstItem.Expression.Accept(
                        ScalarExpressionEvaluator.Singleton,
                        element));
            }
            else
            {
                orderedDataSource = dataSource.OrderBy(
                    element => firstItem.Expression.Accept(
                        ScalarExpressionEvaluator.Singleton,
                        element));
            }

            foreach (SqlOrderByItem sqlOrderByItem in sqlOrderByClause.OrderByItems.Skip(1))
            {
                if (sqlOrderByItem.IsDescending)
                {
                    orderedDataSource = orderedDataSource.ThenByDescending(
                        element => sqlOrderByItem.Expression.Accept(
                            ScalarExpressionEvaluator.Singleton,
                            element));
                }
                else
                {
                    orderedDataSource = orderedDataSource.ThenBy(
                        element => sqlOrderByItem.Expression.Accept(
                            ScalarExpressionEvaluator.Singleton,
                            element));
                }
            }

            // Grab from the left most partition first
            orderedDataSource = orderedDataSource
                                .ThenBy((element) =>
            {
                string rid = ((CosmosString)((CosmosObject)element)["_rid"]).Value;
                PartitionKeyRange partitionKeyRange = ridToPartitionKeyRange[rid];
                return(partitionKeyRange.MinInclusive);
            },
                                        StringComparer.Ordinal);

            // Break all final ties within partition by document id
            if (firstItem.IsDescending)
            {
                orderedDataSource = orderedDataSource
                                    .ThenByDescending(element => ResourceId.Parse(((CosmosString)((CosmosObject)element)["_rid"]).Value).Document);
            }
            else
            {
                orderedDataSource = orderedDataSource
                                    .ThenBy(element => ResourceId.Parse(((CosmosString)((CosmosObject)element)["_rid"]).Value).Document);
            }

            return(orderedDataSource);
        }