public void DuplicateContactedReplicasTests()
        {
            ClientSideRequestStatisticsTraceDatum clientSideRequestStatisticsTraceDatum = new ClientSideRequestStatisticsTraceDatum(DateTime.UtcNow, new TraceSummary());

            clientSideRequestStatisticsTraceDatum.ContactedReplicas.Add(new TransportAddressUri(new Uri("http://storephysicaladdress1.com")));
            clientSideRequestStatisticsTraceDatum.ContactedReplicas.Add(new TransportAddressUri(new Uri("http://storephysicaladdress2.com")));
            clientSideRequestStatisticsTraceDatum.ContactedReplicas.Add(new TransportAddressUri(new Uri("http://storephysicaladdress2.com")));
            clientSideRequestStatisticsTraceDatum.ContactedReplicas.Add(new TransportAddressUri(new Uri("http://storephysicaladdress2.com")));
            clientSideRequestStatisticsTraceDatum.ContactedReplicas.Add(new TransportAddressUri(new Uri("http://storephysicaladdress2.com")));
            clientSideRequestStatisticsTraceDatum.ContactedReplicas.Add(new TransportAddressUri(new Uri("http://storephysicaladdress3.com")));
            ITrace trace = Trace.GetRootTrace("test");

            trace.AddDatum("stats", clientSideRequestStatisticsTraceDatum);
            string  json              = new CosmosTraceDiagnostics(trace).ToString();
            JObject jobject           = JObject.Parse(json);
            JToken  contactedReplicas = jobject["data"]["stats"]["ContactedReplicas"];

            Assert.AreEqual(3, contactedReplicas.Count());
            int count = contactedReplicas[0]["Count"].Value <int>();

            Assert.AreEqual(1, count);
            string uri = contactedReplicas[0]["Uri"].Value <string>();

            Assert.AreEqual("http://storephysicaladdress1.com/", uri);

            count = contactedReplicas[1]["Count"].Value <int>();
            Assert.AreEqual(4, count);
            uri = contactedReplicas[1]["Uri"].Value <string>();
            Assert.AreEqual("http://storephysicaladdress2.com/", uri);

            count = contactedReplicas[2]["Count"].Value <int>();
            Assert.AreEqual(1, count);
            uri = contactedReplicas[2]["Uri"].Value <string>();
            Assert.AreEqual("http://storephysicaladdress3.com/", uri);
        }
        public RegionContactedInDiagnosticsBenchmark()
        {
            ITrace trace = NoOpTrace.Singleton;

            this.noOpTracediagnostics = new Diagnostics.CosmosTraceDiagnostics(trace);
            this.diagnosticsWithData  = new Diagnostics.CosmosTraceDiagnostics(this.CreateTestTraceTree());
        }
示例#3
0
        public void ValidateStoreResultSerialization()
        {
            HashSet <string> storeResultProperties = typeof(StoreResult).GetProperties(BindingFlags.Public | BindingFlags.Instance).Select(x => x.Name).ToHashSet <string>();
            string           datumKey = "ClientStats";
            Trace            trace    = Trace.GetRootTrace("Test");
            ClientSideRequestStatisticsTraceDatum datum = new ClientSideRequestStatisticsTraceDatum(DateTime.UtcNow);

            trace.AddDatum(datumKey, datum);

            StoreResult storeResult = new StoreResult(
                storeResponse: new StoreResponse(),
                exception: null,
                partitionKeyRangeId: 42.ToString(),
                lsn: 1337,
                quorumAckedLsn: 23,
                requestCharge: 3.14,
                currentReplicaSetSize: 4,
                currentWriteQuorum: 3,
                isValid: true,
                storePhysicalAddress: new Uri("http://storephysicaladdress.com"),
                globalCommittedLSN: 1234,
                numberOfReadRegions: 13,
                itemLSN: 15,
                sessionToken: new SimpleSessionToken(42),
                usingLocalLSN: true,
                activityId: Guid.Empty.ToString(),
                backendRequestDurationInMs: "4.2",
                retryAfterInMs: "42",
                transportRequestStats: TraceWriterBaselineTests.CreateTransportRequestStats());

            StoreResponseStatistics storeResponseStatistics = new StoreResponseStatistics(
                DateTime.MinValue,
                DateTime.MaxValue,
                storeResult,
                ResourceType.Document,
                OperationType.Query,
                new Uri("http://someUri1.com"));

            ((List <StoreResponseStatistics>)datum.GetType().GetField("storeResponseStatistics", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(datum)).Add(storeResponseStatistics);

            CosmosTraceDiagnostics diagnostics = new CosmosTraceDiagnostics(trace);
            string        json               = diagnostics.ToString();
            JObject       jObject            = JObject.Parse(json);
            JObject       storeResultJObject = jObject["data"][datumKey]["StoreResponseStatistics"][0]["StoreResult"].ToObject <JObject>();
            List <string> jsonPropertyNames  = storeResultJObject.Properties().Select(p => p.Name).ToList();

            storeResultProperties.Add("BELatencyInMs");
            storeResultProperties.Remove(nameof(storeResult.BackendRequestDurationInMs));
            storeResultProperties.Add("TransportException");
            storeResultProperties.Remove(nameof(storeResult.Exception));
            storeResultProperties.Add("transportRequestTimeline");
            storeResultProperties.Remove(nameof(storeResult.TransportRequestStats));

            foreach (string key in jsonPropertyNames)
            {
                Assert.IsTrue(storeResultProperties.Remove(key), $"Json contains key:{key} not a storeresult property");
            }

            Assert.AreEqual(0, storeResultProperties.Count, $"Json is missing properties: {string.Join(';', storeResultProperties)}");
        }
        public void ContactedRegionsWithNameTest()
        {
            CosmosDiagnostics             diagnostics      = new CosmosTraceDiagnostics(this.CreateTestTraceTree());
            IReadOnlyList <(string, Uri)> regionsContacted = diagnostics.GetContactedRegions();

            Assert.IsNotNull(regionsContacted);
            Assert.AreEqual(regionsContacted.Count, 4);
        }
        public void ContactedRegionsWithNameForClientTelemetryTest()
        {
            CosmosDiagnostics diagnostics = new CosmosTraceDiagnostics(this.CreateTestTraceTree());

            string regionsContacted = ClientTelemetryHelper.GetContactedRegions(diagnostics);

            Assert.IsNotNull(regionsContacted);
            Assert.AreEqual("Central US,Central India,East US 2,France Central", regionsContacted);
        }
        public async Task CreateDropItemTest()
        {
            ToDoActivity testItem = ToDoActivity.CreateRandomToDoActivity();

            ResetSessionToken(this.Container);
            Assert.IsNull(await GetLSNFromSessionContainer(
                              this.Container, this.containerSettings, new PartitionKey(testItem.pk)));
            ItemResponse <ToDoActivity> response = await this.Container.CreateItemAsync <ToDoActivity>(item : testItem);

            Assert.IsNotNull(response);
            Assert.IsNotNull(response.Resource);
            Assert.IsNotNull(response.Diagnostics);
            long?lsnAfterCreate = await GetLSNFromSessionContainer(
                this.Container, this.containerSettings, new PartitionKey(testItem.pk));

            Assert.IsNotNull(lsnAfterCreate);
            CosmosTraceDiagnostics diagnostics = (CosmosTraceDiagnostics)response.Diagnostics;

            Assert.IsFalse(diagnostics.IsGoneExceptionHit());
            Assert.IsFalse(string.IsNullOrEmpty(diagnostics.ToString()));
            Assert.IsTrue(diagnostics.GetClientElapsedTime() > TimeSpan.Zero);

            response = await this.Container.ReadItemAsync <ToDoActivity>(testItem.id, new Cosmos.PartitionKey(testItem.pk));

            Assert.IsNotNull(response);
            Assert.IsNotNull(response.Resource);
            Assert.IsNotNull(response.Diagnostics);
            Assert.IsFalse(string.IsNullOrEmpty(response.Diagnostics.ToString()));
            Assert.IsTrue(response.Diagnostics.GetClientElapsedTime() > TimeSpan.Zero);
            long?lsnAfterRead = await GetLSNFromSessionContainer(
                this.Container, this.containerSettings, new PartitionKey(testItem.pk));

            Assert.IsNotNull(lsnAfterRead);
            Assert.AreEqual(lsnAfterCreate.Value, lsnAfterRead.Value);

            Assert.IsNotNull(response.Headers.GetHeaderValue <string>(Documents.HttpConstants.HttpHeaders.MaxResourceQuota));
            Assert.IsNotNull(response.Headers.GetHeaderValue <string>(Documents.HttpConstants.HttpHeaders.CurrentResourceQuotaUsage));
            ItemResponse <ToDoActivity> deleteResponse = await this.Container.DeleteItemAsync <ToDoActivity>(partitionKey : new Cosmos.PartitionKey(testItem.pk), id : testItem.id);

            Assert.IsNotNull(deleteResponse);
            Assert.IsNotNull(response.Diagnostics);
            Assert.IsFalse(string.IsNullOrEmpty(response.Diagnostics.ToString()));
            Assert.IsTrue(response.Diagnostics.GetClientElapsedTime() > TimeSpan.Zero);
            long?lsnAfterDelete = await GetLSNFromSessionContainer(
                this.Container, this.containerSettings, new PartitionKey(testItem.pk));

            Assert.IsNotNull(lsnAfterDelete);
            Assert.IsTrue(lsnAfterDelete.Value > lsnAfterCreate.Value);
        }
        public void ContactedRegionWithNameForClientTelemetryTest()
        {
            Trace trace;

            using (trace = Trace.GetRootTrace("Root Trace", TraceComponent.Unknown, TraceLevel.Info))
            {
                using (ITrace firstLevel = trace.StartChild("First level Node", TraceComponent.Unknown, TraceLevel.Info))
                {
                    firstLevel.AddDatum("Client Side Request Stats", this.GetDatumObject(Regions.FranceCentral));
                }
            }

            CosmosDiagnostics diagnostics = new CosmosTraceDiagnostics(trace);

            string regionsContacted = ClientTelemetryHelper.GetContactedRegions(diagnostics);

            Assert.IsNotNull(regionsContacted);
            Assert.AreEqual("France Central", regionsContacted);
        }
示例#8
0
        public static void LogDiagnostics(
            ILogger logger,
            string operationName,
            TimeSpan timerContextLatency,
            CTLConfig config,
            CosmosDiagnostics cosmosDiagnostics)
        {
            if (timerContextLatency > config.DiagnosticsThresholdDurationAsTimespan)
            {
                logger.LogInformation($"{operationName}; LatencyInMs:{timerContextLatency.TotalMilliseconds}; request took more than latency threshold {config.DiagnosticsThresholdDuration}, diagnostics: {cosmosDiagnostics}");
            }

            CosmosTraceDiagnostics traceDiagnostics = (CosmosTraceDiagnostics)cosmosDiagnostics;

            if (traceDiagnostics.IsGoneExceptionHit())
            {
                logger.LogInformation($"{operationName}; LatencyInMs:{timerContextLatency.TotalMilliseconds}; request contains 410(GoneExceptions), diagnostics:{cosmosDiagnostics}");
                return;
            }
        }
        public async Task InvalidSessionTokenAfterContainerRecreationAndCollectionCacheRefreshReproTest()
        {
            // ingestionClinet is dedicated client simulating the writes / container recreation in
            // the separate process - like Spark job
            using CosmosClient ingestionClient = TestCommon.CreateCosmosClient();
            Cosmos.Database ingestionDatabase = ingestionClient.GetDatabase(this.database.Id);

            ContainerProperties multiPartitionContainerSettings =
                new ContainerProperties(id: Guid.NewGuid().ToString(), partitionKeyPath: "/pk");
            Container ingestionContainer =
                await ingestionDatabase.CreateContainerAsync(multiPartitionContainerSettings);

            const int itemCountToBeIngested = 10;
            string    pk        = Guid.NewGuid().ToString("N");
            long?     latestLsn = null;

            Console.WriteLine("INGEST DOCUMENTS");
            for (int i = 0; i < itemCountToBeIngested; i++)
            {
                ToDoActivity testItem = ToDoActivity.CreateRandomToDoActivity();
                testItem.pk = pk;

                ItemResponse <ToDoActivity> response =
                    await ingestionContainer.CreateItemAsync <ToDoActivity>(item : testItem);

                Assert.IsNotNull(response);
                Assert.IsNotNull(response.Resource);
                Assert.IsNotNull(response.Diagnostics);
                long?lsnAfterCreate = await GetLSNFromSessionContainer(
                    ingestionContainer, multiPartitionContainerSettings, new PartitionKey(pk));

                Assert.IsNotNull(lsnAfterCreate);
                Assert.IsTrue(latestLsn == null || lsnAfterCreate.Value > latestLsn.Value);
                latestLsn = lsnAfterCreate;
                CosmosTraceDiagnostics diagnostics = (CosmosTraceDiagnostics)response.Diagnostics;
                Assert.IsFalse(diagnostics.IsGoneExceptionHit());
                Assert.IsFalse(string.IsNullOrEmpty(diagnostics.ToString()));
                Assert.IsTrue(diagnostics.GetClientElapsedTime() > TimeSpan.Zero);
            }

            // Dedciated query client used only for queries simulating the customer's app
            string    lastRequestedSessionToken = null;
            Container queryContainer            = TransportClientHelper.GetContainerWithIntercepter(
                this.database.Id,
                ingestionContainer.Id,
                (uri, operation, request) =>
            {
                if (request.ResourceType == ResourceType.Document &&
                    request.OperationType == OperationType.Query)
                {
                    lastRequestedSessionToken = request.Headers[HttpConstants.HttpHeaders.SessionToken];
                }
            },
                false,
                null);

            long?lsnAfterQueryOnOldContainer = null;

            // Issueing two queries - first won't use session tokens yet
            // second will provide session tokens captured from first request in the request to the backend
            for (int i = 0; i < 2; i++)
            {
                Console.WriteLine("RUN QUERY ON OLD CONTAINER ({0})", i);
                using FeedIterator <JObject> queryIteratorOldContainer = queryContainer.GetItemQueryIterator <JObject>(
                          new QueryDefinition("Select c.id FROM c"),
                          continuationToken: null,
                          new QueryRequestOptions
                {
                    ConsistencyLevel = Cosmos.ConsistencyLevel.Session,
                    PartitionKey     = new Cosmos.PartitionKey(pk)
                });
                int itemCountOldContainer = 0;
                while (queryIteratorOldContainer.HasMoreResults)
                {
                    FeedResponse <JObject> response = await queryIteratorOldContainer.ReadNextAsync();

                    if (i == 0)
                    {
                        string diagnosticString = response.Diagnostics.ToString();
                        Assert.IsTrue(diagnosticString.Contains("PKRangeCache Info("));
                        JObject diagnosticJobject = JObject.Parse(diagnosticString);
                        JToken  actualToken       = diagnosticJobject.SelectToken("$.children[0].children[?(@.name=='Get Partition Key Ranges')].children[?(@.name=='Try Get Overlapping Ranges')].data");
                        JToken  actualNode        = actualToken.Children().First().First();

                        Assert.IsTrue(actualNode["Previous Continuation Token"].ToString().Length == 0);
                        Assert.IsTrue(actualNode["Continuation Token"].ToString().Length > 0);
                    }

                    itemCountOldContainer += response.Count;
                }

                Assert.AreEqual(itemCountToBeIngested, itemCountOldContainer);
                lsnAfterQueryOnOldContainer = await GetLSNFromSessionContainer(
                    queryContainer, multiPartitionContainerSettings, new PartitionKey(pk));

                Assert.IsNotNull(lsnAfterQueryOnOldContainer);
                Assert.AreEqual(latestLsn.Value, lsnAfterQueryOnOldContainer.Value);
                if (i == 0)
                {
                    Assert.IsNull(lastRequestedSessionToken);
                }
                else
                {
                    Assert.IsNotNull(lastRequestedSessionToken);
                    Assert.AreEqual(latestLsn.Value, SessionTokenHelper.Parse(lastRequestedSessionToken).LSN);
                }
            }

            Console.WriteLine(
                "DELETE CONTAINER {0}",
                (await queryContainer.ReadContainerAsync()).Resource.ResourceId);
            await ingestionContainer.DeleteContainerAsync();

            Console.WriteLine("RECREATING CONTAINER...");
            ContainerResponse ingestionContainerResponse =
                await ingestionDatabase.CreateContainerAsync(multiPartitionContainerSettings);

            ingestionContainer = ingestionContainerResponse.Container;

            string responseSessionTokenValue =
                ingestionContainerResponse.Headers[HttpConstants.HttpHeaders.SessionToken];
            long?lsnAfterRecreatingContainerFromIngestionClient = responseSessionTokenValue != null?
                                                                  SessionTokenHelper.Parse(responseSessionTokenValue).LSN : null;

            Console.WriteLine(
                "RECREATED CONTAINER with new CollectionRid: {0} - LSN: {1}",
                ingestionContainerResponse.Resource.ResourceId,
                lsnAfterRecreatingContainerFromIngestionClient);

            // validates that the query container still uses the LSN captured from the old LSN
            long?lsnAfterCreatingNewContainerFromQueryClient = await GetLSNFromSessionContainer(
                queryContainer, multiPartitionContainerSettings, new PartitionKey(pk));

            Assert.IsNotNull(lsnAfterCreatingNewContainerFromQueryClient);
            Assert.AreEqual(latestLsn.Value, lsnAfterCreatingNewContainerFromQueryClient.Value);

            Console.WriteLine("GET FEED RANGES");
            // this will force a CollectionCache refresh - because no pk ranegs can be identified
            // for the old container anymore
            _ = await queryContainer.GetFeedRangesAsync();


            Console.WriteLine("RUN QUERY ON NEW CONTAINER");
            int itemCountNewContainer = 0;

            using FeedIterator <JObject> queryIteratorNewContainer = queryContainer.GetItemQueryIterator <JObject>(
                      new QueryDefinition("Select c.id FROM c"),
                      continuationToken: null,
                      new QueryRequestOptions
            {
                ConsistencyLevel = Cosmos.ConsistencyLevel.Session,
                PartitionKey     = new Cosmos.PartitionKey(pk),
            });
            Console.WriteLine("Query iterator created");
            while (queryIteratorNewContainer.HasMoreResults)
            {
                Console.WriteLine("Retrieving first page");
                try
                {
                    FeedResponse <JObject> response = await queryIteratorNewContainer.ReadNextAsync();

                    Console.WriteLine("Request Diagnostics for query against new container: {0}",
                                      response.Diagnostics.ToString());
                    itemCountNewContainer += response.Count;
                }
                catch (CosmosException cosmosException)
                {
                    Console.WriteLine("COSMOS EXCEPTION: {0}", cosmosException);
                    throw;
                }
            }

            Assert.AreEqual(0, itemCountNewContainer);
            long?lsnAfterQueryOnNewContainer = await GetLSNFromSessionContainer(
                queryContainer, multiPartitionContainerSettings, new PartitionKey(pk));

            Assert.IsNotNull(lsnAfterQueryOnNewContainer);
            Assert.IsTrue(
                lastRequestedSessionToken == null ||
                SessionTokenHelper.Parse(lastRequestedSessionToken).LSN ==
                lsnAfterRecreatingContainerFromIngestionClient,
                $"The requested session token {lastRequestedSessionToken} on the last query request should be null " +
                $"or have LSN '{lsnAfterRecreatingContainerFromIngestionClient}' (which is the LSN after " +
                "re-creating the container) if the session cache or the new CollectionName to Rid mapping was " +
                "correctly populated in the SessionCache.");
        }