From 2caa20c8a605ab5b8eed319304679fd2e6011b95 Mon Sep 17 00:00:00 2001 From: Matias Quaranta Date: Thu, 18 Mar 2021 11:25:17 -0700 Subject: [PATCH 01/19] 3.18.0-preview: Adds changelog and contract files (#2309) * version bump * changelog * Contract files * adding latest pr * changelog * version bump again * contracts * removing 3.18 contract * changelog * regression notes * notes * more changelog * changelog Co-authored-by: j82w --- Directory.Build.props | 4 +- .../contracts/API_3.18.0-preview.txt | 1433 +++++++++++++++++ changelog.md | 15 + 3 files changed, 1450 insertions(+), 2 deletions(-) create mode 100644 Microsoft.Azure.Cosmos/contracts/API_3.18.0-preview.txt diff --git a/Directory.Build.props b/Directory.Build.props index 989bdb3e5f..4b7e4790c8 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,8 +2,8 @@ 3.17.0 - 3.17.0 - preview1 + 3.18.0 + preview 3.17.1 1.0.0-previewV12 1.1.0-preview1 diff --git a/Microsoft.Azure.Cosmos/contracts/API_3.18.0-preview.txt b/Microsoft.Azure.Cosmos/contracts/API_3.18.0-preview.txt new file mode 100644 index 0000000000..24a1078e3b --- /dev/null +++ b/Microsoft.Azure.Cosmos/contracts/API_3.18.0-preview.txt @@ -0,0 +1,1433 @@ +namespace Microsoft.Azure.Cosmos +{ + public class AccountConsistency + { + public AccountConsistency(); + public ConsistencyLevel DefaultConsistencyLevel { get; } + public int MaxStalenessIntervalInSeconds { get; } + public int MaxStalenessPrefix { get; } + } + public class AccountProperties + { + public AccountConsistency Consistency { get; } + public string ETag { get; } + public string Id { get; } + public IEnumerable ReadableRegions { get; } + public IEnumerable WritableRegions { get; } + } + public class AccountRegion + { + public AccountRegion(); + public string Endpoint { get; } + public string Name { get; } + } + public sealed class BoundingBoxProperties + { + public BoundingBoxProperties(); + public double Xmax { get; set; } + public double Xmin { get; set; } + public double Ymax { get; set; } + public double Ymin { get; set; } + } + public abstract class ChangeFeedEstimator + { + protected ChangeFeedEstimator(); + public abstract FeedIterator GetCurrentStateIterator(ChangeFeedEstimatorRequestOptions changeFeedEstimatorRequestOptions=null); + } + public sealed class ChangeFeedEstimatorRequestOptions + { + public ChangeFeedEstimatorRequestOptions(); + public Nullable MaxItemCount { get; set; } + } + public abstract class ChangeFeedMode + { + public static ChangeFeedMode FullFidelity { get; } + public static ChangeFeedMode Incremental { get; } + } + public sealed class ChangeFeedPolicy + { + public ChangeFeedPolicy(); + public static TimeSpan FullFidelityNoRetention { get; } + public TimeSpan FullFidelityRetention { get; set; } + } + public abstract class ChangeFeedProcessor + { + protected ChangeFeedProcessor(); + public abstract Task StartAsync(); + public abstract Task StopAsync(); + } + public class ChangeFeedProcessorBuilder + { + public ChangeFeedProcessor Build(); + public ChangeFeedProcessorBuilder WithInstanceName(string instanceName); + public ChangeFeedProcessorBuilder WithLeaseConfiguration(Nullable acquireInterval=default(Nullable), Nullable expirationInterval=default(Nullable), Nullable renewInterval=default(Nullable)); + public ChangeFeedProcessorBuilder WithLeaseContainer(Container leaseContainer); + public ChangeFeedProcessorBuilder WithMaxItems(int maxItemCount); + public ChangeFeedProcessorBuilder WithPollInterval(TimeSpan pollInterval); + public ChangeFeedProcessorBuilder WithStartTime(DateTime startTime); + } + public sealed class ChangeFeedProcessorState + { + public ChangeFeedProcessorState(string leaseToken, long estimatedLag, string instanceName); + public long EstimatedLag { get; } + public string InstanceName { get; } + public string LeaseToken { get; } + } + public sealed class ChangeFeedRequestOptions : RequestOptions + { + public ChangeFeedRequestOptions(); + public bool EmitOldContinuationToken { get; set; } + public new string IfMatchEtag { get; set; } + public new string IfNoneMatchEtag { get; set; } + public Nullable PageSizeHint { get; set; } + } + public abstract class ChangeFeedStartFrom + { + public static ChangeFeedStartFrom Beginning(); + public static ChangeFeedStartFrom Beginning(FeedRange feedRange); + public static ChangeFeedStartFrom ContinuationToken(string continuationToken); + public static ChangeFeedStartFrom Now(); + public static ChangeFeedStartFrom Now(FeedRange feedRange); + public static ChangeFeedStartFrom Time(DateTime dateTimeUtc); + public static ChangeFeedStartFrom Time(DateTime dateTimeUtc, FeedRange feedRange); + } + public sealed class ClientEncryptionIncludedPath + { + public ClientEncryptionIncludedPath(); + public string ClientEncryptionKeyId { get; set; } + public string EncryptionAlgorithm { get; set; } + public string EncryptionType { get; set; } + public string Path { get; set; } + } + public abstract class ClientEncryptionKey + { + protected ClientEncryptionKey(); + public abstract string Id { get; } + public abstract Task ReadAsync(RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceAsync(ClientEncryptionKeyProperties clientEncryptionKeyProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + } + public class ClientEncryptionKeyProperties : IEquatable + { + protected ClientEncryptionKeyProperties(); + public ClientEncryptionKeyProperties(string id, string encryptionAlgorithm, byte[] wrappedDataEncryptionKey, EncryptionKeyWrapMetadata encryptionKeyWrapMetadata); + public Nullable CreatedTime { get; } + public string EncryptionAlgorithm { get; } + public EncryptionKeyWrapMetadata EncryptionKeyWrapMetadata { get; } + public string ETag { get; } + public string Id { get; } + public Nullable LastModified { get; } + public virtual string SelfLink { get; } + public byte[] WrappedDataEncryptionKey { get; } + public bool Equals(ClientEncryptionKeyProperties other); + public override bool Equals(object obj); + public override int GetHashCode(); + } + public class ClientEncryptionKeyResponse : Response + { + protected ClientEncryptionKeyResponse(); + public override string ActivityId { get; } + public virtual ClientEncryptionKey ClientEncryptionKey { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public override double RequestCharge { get; } + public override ClientEncryptionKeyProperties Resource { get; } + public override HttpStatusCode StatusCode { get; } + public static implicit operator ClientEncryptionKey (ClientEncryptionKeyResponse response); + } + public sealed class ClientEncryptionPolicy + { + public ClientEncryptionPolicy(IEnumerable includedPaths); + public IEnumerable IncludedPaths { get; } + } + public sealed class CompositePath + { + public CompositePath(); + public CompositePathSortOrder Order { get; set; } + public string Path { get; set; } + } + public enum CompositePathSortOrder + { + Ascending = 0, + Descending = 1, + } + public class ConflictProperties + { + public ConflictProperties(); + public string Id { get; } + public OperationKind OperationKind { get; } + public string SelfLink { get; } + } + public enum ConflictResolutionMode + { + Custom = 1, + LastWriterWins = 0, + } + public class ConflictResolutionPolicy + { + public ConflictResolutionPolicy(); + public ConflictResolutionMode Mode { get; set; } + public string ResolutionPath { get; set; } + public string ResolutionProcedure { get; set; } + } + public abstract class Conflicts + { + protected Conflicts(); + public abstract Task DeleteAsync(ConflictProperties conflict, PartitionKey partitionKey, CancellationToken cancellationToken=default(CancellationToken)); + public abstract FeedIterator GetConflictQueryIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetConflictQueryIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetConflictQueryStreamIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetConflictQueryStreamIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract T ReadConflictContent(ConflictProperties conflict); + public abstract Task> ReadCurrentAsync(ConflictProperties conflict, PartitionKey partitionKey, CancellationToken cancellationToken=default(CancellationToken)); + } + public enum ConnectionMode + { + Direct = 1, + Gateway = 0, + } + public enum ConsistencyLevel + { + BoundedStaleness = 1, + ConsistentPrefix = 4, + Eventual = 3, + Session = 2, + Strong = 0, + } + public abstract class Container + { + protected Container(); + public abstract Conflicts Conflicts { get; } + public abstract Database Database { get; } + public abstract string Id { get; } + public abstract Scripts Scripts { get; } + public abstract Task> CreateItemAsync(T item, Nullable partitionKey=default(Nullable), ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateItemStreamAsync(Stream streamPayload, PartitionKey partitionKey, ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract TransactionalBatch CreateTransactionalBatch(PartitionKey partitionKey); + public abstract Task DeleteContainerAsync(ContainerRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task DeleteContainerStreamAsync(ContainerRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task> DeleteItemAsync(string id, PartitionKey partitionKey, ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task DeleteItemStreamAsync(string id, PartitionKey partitionKey, ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract ChangeFeedEstimator GetChangeFeedEstimator(string processorName, Container leaseContainer); + public abstract ChangeFeedProcessorBuilder GetChangeFeedEstimatorBuilder(string processorName, Container.ChangesEstimationHandler estimationDelegate, Nullable estimationPeriod=default(Nullable)); + public abstract FeedIterator GetChangeFeedIterator(ChangeFeedStartFrom changeFeedStartFrom, ChangeFeedMode changeFeedMode, ChangeFeedRequestOptions changeFeedRequestOptions=null); + public abstract ChangeFeedProcessorBuilder GetChangeFeedProcessorBuilder(string processorName, Container.ChangesHandler onChangesDelegate); + public abstract FeedIterator GetChangeFeedStreamIterator(ChangeFeedStartFrom changeFeedStartFrom, ChangeFeedMode changeFeedMode, ChangeFeedRequestOptions changeFeedRequestOptions=null); + public abstract Task> GetFeedRangesAsync(CancellationToken cancellationToken=default(CancellationToken)); + public abstract IOrderedQueryable GetItemLinqQueryable(bool allowSynchronousQueryExecution=false, string continuationToken=null, QueryRequestOptions requestOptions=null, CosmosLinqSerializerOptions linqSerializerOptions=null); + public abstract FeedIterator GetItemQueryIterator(FeedRange feedRange, QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetItemQueryIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetItemQueryIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetItemQueryStreamIterator(FeedRange feedRange, QueryDefinition queryDefinition, string continuationToken, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetItemQueryStreamIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetItemQueryStreamIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract Task> GetPartitionKeyRangesAsync(FeedRange feedRange, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task> PatchItemAsync(string id, PartitionKey partitionKey, IReadOnlyList patchOperations, PatchItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task PatchItemStreamAsync(string id, PartitionKey partitionKey, IReadOnlyList patchOperations, PatchItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReadContainerAsync(ContainerRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReadContainerStreamAsync(ContainerRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task> ReadItemAsync(string id, PartitionKey partitionKey, ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReadItemStreamAsync(string id, PartitionKey partitionKey, ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReadThroughputAsync(RequestOptions requestOptions, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task> ReadThroughputAsync(CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceContainerAsync(ContainerProperties containerProperties, ContainerRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceContainerStreamAsync(ContainerProperties containerProperties, ContainerRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task> ReplaceItemAsync(T item, string id, Nullable partitionKey=default(Nullable), ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceItemStreamAsync(Stream streamPayload, string id, PartitionKey partitionKey, ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceThroughputAsync(ThroughputProperties throughputProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceThroughputAsync(int throughput, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task> UpsertItemAsync(T item, Nullable partitionKey=default(Nullable), ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task UpsertItemStreamAsync(Stream streamPayload, PartitionKey partitionKey, ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public delegate Task ChangesEstimationHandler(long estimatedPendingChanges, CancellationToken cancellationToken); + public delegate Task ChangesHandler(IReadOnlyCollection changes, CancellationToken cancellationToken); + } + public class ContainerProperties + { + public ContainerProperties(); + public ContainerProperties(string id, IReadOnlyList partitionKeyPaths); + public ContainerProperties(string id, string partitionKeyPath); + public Nullable AnalyticalStoreTimeToLiveInSeconds { get; set; } + public ChangeFeedPolicy ChangeFeedPolicy { get; set; } + public ClientEncryptionPolicy ClientEncryptionPolicy { get; set; } + public ConflictResolutionPolicy ConflictResolutionPolicy { get; set; } + public Nullable DefaultTimeToLive { get; set; } + public string ETag { get; } + public GeospatialConfig GeospatialConfig { get; set; } + public string Id { get; set; } + public IndexingPolicy IndexingPolicy { get; set; } + public Nullable LastModified { get; } + public Nullable PartitionKeyDefinitionVersion { get; set; } + public string PartitionKeyPath { get; set; } + public IReadOnlyList PartitionKeyPaths { get; set; } + public string SelfLink { get; } + public string TimeToLivePropertyPath { get; set; } + public UniqueKeyPolicy UniqueKeyPolicy { get; set; } + } + public class ContainerRequestOptions : RequestOptions + { + public ContainerRequestOptions(); + public bool PopulateQuotaInfo { get; set; } + } + public class ContainerResponse : Response + { + protected ContainerResponse(); + public override string ActivityId { get; } + public virtual Container Container { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public override double RequestCharge { get; } + public override ContainerProperties Resource { get; } + public override HttpStatusCode StatusCode { get; } + public static implicit operator Container (ContainerResponse response); + } + public class CosmosClient : IDisposable + { + protected CosmosClient(); + public CosmosClient(string accountEndpoint, TokenCredential tokenCredential, CosmosClientOptions clientOptions=null); + public CosmosClient(string connectionString, CosmosClientOptions clientOptions=null); + public CosmosClient(string accountEndpoint, string authKeyOrResourceToken, CosmosClientOptions clientOptions=null); + public virtual CosmosClientOptions ClientOptions { get; } + public virtual Uri Endpoint { get; } + public virtual CosmosResponseFactory ResponseFactory { get; } + public static Task CreateAndInitializeAsync(string accountEndpoint, TokenCredential tokenCredential, IReadOnlyList> containers, CosmosClientOptions cosmosClientOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public static Task CreateAndInitializeAsync(string connectionString, IReadOnlyList> containers, CosmosClientOptions cosmosClientOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public static Task CreateAndInitializeAsync(string accountEndpoint, string authKeyOrResourceToken, IReadOnlyList> containers, CosmosClientOptions cosmosClientOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public virtual Task CreateDatabaseAsync(string id, ThroughputProperties throughputProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public virtual Task CreateDatabaseAsync(string id, Nullable throughput=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public virtual Task CreateDatabaseIfNotExistsAsync(string id, ThroughputProperties throughputProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public virtual Task CreateDatabaseIfNotExistsAsync(string id, Nullable throughput=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public virtual Task CreateDatabaseStreamAsync(DatabaseProperties databaseProperties, Nullable throughput=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public void Dispose(); + protected virtual void Dispose(bool disposing); + public virtual Container GetContainer(string databaseId, string containerId); + public virtual Database GetDatabase(string id); + public virtual FeedIterator GetDatabaseQueryIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public virtual FeedIterator GetDatabaseQueryIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public virtual FeedIterator GetDatabaseQueryStreamIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public virtual FeedIterator GetDatabaseQueryStreamIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public virtual Task ReadAccountAsync(); + } + public class CosmosClientOptions + { + public CosmosClientOptions(); + public bool AllowBulkExecution { get; set; } + public string ApplicationName { get; set; } + public IReadOnlyList ApplicationPreferredRegions { get; set; } + public string ApplicationRegion { get; set; } + public ConnectionMode ConnectionMode { get; set; } + public Nullable ConsistencyLevel { get; set; } + public Collection CustomHandlers { get; } + public Nullable EnableContentResponseOnWrite { get; set; } + public bool EnableTcpConnectionEndpointRediscovery { get; set; } + public int GatewayModeMaxConnectionLimit { get; set; } + public Func HttpClientFactory { get; set; } + public Nullable IdleTcpConnectionTimeout { get; set; } + public bool LimitToEndpoint { get; set; } + public Nullable MaxRequestsPerTcpConnection { get; set; } + public Nullable MaxRetryAttemptsOnRateLimitedRequests { get; set; } + public Nullable MaxRetryWaitTimeOnRateLimitedRequests { get; set; } + public Nullable MaxTcpConnectionsPerEndpoint { get; set; } + public Nullable OpenTcpConnectionTimeout { get; set; } + public Nullable PortReuseMode { get; set; } + public TimeSpan RequestTimeout { get; set; } + public CosmosSerializer Serializer { get; set; } + public CosmosSerializationOptions SerializerOptions { get; set; } + public Nullable TokenCredentialBackgroundRefreshInterval { get; set; } + public IWebProxy WebProxy { get; set; } + } + public abstract class CosmosDiagnostics + { + protected CosmosDiagnostics(); + public virtual TimeSpan GetClientElapsedTime(); + public abstract IReadOnlyList> GetContactedRegions(); + public abstract override string ToString(); + } + public class CosmosException : Exception + { + public CosmosException(string message, HttpStatusCode statusCode, int subStatusCode, string activityId, double requestCharge); + public virtual string ActivityId { get; } + public virtual CosmosDiagnostics Diagnostics { get; } + public virtual Headers Headers { get; } + public virtual double RequestCharge { get; } + public virtual string ResponseBody { get; } + public virtual Nullable RetryAfter { get; } + public override string StackTrace { get; } + public virtual HttpStatusCode StatusCode { get; } + public virtual int SubStatusCode { get; } + public override string ToString(); + public virtual bool TryGetHeader(string headerName, out string value); + } + public sealed class CosmosLinqSerializerOptions + { + public CosmosLinqSerializerOptions(); + public CosmosPropertyNamingPolicy PropertyNamingPolicy { get; set; } + } + public class CosmosOperationCanceledException : OperationCanceledException + { + public CosmosOperationCanceledException(OperationCanceledException originalException, CosmosDiagnostics diagnostics); + public override IDictionary Data { get; } + public CosmosDiagnostics Diagnostics { get; } + public override string HelpLink { get; set; } + public override string Message { get; } + public override string Source { get; set; } + public override string StackTrace { get; } + public override Exception GetBaseException(); + public override string ToString(); + } + public enum CosmosPropertyNamingPolicy + { + CamelCase = 1, + Default = 0, + } + public abstract class CosmosResponseFactory + { + protected CosmosResponseFactory(); + public abstract FeedResponse CreateItemFeedResponse(ResponseMessage responseMessage); + public abstract ItemResponse CreateItemResponse(ResponseMessage responseMessage); + public abstract StoredProcedureExecuteResponse CreateStoredProcedureExecuteResponse(ResponseMessage responseMessage); + } + public sealed class CosmosSerializationOptions + { + public CosmosSerializationOptions(); + public bool IgnoreNullValues { get; set; } + public bool Indented { get; set; } + public CosmosPropertyNamingPolicy PropertyNamingPolicy { get; set; } + } + public abstract class CosmosSerializer + { + protected CosmosSerializer(); + public abstract T FromStream(Stream stream); + public abstract Stream ToStream(T input); + } + public abstract class Database + { + protected Database(); + public abstract CosmosClient Client { get; } + public abstract string Id { get; } + public abstract Task CreateClientEncryptionKeyAsync(ClientEncryptionKeyProperties clientEncryptionKeyProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateContainerAsync(ContainerProperties containerProperties, ThroughputProperties throughputProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateContainerAsync(ContainerProperties containerProperties, Nullable throughput=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateContainerAsync(string id, string partitionKeyPath, Nullable throughput=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateContainerIfNotExistsAsync(ContainerProperties containerProperties, ThroughputProperties throughputProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateContainerIfNotExistsAsync(ContainerProperties containerProperties, Nullable throughput=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateContainerIfNotExistsAsync(string id, string partitionKeyPath, Nullable throughput=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateContainerStreamAsync(ContainerProperties containerProperties, ThroughputProperties throughputProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateContainerStreamAsync(ContainerProperties containerProperties, Nullable throughput=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateUserAsync(string id, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract ContainerBuilder DefineContainer(string name, string partitionKeyPath); + public abstract Task DeleteAsync(RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task DeleteStreamAsync(RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract ClientEncryptionKey GetClientEncryptionKey(string id); + public abstract FeedIterator GetClientEncryptionKeyQueryIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract Container GetContainer(string id); + public abstract FeedIterator GetContainerQueryIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetContainerQueryIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetContainerQueryStreamIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetContainerQueryStreamIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract User GetUser(string id); + public abstract FeedIterator GetUserQueryIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetUserQueryIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract Task ReadAsync(RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReadStreamAsync(RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReadThroughputAsync(RequestOptions requestOptions, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task> ReadThroughputAsync(CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceThroughputAsync(ThroughputProperties throughputProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceThroughputAsync(int throughput, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task UpsertUserAsync(string id, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + } + public class DatabaseProperties + { + public DatabaseProperties(); + public DatabaseProperties(string id); + public string ETag { get; } + public string Id { get; set; } + public Nullable LastModified { get; } + public string SelfLink { get; } + } + public class DatabaseResponse : Response + { + protected DatabaseResponse(); + public override string ActivityId { get; } + public virtual Database Database { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public override double RequestCharge { get; } + public override DatabaseProperties Resource { get; } + public override HttpStatusCode StatusCode { get; } + public static implicit operator Database (DatabaseResponse response); + } + public enum DataType + { + LineString = 3, + MultiPolygon = 5, + Number = 0, + Point = 2, + Polygon = 4, + String = 1, + } + public class EncryptionKeyWrapMetadata : IEquatable + { + public EncryptionKeyWrapMetadata(EncryptionKeyWrapMetadata source); + public EncryptionKeyWrapMetadata(string name, string value); + public string Name { get; } + public string Value { get; } + public bool Equals(EncryptionKeyWrapMetadata other); + public override bool Equals(object obj); + public override int GetHashCode(); + } + public sealed class ExcludedPath + { + public ExcludedPath(); + public string Path { get; set; } + } + public abstract class FeedIterator : IDisposable + { + protected FeedIterator(); + public abstract bool HasMoreResults { get; } + public void Dispose(); + protected virtual void Dispose(bool disposing); + public abstract Task ReadNextAsync(CancellationToken cancellationToken=default(CancellationToken)); + } + public abstract class FeedIterator : IDisposable + { + protected FeedIterator(); + public abstract bool HasMoreResults { get; } + public void Dispose(); + protected virtual void Dispose(bool disposing); + public abstract Task> ReadNextAsync(CancellationToken cancellationToken=default(CancellationToken)); + } + public abstract class FeedRange + { + protected FeedRange(); + public static FeedRange FromJsonString(string toStringValue); + public static FeedRange FromPartitionKey(PartitionKey partitionKey); + public abstract string ToJsonString(); + } + public abstract class FeedResponse : IEnumerable, IEnumerable + { + protected FeedResponse(); + public override string ActivityId { get; } + public abstract string ContinuationToken { get; } + public abstract int Count { get; } + public override string ETag { get; } + public override double RequestCharge { get; } + public abstract IEnumerator GetEnumerator(); + IEnumerator System.Collections.IEnumerable.GetEnumerator(); + } + public sealed class GeospatialConfig + { + public GeospatialConfig(); + public GeospatialConfig(GeospatialType geospatialType); + public GeospatialType GeospatialType { get; set; } + } + public enum GeospatialType + { + Geography = 0, + Geometry = 1, + } + public class Headers : IEnumerable + { + public Headers(); + public virtual string ActivityId { get; } + public virtual string ContentLength { get; set; } + public virtual string ContentType { get; } + public virtual string ContinuationToken { get; } + public virtual string ETag { get; } + public virtual string this[string headerName] { get; set; } + public virtual string Location { get; } + public virtual double RequestCharge { get; } + public virtual string Session { get; } + public virtual void Add(string headerName, IEnumerable values); + public virtual void Add(string headerName, string value); + public virtual string[] AllKeys(); + public virtual string Get(string headerName); + public virtual IEnumerator GetEnumerator(); + public virtual T GetHeaderValue(string headerName); + public virtual string GetValueOrDefault(string headerName); + public virtual void Remove(string headerName); + public virtual void Set(string headerName, string value); + IEnumerator System.Collections.IEnumerable.GetEnumerator(); + public virtual bool TryGetValue(string headerName, out string value); + } + public sealed class IncludedPath + { + public IncludedPath(); + public string Path { get; set; } + } + public enum IndexingDirective + { + Default = 0, + Exclude = 2, + Include = 1, + } + public enum IndexingMode + { + Consistent = 0, + Lazy = 1, + None = 2, + } + public sealed class IndexingPolicy + { + public IndexingPolicy(); + public bool Automatic { get; set; } + public Collection> CompositeIndexes { get; } + public Collection ExcludedPaths { get; } + public Collection IncludedPaths { get; } + public IndexingMode IndexingMode { get; set; } + public Collection SpatialIndexes { get; } + } + public enum IndexKind + { + Hash = 0, + Range = 1, + Spatial = 2, + } + public class ItemRequestOptions : RequestOptions + { + public ItemRequestOptions(); + public Nullable ConsistencyLevel { get; set; } + public Nullable EnableContentResponseOnWrite { get; set; } + public Nullable IndexingDirective { get; set; } + public IEnumerable PostTriggers { get; set; } + public IEnumerable PreTriggers { get; set; } + public string SessionToken { get; set; } + } + public class ItemResponse : Response + { + protected ItemResponse(); + public override string ActivityId { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public override double RequestCharge { get; } + public override T Resource { get; } + public override HttpStatusCode StatusCode { get; } + } + public enum OperationKind + { + Create = 1, + Delete = 3, + Invalid = 0, + Read = 4, + Replace = 2, + } + public struct PartitionKey : IEquatable + { + public static readonly PartitionKey None; + public static readonly PartitionKey Null; + public static readonly string SystemKeyName; + public static readonly string SystemKeyPath; + public PartitionKey(bool partitionKeyValue); + public PartitionKey(double partitionKeyValue); + public PartitionKey(string partitionKeyValue); + public bool Equals(PartitionKey other); + public override bool Equals(object obj); + public override int GetHashCode(); + public static bool operator ==(PartitionKey left, PartitionKey right); + public static bool operator !=(PartitionKey left, PartitionKey right); + public override string ToString(); + } + public sealed class PartitionKeyBuilder + { + public PartitionKeyBuilder(); + public PartitionKeyBuilder Add(bool val); + public PartitionKeyBuilder Add(double val); + public PartitionKeyBuilder Add(string val); + public PartitionKeyBuilder AddNoneType(); + public PartitionKeyBuilder AddNullValue(); + public PartitionKey Build(); + } + public enum PartitionKeyDefinitionVersion + { + V1 = 1, + V2 = 2, + } + public sealed class PatchItemRequestOptions : ItemRequestOptions + { + public PatchItemRequestOptions(); + public string FilterPredicate { get; set; } + } + public abstract class PatchOperation + { + protected PatchOperation(); + public abstract PatchOperationType OperationType { get; } + public abstract string Path { get; } + public static PatchOperation Add(string path, T value); + public static PatchOperation Increment(string path, double value); + public static PatchOperation Increment(string path, long value); + public static PatchOperation Remove(string path); + public static PatchOperation Replace(string path, T value); + public static PatchOperation Set(string path, T value); + } + public enum PatchOperationType + { + Add = 0, + Increment = 4, + Remove = 1, + Replace = 2, + Set = 3, + } + public abstract class PatchOperation : PatchOperation + { + protected PatchOperation(); + public abstract T Value { get; } + } + public abstract class Permission + { + protected Permission(); + public abstract string Id { get; } + public abstract Task DeleteAsync(RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReadAsync(Nullable tokenExpiryInSeconds=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceAsync(PermissionProperties permissionProperties, Nullable tokenExpiryInSeconds=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + } + public enum PermissionMode : byte + { + All = (byte)2, + Read = (byte)1, + } + public class PermissionProperties + { + public PermissionProperties(string id, PermissionMode permissionMode, Container container, PartitionKey resourcePartitionKey, string itemId); + public PermissionProperties(string id, PermissionMode permissionMode, Container container, Nullable resourcePartitionKey=default(Nullable)); + public string ETag { get; } + public string Id { get; } + public Nullable LastModified { get; } + public PermissionMode PermissionMode { get; } + public Nullable ResourcePartitionKey { get; set; } + public string ResourceUri { get; } + public string SelfLink { get; } + public string Token { get; } + } + public class PermissionResponse : Response + { + protected PermissionResponse(); + public override string ActivityId { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public virtual Permission Permission { get; } + public override double RequestCharge { get; } + public override PermissionProperties Resource { get; } + public override HttpStatusCode StatusCode { get; } + public static implicit operator Permission (PermissionResponse response); + } + public enum PortReuseMode + { + PrivatePortPool = 1, + ReuseUnicastPort = 0, + } + public class QueryDefinition + { + public QueryDefinition(string query); + public string QueryText { get; } + public IReadOnlyList> GetQueryParameters(); + public QueryDefinition WithParameter(string name, object value); + } + public class QueryRequestOptions : RequestOptions + { + public QueryRequestOptions(); + public Nullable ConsistencyLevel { get; set; } + public Nullable EnableLowPrecisionOrderBy { get; set; } + public Nullable EnableScanInQuery { get; set; } + public Nullable MaxBufferedItemCount { get; set; } + public Nullable MaxConcurrency { get; set; } + public Nullable MaxItemCount { get; set; } + public Nullable PartitionKey { get; set; } + public Nullable ResponseContinuationTokenLimitInKb { get; set; } + public string SessionToken { get; set; } + } + public static class Regions + { + public const string AustraliaCentral = "Australia Central"; + public const string AustraliaCentral2 = "Australia Central 2"; + public const string AustraliaEast = "Australia East"; + public const string AustraliaSoutheast = "Australia Southeast"; + public const string BrazilSouth = "Brazil South"; + public const string BrazilSoutheast = "Brazil Southeast"; + public const string CanadaCentral = "Canada Central"; + public const string CanadaEast = "Canada East"; + public const string CentralIndia = "Central India"; + public const string CentralUS = "Central US"; + public const string CentralUSEUAP = "Central US EUAP"; + public const string ChinaEast = "China East"; + public const string ChinaEast2 = "China East 2"; + public const string ChinaNorth = "China North"; + public const string ChinaNorth2 = "China North 2"; + public const string EastAsia = "East Asia"; + public const string EastUS = "East US"; + public const string EastUS2 = "East US 2"; + public const string EastUS2EUAP = "East US 2 EUAP"; + public const string EastUSSLV = "East US SLV"; + public const string FranceCentral = "France Central"; + public const string FranceSouth = "France South"; + public const string GermanyCentral = "Germany Central"; + public const string GermanyNorth = "Germany North"; + public const string GermanyNortheast = "Germany Northeast"; + public const string GermanyWestCentral = "Germany West Central"; + public const string JapanEast = "Japan East"; + public const string JapanWest = "Japan West"; + public const string JioIndiaCentral = "Jio India Central"; + public const string JioIndiaWest = "Jio India West"; + public const string KoreaCentral = "Korea Central"; + public const string KoreaSouth = "Korea South"; + public const string NorthCentralUS = "North Central US"; + public const string NorthEurope = "North Europe"; + public const string NorwayEast = "Norway East"; + public const string NorwayWest = "Norway West"; + public const string SouthAfricaNorth = "South Africa North"; + public const string SouthAfricaWest = "South Africa West"; + public const string SouthCentralUS = "South Central US"; + public const string SoutheastAsia = "Southeast Asia"; + public const string SouthIndia = "South India"; + public const string SwitzerlandNorth = "Switzerland North"; + public const string SwitzerlandWest = "Switzerland West"; + public const string UAECentral = "UAE Central"; + public const string UAENorth = "UAE North"; + public const string UKSouth = "UK South"; + public const string UKWest = "UK West"; + public const string USDoDCentral = "USDoD Central"; + public const string USDoDEast = "USDoD East"; + public const string USGovArizona = "USGov Arizona"; + public const string USGovTexas = "USGov Texas"; + public const string USGovVirginia = "USGov Virginia"; + public const string USNatEast = "USNat East"; + public const string USNatWest = "USNat West"; + public const string USSecEast = "USSec East"; + public const string USSecWest = "USSec West"; + public const string WestCentralUS = "West Central US"; + public const string WestEurope = "West Europe"; + public const string WestIndia = "West India"; + public const string WestUS = "West US"; + public const string WestUS2 = "West US 2"; + public const string WestUS3 = "West US 3"; + } + public abstract class RequestHandler + { + protected RequestHandler(); + public RequestHandler InnerHandler { get; set; } + public virtual Task SendAsync(RequestMessage request, CancellationToken cancellationToken); + } + public class RequestMessage : IDisposable + { + public RequestMessage(); + public RequestMessage(HttpMethod method, Uri requestUri); + public virtual Stream Content { get; set; } + public virtual Headers Headers { get; } + public virtual HttpMethod Method { get; } + public virtual Dictionary Properties { get; } + public virtual Uri RequestUri { get; } + public void Dispose(); + protected virtual void Dispose(bool disposing); + } + public class RequestOptions + { + public RequestOptions(); + public string IfMatchEtag { get; set; } + public string IfNoneMatchEtag { get; set; } + public IReadOnlyDictionary Properties { get; set; } + } + public class ResponseMessage : IDisposable + { + public ResponseMessage(); + public ResponseMessage(HttpStatusCode statusCode, RequestMessage requestMessage=null, string errorMessage=null); + public virtual Stream Content { get; set; } + public virtual string ContinuationToken { get; } + public virtual CosmosDiagnostics Diagnostics { get; } + public virtual string ErrorMessage { get; } + public virtual Headers Headers { get; } + public virtual bool IsSuccessStatusCode { get; } + public virtual RequestMessage RequestMessage { get; } + public virtual HttpStatusCode StatusCode { get; } + public void Dispose(); + protected virtual void Dispose(bool disposing); + public virtual ResponseMessage EnsureSuccessStatusCode(); + } + public abstract class Response + { + protected Response(); + public abstract string ActivityId { get; } + public abstract CosmosDiagnostics Diagnostics { get; } + public abstract string ETag { get; } + public abstract Headers Headers { get; } + public abstract double RequestCharge { get; } + public abstract T Resource { get; } + public abstract HttpStatusCode StatusCode { get; } + public static implicit operator T (Response response); + } + public sealed class SpatialPath + { + public SpatialPath(); + public BoundingBoxProperties BoundingBox { get; set; } + public string Path { get; set; } + public Collection SpatialTypes { get; } + } + public enum SpatialType + { + LineString = 1, + MultiPolygon = 3, + Point = 0, + Polygon = 2, + } + public class ThroughputProperties + { + public Nullable AutoscaleMaxThroughput { get; } + public string ETag { get; } + public Nullable LastModified { get; } + public string SelfLink { get; } + public Nullable Throughput { get; } + public static ThroughputProperties CreateAutoscaleThroughput(int autoscaleMaxThroughput); + public static ThroughputProperties CreateManualThroughput(int throughput); + } + public class ThroughputResponse : Response + { + protected ThroughputResponse(); + public override string ActivityId { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public Nullable IsReplacePending { get; } + public Nullable MinThroughput { get; } + public override double RequestCharge { get; } + public override ThroughputProperties Resource { get; } + public override HttpStatusCode StatusCode { get; } + public static implicit operator ThroughputProperties (ThroughputResponse response); + } + public abstract class TransactionalBatch + { + protected TransactionalBatch(); + public abstract TransactionalBatch CreateItemStream(Stream streamPayload, TransactionalBatchItemRequestOptions requestOptions=null); + public abstract TransactionalBatch CreateItem(T item, TransactionalBatchItemRequestOptions requestOptions=null); + public abstract TransactionalBatch DeleteItem(string id, TransactionalBatchItemRequestOptions requestOptions=null); + public abstract Task ExecuteAsync(TransactionalBatchRequestOptions requestOptions, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ExecuteAsync(CancellationToken cancellationToken=default(CancellationToken)); + public abstract TransactionalBatch PatchItem(string id, IReadOnlyList patchOperations, TransactionalBatchPatchItemRequestOptions requestOptions=null); + public abstract TransactionalBatch ReadItem(string id, TransactionalBatchItemRequestOptions requestOptions=null); + public abstract TransactionalBatch ReplaceItemStream(string id, Stream streamPayload, TransactionalBatchItemRequestOptions requestOptions=null); + public abstract TransactionalBatch ReplaceItem(string id, T item, TransactionalBatchItemRequestOptions requestOptions=null); + public abstract TransactionalBatch UpsertItemStream(Stream streamPayload, TransactionalBatchItemRequestOptions requestOptions=null); + public abstract TransactionalBatch UpsertItem(T item, TransactionalBatchItemRequestOptions requestOptions=null); + } + public class TransactionalBatchItemRequestOptions : RequestOptions + { + public TransactionalBatchItemRequestOptions(); + public Nullable EnableContentResponseOnWrite { get; set; } + public Nullable IndexingDirective { get; set; } + } + public class TransactionalBatchOperationResult + { + protected TransactionalBatchOperationResult(); + public virtual string ETag { get; } + public virtual bool IsSuccessStatusCode { get; } + public virtual Stream ResourceStream { get; } + public virtual TimeSpan RetryAfter { get; } + public virtual HttpStatusCode StatusCode { get; } + } + public class TransactionalBatchOperationResult : TransactionalBatchOperationResult + { + protected TransactionalBatchOperationResult(); + public virtual T Resource { get; set; } + } + public class TransactionalBatchPatchItemRequestOptions : TransactionalBatchItemRequestOptions + { + public TransactionalBatchPatchItemRequestOptions(); + public string FilterPredicate { get; set; } + } + public class TransactionalBatchRequestOptions : RequestOptions + { + public TransactionalBatchRequestOptions(); + public Nullable ConsistencyLevel { get; set; } + public string SessionToken { get; set; } + } + public class TransactionalBatchResponse : IDisposable, IEnumerable, IEnumerable, IReadOnlyCollection, IReadOnlyList + { + protected TransactionalBatchResponse(); + public virtual string ActivityId { get; } + public virtual int Count { get; } + public virtual CosmosDiagnostics Diagnostics { get; } + public virtual string ErrorMessage { get; } + public virtual Headers Headers { get; } + public virtual bool IsSuccessStatusCode { get; } + public virtual TransactionalBatchOperationResult this[int index] { get; } + public virtual double RequestCharge { get; } + public virtual Nullable RetryAfter { get; } + public virtual HttpStatusCode StatusCode { get; } + public void Dispose(); + protected virtual void Dispose(bool disposing); + public virtual IEnumerator GetEnumerator(); + public virtual TransactionalBatchOperationResult GetOperationResultAtIndex(int index); + IEnumerator System.Collections.IEnumerable.GetEnumerator(); + } + public class UniqueKey + { + public UniqueKey(); + public Collection Paths { get; } + } + public sealed class UniqueKeyPolicy + { + public UniqueKeyPolicy(); + public Collection UniqueKeys { get; } + } + public abstract class User + { + protected User(); + public abstract string Id { get; } + public abstract Task CreatePermissionAsync(PermissionProperties permissionProperties, Nullable tokenExpiryInSeconds=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task DeleteAsync(RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Permission GetPermission(string id); + public abstract FeedIterator GetPermissionQueryIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetPermissionQueryIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract Task ReadAsync(RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceAsync(UserProperties userProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task UpsertPermissionAsync(PermissionProperties permissionProperties, Nullable tokenExpiryInSeconds=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + } + public class UserProperties + { + protected UserProperties(); + public UserProperties(string id); + public string ETag { get; } + public string Id { get; set; } + public Nullable LastModified { get; } + public string SelfLink { get; } + } + public class UserResponse : Response + { + protected UserResponse(); + public override string ActivityId { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public override double RequestCharge { get; } + public override UserProperties Resource { get; } + public override HttpStatusCode StatusCode { get; } + public virtual User User { get; } + public static implicit operator User (UserResponse response); + } +} +namespace Microsoft.Azure.Cosmos.Fluent +{ + public class ChangeFeedPolicyDefinition + { + public ContainerBuilder Attach(); + } + public sealed class ClientEncryptionPolicyDefinition + { + public ContainerBuilder Attach(); + public ClientEncryptionPolicyDefinition WithIncludedPath(ClientEncryptionIncludedPath path); + } + public class CompositeIndexDefinition + { + public T Attach(); + public CompositeIndexDefinition Path(string path); + public CompositeIndexDefinition Path(string path, CompositePathSortOrder sortOrder); + } + public class ConflictResolutionDefinition + { + public ContainerBuilder Attach(); + public ConflictResolutionDefinition WithCustomStoredProcedureResolution(string conflictResolutionProcedure); + public ConflictResolutionDefinition WithLastWriterWinsResolution(string conflictResolutionPath); + } + public class ContainerBuilder : ContainerDefinition + { + protected ContainerBuilder(); + public new ContainerProperties Build(); + public Task CreateAsync(ThroughputProperties throughputProperties, CancellationToken cancellationToken=default(CancellationToken)); + public Task CreateAsync(Nullable throughput=default(Nullable), CancellationToken cancellationToken=default(CancellationToken)); + public Task CreateIfNotExistsAsync(ThroughputProperties throughputProperties, CancellationToken cancellationToken=default(CancellationToken)); + public Task CreateIfNotExistsAsync(Nullable throughput=default(Nullable), CancellationToken cancellationToken=default(CancellationToken)); + public ChangeFeedPolicyDefinition WithChangeFeedPolicy(TimeSpan retention); + public ClientEncryptionPolicyDefinition WithClientEncryptionPolicy(); + public ConflictResolutionDefinition WithConflictResolution(); + public UniqueKeyDefinition WithUniqueKey(); + } + public abstract class ContainerDefinition where T : ContainerDefinition + { + public ContainerDefinition(); + public ContainerProperties Build(); + public T WithDefaultTimeToLive(int defaultTtlInSeconds); + public T WithDefaultTimeToLive(TimeSpan defaultTtlTimeSpan); + public IndexingPolicyDefinition WithIndexingPolicy(); + public T WithPartitionKeyDefinitionVersion(PartitionKeyDefinitionVersion partitionKeyDefinitionVersion); + public T WithTimeToLivePropertyPath(string propertyPath); + } + public class CosmosClientBuilder + { + public CosmosClientBuilder(string connectionString); + public CosmosClientBuilder(string accountEndpoint, string authKeyOrResourceToken); + public CosmosClientBuilder AddCustomHandlers(params RequestHandler[] customHandlers); + public CosmosClient Build(); + public CosmosClientBuilder WithApplicationName(string applicationName); + public CosmosClientBuilder WithApplicationPreferredRegions(IReadOnlyList applicationPreferredRegions); + public CosmosClientBuilder WithApplicationRegion(string applicationRegion); + public CosmosClientBuilder WithBulkExecution(bool enabled); + public CosmosClientBuilder WithConnectionModeDirect(); + public CosmosClientBuilder WithConnectionModeDirect(Nullable idleTcpConnectionTimeout=default(Nullable), Nullable openTcpConnectionTimeout=default(Nullable), Nullable maxRequestsPerTcpConnection=default(Nullable), Nullable maxTcpConnectionsPerEndpoint=default(Nullable), Nullable portReuseMode=default(Nullable), Nullable enableTcpConnectionEndpointRediscovery=default(Nullable)); + public CosmosClientBuilder WithConnectionModeGateway(Nullable maxConnectionLimit=default(Nullable), IWebProxy webProxy=null); + public CosmosClientBuilder WithConsistencyLevel(ConsistencyLevel consistencyLevel); + public CosmosClientBuilder WithContentResponseOnWrite(bool contentResponseOnWrite); + public CosmosClientBuilder WithCustomSerializer(CosmosSerializer cosmosJsonSerializer); + public CosmosClientBuilder WithHttpClientFactory(Func httpClientFactory); + public CosmosClientBuilder WithLimitToEndpoint(bool limitToEndpoint); + public CosmosClientBuilder WithRequestTimeout(TimeSpan requestTimeout); + public CosmosClientBuilder WithSerializerOptions(CosmosSerializationOptions cosmosSerializerOptions); + public CosmosClientBuilder WithThrottlingRetryOptions(TimeSpan maxRetryWaitTimeOnThrottledRequests, int maxRetryAttemptsOnThrottledRequests); + } + public class IndexingPolicyDefinition + { + public IndexingPolicyDefinition(); + public T Attach(); + public IndexingPolicyDefinition WithAutomaticIndexing(bool enabled); + public CompositeIndexDefinition> WithCompositeIndex(); + public PathsDefinition> WithExcludedPaths(); + public PathsDefinition> WithIncludedPaths(); + public IndexingPolicyDefinition WithIndexingMode(IndexingMode indexingMode); + public SpatialIndexDefinition> WithSpatialIndex(); + } + public class PathsDefinition + { + public T Attach(); + public PathsDefinition Path(string path); + } + public class SpatialIndexDefinition + { + public T Attach(); + public SpatialIndexDefinition Path(string path); + public SpatialIndexDefinition Path(string path, params SpatialType[] spatialTypes); + } + public class UniqueKeyDefinition + { + public ContainerBuilder Attach(); + public UniqueKeyDefinition Path(string path); + } +} +namespace Microsoft.Azure.Cosmos.Linq +{ + public static class CosmosLinq + { + public static object InvokeUserDefinedFunction(string udfName, params object[] arguments); + } + public static class CosmosLinqExtensions + { + public static Task> AverageAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> AverageAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> AverageAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> AverageAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task>> AverageAsync(this IQueryable> source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task>> AverageAsync(this IQueryable> source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task>> AverageAsync(this IQueryable> source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task>> AverageAsync(this IQueryable> source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task>> AverageAsync(this IQueryable> source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> AverageAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> CountAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static bool IsDefined(this object obj); + public static bool IsNull(this object obj); + public static bool IsPrimitive(this object obj); + public static Task> MaxAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> MinAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> SumAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> SumAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> SumAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> SumAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task>> SumAsync(this IQueryable> source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task>> SumAsync(this IQueryable> source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task>> SumAsync(this IQueryable> source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task>> SumAsync(this IQueryable> source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task>> SumAsync(this IQueryable> source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> SumAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static FeedIterator ToFeedIterator(this IQueryable query); + public static QueryDefinition ToQueryDefinition(this IQueryable query); + public static QueryDefinition ToQueryDefinition(this IQueryable query, IDictionary namedParameters); + public static FeedIterator ToStreamIterator(this IQueryable query); + } +} +namespace Microsoft.Azure.Cosmos.Scripts +{ + public abstract class Scripts + { + protected Scripts(); + public abstract Task CreateStoredProcedureAsync(StoredProcedureProperties storedProcedureProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateTriggerAsync(TriggerProperties triggerProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateUserDefinedFunctionAsync(UserDefinedFunctionProperties userDefinedFunctionProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task DeleteStoredProcedureAsync(string id, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task DeleteTriggerAsync(string id, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task DeleteUserDefinedFunctionAsync(string id, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task> ExecuteStoredProcedureAsync(string storedProcedureId, PartitionKey partitionKey, dynamic parameters, StoredProcedureRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ExecuteStoredProcedureStreamAsync(string storedProcedureId, PartitionKey partitionKey, dynamic parameters, StoredProcedureRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ExecuteStoredProcedureStreamAsync(string storedProcedureId, Stream streamPayload, PartitionKey partitionKey, StoredProcedureRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract FeedIterator GetStoredProcedureQueryIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetStoredProcedureQueryIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetStoredProcedureQueryStreamIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetStoredProcedureQueryStreamIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetTriggerQueryIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetTriggerQueryIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetTriggerQueryStreamIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetTriggerQueryStreamIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetUserDefinedFunctionQueryIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetUserDefinedFunctionQueryIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetUserDefinedFunctionQueryStreamIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetUserDefinedFunctionQueryStreamIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract Task ReadStoredProcedureAsync(string id, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReadTriggerAsync(string id, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReadUserDefinedFunctionAsync(string id, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceStoredProcedureAsync(StoredProcedureProperties storedProcedureProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceTriggerAsync(TriggerProperties triggerProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceUserDefinedFunctionAsync(UserDefinedFunctionProperties userDefinedFunctionProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + } + public class StoredProcedureExecuteResponse : Response + { + protected StoredProcedureExecuteResponse(); + public override string ActivityId { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public override double RequestCharge { get; } + public override T Resource { get; } + public virtual string ScriptLog { get; } + public virtual string SessionToken { get; } + public override HttpStatusCode StatusCode { get; } + } + public class StoredProcedureProperties + { + public StoredProcedureProperties(); + public StoredProcedureProperties(string id, string body); + public string Body { get; set; } + public string ETag { get; } + public string Id { get; set; } + public Nullable LastModified { get; } + public string SelfLink { get; } + } + public class StoredProcedureRequestOptions : RequestOptions + { + public StoredProcedureRequestOptions(); + public Nullable ConsistencyLevel { get; set; } + public bool EnableScriptLogging { get; set; } + public string SessionToken { get; set; } + } + public class StoredProcedureResponse : Response + { + protected StoredProcedureResponse(); + public override string ActivityId { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public override double RequestCharge { get; } + public override StoredProcedureProperties Resource { get; } + public virtual string SessionToken { get; } + public override HttpStatusCode StatusCode { get; } + public static implicit operator StoredProcedureProperties (StoredProcedureResponse response); + } + public enum TriggerOperation : short + { + All = (short)0, + Create = (short)1, + Delete = (short)3, + Replace = (short)4, + Update = (short)2, + } + public class TriggerProperties + { + public TriggerProperties(); + public string Body { get; set; } + public string ETag { get; } + public string Id { get; set; } + public string SelfLink { get; } + public TriggerOperation TriggerOperation { get; set; } + public TriggerType TriggerType { get; set; } + } + public class TriggerResponse : Response + { + protected TriggerResponse(); + public override string ActivityId { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public override double RequestCharge { get; } + public override TriggerProperties Resource { get; } + public override HttpStatusCode StatusCode { get; } + public static implicit operator TriggerProperties (TriggerResponse response); + } + public enum TriggerType : byte + { + Post = (byte)1, + Pre = (byte)0, + } + public class UserDefinedFunctionProperties + { + public UserDefinedFunctionProperties(); + public string Body { get; set; } + public string ETag { get; } + public string Id { get; set; } + public string SelfLink { get; } + } + public class UserDefinedFunctionResponse : Response + { + protected UserDefinedFunctionResponse(); + public override string ActivityId { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public override double RequestCharge { get; } + public override UserDefinedFunctionProperties Resource { get; } + public override HttpStatusCode StatusCode { get; } + public static implicit operator UserDefinedFunctionProperties (UserDefinedFunctionResponse response); + } +} +namespace Microsoft.Azure.Cosmos.Spatial +{ + public sealed class BoundingBox : IEquatable + { + public BoundingBox(Position min, Position max); + public Position Max { get; } + public Position Min { get; } + public bool Equals(BoundingBox other); + public override bool Equals(object obj); + public override int GetHashCode(); + } + public abstract class Crs + { + protected Crs(CrsType type); + public static Crs Default { get; } + public CrsType Type { get; } + public static Crs Unspecified { get; } + public static LinkedCrs Linked(string href); + public static LinkedCrs Linked(string href, string type); + public static NamedCrs Named(string name); + } + public enum CrsType + { + Linked = 1, + Named = 0, + Unspecified = 2, + } + public abstract class Geometry + { + protected Geometry(GeometryType type, GeometryParams geometryParams); + public IDictionary AdditionalProperties { get; } + public BoundingBox BoundingBox { get; } + public Crs Crs { get; } + public GeometryType Type { get; } + public double Distance(Geometry to); + public override bool Equals(object obj); + public override int GetHashCode(); + public bool Intersects(Geometry geometry2); + public bool IsValid(); + public GeometryValidationResult IsValidDetailed(); + public bool Within(Geometry outer); + } + public class GeometryParams + { + public GeometryParams(); + public IDictionary AdditionalProperties { get; set; } + public BoundingBox BoundingBox { get; set; } + public Crs Crs { get; set; } + } + public enum GeometryShape + { + GeometryCollection = 6, + LineString = 2, + MultiLineString = 3, + MultiPoint = 1, + MultiPolygon = 5, + Point = 0, + Polygon = 4, + } + public enum GeometryType + { + GeometryCollection = 6, + LineString = 2, + MultiLineString = 3, + MultiPoint = 1, + MultiPolygon = 5, + Point = 0, + Polygon = 4, + } + public class GeometryValidationResult + { + public GeometryValidationResult(); + public bool IsValid { get; } + public string Reason { get; } + } + public sealed class LinearRing : IEquatable + { + public LinearRing(IList coordinates); + public ReadOnlyCollection Positions { get; } + public bool Equals(LinearRing other); + public override bool Equals(object obj); + public override int GetHashCode(); + } + public sealed class LineString : Geometry, IEquatable + { + public LineString(IList coordinates); + public LineString(IList coordinates, GeometryParams geometryParams); + public ReadOnlyCollection Positions { get; } + public bool Equals(LineString other); + public override bool Equals(object obj); + public override int GetHashCode(); + } + public sealed class LinkedCrs : Crs, IEquatable + { + public string Href { get; } + public string HrefType { get; } + public bool Equals(LinkedCrs other); + public override bool Equals(object obj); + public override int GetHashCode(); + } + public sealed class MultiPolygon : Geometry, IEquatable + { + public MultiPolygon(IList polygons); + public MultiPolygon(IList polygons, GeometryParams geometryParams); + public ReadOnlyCollection Polygons { get; } + public bool Equals(MultiPolygon other); + public override bool Equals(object obj); + public override int GetHashCode(); + } + public sealed class NamedCrs : Crs, IEquatable + { + public string Name { get; } + public bool Equals(NamedCrs other); + public override bool Equals(object obj); + public override int GetHashCode(); + } + public sealed class Point : Geometry, IEquatable + { + public Point(Position position); + public Point(Position position, GeometryParams geometryParams); + public Point(double longitude, double latitude); + public Position Position { get; } + public bool Equals(Point other); + public override bool Equals(object obj); + public override int GetHashCode(); + } + public sealed class Polygon : Geometry, IEquatable + { + public Polygon(IList rings); + public Polygon(IList rings, GeometryParams geometryParams); + public Polygon(IList externalRingPositions); + public ReadOnlyCollection Rings { get; } + public bool Equals(Polygon other); + public override bool Equals(object obj); + public override int GetHashCode(); + } + public sealed class PolygonCoordinates : IEquatable + { + public PolygonCoordinates(IList rings); + public ReadOnlyCollection Rings { get; } + public bool Equals(PolygonCoordinates other); + public override bool Equals(object obj); + public override int GetHashCode(); + } + public sealed class Position : IEquatable + { + public Position(IList coordinates); + public Position(double longitude, double latitude); + public Position(double longitude, double latitude, Nullable altitude); + public Nullable Altitude { get; } + public ReadOnlyCollection Coordinates { get; } + public double Latitude { get; } + public double Longitude { get; } + public bool Equals(Position other); + public override bool Equals(object obj); + public override int GetHashCode(); + } +} diff --git a/changelog.md b/changelog.md index b63aa9a5f0..e07122f172 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,21 @@ Preview features are treated as a separate branch and will not be included in th The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +### [3.18.0-preview](https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.18.0-preview) - 2021-03-17 + +#### Added +- [#2308](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2308) Patch: Adds preview support for Patch API +- [#2312](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2312) Diagnostics: Adds Api for getting all regions contacted by a request + +#### Fixed +- [#2314](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2314) Diagnostics: Fixes concurrency of cache +- [#2303](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2303) CosmosException : Fixed exception messages to remove JSON formatting +- [#2311](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2311) Spatial: Fixed deserialization when Json does not represent a Spatial type +- [#2284](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2284) Diagnostics: Adds traces for cache operations. Introduced in 3.17.0 PR [#2097](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2097) +- [#2278](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2278) Documentation: Fixed typos in comment examples (Thanks to paulomorgado) +- [#2279](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2279) Availability: Fixed region failover logic on control plane hot path when gateway hangs. Introduced in 3.16.0 PR [#1954](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/1954) +- [#2286](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2286) Diagnostics: Fixed regression which caused ActivityId to not get included. Introduced in 3.17.0 PR [#2097](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2097) + ### [3.17.0](https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.17.0) - 2021-03-02 #### Added From f16153b98627890f3328b3c4b3d2d3c2265f22cf Mon Sep 17 00:00:00 2001 From: ayanMSFT <53790657+ayanMSFT@users.noreply.github.com> Date: Thu, 18 Mar 2021 18:22:02 -0700 Subject: [PATCH 02/19] [Internal] LocalRegionRequest: Adds the ability to pass location header during Address Resolution (#2318) Co-authored-by: j82w --- Directory.Build.props | 2 +- .../src/Routing/AddressResolver.cs | 1 + .../src/Routing/GatewayAddressCache.cs | 126 ++++++++++-------- .../GatewayAddressCacheTests.cs | 59 ++++++++ 4 files changed, 135 insertions(+), 53 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 4b7e4790c8..510cc5c931 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,7 +4,7 @@ 3.17.0 3.18.0 preview - 3.17.1 + 3.17.2 1.0.0-previewV12 1.1.0-preview1 $([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../')) diff --git a/Microsoft.Azure.Cosmos/src/Routing/AddressResolver.cs b/Microsoft.Azure.Cosmos/src/Routing/AddressResolver.cs index b4c249b549..a423002b1f 100644 --- a/Microsoft.Azure.Cosmos/src/Routing/AddressResolver.cs +++ b/Microsoft.Azure.Cosmos/src/Routing/AddressResolver.cs @@ -70,6 +70,7 @@ public async Task ResolveAsync( request.RequestContext.TargetIdentity = result.TargetServiceIdentity; request.RequestContext.ResolvedPartitionKeyRange = result.TargetPartitionKeyRange; request.RequestContext.RegionName = this.location; + request.RequestContext.LocalRegionRequest = result.Addresses.IsLocalRegion; await this.requestSigner.SignRequestAsync(request, cancellationToken); diff --git a/Microsoft.Azure.Cosmos/src/Routing/GatewayAddressCache.cs b/Microsoft.Azure.Cosmos/src/Routing/GatewayAddressCache.cs index 68c444b731..cd5c73b7a4 100644 --- a/Microsoft.Azure.Cosmos/src/Routing/GatewayAddressCache.cs +++ b/Microsoft.Azure.Cosmos/src/Routing/GatewayAddressCache.cs @@ -96,7 +96,7 @@ public async Task OpenAsync( IReadOnlyList partitionKeyRangeIdentities, CancellationToken cancellationToken) { - List>> tasks = new List>>(); + List> tasks = new List>(); int batchSize = GatewayAddressCache.DefaultBatchSize; #if !(NETSTANDARD15 || NETSTANDARD16) @@ -133,18 +133,25 @@ public async Task OpenAsync( } } - foreach (FeedResource
response in await Task.WhenAll(tasks)) + foreach (DocumentServiceResponse response in await Task.WhenAll(tasks)) { - IEnumerable> addressInfos = - response.Where(addressInfo => ProtocolFromString(addressInfo.Protocol) == this.protocol) - .GroupBy(address => address.PartitionKeyRangeId, StringComparer.Ordinal) - .Select(group => this.ToPartitionAddressAndRange(collection.ResourceId, @group.ToList())); - - foreach (Tuple addressInfo in addressInfos) + using (response) { - this.serverPartitionAddressCache.Set( - new PartitionKeyRangeIdentity(collection.ResourceId, addressInfo.Item1.PartitionKeyRangeId), - addressInfo.Item2); + FeedResource
addressFeed = response.GetResource>(); + + bool inNetworkRequest = this.IsInNetworkRequest(response); + + IEnumerable> addressInfos = + addressFeed.Where(addressInfo => ProtocolFromString(addressInfo.Protocol) == this.protocol) + .GroupBy(address => address.PartitionKeyRangeId, StringComparer.Ordinal) + .Select(group => this.ToPartitionAddressAndRange(collection.ResourceId, @group.ToList(), inNetworkRequest)); + + foreach (Tuple addressInfo in addressInfos) + { + this.serverPartitionAddressCache.Set( + new PartitionKeyRangeIdentity(collection.ResourceId, addressInfo.Item1.PartitionKeyRangeId), + addressInfo.Item2); + } } } } @@ -322,17 +329,22 @@ private async Task try { - FeedResource
masterAddresses = await this.GetMasterAddressesViaGatewayAsync( + using (DocumentServiceResponse response = await this.GetMasterAddressesViaGatewayAsync( request, ResourceType.Database, null, entryUrl, forceRefresh, - false); + false)) + { + FeedResource
masterAddresses = response.GetResource>(); - masterAddressAndRange = this.ToPartitionAddressAndRange(string.Empty, masterAddresses.ToList()); - this.masterPartitionAddressCache = masterAddressAndRange; - this.suboptimalMasterPartitionTimestamp = DateTime.MaxValue; + bool inNetworkRequest = this.IsInNetworkRequest(response); + + masterAddressAndRange = this.ToPartitionAddressAndRange(string.Empty, masterAddresses.ToList(), inNetworkRequest); + this.masterPartitionAddressCache = masterAddressAndRange; + this.suboptimalMasterPartitionTimestamp = DateTime.MaxValue; + } } catch (Exception) { @@ -355,33 +367,38 @@ private async Task GetAddressesForRangeIdAsync( string partitionKeyRangeId, bool forceRefresh) { - FeedResource
response = - await this.GetServerAddressesViaGatewayAsync(request, collectionRid, new[] { partitionKeyRangeId }, forceRefresh); + using (DocumentServiceResponse response = + await this.GetServerAddressesViaGatewayAsync(request, collectionRid, new[] { partitionKeyRangeId }, forceRefresh)) + { + FeedResource
addressFeed = response.GetResource>(); - IEnumerable> addressInfos = - response.Where(addressInfo => ProtocolFromString(addressInfo.Protocol) == this.protocol) - .GroupBy(address => address.PartitionKeyRangeId, StringComparer.Ordinal) - .Select(group => this.ToPartitionAddressAndRange(collectionRid, @group.ToList())); + bool inNetworkRequest = this.IsInNetworkRequest(response); - Tuple result = - addressInfos.SingleOrDefault( - addressInfo => StringComparer.Ordinal.Equals(addressInfo.Item1.PartitionKeyRangeId, partitionKeyRangeId)); + IEnumerable> addressInfos = + addressFeed.Where(addressInfo => ProtocolFromString(addressInfo.Protocol) == this.protocol) + .GroupBy(address => address.PartitionKeyRangeId, StringComparer.Ordinal) + .Select(group => this.ToPartitionAddressAndRange(collectionRid, @group.ToList(), inNetworkRequest)); - if (result == null) - { - string errorMessage = string.Format( - CultureInfo.InvariantCulture, - RMResources.PartitionKeyRangeNotFound, - partitionKeyRangeId, - collectionRid); + Tuple result = + addressInfos.SingleOrDefault( + addressInfo => StringComparer.Ordinal.Equals(addressInfo.Item1.PartitionKeyRangeId, partitionKeyRangeId)); - throw new PartitionKeyRangeGoneException(errorMessage) { ResourceAddress = collectionRid }; - } + if (result == null) + { + string errorMessage = string.Format( + CultureInfo.InvariantCulture, + RMResources.PartitionKeyRangeNotFound, + partitionKeyRangeId, + collectionRid); + + throw new PartitionKeyRangeGoneException(errorMessage) { ResourceAddress = collectionRid }; + } - return result.Item2; + return result.Item2; + } } - private async Task> GetMasterAddressesViaGatewayAsync( + private async Task GetMasterAddressesViaGatewayAsync( DocumentServiceRequest request, ResourceType resourceType, string resourceAddress, @@ -435,16 +452,13 @@ private async Task> GetMasterAddressesViaGatewayAsync( trace: NoOpTrace.Singleton, cancellationToken: default)) { - using (DocumentServiceResponse documentServiceResponse = - await ClientExtensions.ParseResponseAsync(httpResponseMessage)) - { - GatewayAddressCache.LogAddressResolutionEnd(request, identifier); - return documentServiceResponse.GetResource>(); - } + DocumentServiceResponse documentServiceResponse = await ClientExtensions.ParseResponseAsync(httpResponseMessage); + GatewayAddressCache.LogAddressResolutionEnd(request, identifier); + return documentServiceResponse; } } - private async Task> GetServerAddressesViaGatewayAsync( + private async Task GetServerAddressesViaGatewayAsync( DocumentServiceRequest request, string collectionRid, IEnumerable partitionKeyRangeIds, @@ -513,17 +527,13 @@ private async Task> GetServerAddressesViaGatewayAsync( trace: NoOpTrace.Singleton, cancellationToken: default)) { - using (DocumentServiceResponse documentServiceResponse = - await ClientExtensions.ParseResponseAsync(httpResponseMessage)) - { - GatewayAddressCache.LogAddressResolutionEnd(request, identifier); - - return documentServiceResponse.GetResource>(); - } + DocumentServiceResponse documentServiceResponse = await ClientExtensions.ParseResponseAsync(httpResponseMessage); + GatewayAddressCache.LogAddressResolutionEnd(request, identifier); + return documentServiceResponse; } } - internal Tuple ToPartitionAddressAndRange(string collectionRid, IList
addresses) + internal Tuple ToPartitionAddressAndRange(string collectionRid, IList
addresses, bool inNetworkRequest) { Address address = addresses.First(); @@ -561,7 +571,19 @@ internal Tuple ToPartiti return Tuple.Create( partitionKeyRangeIdentity, - new PartitionAddressInformation(addressInfos)); + new PartitionAddressInformation(addressInfos, inNetworkRequest)); + } + + private bool IsInNetworkRequest(DocumentServiceResponse documentServiceResponse) + { + bool inNetworkRequest = false; + string inNetworkHeader = documentServiceResponse.ResponseHeaders.Get(HttpConstants.HttpHeaders.LocalRegionRequest); + if (!string.IsNullOrEmpty(inNetworkHeader)) + { + bool.TryParse(inNetworkHeader, out inNetworkRequest); + } + + return inNetworkRequest; } private static string LogAddressResolutionStart(DocumentServiceRequest request, Uri targetEndpoint) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayAddressCacheTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayAddressCacheTests.cs index 82b4f38774..50db0043c1 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayAddressCacheTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayAddressCacheTests.cs @@ -165,15 +165,66 @@ public void GlobalAddressResolverUpdateAsyncSynchronizationTest() } } + [TestMethod] + [Owner("aysarkar")] + public async Task GatewayAddressCacheInNetworkRequestTestAsync() + { + FakeMessageHandler messageHandler = new FakeMessageHandler(); + HttpClient httpClient = new HttpClient(messageHandler); + httpClient.Timeout = TimeSpan.FromSeconds(120); + GatewayAddressCache cache = new GatewayAddressCache( + new Uri(GatewayAddressCacheTests.DatabaseAccountApiEndpoint), + Documents.Client.Protocol.Https, + this.mockTokenProvider.Object, + this.mockServiceConfigReader.Object, + MockCosmosUtil.CreateCosmosHttpClient(() => httpClient), + suboptimalPartitionForceRefreshIntervalInSeconds: 2, + enableTcpConnectionEndpointRediscovery: true); + + // No header should be present. + PartitionAddressInformation legacyRequest = await cache.TryGetAddressesAsync( + DocumentServiceRequest.Create(OperationType.Invalid, ResourceType.Address, AuthorizationTokenType.Invalid), + this.testPartitionKeyRangeIdentity, + this.serviceIdentity, + false, + CancellationToken.None); + + + Assert.IsFalse(legacyRequest.IsLocalRegion); + + // Header indicates the request is from the same azure region. + messageHandler.Headers[HttpConstants.HttpHeaders.LocalRegionRequest] = "true"; + PartitionAddressInformation inNetworkAddresses = await cache.TryGetAddressesAsync( + DocumentServiceRequest.Create(OperationType.Invalid, ResourceType.Address, AuthorizationTokenType.Invalid), + this.testPartitionKeyRangeIdentity, + this.serviceIdentity, + true, + CancellationToken.None); + Assert.IsTrue(inNetworkAddresses.IsLocalRegion); + + // Header indicates the request is not from the same azure region. + messageHandler.Headers[HttpConstants.HttpHeaders.LocalRegionRequest] = "false"; + PartitionAddressInformation outOfNetworkAddresses = await cache.TryGetAddressesAsync( + DocumentServiceRequest.Create(OperationType.Invalid, ResourceType.Address, AuthorizationTokenType.Invalid), + this.testPartitionKeyRangeIdentity, + this.serviceIdentity, + true, + CancellationToken.None); + Assert.IsFalse(outOfNetworkAddresses.IsLocalRegion); + } + private class FakeMessageHandler : HttpMessageHandler { private bool returnFullReplicaSet; private bool returnUpdatedAddresses; + public Dictionary Headers { get; set; } + public FakeMessageHandler() { this.returnFullReplicaSet = false; this.returnUpdatedAddresses = false; + this.Headers = new Dictionary(); } protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) @@ -224,6 +275,14 @@ protected override Task SendAsync(HttpRequestMessage reques Content = content, }; + if (this.Headers != null) + { + foreach (KeyValuePair headerPair in this.Headers) + { + responseMessage.Headers.Add(headerPair.Key, headerPair.Value); + } + } + return Task.FromResult(responseMessage); } } From 35d1744ffbc8995465691bb4fb2e2a009c053d9c Mon Sep 17 00:00:00 2001 From: j82w Date: Fri, 19 Mar 2021 14:02:19 -0700 Subject: [PATCH 03/19] Changelog: Adds 3.17.1 notes (#2321) * Changelog: Adds 3.17.1 notes * Fix the date * Update version * Update changelog.md Co-authored-by: Matias Quaranta * Add contract file Co-authored-by: Matias Quaranta --- Directory.Build.props | 4 +- .../contracts/API_3.17.1.txt | 1253 +++++++++++++++++ changelog.md | 15 +- 3 files changed, 1268 insertions(+), 4 deletions(-) create mode 100644 Microsoft.Azure.Cosmos/contracts/API_3.17.1.txt diff --git a/Directory.Build.props b/Directory.Build.props index 510cc5c931..32908fab38 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 3.17.0 + 3.17.1 3.18.0 preview 3.17.2 @@ -11,4 +11,4 @@ $(DefineConstants);PREVIEW - \ No newline at end of file + diff --git a/Microsoft.Azure.Cosmos/contracts/API_3.17.1.txt b/Microsoft.Azure.Cosmos/contracts/API_3.17.1.txt new file mode 100644 index 0000000000..b39b41e90c --- /dev/null +++ b/Microsoft.Azure.Cosmos/contracts/API_3.17.1.txt @@ -0,0 +1,1253 @@ +namespace Microsoft.Azure.Cosmos +{ + public class AccountConsistency + { + public AccountConsistency(); + public ConsistencyLevel DefaultConsistencyLevel { get; } + public int MaxStalenessIntervalInSeconds { get; } + public int MaxStalenessPrefix { get; } + } + public class AccountProperties + { + public AccountConsistency Consistency { get; } + public string ETag { get; } + public string Id { get; } + public IEnumerable ReadableRegions { get; } + public IEnumerable WritableRegions { get; } + } + public class AccountRegion + { + public AccountRegion(); + public string Endpoint { get; } + public string Name { get; } + } + public sealed class BoundingBoxProperties + { + public BoundingBoxProperties(); + public double Xmax { get; set; } + public double Xmin { get; set; } + public double Ymax { get; set; } + public double Ymin { get; set; } + } + public abstract class ChangeFeedEstimator + { + protected ChangeFeedEstimator(); + public abstract FeedIterator GetCurrentStateIterator(ChangeFeedEstimatorRequestOptions changeFeedEstimatorRequestOptions=null); + } + public sealed class ChangeFeedEstimatorRequestOptions + { + public ChangeFeedEstimatorRequestOptions(); + public Nullable MaxItemCount { get; set; } + } + public abstract class ChangeFeedProcessor + { + protected ChangeFeedProcessor(); + public abstract Task StartAsync(); + public abstract Task StopAsync(); + } + public class ChangeFeedProcessorBuilder + { + public ChangeFeedProcessor Build(); + public ChangeFeedProcessorBuilder WithInstanceName(string instanceName); + public ChangeFeedProcessorBuilder WithLeaseConfiguration(Nullable acquireInterval=default(Nullable), Nullable expirationInterval=default(Nullable), Nullable renewInterval=default(Nullable)); + public ChangeFeedProcessorBuilder WithLeaseContainer(Container leaseContainer); + public ChangeFeedProcessorBuilder WithMaxItems(int maxItemCount); + public ChangeFeedProcessorBuilder WithPollInterval(TimeSpan pollInterval); + public ChangeFeedProcessorBuilder WithStartTime(DateTime startTime); + } + public sealed class ChangeFeedProcessorState + { + public ChangeFeedProcessorState(string leaseToken, long estimatedLag, string instanceName); + public long EstimatedLag { get; } + public string InstanceName { get; } + public string LeaseToken { get; } + } + public sealed class CompositePath + { + public CompositePath(); + public CompositePathSortOrder Order { get; set; } + public string Path { get; set; } + } + public enum CompositePathSortOrder + { + Ascending = 0, + Descending = 1, + } + public class ConflictProperties + { + public ConflictProperties(); + public string Id { get; } + public OperationKind OperationKind { get; } + public string SelfLink { get; } + } + public enum ConflictResolutionMode + { + Custom = 1, + LastWriterWins = 0, + } + public class ConflictResolutionPolicy + { + public ConflictResolutionPolicy(); + public ConflictResolutionMode Mode { get; set; } + public string ResolutionPath { get; set; } + public string ResolutionProcedure { get; set; } + } + public abstract class Conflicts + { + protected Conflicts(); + public abstract Task DeleteAsync(ConflictProperties conflict, PartitionKey partitionKey, CancellationToken cancellationToken=default(CancellationToken)); + public abstract FeedIterator GetConflictQueryIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetConflictQueryIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetConflictQueryStreamIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetConflictQueryStreamIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract T ReadConflictContent(ConflictProperties conflict); + public abstract Task> ReadCurrentAsync(ConflictProperties conflict, PartitionKey partitionKey, CancellationToken cancellationToken=default(CancellationToken)); + } + public enum ConnectionMode + { + Direct = 1, + Gateway = 0, + } + public enum ConsistencyLevel + { + BoundedStaleness = 1, + ConsistentPrefix = 4, + Eventual = 3, + Session = 2, + Strong = 0, + } + public abstract class Container + { + protected Container(); + public abstract Conflicts Conflicts { get; } + public abstract Database Database { get; } + public abstract string Id { get; } + public abstract Scripts Scripts { get; } + public abstract Task> CreateItemAsync(T item, Nullable partitionKey=default(Nullable), ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateItemStreamAsync(Stream streamPayload, PartitionKey partitionKey, ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract TransactionalBatch CreateTransactionalBatch(PartitionKey partitionKey); + public abstract Task DeleteContainerAsync(ContainerRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task DeleteContainerStreamAsync(ContainerRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task> DeleteItemAsync(string id, PartitionKey partitionKey, ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task DeleteItemStreamAsync(string id, PartitionKey partitionKey, ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract ChangeFeedEstimator GetChangeFeedEstimator(string processorName, Container leaseContainer); + public abstract ChangeFeedProcessorBuilder GetChangeFeedEstimatorBuilder(string processorName, Container.ChangesEstimationHandler estimationDelegate, Nullable estimationPeriod=default(Nullable)); + public abstract ChangeFeedProcessorBuilder GetChangeFeedProcessorBuilder(string processorName, Container.ChangesHandler onChangesDelegate); + public abstract IOrderedQueryable GetItemLinqQueryable(bool allowSynchronousQueryExecution=false, string continuationToken=null, QueryRequestOptions requestOptions=null, CosmosLinqSerializerOptions linqSerializerOptions=null); + public abstract FeedIterator GetItemQueryIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetItemQueryIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetItemQueryStreamIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetItemQueryStreamIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract Task ReadContainerAsync(ContainerRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReadContainerStreamAsync(ContainerRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task> ReadItemAsync(string id, PartitionKey partitionKey, ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReadItemStreamAsync(string id, PartitionKey partitionKey, ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReadThroughputAsync(RequestOptions requestOptions, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task> ReadThroughputAsync(CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceContainerAsync(ContainerProperties containerProperties, ContainerRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceContainerStreamAsync(ContainerProperties containerProperties, ContainerRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task> ReplaceItemAsync(T item, string id, Nullable partitionKey=default(Nullable), ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceItemStreamAsync(Stream streamPayload, string id, PartitionKey partitionKey, ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceThroughputAsync(ThroughputProperties throughputProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceThroughputAsync(int throughput, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task> UpsertItemAsync(T item, Nullable partitionKey=default(Nullable), ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task UpsertItemStreamAsync(Stream streamPayload, PartitionKey partitionKey, ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public delegate Task ChangesEstimationHandler(long estimatedPendingChanges, CancellationToken cancellationToken); + public delegate Task ChangesHandler(IReadOnlyCollection changes, CancellationToken cancellationToken); + } + public class ContainerProperties + { + public ContainerProperties(); + public ContainerProperties(string id, string partitionKeyPath); + public Nullable AnalyticalStoreTimeToLiveInSeconds { get; set; } + public ConflictResolutionPolicy ConflictResolutionPolicy { get; set; } + public Nullable DefaultTimeToLive { get; set; } + public string ETag { get; } + public GeospatialConfig GeospatialConfig { get; set; } + public string Id { get; set; } + public IndexingPolicy IndexingPolicy { get; set; } + public Nullable LastModified { get; } + public Nullable PartitionKeyDefinitionVersion { get; set; } + public string PartitionKeyPath { get; set; } + public string SelfLink { get; } + public string TimeToLivePropertyPath { get; set; } + public UniqueKeyPolicy UniqueKeyPolicy { get; set; } + } + public class ContainerRequestOptions : RequestOptions + { + public ContainerRequestOptions(); + public bool PopulateQuotaInfo { get; set; } + } + public class ContainerResponse : Response + { + protected ContainerResponse(); + public override string ActivityId { get; } + public virtual Container Container { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public override double RequestCharge { get; } + public override ContainerProperties Resource { get; } + public override HttpStatusCode StatusCode { get; } + public static implicit operator Container (ContainerResponse response); + } + public class CosmosClient : IDisposable + { + protected CosmosClient(); + public CosmosClient(string connectionString, CosmosClientOptions clientOptions=null); + public CosmosClient(string accountEndpoint, string authKeyOrResourceToken, CosmosClientOptions clientOptions=null); + public virtual CosmosClientOptions ClientOptions { get; } + public virtual Uri Endpoint { get; } + public static Task CreateAndInitializeAsync(string connectionString, IReadOnlyList> containers, CosmosClientOptions cosmosClientOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public static Task CreateAndInitializeAsync(string accountEndpoint, string authKeyOrResourceToken, IReadOnlyList> containers, CosmosClientOptions cosmosClientOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public virtual Task CreateDatabaseAsync(string id, ThroughputProperties throughputProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public virtual Task CreateDatabaseAsync(string id, Nullable throughput=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public virtual Task CreateDatabaseIfNotExistsAsync(string id, ThroughputProperties throughputProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public virtual Task CreateDatabaseIfNotExistsAsync(string id, Nullable throughput=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public virtual Task CreateDatabaseStreamAsync(DatabaseProperties databaseProperties, Nullable throughput=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public void Dispose(); + protected virtual void Dispose(bool disposing); + public virtual Container GetContainer(string databaseId, string containerId); + public virtual Database GetDatabase(string id); + public virtual FeedIterator GetDatabaseQueryIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public virtual FeedIterator GetDatabaseQueryIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public virtual FeedIterator GetDatabaseQueryStreamIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public virtual FeedIterator GetDatabaseQueryStreamIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public virtual Task ReadAccountAsync(); + } + public class CosmosClientOptions + { + public CosmosClientOptions(); + public bool AllowBulkExecution { get; set; } + public string ApplicationName { get; set; } + public IReadOnlyList ApplicationPreferredRegions { get; set; } + public string ApplicationRegion { get; set; } + public ConnectionMode ConnectionMode { get; set; } + public Nullable ConsistencyLevel { get; set; } + public Collection CustomHandlers { get; } + public Nullable EnableContentResponseOnWrite { get; set; } + public bool EnableTcpConnectionEndpointRediscovery { get; set; } + public int GatewayModeMaxConnectionLimit { get; set; } + public Func HttpClientFactory { get; set; } + public Nullable IdleTcpConnectionTimeout { get; set; } + public bool LimitToEndpoint { get; set; } + public Nullable MaxRequestsPerTcpConnection { get; set; } + public Nullable MaxRetryAttemptsOnRateLimitedRequests { get; set; } + public Nullable MaxRetryWaitTimeOnRateLimitedRequests { get; set; } + public Nullable MaxTcpConnectionsPerEndpoint { get; set; } + public Nullable OpenTcpConnectionTimeout { get; set; } + public Nullable PortReuseMode { get; set; } + public TimeSpan RequestTimeout { get; set; } + public CosmosSerializer Serializer { get; set; } + public CosmosSerializationOptions SerializerOptions { get; set; } + public IWebProxy WebProxy { get; set; } + } + public abstract class CosmosDiagnostics + { + protected CosmosDiagnostics(); + public virtual TimeSpan GetClientElapsedTime(); + public abstract override string ToString(); + } + public class CosmosException : Exception + { + public CosmosException(string message, HttpStatusCode statusCode, int subStatusCode, string activityId, double requestCharge); + public virtual string ActivityId { get; } + public virtual CosmosDiagnostics Diagnostics { get; } + public virtual Headers Headers { get; } + public virtual double RequestCharge { get; } + public virtual string ResponseBody { get; } + public virtual Nullable RetryAfter { get; } + public override string StackTrace { get; } + public virtual HttpStatusCode StatusCode { get; } + public virtual int SubStatusCode { get; } + public override string ToString(); + public virtual bool TryGetHeader(string headerName, out string value); + } + public sealed class CosmosLinqSerializerOptions + { + public CosmosLinqSerializerOptions(); + public CosmosPropertyNamingPolicy PropertyNamingPolicy { get; set; } + } + public class CosmosOperationCanceledException : OperationCanceledException + { + public CosmosOperationCanceledException(OperationCanceledException originalException, CosmosDiagnostics diagnostics); + public override IDictionary Data { get; } + public CosmosDiagnostics Diagnostics { get; } + public override string HelpLink { get; set; } + public override string Message { get; } + public override string Source { get; set; } + public override string StackTrace { get; } + public override Exception GetBaseException(); + public override string ToString(); + } + public enum CosmosPropertyNamingPolicy + { + CamelCase = 1, + Default = 0, + } + public sealed class CosmosSerializationOptions + { + public CosmosSerializationOptions(); + public bool IgnoreNullValues { get; set; } + public bool Indented { get; set; } + public CosmosPropertyNamingPolicy PropertyNamingPolicy { get; set; } + } + public abstract class CosmosSerializer + { + protected CosmosSerializer(); + public abstract T FromStream(Stream stream); + public abstract Stream ToStream(T input); + } + public abstract class Database + { + protected Database(); + public abstract CosmosClient Client { get; } + public abstract string Id { get; } + public abstract Task CreateContainerAsync(ContainerProperties containerProperties, ThroughputProperties throughputProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateContainerAsync(ContainerProperties containerProperties, Nullable throughput=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateContainerAsync(string id, string partitionKeyPath, Nullable throughput=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateContainerIfNotExistsAsync(ContainerProperties containerProperties, ThroughputProperties throughputProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateContainerIfNotExistsAsync(ContainerProperties containerProperties, Nullable throughput=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateContainerIfNotExistsAsync(string id, string partitionKeyPath, Nullable throughput=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateContainerStreamAsync(ContainerProperties containerProperties, ThroughputProperties throughputProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateContainerStreamAsync(ContainerProperties containerProperties, Nullable throughput=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateUserAsync(string id, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract ContainerBuilder DefineContainer(string name, string partitionKeyPath); + public abstract Task DeleteAsync(RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task DeleteStreamAsync(RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Container GetContainer(string id); + public abstract FeedIterator GetContainerQueryIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetContainerQueryIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetContainerQueryStreamIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetContainerQueryStreamIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract User GetUser(string id); + public abstract FeedIterator GetUserQueryIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetUserQueryIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract Task ReadAsync(RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReadStreamAsync(RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReadThroughputAsync(RequestOptions requestOptions, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task> ReadThroughputAsync(CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceThroughputAsync(ThroughputProperties throughputProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceThroughputAsync(int throughput, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task UpsertUserAsync(string id, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + } + public class DatabaseProperties + { + public DatabaseProperties(); + public DatabaseProperties(string id); + public string ETag { get; } + public string Id { get; set; } + public Nullable LastModified { get; } + public string SelfLink { get; } + } + public class DatabaseResponse : Response + { + protected DatabaseResponse(); + public override string ActivityId { get; } + public virtual Database Database { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public override double RequestCharge { get; } + public override DatabaseProperties Resource { get; } + public override HttpStatusCode StatusCode { get; } + public static implicit operator Database (DatabaseResponse response); + } + public enum DataType + { + LineString = 3, + MultiPolygon = 5, + Number = 0, + Point = 2, + Polygon = 4, + String = 1, + } + public sealed class ExcludedPath + { + public ExcludedPath(); + public string Path { get; set; } + } + public abstract class FeedIterator : IDisposable + { + protected FeedIterator(); + public abstract bool HasMoreResults { get; } + public void Dispose(); + protected virtual void Dispose(bool disposing); + public abstract Task ReadNextAsync(CancellationToken cancellationToken=default(CancellationToken)); + } + public abstract class FeedIterator : IDisposable + { + protected FeedIterator(); + public abstract bool HasMoreResults { get; } + public void Dispose(); + protected virtual void Dispose(bool disposing); + public abstract Task> ReadNextAsync(CancellationToken cancellationToken=default(CancellationToken)); + } + public abstract class FeedResponse : IEnumerable, IEnumerable + { + protected FeedResponse(); + public override string ActivityId { get; } + public abstract string ContinuationToken { get; } + public abstract int Count { get; } + public override string ETag { get; } + public override double RequestCharge { get; } + public abstract IEnumerator GetEnumerator(); + IEnumerator System.Collections.IEnumerable.GetEnumerator(); + } + public sealed class GeospatialConfig + { + public GeospatialConfig(); + public GeospatialConfig(GeospatialType geospatialType); + public GeospatialType GeospatialType { get; set; } + } + public enum GeospatialType + { + Geography = 0, + Geometry = 1, + } + public class Headers : IEnumerable + { + public Headers(); + public virtual string ActivityId { get; } + public virtual string ContentLength { get; set; } + public virtual string ContentType { get; } + public virtual string ContinuationToken { get; } + public virtual string ETag { get; } + public virtual string this[string headerName] { get; set; } + public virtual string Location { get; } + public virtual double RequestCharge { get; } + public virtual string Session { get; } + public virtual void Add(string headerName, IEnumerable values); + public virtual void Add(string headerName, string value); + public virtual string[] AllKeys(); + public virtual string Get(string headerName); + public virtual IEnumerator GetEnumerator(); + public virtual T GetHeaderValue(string headerName); + public virtual string GetValueOrDefault(string headerName); + public virtual void Remove(string headerName); + public virtual void Set(string headerName, string value); + IEnumerator System.Collections.IEnumerable.GetEnumerator(); + public virtual bool TryGetValue(string headerName, out string value); + } + public sealed class IncludedPath + { + public IncludedPath(); + public string Path { get; set; } + } + public enum IndexingDirective + { + Default = 0, + Exclude = 2, + Include = 1, + } + public enum IndexingMode + { + Consistent = 0, + Lazy = 1, + None = 2, + } + public sealed class IndexingPolicy + { + public IndexingPolicy(); + public bool Automatic { get; set; } + public Collection> CompositeIndexes { get; } + public Collection ExcludedPaths { get; } + public Collection IncludedPaths { get; } + public IndexingMode IndexingMode { get; set; } + public Collection SpatialIndexes { get; } + } + public enum IndexKind + { + Hash = 0, + Range = 1, + Spatial = 2, + } + public class ItemRequestOptions : RequestOptions + { + public ItemRequestOptions(); + public Nullable ConsistencyLevel { get; set; } + public Nullable EnableContentResponseOnWrite { get; set; } + public Nullable IndexingDirective { get; set; } + public IEnumerable PostTriggers { get; set; } + public IEnumerable PreTriggers { get; set; } + public string SessionToken { get; set; } + } + public class ItemResponse : Response + { + protected ItemResponse(); + public override string ActivityId { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public override double RequestCharge { get; } + public override T Resource { get; } + public override HttpStatusCode StatusCode { get; } + } + public enum OperationKind + { + Create = 1, + Delete = 3, + Invalid = 0, + Read = 4, + Replace = 2, + } + public struct PartitionKey : IEquatable + { + public static readonly PartitionKey None; + public static readonly PartitionKey Null; + public static readonly string SystemKeyName; + public static readonly string SystemKeyPath; + public PartitionKey(bool partitionKeyValue); + public PartitionKey(double partitionKeyValue); + public PartitionKey(string partitionKeyValue); + public bool Equals(PartitionKey other); + public override bool Equals(object obj); + public override int GetHashCode(); + public static bool operator ==(PartitionKey left, PartitionKey right); + public static bool operator !=(PartitionKey left, PartitionKey right); + public override string ToString(); + } + public enum PartitionKeyDefinitionVersion + { + V1 = 1, + V2 = 2, + } + public abstract class Permission + { + protected Permission(); + public abstract string Id { get; } + public abstract Task DeleteAsync(RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReadAsync(Nullable tokenExpiryInSeconds=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceAsync(PermissionProperties permissionProperties, Nullable tokenExpiryInSeconds=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + } + public enum PermissionMode : byte + { + All = (byte)2, + Read = (byte)1, + } + public class PermissionProperties + { + public PermissionProperties(string id, PermissionMode permissionMode, Container container, PartitionKey resourcePartitionKey, string itemId); + public PermissionProperties(string id, PermissionMode permissionMode, Container container, Nullable resourcePartitionKey=default(Nullable)); + public string ETag { get; } + public string Id { get; } + public Nullable LastModified { get; } + public PermissionMode PermissionMode { get; } + public Nullable ResourcePartitionKey { get; set; } + public string ResourceUri { get; } + public string SelfLink { get; } + public string Token { get; } + } + public class PermissionResponse : Response + { + protected PermissionResponse(); + public override string ActivityId { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public virtual Permission Permission { get; } + public override double RequestCharge { get; } + public override PermissionProperties Resource { get; } + public override HttpStatusCode StatusCode { get; } + public static implicit operator Permission (PermissionResponse response); + } + public enum PortReuseMode + { + PrivatePortPool = 1, + ReuseUnicastPort = 0, + } + public class QueryDefinition + { + public QueryDefinition(string query); + public string QueryText { get; } + public IReadOnlyList> GetQueryParameters(); + public QueryDefinition WithParameter(string name, object value); + } + public class QueryRequestOptions : RequestOptions + { + public QueryRequestOptions(); + public Nullable ConsistencyLevel { get; set; } + public Nullable EnableLowPrecisionOrderBy { get; set; } + public Nullable EnableScanInQuery { get; set; } + public Nullable MaxBufferedItemCount { get; set; } + public Nullable MaxConcurrency { get; set; } + public Nullable MaxItemCount { get; set; } + public Nullable PartitionKey { get; set; } + public Nullable ResponseContinuationTokenLimitInKb { get; set; } + public string SessionToken { get; set; } + } + public static class Regions + { + public const string AustraliaCentral = "Australia Central"; + public const string AustraliaCentral2 = "Australia Central 2"; + public const string AustraliaEast = "Australia East"; + public const string AustraliaSoutheast = "Australia Southeast"; + public const string BrazilSouth = "Brazil South"; + public const string BrazilSoutheast = "Brazil Southeast"; + public const string CanadaCentral = "Canada Central"; + public const string CanadaEast = "Canada East"; + public const string CentralIndia = "Central India"; + public const string CentralUS = "Central US"; + public const string CentralUSEUAP = "Central US EUAP"; + public const string ChinaEast = "China East"; + public const string ChinaEast2 = "China East 2"; + public const string ChinaNorth = "China North"; + public const string ChinaNorth2 = "China North 2"; + public const string EastAsia = "East Asia"; + public const string EastUS = "East US"; + public const string EastUS2 = "East US 2"; + public const string EastUS2EUAP = "East US 2 EUAP"; + public const string EastUSSLV = "East US SLV"; + public const string FranceCentral = "France Central"; + public const string FranceSouth = "France South"; + public const string GermanyCentral = "Germany Central"; + public const string GermanyNorth = "Germany North"; + public const string GermanyNortheast = "Germany Northeast"; + public const string GermanyWestCentral = "Germany West Central"; + public const string JapanEast = "Japan East"; + public const string JapanWest = "Japan West"; + public const string JioIndiaCentral = "Jio India Central"; + public const string JioIndiaWest = "Jio India West"; + public const string KoreaCentral = "Korea Central"; + public const string KoreaSouth = "Korea South"; + public const string NorthCentralUS = "North Central US"; + public const string NorthEurope = "North Europe"; + public const string NorwayEast = "Norway East"; + public const string NorwayWest = "Norway West"; + public const string SouthAfricaNorth = "South Africa North"; + public const string SouthAfricaWest = "South Africa West"; + public const string SouthCentralUS = "South Central US"; + public const string SoutheastAsia = "Southeast Asia"; + public const string SouthIndia = "South India"; + public const string SwitzerlandNorth = "Switzerland North"; + public const string SwitzerlandWest = "Switzerland West"; + public const string UAECentral = "UAE Central"; + public const string UAENorth = "UAE North"; + public const string UKSouth = "UK South"; + public const string UKWest = "UK West"; + public const string USDoDCentral = "USDoD Central"; + public const string USDoDEast = "USDoD East"; + public const string USGovArizona = "USGov Arizona"; + public const string USGovTexas = "USGov Texas"; + public const string USGovVirginia = "USGov Virginia"; + public const string USNatEast = "USNat East"; + public const string USNatWest = "USNat West"; + public const string USSecEast = "USSec East"; + public const string USSecWest = "USSec West"; + public const string WestCentralUS = "West Central US"; + public const string WestEurope = "West Europe"; + public const string WestIndia = "West India"; + public const string WestUS = "West US"; + public const string WestUS2 = "West US 2"; + public const string WestUS3 = "West US 3"; + } + public abstract class RequestHandler + { + protected RequestHandler(); + public RequestHandler InnerHandler { get; set; } + public virtual Task SendAsync(RequestMessage request, CancellationToken cancellationToken); + } + public class RequestMessage : IDisposable + { + public RequestMessage(); + public RequestMessage(HttpMethod method, Uri requestUri); + public virtual Stream Content { get; set; } + public virtual Headers Headers { get; } + public virtual HttpMethod Method { get; } + public virtual Dictionary Properties { get; } + public virtual Uri RequestUri { get; } + public void Dispose(); + protected virtual void Dispose(bool disposing); + } + public class RequestOptions + { + public RequestOptions(); + public string IfMatchEtag { get; set; } + public string IfNoneMatchEtag { get; set; } + public IReadOnlyDictionary Properties { get; set; } + } + public class ResponseMessage : IDisposable + { + public ResponseMessage(); + public ResponseMessage(HttpStatusCode statusCode, RequestMessage requestMessage=null, string errorMessage=null); + public virtual Stream Content { get; set; } + public virtual string ContinuationToken { get; } + public virtual CosmosDiagnostics Diagnostics { get; } + public virtual string ErrorMessage { get; } + public virtual Headers Headers { get; } + public virtual bool IsSuccessStatusCode { get; } + public virtual RequestMessage RequestMessage { get; } + public virtual HttpStatusCode StatusCode { get; } + public void Dispose(); + protected virtual void Dispose(bool disposing); + public virtual ResponseMessage EnsureSuccessStatusCode(); + } + public abstract class Response + { + protected Response(); + public abstract string ActivityId { get; } + public abstract CosmosDiagnostics Diagnostics { get; } + public abstract string ETag { get; } + public abstract Headers Headers { get; } + public abstract double RequestCharge { get; } + public abstract T Resource { get; } + public abstract HttpStatusCode StatusCode { get; } + public static implicit operator T (Response response); + } + public sealed class SpatialPath + { + public SpatialPath(); + public BoundingBoxProperties BoundingBox { get; set; } + public string Path { get; set; } + public Collection SpatialTypes { get; } + } + public enum SpatialType + { + LineString = 1, + MultiPolygon = 3, + Point = 0, + Polygon = 2, + } + public class ThroughputProperties + { + public Nullable AutoscaleMaxThroughput { get; } + public string ETag { get; } + public Nullable LastModified { get; } + public string SelfLink { get; } + public Nullable Throughput { get; } + public static ThroughputProperties CreateAutoscaleThroughput(int autoscaleMaxThroughput); + public static ThroughputProperties CreateManualThroughput(int throughput); + } + public class ThroughputResponse : Response + { + protected ThroughputResponse(); + public override string ActivityId { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public Nullable IsReplacePending { get; } + public Nullable MinThroughput { get; } + public override double RequestCharge { get; } + public override ThroughputProperties Resource { get; } + public override HttpStatusCode StatusCode { get; } + public static implicit operator ThroughputProperties (ThroughputResponse response); + } + public abstract class TransactionalBatch + { + protected TransactionalBatch(); + public abstract TransactionalBatch CreateItemStream(Stream streamPayload, TransactionalBatchItemRequestOptions requestOptions=null); + public abstract TransactionalBatch CreateItem(T item, TransactionalBatchItemRequestOptions requestOptions=null); + public abstract TransactionalBatch DeleteItem(string id, TransactionalBatchItemRequestOptions requestOptions=null); + public abstract Task ExecuteAsync(TransactionalBatchRequestOptions requestOptions, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ExecuteAsync(CancellationToken cancellationToken=default(CancellationToken)); + public abstract TransactionalBatch ReadItem(string id, TransactionalBatchItemRequestOptions requestOptions=null); + public abstract TransactionalBatch ReplaceItemStream(string id, Stream streamPayload, TransactionalBatchItemRequestOptions requestOptions=null); + public abstract TransactionalBatch ReplaceItem(string id, T item, TransactionalBatchItemRequestOptions requestOptions=null); + public abstract TransactionalBatch UpsertItemStream(Stream streamPayload, TransactionalBatchItemRequestOptions requestOptions=null); + public abstract TransactionalBatch UpsertItem(T item, TransactionalBatchItemRequestOptions requestOptions=null); + } + public class TransactionalBatchItemRequestOptions : RequestOptions + { + public TransactionalBatchItemRequestOptions(); + public Nullable EnableContentResponseOnWrite { get; set; } + public Nullable IndexingDirective { get; set; } + } + public class TransactionalBatchOperationResult + { + protected TransactionalBatchOperationResult(); + public virtual string ETag { get; } + public virtual bool IsSuccessStatusCode { get; } + public virtual Stream ResourceStream { get; } + public virtual TimeSpan RetryAfter { get; } + public virtual HttpStatusCode StatusCode { get; } + } + public class TransactionalBatchOperationResult : TransactionalBatchOperationResult + { + protected TransactionalBatchOperationResult(); + public virtual T Resource { get; set; } + } + public class TransactionalBatchRequestOptions : RequestOptions + { + public TransactionalBatchRequestOptions(); + public Nullable ConsistencyLevel { get; set; } + public string SessionToken { get; set; } + } + public class TransactionalBatchResponse : IDisposable, IEnumerable, IEnumerable, IReadOnlyCollection, IReadOnlyList + { + protected TransactionalBatchResponse(); + public virtual string ActivityId { get; } + public virtual int Count { get; } + public virtual CosmosDiagnostics Diagnostics { get; } + public virtual string ErrorMessage { get; } + public virtual Headers Headers { get; } + public virtual bool IsSuccessStatusCode { get; } + public virtual TransactionalBatchOperationResult this[int index] { get; } + public virtual double RequestCharge { get; } + public virtual Nullable RetryAfter { get; } + public virtual HttpStatusCode StatusCode { get; } + public void Dispose(); + protected virtual void Dispose(bool disposing); + public virtual IEnumerator GetEnumerator(); + public virtual TransactionalBatchOperationResult GetOperationResultAtIndex(int index); + IEnumerator System.Collections.IEnumerable.GetEnumerator(); + } + public class UniqueKey + { + public UniqueKey(); + public Collection Paths { get; } + } + public sealed class UniqueKeyPolicy + { + public UniqueKeyPolicy(); + public Collection UniqueKeys { get; } + } + public abstract class User + { + protected User(); + public abstract string Id { get; } + public abstract Task CreatePermissionAsync(PermissionProperties permissionProperties, Nullable tokenExpiryInSeconds=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task DeleteAsync(RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Permission GetPermission(string id); + public abstract FeedIterator GetPermissionQueryIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetPermissionQueryIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract Task ReadAsync(RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceAsync(UserProperties userProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task UpsertPermissionAsync(PermissionProperties permissionProperties, Nullable tokenExpiryInSeconds=default(Nullable), RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + } + public class UserProperties + { + protected UserProperties(); + public UserProperties(string id); + public string ETag { get; } + public string Id { get; set; } + public Nullable LastModified { get; } + public string SelfLink { get; } + } + public class UserResponse : Response + { + protected UserResponse(); + public override string ActivityId { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public override double RequestCharge { get; } + public override UserProperties Resource { get; } + public override HttpStatusCode StatusCode { get; } + public virtual User User { get; } + public static implicit operator User (UserResponse response); + } +} +namespace Microsoft.Azure.Cosmos.Fluent +{ + public class CompositeIndexDefinition + { + public T Attach(); + public CompositeIndexDefinition Path(string path); + public CompositeIndexDefinition Path(string path, CompositePathSortOrder sortOrder); + } + public class ConflictResolutionDefinition + { + public ContainerBuilder Attach(); + public ConflictResolutionDefinition WithCustomStoredProcedureResolution(string conflictResolutionProcedure); + public ConflictResolutionDefinition WithLastWriterWinsResolution(string conflictResolutionPath); + } + public class ContainerBuilder : ContainerDefinition + { + protected ContainerBuilder(); + public new ContainerProperties Build(); + public Task CreateAsync(ThroughputProperties throughputProperties, CancellationToken cancellationToken=default(CancellationToken)); + public Task CreateAsync(Nullable throughput=default(Nullable), CancellationToken cancellationToken=default(CancellationToken)); + public Task CreateIfNotExistsAsync(ThroughputProperties throughputProperties, CancellationToken cancellationToken=default(CancellationToken)); + public Task CreateIfNotExistsAsync(Nullable throughput=default(Nullable), CancellationToken cancellationToken=default(CancellationToken)); + public ConflictResolutionDefinition WithConflictResolution(); + public UniqueKeyDefinition WithUniqueKey(); + } + public abstract class ContainerDefinition where T : ContainerDefinition + { + public ContainerDefinition(); + public ContainerProperties Build(); + public T WithDefaultTimeToLive(int defaultTtlInSeconds); + public T WithDefaultTimeToLive(TimeSpan defaultTtlTimeSpan); + public IndexingPolicyDefinition WithIndexingPolicy(); + public T WithPartitionKeyDefinitionVersion(PartitionKeyDefinitionVersion partitionKeyDefinitionVersion); + public T WithTimeToLivePropertyPath(string propertyPath); + } + public class CosmosClientBuilder + { + public CosmosClientBuilder(string connectionString); + public CosmosClientBuilder(string accountEndpoint, string authKeyOrResourceToken); + public CosmosClientBuilder AddCustomHandlers(params RequestHandler[] customHandlers); + public CosmosClient Build(); + public CosmosClientBuilder WithApplicationName(string applicationName); + public CosmosClientBuilder WithApplicationPreferredRegions(IReadOnlyList applicationPreferredRegions); + public CosmosClientBuilder WithApplicationRegion(string applicationRegion); + public CosmosClientBuilder WithBulkExecution(bool enabled); + public CosmosClientBuilder WithConnectionModeDirect(); + public CosmosClientBuilder WithConnectionModeDirect(Nullable idleTcpConnectionTimeout=default(Nullable), Nullable openTcpConnectionTimeout=default(Nullable), Nullable maxRequestsPerTcpConnection=default(Nullable), Nullable maxTcpConnectionsPerEndpoint=default(Nullable), Nullable portReuseMode=default(Nullable), Nullable enableTcpConnectionEndpointRediscovery=default(Nullable)); + public CosmosClientBuilder WithConnectionModeGateway(Nullable maxConnectionLimit=default(Nullable), IWebProxy webProxy=null); + public CosmosClientBuilder WithConsistencyLevel(ConsistencyLevel consistencyLevel); + public CosmosClientBuilder WithContentResponseOnWrite(bool contentResponseOnWrite); + public CosmosClientBuilder WithCustomSerializer(CosmosSerializer cosmosJsonSerializer); + public CosmosClientBuilder WithHttpClientFactory(Func httpClientFactory); + public CosmosClientBuilder WithLimitToEndpoint(bool limitToEndpoint); + public CosmosClientBuilder WithRequestTimeout(TimeSpan requestTimeout); + public CosmosClientBuilder WithSerializerOptions(CosmosSerializationOptions cosmosSerializerOptions); + public CosmosClientBuilder WithThrottlingRetryOptions(TimeSpan maxRetryWaitTimeOnThrottledRequests, int maxRetryAttemptsOnThrottledRequests); + } + public class IndexingPolicyDefinition + { + public IndexingPolicyDefinition(); + public T Attach(); + public IndexingPolicyDefinition WithAutomaticIndexing(bool enabled); + public CompositeIndexDefinition> WithCompositeIndex(); + public PathsDefinition> WithExcludedPaths(); + public PathsDefinition> WithIncludedPaths(); + public IndexingPolicyDefinition WithIndexingMode(IndexingMode indexingMode); + public SpatialIndexDefinition> WithSpatialIndex(); + } + public class PathsDefinition + { + public T Attach(); + public PathsDefinition Path(string path); + } + public class SpatialIndexDefinition + { + public T Attach(); + public SpatialIndexDefinition Path(string path); + public SpatialIndexDefinition Path(string path, params SpatialType[] spatialTypes); + } + public class UniqueKeyDefinition + { + public ContainerBuilder Attach(); + public UniqueKeyDefinition Path(string path); + } +} +namespace Microsoft.Azure.Cosmos.Linq +{ + public static class CosmosLinq + { + public static object InvokeUserDefinedFunction(string udfName, params object[] arguments); + } + public static class CosmosLinqExtensions + { + public static Task> AverageAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> AverageAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> AverageAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> AverageAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task>> AverageAsync(this IQueryable> source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task>> AverageAsync(this IQueryable> source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task>> AverageAsync(this IQueryable> source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task>> AverageAsync(this IQueryable> source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task>> AverageAsync(this IQueryable> source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> AverageAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> CountAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static bool IsDefined(this object obj); + public static bool IsNull(this object obj); + public static bool IsPrimitive(this object obj); + public static Task> MaxAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> MinAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> SumAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> SumAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> SumAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> SumAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task>> SumAsync(this IQueryable> source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task>> SumAsync(this IQueryable> source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task>> SumAsync(this IQueryable> source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task>> SumAsync(this IQueryable> source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task>> SumAsync(this IQueryable> source, CancellationToken cancellationToken=default(CancellationToken)); + public static Task> SumAsync(this IQueryable source, CancellationToken cancellationToken=default(CancellationToken)); + public static FeedIterator ToFeedIterator(this IQueryable query); + public static QueryDefinition ToQueryDefinition(this IQueryable query); + public static FeedIterator ToStreamIterator(this IQueryable query); + } +} +namespace Microsoft.Azure.Cosmos.Scripts +{ + public abstract class Scripts + { + protected Scripts(); + public abstract Task CreateStoredProcedureAsync(StoredProcedureProperties storedProcedureProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateTriggerAsync(TriggerProperties triggerProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task CreateUserDefinedFunctionAsync(UserDefinedFunctionProperties userDefinedFunctionProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task DeleteStoredProcedureAsync(string id, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task DeleteTriggerAsync(string id, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task DeleteUserDefinedFunctionAsync(string id, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task> ExecuteStoredProcedureAsync(string storedProcedureId, PartitionKey partitionKey, dynamic parameters, StoredProcedureRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ExecuteStoredProcedureStreamAsync(string storedProcedureId, PartitionKey partitionKey, dynamic parameters, StoredProcedureRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ExecuteStoredProcedureStreamAsync(string storedProcedureId, Stream streamPayload, PartitionKey partitionKey, StoredProcedureRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract FeedIterator GetStoredProcedureQueryIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetStoredProcedureQueryIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetStoredProcedureQueryStreamIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetStoredProcedureQueryStreamIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetTriggerQueryIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetTriggerQueryIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetTriggerQueryStreamIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetTriggerQueryStreamIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetUserDefinedFunctionQueryIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetUserDefinedFunctionQueryIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetUserDefinedFunctionQueryStreamIterator(QueryDefinition queryDefinition, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract FeedIterator GetUserDefinedFunctionQueryStreamIterator(string queryText=null, string continuationToken=null, QueryRequestOptions requestOptions=null); + public abstract Task ReadStoredProcedureAsync(string id, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReadTriggerAsync(string id, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReadUserDefinedFunctionAsync(string id, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceStoredProcedureAsync(StoredProcedureProperties storedProcedureProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceTriggerAsync(TriggerProperties triggerProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + public abstract Task ReplaceUserDefinedFunctionAsync(UserDefinedFunctionProperties userDefinedFunctionProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken)); + } + public class StoredProcedureExecuteResponse : Response + { + protected StoredProcedureExecuteResponse(); + public override string ActivityId { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public override double RequestCharge { get; } + public override T Resource { get; } + public virtual string ScriptLog { get; } + public virtual string SessionToken { get; } + public override HttpStatusCode StatusCode { get; } + } + public class StoredProcedureProperties + { + public StoredProcedureProperties(); + public StoredProcedureProperties(string id, string body); + public string Body { get; set; } + public string ETag { get; } + public string Id { get; set; } + public Nullable LastModified { get; } + public string SelfLink { get; } + } + public class StoredProcedureRequestOptions : RequestOptions + { + public StoredProcedureRequestOptions(); + public Nullable ConsistencyLevel { get; set; } + public bool EnableScriptLogging { get; set; } + public string SessionToken { get; set; } + } + public class StoredProcedureResponse : Response + { + protected StoredProcedureResponse(); + public override string ActivityId { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public override double RequestCharge { get; } + public override StoredProcedureProperties Resource { get; } + public virtual string SessionToken { get; } + public override HttpStatusCode StatusCode { get; } + public static implicit operator StoredProcedureProperties (StoredProcedureResponse response); + } + public enum TriggerOperation : short + { + All = (short)0, + Create = (short)1, + Delete = (short)3, + Replace = (short)4, + Update = (short)2, + } + public class TriggerProperties + { + public TriggerProperties(); + public string Body { get; set; } + public string ETag { get; } + public string Id { get; set; } + public string SelfLink { get; } + public TriggerOperation TriggerOperation { get; set; } + public TriggerType TriggerType { get; set; } + } + public class TriggerResponse : Response + { + protected TriggerResponse(); + public override string ActivityId { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public override double RequestCharge { get; } + public override TriggerProperties Resource { get; } + public override HttpStatusCode StatusCode { get; } + public static implicit operator TriggerProperties (TriggerResponse response); + } + public enum TriggerType : byte + { + Post = (byte)1, + Pre = (byte)0, + } + public class UserDefinedFunctionProperties + { + public UserDefinedFunctionProperties(); + public string Body { get; set; } + public string ETag { get; } + public string Id { get; set; } + public string SelfLink { get; } + } + public class UserDefinedFunctionResponse : Response + { + protected UserDefinedFunctionResponse(); + public override string ActivityId { get; } + public override CosmosDiagnostics Diagnostics { get; } + public override string ETag { get; } + public override Headers Headers { get; } + public override double RequestCharge { get; } + public override UserDefinedFunctionProperties Resource { get; } + public override HttpStatusCode StatusCode { get; } + public static implicit operator UserDefinedFunctionProperties (UserDefinedFunctionResponse response); + } +} +namespace Microsoft.Azure.Cosmos.Spatial +{ + public sealed class BoundingBox : IEquatable + { + public BoundingBox(Position min, Position max); + public Position Max { get; } + public Position Min { get; } + public bool Equals(BoundingBox other); + public override bool Equals(object obj); + public override int GetHashCode(); + } + public abstract class Crs + { + protected Crs(CrsType type); + public static Crs Default { get; } + public CrsType Type { get; } + public static Crs Unspecified { get; } + public static LinkedCrs Linked(string href); + public static LinkedCrs Linked(string href, string type); + public static NamedCrs Named(string name); + } + public enum CrsType + { + Linked = 1, + Named = 0, + Unspecified = 2, + } + public abstract class Geometry + { + protected Geometry(GeometryType type, GeometryParams geometryParams); + public IDictionary AdditionalProperties { get; } + public BoundingBox BoundingBox { get; } + public Crs Crs { get; } + public GeometryType Type { get; } + public double Distance(Geometry to); + public override bool Equals(object obj); + public override int GetHashCode(); + public bool Intersects(Geometry geometry2); + public bool IsValid(); + public GeometryValidationResult IsValidDetailed(); + public bool Within(Geometry outer); + } + public class GeometryParams + { + public GeometryParams(); + public IDictionary AdditionalProperties { get; set; } + public BoundingBox BoundingBox { get; set; } + public Crs Crs { get; set; } + } + public enum GeometryShape + { + GeometryCollection = 6, + LineString = 2, + MultiLineString = 3, + MultiPoint = 1, + MultiPolygon = 5, + Point = 0, + Polygon = 4, + } + public enum GeometryType + { + GeometryCollection = 6, + LineString = 2, + MultiLineString = 3, + MultiPoint = 1, + MultiPolygon = 5, + Point = 0, + Polygon = 4, + } + public class GeometryValidationResult + { + public GeometryValidationResult(); + public bool IsValid { get; } + public string Reason { get; } + } + public sealed class LinearRing : IEquatable + { + public LinearRing(IList coordinates); + public ReadOnlyCollection Positions { get; } + public bool Equals(LinearRing other); + public override bool Equals(object obj); + public override int GetHashCode(); + } + public sealed class LineString : Geometry, IEquatable + { + public LineString(IList coordinates); + public LineString(IList coordinates, GeometryParams geometryParams); + public ReadOnlyCollection Positions { get; } + public bool Equals(LineString other); + public override bool Equals(object obj); + public override int GetHashCode(); + } + public sealed class LinkedCrs : Crs, IEquatable + { + public string Href { get; } + public string HrefType { get; } + public bool Equals(LinkedCrs other); + public override bool Equals(object obj); + public override int GetHashCode(); + } + public sealed class MultiPolygon : Geometry, IEquatable + { + public MultiPolygon(IList polygons); + public MultiPolygon(IList polygons, GeometryParams geometryParams); + public ReadOnlyCollection Polygons { get; } + public bool Equals(MultiPolygon other); + public override bool Equals(object obj); + public override int GetHashCode(); + } + public sealed class NamedCrs : Crs, IEquatable + { + public string Name { get; } + public bool Equals(NamedCrs other); + public override bool Equals(object obj); + public override int GetHashCode(); + } + public sealed class Point : Geometry, IEquatable + { + public Point(Position position); + public Point(Position position, GeometryParams geometryParams); + public Point(double longitude, double latitude); + public Position Position { get; } + public bool Equals(Point other); + public override bool Equals(object obj); + public override int GetHashCode(); + } + public sealed class Polygon : Geometry, IEquatable + { + public Polygon(IList rings); + public Polygon(IList rings, GeometryParams geometryParams); + public Polygon(IList externalRingPositions); + public ReadOnlyCollection Rings { get; } + public bool Equals(Polygon other); + public override bool Equals(object obj); + public override int GetHashCode(); + } + public sealed class PolygonCoordinates : IEquatable + { + public PolygonCoordinates(IList rings); + public ReadOnlyCollection Rings { get; } + public bool Equals(PolygonCoordinates other); + public override bool Equals(object obj); + public override int GetHashCode(); + } + public sealed class Position : IEquatable + { + public Position(IList coordinates); + public Position(double longitude, double latitude); + public Position(double longitude, double latitude, Nullable altitude); + public Nullable Altitude { get; } + public ReadOnlyCollection Coordinates { get; } + public double Latitude { get; } + public double Longitude { get; } + public bool Equals(Position other); + public override bool Equals(object obj); + public override int GetHashCode(); + } +} \ No newline at end of file diff --git a/changelog.md b/changelog.md index e07122f172..d972ba939a 100644 --- a/changelog.md +++ b/changelog.md @@ -3,14 +3,25 @@ Preview features are treated as a separate branch and will not be included in th The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -### [3.18.0-preview](https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.18.0-preview) - 2021-03-17 +### [3.18.0-preview](https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.18.0-preview) - 2021-03-18 #### Added - [#2308](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2308) Patch: Adds preview support for Patch API - [#2312](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2312) Diagnostics: Adds Api for getting all regions contacted by a request #### Fixed -- [#2314](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2314) Diagnostics: Fixes concurrency of cache +- [#2314](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2314) Diagnostics: Fixes InvalidOperationException caused by concurrently modifing a dictionary in TraceWriter. Introduced in 3.17.0 PR [#2242](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2242) +- [#2303](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2303) CosmosException : Fixed exception messages to remove JSON formatting +- [#2311](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2311) Spatial: Fixed deserialization when Json does not represent a Spatial type +- [#2284](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2284) Diagnostics: Adds traces for cache operations. Introduced in 3.17.0 PR [#2097](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2097) +- [#2278](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2278) Documentation: Fixed typos in comment examples (Thanks to paulomorgado) +- [#2279](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2279) Availability: Fixed region failover logic on control plane hot path when gateway hangs. Introduced in 3.16.0 PR [#1954](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/1954) +- [#2286](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2286) Diagnostics: Fixed regression which caused ActivityId to not get included. Introduced in 3.17.0 PR [#2097](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2097) + +### [3.17.1](https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.17.1) - 2021-03-19 + +#### Fixed +- [#2314](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2314) Diagnostics: Fixes InvalidOperationException caused by concurrently modifying a dictionary in TraceWriter. Introduced in 3.17.0 PR [#2242](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2242) - [#2303](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2303) CosmosException : Fixed exception messages to remove JSON formatting - [#2311](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2311) Spatial: Fixed deserialization when Json does not represent a Spatial type - [#2284](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2284) Diagnostics: Adds traces for cache operations. Introduced in 3.17.0 PR [#2097](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2097) From 8703a8741fc05a7338ebd5ab5c0c107eaa1fbc3f Mon Sep 17 00:00:00 2001 From: Santosh Kulkarni <66682828+kr-santosh@users.noreply.github.com> Date: Tue, 23 Mar 2021 03:05:05 +0530 Subject: [PATCH 04/19] ContainerBuilder : Adds public Constructor to create ContainerBuilder instance. (#2241) * Make methods virtual and Expose ContainerBuilder constructor. * Update ContainerBuilder.cs * Fixes. * Update ContainerBuilder.cs Co-authored-by: j82w --- .../src/Fluent/Settings/ContainerBuilder.cs | 21 ++++++++++------ .../src/Resource/Database/DatabaseCore.cs | 12 +-------- .../Contracts/DotNetSDKAPI.json | 5 ++++ .../ContainerDefinitionForCreateTests.cs | 25 ++++++++++++------- 4 files changed, 36 insertions(+), 27 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Fluent/Settings/ContainerBuilder.cs b/Microsoft.Azure.Cosmos/src/Fluent/Settings/ContainerBuilder.cs index 397aab9566..3ba0168265 100644 --- a/Microsoft.Azure.Cosmos/src/Fluent/Settings/ContainerBuilder.cs +++ b/Microsoft.Azure.Cosmos/src/Fluent/Settings/ContainerBuilder.cs @@ -28,15 +28,22 @@ protected ContainerBuilder() { } - internal ContainerBuilder( - Database cosmosContainers, - CosmosClientContext clientContext, + /// + /// Creates an instance of ContainerBuilder . + /// + /// The Microsoft.Azure.Cosmos.Database object. + /// Azure Cosmos container name to create. + /// The path to the partition key. Example: /partitionKey + public ContainerBuilder( + Database database, string name, - string partitionKeyPath = null) - : base(name, partitionKeyPath) + string partitionKeyPath) + : base( + string.IsNullOrEmpty(name) ? throw new ArgumentNullException(nameof(name)) : name, + string.IsNullOrEmpty(partitionKeyPath) ? throw new ArgumentNullException(nameof(partitionKeyPath)) : partitionKeyPath) { - this.database = cosmosContainers; - this.clientContext = clientContext; + this.database = database ?? throw new ArgumentNullException(nameof(database)); + this.clientContext = database.Client.ClientContext; this.containerUri = UriFactory.CreateDocumentCollectionUri(this.database.Id, name); } diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs index ab0cc9f918..faab570dda 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs @@ -681,17 +681,7 @@ public override ContainerBuilder DefineContainer( string name, string partitionKeyPath) { - if (string.IsNullOrEmpty(name)) - { - throw new ArgumentNullException(nameof(name)); - } - - if (string.IsNullOrEmpty(partitionKeyPath)) - { - throw new ArgumentNullException(nameof(partitionKeyPath)); - } - - return new ContainerBuilder(this, this.ClientContext, name, partitionKeyPath); + return new ContainerBuilder(this, name, partitionKeyPath); } #if PREVIEW diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json index 31507703ae..edf73ebdfd 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json @@ -2910,6 +2910,11 @@ "AsyncStateMachineAttribute" ], "MethodInfo": "System.Threading.Tasks.Task`1[Microsoft.Azure.Cosmos.ContainerResponse] CreateIfNotExistsAsync(System.Nullable`1[System.Int32], System.Threading.CancellationToken);IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "Void .ctor(Microsoft.Azure.Cosmos.Database, System.String, System.String)": { + "Type": "Constructor", + "Attributes": [], + "MethodInfo": "[Void .ctor(Microsoft.Azure.Cosmos.Database, System.String, System.String), Void .ctor(Microsoft.Azure.Cosmos.Database, System.String, System.String)]" } }, "NestedTypes": {} diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Fluent/ContainerDefinitionForCreateTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Fluent/ContainerDefinitionForCreateTests.cs index e47d300421..58361f89bb 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Fluent/ContainerDefinitionForCreateTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Fluent/ContainerDefinitionForCreateTests.cs @@ -28,10 +28,10 @@ public class ContainerDefinitionForCreateTests public async Task MissingPKForCreateThrows() { Mock mockContainers = new Mock(); - + Mock mockClient = new Mock(); + mockContainers.Setup(m => m.Client).Returns(mockClient.Object); ContainerBuilder containerFluentDefinitionForCreate = new ContainerBuilder( mockContainers.Object, - GetContext(), containerName, null); @@ -53,6 +53,8 @@ public async Task MissingPKForReplace_CallsReadAsync() .ReturnsAsync(mockContainerResponse.Object); Mock mockContainers = new Mock(); + Mock mockClient = new Mock(); + mockContainers.Setup(m => m.Client).Returns(mockClient.Object); mockContainers .Setup(c => c.CreateContainerAsync( It.Is((settings) => settings.PartitionKeyPath.Equals(partitionKey)), @@ -65,7 +67,6 @@ public async Task MissingPKForReplace_CallsReadAsync() ContainerBuilder containerFluentDefinitionForCreate = new ContainerBuilder( mockContainers.Object, - GetContext(), containerName, null); @@ -79,6 +80,8 @@ public async Task WithThroughput() { Mock mockContainerResponse = new Mock(); Mock mockContainers = new Mock(); + Mock mockClient = new Mock(); + mockContainers.Setup(m => m.Client).Returns(mockClient.Object); mockContainers .Setup(c => c.CreateContainerAsync( It.IsAny(), @@ -92,7 +95,6 @@ public async Task WithThroughput() ContainerBuilder containerFluentDefinitionForCreate = new ContainerBuilder( mockContainers.Object, - GetContext(), containerName, partitionKey); @@ -111,6 +113,8 @@ public async Task WithTimeToLivePropertyPath() { Mock mockContainerResponse = new Mock(); Mock mockContainers = new Mock(); + Mock mockClient = new Mock(); + mockContainers.Setup(m => m.Client).Returns(mockClient.Object); mockContainers .Setup(c => c.CreateContainerAsync( #pragma warning disable CS0612 // Type or member is obsolete @@ -126,7 +130,6 @@ public async Task WithTimeToLivePropertyPath() ContainerBuilder containerFluentDefinitionForCreate = new ContainerBuilder( mockContainers.Object, - GetContext(), containerName, partitionKey); @@ -148,6 +151,8 @@ public async Task WithDefaultTimeToLiveTimeSpan() { Mock mockContainerResponse = new Mock(); Mock mockContainers = new Mock(); + Mock mockClient = new Mock(); + mockContainers.Setup(m => m.Client).Returns(mockClient.Object); mockContainers .Setup(c => c.CreateContainerAsync( It.Is((settings) => settings.DefaultTimeToLive.Equals((int)timeToLive.TotalSeconds)), @@ -161,7 +166,6 @@ public async Task WithDefaultTimeToLiveTimeSpan() ContainerBuilder containerFluentDefinitionForCreate = new ContainerBuilder( mockContainers.Object, - GetContext(), containerName, partitionKey); @@ -181,6 +185,8 @@ public async Task WithDefaultTimeToLiveInt() { Mock mockContainerResponse = new Mock(); Mock mockContainers = new Mock(); + Mock mockClient = new Mock(); + mockContainers.Setup(m => m.Client).Returns(mockClient.Object); mockContainers .Setup(c => c.CreateContainerAsync( It.Is((settings) => settings.DefaultTimeToLive.Equals((int)timeToLive.TotalSeconds)), @@ -194,7 +200,6 @@ public async Task WithDefaultTimeToLiveInt() ContainerBuilder containerFluentDefinitionForCreate = new ContainerBuilder( mockContainers.Object, - GetContext(), containerName, partitionKey); @@ -214,6 +219,8 @@ public async Task WithIndexingPolicy() { Mock mockContainerResponse = new Mock(); Mock mockContainers = new Mock(); + Mock mockClient = new Mock(); + mockContainers.Setup(m => m.Client).Returns(mockClient.Object); mockContainers .Setup(c => c.CreateContainerAsync( It.Is((settings) => IndexingMode.None.Equals(settings.IndexingPolicy.IndexingMode) && !settings.IndexingPolicy.Automatic), @@ -227,7 +234,6 @@ public async Task WithIndexingPolicy() ContainerBuilder containerFluentDefinitionForCreate = new ContainerBuilder( mockContainers.Object, - GetContext(), containerName, partitionKey); @@ -250,6 +256,8 @@ public async Task WithUniqueKey() { Mock mockContainerResponse = new Mock(); Mock mockContainers = new Mock(); + Mock mockClient = new Mock(); + mockContainers.Setup(m => m.Client).Returns(mockClient.Object); mockContainers .Setup(c => c.CreateContainerAsync( It.Is((settings) => settings.UniqueKeyPolicy.UniqueKeys.Count == 1 && path.Equals(settings.UniqueKeyPolicy.UniqueKeys[0].Paths[0])), @@ -263,7 +271,6 @@ public async Task WithUniqueKey() ContainerBuilder containerFluentDefinitionForCreate = new ContainerBuilder( mockContainers.Object, - GetContext(), containerName, partitionKey); From 3eebc5f1446bfae631dfab752f0ad6fd68c5bb39 Mon Sep 17 00:00:00 2001 From: neildsh <35383880+neildsh@users.noreply.github.com> Date: Mon, 22 Mar 2021 16:22:22 -0700 Subject: [PATCH 05/19] Query: Fixes COUNT(DISTINCT) in V3 SDK by upgrading Direct package version (#2282) * refresh Direct package and enable dcount in V3 SDK * Fix up build break --- .../Core/QueryClient/CosmosQueryClient.cs | 1 + .../Core/QueryPlan/QueryPartitionProvider.cs | 25 +++--- .../Query/Core/QueryPlan/QueryPlanHandler.cs | 1 + .../DefaultDocumentQueryExecutionContext.cs | 19 ++-- .../DocumentQueryExecutionContextBase.cs | 14 +-- .../DocumentQueryExecutionContextFactory.cs | 9 +- .../Query/v3Query/CosmosQueryClientCore.cs | 14 +-- .../src/Routing/PartitionRoutingHelper.cs | 4 +- .../Query/DistinctQueryTests.cs | 88 +++++++++++++------ .../Query/ParsingBenchmark.cs | 3 +- .../Query/Pipeline/FullPipelineTests.cs | 1 + .../Query/QueryPlanBaselineTests.cs | 3 +- .../Tracing/TraceWriterBaselineTests.cs | 3 +- 13 files changed, 124 insertions(+), 61 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/QueryClient/CosmosQueryClient.cs b/Microsoft.Azure.Cosmos/src/Query/Core/QueryClient/CosmosQueryClient.cs index ee512ce848..7a59c8daae 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/QueryClient/CosmosQueryClient.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/QueryClient/CosmosQueryClient.cs @@ -44,6 +44,7 @@ public abstract Task> TryGetPartitionedQ bool isContinuationExpected, bool allowNonValueAggregateQuery, bool hasLogicalPartitionKey, + bool allowDCount, CancellationToken cancellationToken); public abstract Task> ExecuteItemQueryAsync( diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/QueryPlan/QueryPartitionProvider.cs b/Microsoft.Azure.Cosmos/src/Query/Core/QueryPlan/QueryPartitionProvider.cs index 35da857819..5042b6f396 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/QueryPlan/QueryPartitionProvider.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/QueryPlan/QueryPartitionProvider.cs @@ -109,15 +109,17 @@ public TryCatch TryGetPartitionedQueryExecutionIn bool requireFormattableOrderByQuery, bool isContinuationExpected, bool allowNonValueAggregateQuery, - bool hasLogicalPartitionKey) + bool hasLogicalPartitionKey, + bool allowDCount) { TryCatch tryGetInternalQueryInfo = this.TryGetPartitionedQueryExecutionInfoInternal( - querySpec, - partitionKeyDefinition, - requireFormattableOrderByQuery, - isContinuationExpected, - allowNonValueAggregateQuery, - hasLogicalPartitionKey); + querySpec: querySpec, + partitionKeyDefinition: partitionKeyDefinition, + requireFormattableOrderByQuery: requireFormattableOrderByQuery, + isContinuationExpected: isContinuationExpected, + allowNonValueAggregateQuery: allowNonValueAggregateQuery, + hasLogicalPartitionKey: hasLogicalPartitionKey, + allowDCount: allowDCount); if (!tryGetInternalQueryInfo.Succeeded) { return TryCatch.FromException(tryGetInternalQueryInfo.Exception); @@ -156,7 +158,8 @@ internal TryCatch TryGetPartitionedQueryE bool requireFormattableOrderByQuery, bool isContinuationExpected, bool allowNonValueAggregateQuery, - bool hasLogicalPartitionKey) + bool hasLogicalPartitionKey, + bool allowDCount) { if (querySpec == null || partitionKeyDefinition == null) { @@ -200,13 +203,14 @@ internal TryCatch TryGetPartitionedQueryE { fixed (byte* bytePtr = buffer) { - errorCode = ServiceInteropWrapper.GetPartitionKeyRangesFromQuery( + errorCode = ServiceInteropWrapper.GetPartitionKeyRangesFromQuery2( this.serviceProvider, queryText, requireFormattableOrderByQuery, isContinuationExpected, allowNonValueAggregateQuery, hasLogicalPartitionKey, + allowDCount, allParts, partsLengths, (uint)partitionKeyDefinition.Paths.Count, @@ -224,13 +228,14 @@ internal TryCatch TryGetPartitionedQueryE fixed (byte* bytePtr2 = buffer) { - errorCode = ServiceInteropWrapper.GetPartitionKeyRangesFromQuery( + errorCode = ServiceInteropWrapper.GetPartitionKeyRangesFromQuery2( this.serviceProvider, queryText, requireFormattableOrderByQuery, isContinuationExpected, allowNonValueAggregateQuery, hasLogicalPartitionKey, // has logical partition key + allowDCount, allParts, partsLengths, (uint)partitionKeyDefinition.Paths.Count, diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/QueryPlan/QueryPlanHandler.cs b/Microsoft.Azure.Cosmos/src/Query/Core/QueryPlan/QueryPlanHandler.cs index d55c886113..8325050d92 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/QueryPlan/QueryPlanHandler.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/QueryPlan/QueryPlanHandler.cs @@ -115,6 +115,7 @@ private Task> TryGetQueryInfoAsync( isContinuationExpected: false, allowNonValueAggregateQuery: true, hasLogicalPartitionKey: hasLogicalPartitionKey, + allowDCount: true, cancellationToken: cancellationToken); } diff --git a/Microsoft.Azure.Cosmos/src/Query/v2Query/DefaultDocumentQueryExecutionContext.cs b/Microsoft.Azure.Cosmos/src/Query/v2Query/DefaultDocumentQueryExecutionContext.cs index d264c363b3..31e793d250 100644 --- a/Microsoft.Azure.Cosmos/src/Query/v2Query/DefaultDocumentQueryExecutionContext.cs +++ b/Microsoft.Azure.Cosmos/src/Query/v2Query/DefaultDocumentQueryExecutionContext.cs @@ -308,15 +308,16 @@ private static bool ServiceInteropAvailable() } providedRanges = PartitionRoutingHelper.GetProvidedPartitionKeyRanges( - this.QuerySpec, - enableCrossPartitionQuery, - false, - this.isContinuationExpected, - false, //haslogicalpartitionkey - partitionKeyDefinition, - queryPartitionProvider, - version, - out QueryInfo queryInfo); + querySpec: this.QuerySpec, + enableCrossPartitionQuery: enableCrossPartitionQuery, + parallelizeCrossPartitionQuery: false, + isContinuationExpected: this.isContinuationExpected, + hasLogicalPartitionKey: false, + allowDCount: false, + partitionKeyDefinition: partitionKeyDefinition, + queryPartitionProvider: queryPartitionProvider, + clientApiVersion: version, + out QueryInfo _); } else if (request.Properties != null && request.Properties.TryGetValue( WFConstants.BackendHeaders.EffectivePartitionKeyString, diff --git a/Microsoft.Azure.Cosmos/src/Query/v2Query/DocumentQueryExecutionContextBase.cs b/Microsoft.Azure.Cosmos/src/Query/v2Query/DocumentQueryExecutionContextBase.cs index 257730fad8..055869358e 100644 --- a/Microsoft.Azure.Cosmos/src/Query/v2Query/DocumentQueryExecutionContextBase.cs +++ b/Microsoft.Azure.Cosmos/src/Query/v2Query/DocumentQueryExecutionContextBase.cs @@ -159,6 +159,7 @@ public async Task GetPartitionedQueryExecutionInf bool isContinuationExpected, bool allowNonValueAggregateQuery, bool hasLogicalPartitionKey, + bool allowDCount, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -166,12 +167,13 @@ public async Task GetPartitionedQueryExecutionInf QueryPartitionProvider queryPartitionProvider = await this.Client.GetQueryPartitionProviderAsync(); TryCatch tryGetPartitionedQueryExecutionInfo = queryPartitionProvider.TryGetPartitionedQueryExecutionInfo( - this.QuerySpec, - partitionKeyDefinition, - requireFormattableOrderByQuery, - isContinuationExpected, - allowNonValueAggregateQuery, - hasLogicalPartitionKey); + querySpec: this.QuerySpec, + partitionKeyDefinition: partitionKeyDefinition, + requireFormattableOrderByQuery: requireFormattableOrderByQuery, + isContinuationExpected: isContinuationExpected, + allowNonValueAggregateQuery: allowNonValueAggregateQuery, + hasLogicalPartitionKey: hasLogicalPartitionKey, + allowDCount: allowDCount); if (!tryGetPartitionedQueryExecutionInfo.Succeeded) { throw new BadRequestException(tryGetPartitionedQueryExecutionInfo.Exception); diff --git a/Microsoft.Azure.Cosmos/src/Query/v2Query/DocumentQueryExecutionContextFactory.cs b/Microsoft.Azure.Cosmos/src/Query/v2Query/DocumentQueryExecutionContextFactory.cs index c7e507acfa..3501470f83 100644 --- a/Microsoft.Azure.Cosmos/src/Query/v2Query/DocumentQueryExecutionContextFactory.cs +++ b/Microsoft.Azure.Cosmos/src/Query/v2Query/DocumentQueryExecutionContextFactory.cs @@ -103,6 +103,7 @@ public static async Task CreateDocumentQueryExec isContinuationExpected: isContinuationExpected, allowNonValueAggregateQuery: true, hasLogicalPartitionKey: feedOptions.PartitionKey != null, + allowDCount: true, cancellationToken: token); if (DocumentQueryExecutionContextFactory.ShouldCreateSpecializedDocumentQueryExecutionContext( @@ -195,7 +196,8 @@ private static bool ShouldCreateSpecializedDocumentQueryExecutionContext( partitionedQueryExecutionInfo, isContinuationExpected) || DocumentQueryExecutionContextFactory.IsDistinctQuery(partitionedQueryExecutionInfo) || - DocumentQueryExecutionContextFactory.IsGroupByQuery(partitionedQueryExecutionInfo); + DocumentQueryExecutionContextFactory.IsGroupByQuery(partitionedQueryExecutionInfo) || + DocumentQueryExecutionContextFactory.IsDCountQuery(partitionedQueryExecutionInfo); } private static bool IsCrossPartitionQuery( @@ -247,6 +249,11 @@ private static bool IsGroupByQuery(PartitionedQueryExecutionInfo partitionedQuer return partitionedQueryExecutionInfo.QueryInfo.HasGroupBy; } + private static bool IsDCountQuery(PartitionedQueryExecutionInfo partitionedQueryExecutionInfo) + { + return partitionedQueryExecutionInfo.QueryInfo.HasDCount; + } + private static bool TryGetEpkProperty( FeedOptions feedOptions, out string effectivePartitionKeyString) diff --git a/Microsoft.Azure.Cosmos/src/Query/v3Query/CosmosQueryClientCore.cs b/Microsoft.Azure.Cosmos/src/Query/v3Query/CosmosQueryClientCore.cs index a6b3e329e9..151fd90783 100644 --- a/Microsoft.Azure.Cosmos/src/Query/v3Query/CosmosQueryClientCore.cs +++ b/Microsoft.Azure.Cosmos/src/Query/v3Query/CosmosQueryClientCore.cs @@ -84,15 +84,17 @@ public override async Task> TryGetPartit bool isContinuationExpected, bool allowNonValueAggregateQuery, bool hasLogicalPartitionKey, + bool allowDCount, CancellationToken cancellationToken) { return (await this.documentClient.QueryPartitionProvider).TryGetPartitionedQueryExecutionInfo( - sqlQuerySpec, - partitionKeyDefinition, - requireFormattableOrderByQuery, - isContinuationExpected, - allowNonValueAggregateQuery, - hasLogicalPartitionKey); + querySpec: sqlQuerySpec, + partitionKeyDefinition: partitionKeyDefinition, + requireFormattableOrderByQuery: requireFormattableOrderByQuery, + isContinuationExpected: isContinuationExpected, + allowNonValueAggregateQuery: allowNonValueAggregateQuery, + hasLogicalPartitionKey: hasLogicalPartitionKey, + allowDCount: allowDCount); } public override async Task> ExecuteItemQueryAsync( diff --git a/Microsoft.Azure.Cosmos/src/Routing/PartitionRoutingHelper.cs b/Microsoft.Azure.Cosmos/src/Routing/PartitionRoutingHelper.cs index 68fd3656e2..c645d4cc55 100644 --- a/Microsoft.Azure.Cosmos/src/Routing/PartitionRoutingHelper.cs +++ b/Microsoft.Azure.Cosmos/src/Routing/PartitionRoutingHelper.cs @@ -31,6 +31,7 @@ public static IReadOnlyList> GetProvidedPartitionKeyRanges( bool parallelizeCrossPartitionQuery, bool isContinuationExpected, bool hasLogicalPartitionKey, + bool allowDCount, PartitionKeyDefinition partitionKeyDefinition, QueryPartitionProvider queryPartitionProvider, string clientApiVersion, @@ -57,7 +58,8 @@ public static IReadOnlyList> GetProvidedPartitionKeyRanges( requireFormattableOrderByQuery: VersionUtility.IsLaterThan(clientApiVersion, HttpConstants.VersionDates.v2016_11_14), isContinuationExpected: isContinuationExpected, allowNonValueAggregateQuery: false, - hasLogicalPartitionKey: hasLogicalPartitionKey); + hasLogicalPartitionKey: hasLogicalPartitionKey, + allowDCount: allowDCount); if (!tryGetPartitionQueryExecutionInfo.Succeeded) { throw new BadRequestException(tryGetPartitionQueryExecutionInfo.Exception); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Query/DistinctQueryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Query/DistinctQueryTests.cs index 5345b2adc3..f67fc52a2a 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Query/DistinctQueryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Query/DistinctQueryTests.cs @@ -19,56 +19,56 @@ async Task ImplementationAsync(Container container, IReadOnlyList #region Queries // To verify distint queries you can run it once without the distinct clause and run it through a hash set // then compare to the query with the distinct clause. - List queries = new List() + List<(string, bool)> queries = new List<(string, bool)>() { // basic distinct queries - "SELECT {0} VALUE null", + ("SELECT {0} VALUE null", true), // number value distinct queries - "SELECT {0} VALUE c.income from c", + ("SELECT {0} VALUE c.income from c", true), // string value distinct queries - "SELECT {0} VALUE c.name from c", + ("SELECT {0} VALUE c.name from c", true), // array value distinct queries - "SELECT {0} VALUE c.children from c", + ("SELECT {0} VALUE c.children from c", true), // object value distinct queries - "SELECT {0} VALUE c.pet from c", + ("SELECT {0} VALUE c.pet from c", true), // scalar expressions distinct query - "SELECT {0} VALUE c.age % 2 FROM c", + ("SELECT {0} VALUE c.age % 2 FROM c", true), // distinct queries with order by - "SELECT {0} VALUE c.age FROM c ORDER BY c.age", + ("SELECT {0} VALUE c.age FROM c ORDER BY c.age", false), // distinct queries with top and no matching order by - "SELECT {0} TOP 2147483647 VALUE c.age FROM c", + ("SELECT {0} TOP 2147483647 VALUE c.age FROM c", false), // distinct queries with top and matching order by - "SELECT {0} TOP 2147483647 VALUE c.age FROM c ORDER BY c.age", + ("SELECT {0} TOP 2147483647 VALUE c.age FROM c ORDER BY c.age", false), // distinct queries with aggregates - "SELECT {0} VALUE MAX(c.age) FROM c", + ("SELECT {0} VALUE MAX(c.age) FROM c", false), // distinct queries with joins - "SELECT {0} VALUE c.age FROM p JOIN c IN p.children", + ("SELECT {0} VALUE c.age FROM p JOIN c IN p.children", true), // distinct queries in subqueries - "SELECT {0} r.age, s FROM r JOIN (SELECT DISTINCT VALUE c FROM (SELECT 1 a) c) s WHERE r.age > 25", + ("SELECT {0} r.age, s FROM r JOIN (SELECT DISTINCT VALUE c FROM (SELECT 1 a) c) s WHERE r.age > 25", false), // distinct queries in scalar subqeries - "SELECT {0} p.name, (SELECT DISTINCT VALUE p.age) AS Age FROM p", + ("SELECT {0} p.name, (SELECT DISTINCT VALUE p.age) AS Age FROM p", true), // select * - "SELECT {0} * FROM c", + ("SELECT {0} * FROM c", true) }; #endregion #region ExecuteNextAsync API // run the query with distinct and without + MockDistinctMap // Should receive same results // PageSize = 1 guarantees that the backend will return some duplicates. - foreach (string query in queries) + foreach ((string query, bool allowDCount) in queries) { string queryWithoutDistinct = string.Format(query, ""); @@ -109,7 +109,7 @@ async Task ImplementationAsync(Container container, IReadOnlyList documentsFromWithDistinct.AddRange(cosmosQueryResponse); } - Assert.AreEqual(documentsFromWithDistinct.Count, documentsFromWithoutDistinct.Count()); + Assert.AreEqual(documentsFromWithDistinct.Count, documentsFromWithoutDistinct.Count); for (int i = 0; i < documentsFromWithDistinct.Count; i++) { CosmosElement documentFromWithDistinct = documentsFromWithDistinct.ElementAt(i); @@ -119,6 +119,26 @@ async Task ImplementationAsync(Container container, IReadOnlyList actual: documentFromWithDistinct, message: $"{documentFromWithDistinct} did not match {documentFromWithoutDistinct} at index {i} for {queryWithDistinct}, with page size: {pageSize} on a container"); } + + if (allowDCount) + { + string queryWithDCount = $"SELECT VALUE COUNT(1) FROM({queryWithDistinct})"; + + List documentsWithDCount = new List(); + FeedIterator documentQueryWithDCount = container.GetItemQueryIterator( + queryWithDCount, + requestOptions: requestOptions); + + while (documentQueryWithDCount.HasMoreResults) + { + FeedResponse cosmosQueryResponse = await documentQueryWithDCount.ReadNextAsync(); + documentsWithDCount.AddRange(cosmosQueryResponse); + } + + Assert.AreEqual(1, documentsWithDCount.Count); + long dcount = Number64.ToLong((documentsWithDCount.First() as CosmosNumber).Value); + Assert.AreEqual(documentsFromWithoutDistinct.Count, dcount); + } } } #endregion @@ -186,15 +206,15 @@ async Task ImplemenationAsync(Container container, IReadOnlyList d { // Run the ordered distinct query through the continuation api, should result in the same set // since the previous hash is passed in the continuation token. - foreach (string query in new string[] + foreach ((string query, bool allowDCount) in new (string, bool)[] { - "SELECT {0} VALUE c.age FROM c ORDER BY c.age", - "SELECT {0} VALUE c.name FROM c ORDER BY c.name", - "SELECT {0} VALUE c.name from c", - "SELECT {0} VALUE c.age from c", - "SELECT {0} VALUE c.mixedTypeField from c", - "SELECT {0} TOP 2147483647 VALUE c.city from c", - "SELECT {0} VALUE c.age from c ORDER BY c.name", + ("SELECT {0} VALUE c.age FROM c ORDER BY c.age", false), + ("SELECT {0} VALUE c.name FROM c ORDER BY c.name", false), + ("SELECT {0} VALUE c.name from c", true), + ("SELECT {0} VALUE c.age from c", true), + ("SELECT {0} VALUE c.mixedTypeField from c", true), + ("SELECT {0} TOP 2147483647 VALUE c.city from c", false), + ("SELECT {0} VALUE c.age from c ORDER BY c.name", false) }) { string queryWithoutDistinct = string.Format(query, ""); @@ -229,6 +249,24 @@ async Task ImplemenationAsync(Container container, IReadOnlyList d expected: CosmosArray.Create(documentsFromWithDistinct), actual: CosmosArray.Create(documentsFromWithoutDistinct), message: $"Documents didn't match for {queryWithDistinct} on a Partitioned container"); + + if (allowDCount) + { + string queryWithDCount = $"SELECT VALUE COUNT(1) FROM({queryWithDistinct})"; + List documentsWithDCount = await QueryTestsBase.RunQueryCombinationsAsync( + container, + queryWithDCount, + new QueryRequestOptions() + { + MaxConcurrency = 10, + MaxItemCount = pageSize + }, + QueryDrainingMode.HoldState | QueryDrainingMode.CosmosElementContinuationToken); + + Assert.AreEqual(1, documentsWithDCount.Count); + long dcount = Number64.ToLong((documentsWithDCount.First() as CosmosNumber).Value); + Assert.AreEqual(documentsFromWithoutDistinct.Count, dcount); + } } } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Query/ParsingBenchmark.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Query/ParsingBenchmark.cs index 3116ac4e0f..cc24ddc86e 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Query/ParsingBenchmark.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Query/ParsingBenchmark.cs @@ -123,7 +123,8 @@ private static void ParseUsingNativeParser(SqlQuerySpec sqlQuerySpec) requireFormattableOrderByQuery: true, isContinuationExpected: false, allowNonValueAggregateQuery: true, - hasLogicalPartitionKey: false); + hasLogicalPartitionKey: false, + allowDCount: true); tryGetQueryPlan.ThrowIfFailed(); } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/FullPipelineTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/FullPipelineTests.cs index e46344df8d..78fc239f2f 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/FullPipelineTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Pipeline/FullPipelineTests.cs @@ -370,6 +370,7 @@ private static QueryInfo GetQueryPlan(string query) requireFormattableOrderByQuery: true, isContinuationExpected: false, allowNonValueAggregateQuery: true, + allowDCount: true, hasLogicalPartitionKey: false); info.ThrowIfFailed(); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/QueryPlanBaselineTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/QueryPlanBaselineTests.cs index 3304fbcd63..abfbd9cedc 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/QueryPlanBaselineTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/QueryPlanBaselineTests.cs @@ -1348,7 +1348,8 @@ public override QueryPlanBaselineTestOutput ExecuteTest(QueryPlanBaselineTestInp requireFormattableOrderByQuery: true, isContinuationExpected: false, allowNonValueAggregateQuery: true, - hasLogicalPartitionKey: false); + hasLogicalPartitionKey: false, + allowDCount: true); if (info.Failed) { diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Tracing/TraceWriterBaselineTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Tracing/TraceWriterBaselineTests.cs index c2a5f0285d..4990e27acf 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Tracing/TraceWriterBaselineTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Tracing/TraceWriterBaselineTests.cs @@ -692,7 +692,8 @@ private static QueryInfo GetQueryPlan(string query) requireFormattableOrderByQuery: true, isContinuationExpected: false, allowNonValueAggregateQuery: true, - hasLogicalPartitionKey: false); + hasLogicalPartitionKey: false, + allowDCount: true); info.ThrowIfFailed(); return info.Result.QueryInfo; From a9a7100c8d00b6025a8af939949b9618a2effaf4 Mon Sep 17 00:00:00 2001 From: Santosh Kulkarni <66682828+kr-santosh@users.noreply.github.com> Date: Wed, 24 Mar 2021 00:34:57 +0530 Subject: [PATCH 06/19] Client Encryption : Adds support to expose Type in EncryptionKeyWrapMetadata constructor. (#2283) * Exposes Type in EncryptionKeyWrapMetadata. * Update ContainerSettingsTests.cs * Update EncryptionKeyWrapMetadata.cs * Removed algorithm from metadata * Removed private set. * Update DotNetPreviewSDKAPI.json * Make Type Public. Revert public set. * Updated Comment description Co-authored-by: j82w --- .../EncryptionKeyWrapMetadata.cs | 31 ++++++++----------- .../Settings/ClientEncryptionPolicy.cs | 5 +-- .../CosmosDatabaseTests.cs | 13 ++++---- .../Fluent/ContainerSettingsTests.cs | 2 +- .../Contracts/DotNetPreviewSDKAPI.json | 18 +++++++++-- 5 files changed, 40 insertions(+), 29 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Resource/ClientEncryptionKey/EncryptionKeyWrapMetadata.cs b/Microsoft.Azure.Cosmos/src/Resource/ClientEncryptionKey/EncryptionKeyWrapMetadata.cs index 85ab7ffe93..e30babd71d 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/ClientEncryptionKey/EncryptionKeyWrapMetadata.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/ClientEncryptionKey/EncryptionKeyWrapMetadata.cs @@ -25,12 +25,15 @@ private EncryptionKeyWrapMetadata() /// /// Creates a new instance of key wrap metadata. - /// + /// + /// ProviderName of KeyStoreProvider. /// Name of the metadata. /// Value of the metadata. - public EncryptionKeyWrapMetadata(string name, string value) - : this(type: "custom", name: name, value: value) + public EncryptionKeyWrapMetadata(string type, string name, string value) { + this.Type = type ?? throw new ArgumentNullException(nameof(type)); + this.Name = name ?? throw new ArgumentNullException(nameof(name)); + this.Value = value ?? throw new ArgumentNullException(nameof(value)); } /// @@ -38,23 +41,17 @@ public EncryptionKeyWrapMetadata(string name, string value) /// /// Existing instance from which to initialize. public EncryptionKeyWrapMetadata(EncryptionKeyWrapMetadata source) - : this(source?.Type, source?.Name, source?.Value, source?.Algorithm) + : this(source?.Type, source?.Name, source?.Value) { } - internal EncryptionKeyWrapMetadata(string type, string name, string value, string algorithm = null) - { - this.Type = type ?? throw new ArgumentNullException(nameof(type)); - this.Name = name ?? throw new ArgumentNullException(nameof(name)); - this.Value = value ?? throw new ArgumentNullException(nameof(value)); - this.Algorithm = algorithm; - } - + /// + /// Serialized form of metadata. + /// Note: This value is saved in the Cosmos DB service. + /// Implementors of derived implementations should ensure that this does not have (private) key material or credential information. + /// [JsonProperty(PropertyName = "type", NullValueHandling = NullValueHandling.Ignore)] - internal string Type { get; private set; } - - [JsonProperty(PropertyName = "algorithm", NullValueHandling = NullValueHandling.Ignore)] - internal string Algorithm { get; private set; } + public string Type { get; private set; } /// /// Serialized form of metadata. @@ -84,7 +81,6 @@ public override int GetHashCode() { int hashCode = 1265339359; hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(this.Type); - hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(this.Algorithm); hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(this.Name); hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(this.Value); return hashCode; @@ -101,7 +97,6 @@ public bool Equals(EncryptionKeyWrapMetadata other) { return other != null && this.Type == other.Type && - this.Algorithm == other.Algorithm && this.Name == other.Name && this.Value == other.Value; } diff --git a/Microsoft.Azure.Cosmos/src/Resource/Settings/ClientEncryptionPolicy.cs b/Microsoft.Azure.Cosmos/src/Resource/Settings/ClientEncryptionPolicy.cs index 388ccb5372..4708acc410 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Settings/ClientEncryptionPolicy.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Settings/ClientEncryptionPolicy.cs @@ -86,9 +86,10 @@ private void ValidateClientEncryptionIncludedPath(ClientEncryptionIncludedPath c } if (!string.Equals(clientEncryptionIncludedPath.EncryptionType, "Deterministic") && - !string.Equals(clientEncryptionIncludedPath.EncryptionType, "Randomized")) + !string.Equals(clientEncryptionIncludedPath.EncryptionType, "Randomized") && + !string.Equals(clientEncryptionIncludedPath.EncryptionType, "Plaintext")) { - throw new ArgumentException("EncryptionType should be either 'Deterministic' or 'Randomized'.", nameof(clientEncryptionIncludedPath)); + throw new ArgumentException("EncryptionType should be either 'Deterministic' or 'Randomized' or 'Plaintext'.", nameof(clientEncryptionIncludedPath)); } if (string.IsNullOrWhiteSpace(clientEncryptionIncludedPath.EncryptionAlgorithm)) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosDatabaseTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosDatabaseTests.cs index ca73645a5b..a769de0d83 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosDatabaseTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosDatabaseTests.cs @@ -416,7 +416,7 @@ public async Task EncryptionCreateReplaceCek() Assert.IsNotNull(cekProperties.ResourceId); Assert.AreEqual( - new EncryptionKeyWrapMetadata("metadataName", "metadataValue"), + new EncryptionKeyWrapMetadata("custom", "metadataName", "metadataValue"), cekProperties.EncryptionKeyWrapMetadata); // Use a different client instance to avoid (unintentional) cache impact @@ -433,7 +433,7 @@ public async Task EncryptionCreateReplaceCek() Assert.IsNotNull(cekProperties.ResourceId); Assert.AreEqual( - new EncryptionKeyWrapMetadata("metadataName", "updatedMetadataValue"), + new EncryptionKeyWrapMetadata("custom", "metadataName", "updatedMetadataValue"), cekProperties.EncryptionKeyWrapMetadata); // Use a different client instance to avoid (unintentional) cache impact @@ -454,7 +454,7 @@ private static async Task CreateCekAsync(Database rngCsp.GetBytes(rawCek); } - ClientEncryptionKeyProperties cekProperties = new ClientEncryptionKeyProperties(cekId, "AEAD_AES_256_CBC_HMAC_SHA256", rawCek, new EncryptionKeyWrapMetadata("metadataName", "metadataValue")); + ClientEncryptionKeyProperties cekProperties = new ClientEncryptionKeyProperties(cekId, "AEAD_AES_256_CBC_HMAC_SHA256", rawCek, new EncryptionKeyWrapMetadata("custom", "metadataName", "metadataValue")); ClientEncryptionKeyResponse cekResponse = await databaseCore.CreateClientEncryptionKeyAsync(cekProperties); @@ -482,7 +482,7 @@ private static async Task ReplaceCekAsync(Databas rngCsp.GetBytes(rawCek); } - ClientEncryptionKeyProperties cekProperties = new ClientEncryptionKeyProperties(cekId, "AEAD_AES_256_CBC_HMAC_SHA256", rawCek, new EncryptionKeyWrapMetadata("metadataName", "updatedMetadataValue")); + ClientEncryptionKeyProperties cekProperties = new ClientEncryptionKeyProperties(cekId, "AEAD_AES_256_CBC_HMAC_SHA256", rawCek, new EncryptionKeyWrapMetadata("custom", "metadataName", "updatedMetadataValue")); ClientEncryptionKeyResponse cekResponse = await cek.ReplaceAsync(cekProperties); Assert.AreEqual(HttpStatusCode.OK, cekResponse.StatusCode); @@ -513,7 +513,7 @@ public async Task VerifyCekFeedIterator() rngCsp.GetBytes(rawCek1); } - ClientEncryptionKeyProperties cekProperties = new ClientEncryptionKeyProperties(cekId, "AEAD_AES_256_CBC_HMAC_SHA256", rawCek1, new EncryptionKeyWrapMetadata("metadataName", "metadataValue")); + ClientEncryptionKeyProperties cekProperties = new ClientEncryptionKeyProperties(cekId, "AEAD_AES_256_CBC_HMAC_SHA256", rawCek1, new EncryptionKeyWrapMetadata("custom", "metadataName", "metadataValue")); ClientEncryptionKeyResponse cekResponse = await databaseCore.CreateClientEncryptionKeyAsync(cekProperties); @@ -528,7 +528,7 @@ public async Task VerifyCekFeedIterator() rngCsp.GetBytes(rawCek2); } - cekProperties = new ClientEncryptionKeyProperties(cekId, "AEAD_AES_256_CBC_HMAC_SHA256", rawCek2, new EncryptionKeyWrapMetadata("metadataName", "metadataValue")); + cekProperties = new ClientEncryptionKeyProperties(cekId, "AEAD_AES_256_CBC_HMAC_SHA256", rawCek2, new EncryptionKeyWrapMetadata("custom", "metadataName", "metadataValue")); cekResponse = await databaseCore.CreateClientEncryptionKeyAsync(cekProperties); @@ -552,6 +552,7 @@ public async Task VerifyCekFeedIterator() { readDekIds.Add(clientEncryptionKeyProperties.Id); Assert.AreEqual("AEAD_AES_256_CBC_HMAC_SHA256", clientEncryptionKeyProperties.EncryptionAlgorithm); + Assert.AreEqual(cekProperties.EncryptionKeyWrapMetadata.Type, clientEncryptionKeyProperties.EncryptionKeyWrapMetadata.Type); Assert.AreEqual(cekProperties.EncryptionKeyWrapMetadata.Name, clientEncryptionKeyProperties.EncryptionKeyWrapMetadata.Name); Assert.AreEqual(cekProperties.EncryptionKeyWrapMetadata.Value, clientEncryptionKeyProperties.EncryptionKeyWrapMetadata.Value); } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Fluent/ContainerSettingsTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Fluent/ContainerSettingsTests.cs index bfb95b1de7..7a6cdee948 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Fluent/ContainerSettingsTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Fluent/ContainerSettingsTests.cs @@ -677,7 +677,7 @@ public async Task WithClientEncryptionPolicyFailureTest() } catch (ArgumentException ex) { - Assert.IsTrue(ex.Message.Contains("EncryptionType should be either 'Deterministic' or 'Randomized'.")); + Assert.IsTrue(ex.Message.Contains("EncryptionType should be either 'Deterministic' or 'Randomized' or 'Plaintext'.")); } path1.EncryptionType = "Deterministic"; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetPreviewSDKAPI.json b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetPreviewSDKAPI.json index ee98d70409..ea690552dc 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetPreviewSDKAPI.json +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetPreviewSDKAPI.json @@ -801,6 +801,13 @@ ], "MethodInfo": "System.String get_Name();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" }, + "System.String get_Type()[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": { + "Type": "Method", + "Attributes": [ + "CompilerGeneratedAttribute" + ], + "MethodInfo": "System.String get_Type();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, "System.String get_Value()[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": { "Type": "Method", "Attributes": [ @@ -815,6 +822,13 @@ ], "MethodInfo": "System.String Name;CanRead:True;CanWrite:True;System.String get_Name();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" }, + "System.String Type[Newtonsoft.Json.JsonPropertyAttribute(NullValueHandling = 1, PropertyName = \"type\")]": { + "Type": "Property", + "Attributes": [ + "JsonPropertyAttribute" + ], + "MethodInfo": "System.String Type;CanRead:True;CanWrite:True;System.String get_Type();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, "System.String Value[Newtonsoft.Json.JsonPropertyAttribute(NullValueHandling = 1, PropertyName = \"value\")]": { "Type": "Property", "Attributes": [ @@ -827,10 +841,10 @@ "Attributes": [], "MethodInfo": "[Void .ctor(Microsoft.Azure.Cosmos.EncryptionKeyWrapMetadata), Void .ctor(Microsoft.Azure.Cosmos.EncryptionKeyWrapMetadata)]" }, - "Void .ctor(System.String, System.String)": { + "Void .ctor(System.String, System.String, System.String)": { "Type": "Constructor", "Attributes": [], - "MethodInfo": "[Void .ctor(System.String, System.String), Void .ctor(System.String, System.String)]" + "MethodInfo": "[Void .ctor(System.String, System.String, System.String), Void .ctor(System.String, System.String, System.String)]" } }, "NestedTypes": {} From e8812c69b8d2dbf070901f0bb53a05e3cbae3df1 Mon Sep 17 00:00:00 2001 From: Asket Agarwal Date: Wed, 24 Mar 2021 22:55:03 +0530 Subject: [PATCH 07/19] Benchmark Tool: Adds a benchmark for Diagnostics.ToString() (#2332) * Adding Benchmark for diagnostics * Making change to readme * renaming benchmark * disposing response message Co-authored-by: j82w --- .../Tools/Benchmark/CosmosBenchmark.csproj | 2 +- .../Tools/Benchmark/README.md | 2 +- ...istsWithDiagnosticsV3BenchmarkOperation.cs | 99 +++++++++++++++++++ 3 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/v3/ReadStreamExistsWithDiagnosticsV3BenchmarkOperation.cs diff --git a/Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/CosmosBenchmark.csproj b/Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/CosmosBenchmark.csproj index 762bdf5b36..f2ea3f8f1a 100644 --- a/Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/CosmosBenchmark.csproj +++ b/Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/CosmosBenchmark.csproj @@ -33,6 +33,6 @@ - + diff --git a/Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/README.md b/Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/README.md index bb70dead4f..43cf2ef8c0 100644 --- a/Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/README.md +++ b/Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/README.md @@ -36,7 +36,7 @@ export ACCOUNT_KEY= export RESULTS_PK="runs-summary" #For test runs use different one export PL=18 -dotnet run -c Release -- -e $ACCOUNT_ENDPOINT -k $ACCOUNT_KEY --publishresults --resultspartitionkeyvalue $RESULTS_PK -commitid $(git log -1 | head -n 1 | cut -d ' ' -f 2) --commitdate $(git log -1 --date=format:'%Y-%m-%d %H:%M:%S' | grep Date | cut -f 2- -d ':' | sed 's/^[ \t]*//;s/[ \t]*$//' | cut -f 1 -d ' ') --committime $(git log -1 --date=format:'%Y-%m-%d %H:%M:%S' | grep Date | cut -f 2- -d ':' | sed 's/^[ \t]*//;s/[ \t]*$//' | cut -f 2 -d ' ') --branchname $(git rev-parse --abbrev-ref HEAD) --database testdb --container testcol --partitionkeypath /pk -n 500000 -w ReadStreamExistsV3 --pl $PL +dotnet run -c Release -- -e $ACCOUNT_ENDPOINT -k $ACCOUNT_KEY --tcp 10 --enablelatencypercentiles --disablecoresdklogging --publishresults --resultspartitionkeyvalue $RESULTS_PK --commitid $(git log -1 | head -n 1 | cut -d ' ' -f 2) --commitdate $(git log -1 --date=format:'%Y-%m-%d %H:%M:%S' | grep Date | cut -f 2- -d ':' | sed 's/^[ \t]*//;s/[ \t]*$//' | cut -f 1 -d ' ') --committime $(git log -1 --date=format:'%Y-%m-%d %H:%M:%S' | grep Date | cut -f 2- -d ':' | sed 's/^[ \t]*//;s/[ \t]*$//' | cut -f 2 -d ' ') --branchname $(git rev-parse --abbrev-ref HEAD) --database testdb --container testcol --partitionkeypath /pk -n 2000000 -w ReadStreamExistsV3 --pl $PL ``` ![image](https://user-images.githubusercontent.com/6880899/61565403-8e41bd00-aa96-11e9-9996-b7fc77c3aed3.png) diff --git a/Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/v3/ReadStreamExistsWithDiagnosticsV3BenchmarkOperation.cs b/Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/v3/ReadStreamExistsWithDiagnosticsV3BenchmarkOperation.cs new file mode 100644 index 0000000000..ebdc14924b --- /dev/null +++ b/Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/v3/ReadStreamExistsWithDiagnosticsV3BenchmarkOperation.cs @@ -0,0 +1,99 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace CosmosBenchmark +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Threading.Tasks; + using Microsoft.Azure.Cosmos; + + internal class ReadStreamExistsWithDiagnosticsV3BenchmarkOperation : IBenchmarkOperation + { + private readonly Container container; + private readonly string partitionKeyPath; + private readonly Dictionary sampleJObject; + + private readonly string databsaeName; + private readonly string containerName; + + private string nextExecutionItemPartitionKey; + private string nextExecutionItemId; + + public ReadStreamExistsWithDiagnosticsV3BenchmarkOperation( + CosmosClient cosmosClient, + string dbName, + string containerName, + string partitionKeyPath, + string sampleJson) + { + this.databsaeName = dbName; + this.containerName = containerName; + + this.container = cosmosClient.GetContainer(this.databsaeName, this.containerName); + this.partitionKeyPath = partitionKeyPath.Replace("/", ""); + + this.sampleJObject = JsonHelper.Deserialize>(sampleJson); + } + + public async Task ExecuteOnceAsync() + { + using (ResponseMessage itemResponse = await this.container.ReadItemStreamAsync( + this.nextExecutionItemId, + new PartitionKey(this.nextExecutionItemPartitionKey))) + { + if (itemResponse.StatusCode != HttpStatusCode.OK) + { + throw new Exception($"ReadItem failed wth {itemResponse.StatusCode}"); + } + + string diagnostics = itemResponse.Diagnostics.ToString(); + if (string.IsNullOrEmpty(diagnostics)) + { + throw new Exception(); + } + + return new OperationResult() + { + DatabseName = databsaeName, + ContainerName = containerName, + RuCharges = itemResponse.Headers.RequestCharge, + CosmosDiagnostics = itemResponse.Diagnostics, + LazyDiagnostics = () => itemResponse.Diagnostics.ToString(), + }; + } + } + + public async Task PrepareAsync() + { + if (string.IsNullOrEmpty(this.nextExecutionItemId) || + string.IsNullOrEmpty(this.nextExecutionItemPartitionKey)) + { + this.nextExecutionItemId = Guid.NewGuid().ToString(); + this.nextExecutionItemPartitionKey = Guid.NewGuid().ToString(); + + this.sampleJObject["id"] = this.nextExecutionItemId; + this.sampleJObject[this.partitionKeyPath] = this.nextExecutionItemPartitionKey; + + using (MemoryStream inputStream = JsonHelper.ToStream(this.sampleJObject)) + { + using (ResponseMessage itemResponse = await this.container.CreateItemStreamAsync( + inputStream, + new PartitionKey(this.nextExecutionItemPartitionKey))) + { + + System.Buffers.ArrayPool.Shared.Return(inputStream.GetBuffer()); + + if (itemResponse.StatusCode != HttpStatusCode.Created) + { + throw new Exception($"Create failed with statuscode: {itemResponse.StatusCode}"); + } + } + } + } + } + } +} From ec8bf9866e4fe1da8915960f812371c52e2ef7e1 Mon Sep 17 00:00:00 2001 From: Santosh Kulkarni <66682828+kr-santosh@users.noreply.github.com> Date: Thu, 25 Mar 2021 18:35:17 +0530 Subject: [PATCH 08/19] Query : Adds WithParameterStream to QueryDefinition to pass in serialized values (#2222) * Support Stream Value in SqlParameter and disable call to customer serializer. * Updated contracts. * Updated Contracts. * Fixes / Fixed Comment. * removed redundant logic. * Renamed method, updated summary. * Update DotNetSDKAPI.json * Update CosmosItemTests.cs * Fixes as per review comments. Updated tests. Co-authored-by: j82w --- .../src/CosmosSqlQuerySpecJsonConverter.cs | 25 ++- .../src/Query/v3Query/QueryDefinition.cs | 37 ++++ .../src/Serializer/CosmosSerializerCore.cs | 10 +- .../CosmosItemTests.cs | 187 ++++++++++++++++++ .../Contracts/DotNetSDKAPI.json | 5 + 5 files changed, 253 insertions(+), 11 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/CosmosSqlQuerySpecJsonConverter.cs b/Microsoft.Azure.Cosmos/src/CosmosSqlQuerySpecJsonConverter.cs index 7d747124cb..c782605dfa 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosSqlQuerySpecJsonConverter.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosSqlQuerySpecJsonConverter.cs @@ -41,15 +41,27 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s serializer.Serialize(writer, sqlParameter.Name); writer.WritePropertyName("value"); - // Use the user serializer for the parameter values so custom conversions are correctly handled - using (Stream str = this.UserSerializer.ToStream(sqlParameter.Value)) + // if the SqlParameter has stream value we dont pass it through the custom serializer. + if (sqlParameter.Value is SerializedParameterValue serializedEncryptedData) { - using (StreamReader streamReader = new StreamReader(str)) + using (StreamReader streamReader = new StreamReader(serializedEncryptedData.valueStream)) { string parameterValue = streamReader.ReadToEnd(); writer.WriteRawValue(parameterValue); } } + else + { + // Use the user serializer for the parameter values so custom conversions are correctly handled + using (Stream str = this.UserSerializer.ToStream(sqlParameter.Value)) + { + using (StreamReader streamReader = new StreamReader(str)) + { + string parameterValue = streamReader.ReadToEnd(); + writer.WriteRawValue(parameterValue); + } + } + } writer.WriteEndObject(); } @@ -62,15 +74,14 @@ internal static CosmosSerializer CreateSqlQuerySpecSerializer( CosmosSerializer cosmosSerializer, CosmosSerializer propertiesSerializer) { - // If both serializers are the same no need for the custom converter - if (object.ReferenceEquals(cosmosSerializer, propertiesSerializer)) + if (propertiesSerializer is CosmosJsonSerializerWrapper cosmosJsonSerializerWrapper) { - return propertiesSerializer; + propertiesSerializer = cosmosJsonSerializerWrapper.InternalJsonSerializer; } JsonSerializerSettings settings = new JsonSerializerSettings() { - Converters = new List() { new CosmosSqlQuerySpecJsonConverter(cosmosSerializer) } + Converters = new List() { new CosmosSqlQuerySpecJsonConverter(cosmosSerializer ?? propertiesSerializer) } }; return new CosmosJsonSerializerWrapper(new CosmosJsonDotNetSerializer(settings)); diff --git a/Microsoft.Azure.Cosmos/src/Query/v3Query/QueryDefinition.cs b/Microsoft.Azure.Cosmos/src/Query/v3Query/QueryDefinition.cs index 7dec87a20a..d68a4fcea5 100644 --- a/Microsoft.Azure.Cosmos/src/Query/v3Query/QueryDefinition.cs +++ b/Microsoft.Azure.Cosmos/src/Query/v3Query/QueryDefinition.cs @@ -7,6 +7,7 @@ namespace Microsoft.Azure.Cosmos using System; using System.Collections; using System.Collections.Generic; + using System.IO; using Microsoft.Azure.Cosmos.Query.Core; using Newtonsoft.Json; @@ -108,6 +109,37 @@ public QueryDefinition WithParameter(string name, object value) return this; } + /// + /// Add parameters with Stream Value to the SQL query. + /// + /// The name of the parameter. + /// The stream value for the parameter. + /// + /// UseCase : This is useful in cases like running a Query on Encrypted Values, where the value is generated post serialization and then encrypted + /// and we don't want to change the cipher value due to a call to serializer again. + /// If the same name is added again it will replace the original value. + /// + /// + /// + /// + /// + /// + /// An instance of . + public QueryDefinition WithParameterStream(string name, Stream valueStream) + { + // pack it into an internal type for identification. + SerializedParameterValue serializedParameterValue = new SerializedParameterValue + { + valueStream = valueStream + }; + + return this.WithParameter(name, serializedParameterValue); + } + /// /// Returns the names and values of parameters in this . /// @@ -164,4 +196,9 @@ IEnumerator IEnumerable.GetEnumerator() } } } + + internal struct SerializedParameterValue + { + internal Stream valueStream; + } } diff --git a/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializerCore.cs b/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializerCore.cs index ad88ea0422..317ff36526 100644 --- a/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializerCore.cs +++ b/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializerCore.cs @@ -28,7 +28,10 @@ internal CosmosSerializerCore( if (customSerializer == null) { this.customSerializer = null; - this.sqlQuerySpecSerializer = null; + // this would allow us to set the JsonConverter and inturn handle Serialized/Stream Query Parameter Value. + this.sqlQuerySpecSerializer = CosmosSqlQuerySpecJsonConverter.CreateSqlQuerySpecSerializer( + cosmosSerializer: null, + propertiesSerializer: CosmosSerializerCore.propertiesSerializer); this.patchOperationSerializer = null; } else @@ -84,8 +87,7 @@ internal Stream ToStreamSqlQuerySpec(SqlQuerySpec input, ResourceType resourceTy // All the public types that support query use the custom serializer // Internal types like offers will use the default serializer. - if (this.customSerializer != null && - (resourceType == ResourceType.Database || + if (resourceType == ResourceType.Database || resourceType == ResourceType.Collection || resourceType == ResourceType.Document || resourceType == ResourceType.Trigger || @@ -93,7 +95,7 @@ internal Stream ToStreamSqlQuerySpec(SqlQuerySpec input, ResourceType resourceTy resourceType == ResourceType.StoredProcedure || resourceType == ResourceType.Permission || resourceType == ResourceType.User || - resourceType == ResourceType.Conflict)) + resourceType == ResourceType.Conflict) { serializer = this.sqlQuerySpecSerializer; } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs index 02516b3231..2113a8207a 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs @@ -851,6 +851,193 @@ public async Task ItemCustomSerialzierTest() } } + [TestMethod] + public async Task QueryStreamValueTest() + { + DateTime createDateTime = DateTime.UtcNow; + + dynamic testItem1 = new + { + id = "testItem1", + cost = (double?)null, + totalCost = 98.2789, + pk = "MyCustomStatus", + taskNum = 4909, + createdDateTime = createDateTime, + statusCode = HttpStatusCode.Accepted, + itemIds = new int[] { 1, 5, 10 }, + itemcode = new byte?[5] { 0x16, (byte)'\0', 0x3, null, (byte)'}' }, + }; + + dynamic testItem2 = new + { + id = "testItem2", + cost = (double?)null, + totalCost = 98.2789, + pk = "MyCustomStatus", + taskNum = 4909, + createdDateTime = createDateTime, + statusCode = HttpStatusCode.Accepted, + itemIds = new int[] { 1, 5, 10 }, + itemcode = new byte?[5] { 0x16, (byte)'\0', 0x3, null, (byte)'}' }, + }; + + //with Custom Serializer. + JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings() + { + Converters = new List() { new CosmosSerializerHelper.FormatNumbersAsTextConverter() } + }; + + int toStreamCount = 0; + int fromStreamCount = 0; + CosmosSerializerHelper cosmosSerializerHelper = new CosmosSerializerHelper( + jsonSerializerSettings, + toStreamCallBack: (itemValue) => + { + Type itemType = itemValue?.GetType(); + if (itemValue == null + || itemType == typeof(int) + || itemType == typeof(double) + || itemType == typeof(string) + || itemType == typeof(DateTime) + || itemType == typeof(HttpStatusCode) + || itemType == typeof(int[]) + || itemType == typeof(byte)) + { + toStreamCount++; + } + }, + fromStreamCallback: (item) => fromStreamCount++); + + CosmosClientOptions options = new CosmosClientOptions() + { + Serializer = cosmosSerializerHelper + }; + + CosmosClient clientSerializer = TestCommon.CreateCosmosClient(options); + Container containerSerializer = clientSerializer.GetContainer(this.database.Id, this.Container.Id); + + List queryDefinitions = new List() + { + new QueryDefinition("select * from t where t.pk = @pk" ) + .WithParameterStream("@pk", cosmosSerializerHelper.ToStream(testItem1.pk)), + new QueryDefinition("select * from t where t.cost = @cost" ) + .WithParameterStream("@cost", cosmosSerializerHelper.ToStream(testItem1.cost)), + new QueryDefinition("select * from t where t.taskNum = @taskNum" ) + .WithParameterStream("@taskNum", cosmosSerializerHelper.ToStream(testItem1.taskNum)), + new QueryDefinition("select * from t where t.totalCost = @totalCost" ) + .WithParameterStream("@totalCost", cosmosSerializerHelper.ToStream(testItem1.totalCost)), + new QueryDefinition("select * from t where t.createdDateTime = @createdDateTime" ) + .WithParameterStream("@createdDateTime", cosmosSerializerHelper.ToStream(testItem1.createdDateTime)), + new QueryDefinition("select * from t where t.statusCode = @statusCode" ) + .WithParameterStream("@statusCode", cosmosSerializerHelper.ToStream(testItem1.statusCode)), + new QueryDefinition("select * from t where t.itemIds = @itemIds" ) + .WithParameterStream("@itemIds", cosmosSerializerHelper.ToStream(testItem1.itemIds)), + new QueryDefinition("select * from t where t.itemcode = @itemcode" ) + .WithParameterStream("@itemcode", cosmosSerializerHelper.ToStream(testItem1.itemcode)), + new QueryDefinition("select * from t where t.pk = @pk and t.cost = @cost" ) + .WithParameterStream("@pk", cosmosSerializerHelper.ToStream(testItem1.pk)) + .WithParameterStream("@cost", cosmosSerializerHelper.ToStream(testItem1.cost)), + }; + + try + { + await containerSerializer.CreateItemAsync(testItem1); + await containerSerializer.CreateItemAsync(testItem2); + } + catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.Conflict) + { + // Ignore conflicts since the object already exists + } + + foreach (QueryDefinition queryDefinition in queryDefinitions) + { + toStreamCount = 0; + fromStreamCount = 0; + + List allItems = new List(); + int pageCount = 0; + using (FeedIterator feedIterator = containerSerializer.GetItemQueryIterator( + queryDefinition: queryDefinition)) + { + while (feedIterator.HasMoreResults) + { + // Only need once to verify correct serialization of the query definition + FeedResponse response = await feedIterator.ReadNextAsync(this.cancellationToken); + Assert.AreEqual(response.Count, response.Count()); + allItems.AddRange(response); + pageCount++; + } + } + + Assert.AreEqual(2, allItems.Count, $"missing query results. Only found: {allItems.Count} items for query:{queryDefinition.ToSqlQuerySpec().QueryText}"); + + // There should be no call to custom serializer since the parameter values are already serialized. + Assert.AreEqual(0, toStreamCount, $"missing to stream call. Expected: 0 , Actual: {toStreamCount} for query:{queryDefinition.ToSqlQuerySpec().QueryText}"); + Assert.AreEqual(pageCount, fromStreamCount); + } + + // Standard Cosmos Serializer Used + + CosmosClient clientStandardSerializer = TestCommon.CreateCosmosClient(useCustomSeralizer:false); + Container containerStandardSerializer = clientStandardSerializer.GetContainer(this.database.Id, this.Container.Id); + + testItem1 = ToDoActivity.CreateRandomToDoActivity(); + testItem1.pk = "myPk"; + await containerStandardSerializer.CreateItemAsync(testItem1, new Cosmos.PartitionKey(testItem1.pk)); + + testItem2 = ToDoActivity.CreateRandomToDoActivity(); + testItem2.pk = "myPk"; + await containerStandardSerializer.CreateItemAsync(testItem2, new Cosmos.PartitionKey(testItem2.pk)); + CosmosSerializer cosmosSerializer = containerStandardSerializer.Database.Client.ClientOptions.Serializer; + + queryDefinitions = new List() + { + new QueryDefinition("select * from t where t.pk = @pk" ) + .WithParameterStream("@pk", cosmosSerializer.ToStream(testItem1.pk)), + new QueryDefinition("select * from t where t.cost = @cost" ) + .WithParameterStream("@cost", cosmosSerializer.ToStream(testItem1.cost)), + new QueryDefinition("select * from t where t.taskNum = @taskNum" ) + .WithParameterStream("@taskNum", cosmosSerializer.ToStream(testItem1.taskNum)), + new QueryDefinition("select * from t where t.CamelCase = @CamelCase" ) + .WithParameterStream("@CamelCase", cosmosSerializer.ToStream(testItem1.CamelCase)), + new QueryDefinition("select * from t where t.valid = @valid" ) + .WithParameterStream("@valid", cosmosSerializer.ToStream(testItem1.valid)), + new QueryDefinition("select * from t where t.description = @description" ) + .WithParameterStream("@description", cosmosSerializer.ToStream(testItem1.description)), + new QueryDefinition("select * from t where t.pk = @pk and t.cost = @cost" ) + .WithParameterStream("@pk", cosmosSerializer.ToStream(testItem1.pk)) + .WithParameterStream("@cost", cosmosSerializer.ToStream(testItem1.cost)), + }; + + foreach (QueryDefinition queryDefinition in queryDefinitions) + { + List allItems = new List(); + int pageCount = 0; + using (FeedIterator feedIterator = containerStandardSerializer.GetItemQueryIterator( + queryDefinition: queryDefinition)) + { + while (feedIterator.HasMoreResults) + { + // Only need once to verify correct serialization of the query definition + FeedResponse response = await feedIterator.ReadNextAsync(this.cancellationToken); + Assert.AreEqual(response.Count, response.Count()); + allItems.AddRange(response); + pageCount++; + } + } + + Assert.AreEqual(2, allItems.Count, $"missing query results. Only found: {allItems.Count} items for query:{queryDefinition.ToSqlQuerySpec().QueryText}"); + Assert.AreEqual(pageCount, 1); + + + IReadOnlyList<(string Name, object Value)> parameters1 = queryDefinition.GetQueryParameters(); + IReadOnlyList<(string Name, object Value)> parameters2 = queryDefinition.GetQueryParameters(); + + Assert.AreSame(parameters1, parameters2); + } + } + [TestMethod] public async Task ItemIterator() { diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json index edf73ebdfd..086e541e87 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json @@ -4472,6 +4472,11 @@ "Attributes": [], "MethodInfo": "Microsoft.Azure.Cosmos.QueryDefinition WithParameter(System.String, System.Object);IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" }, + "Microsoft.Azure.Cosmos.QueryDefinition WithParameterStream(System.String, System.IO.Stream)": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "Microsoft.Azure.Cosmos.QueryDefinition WithParameterStream(System.String, System.IO.Stream);IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, "System.Collections.Generic.IReadOnlyList`1[System.ValueTuple`2[System.String,System.Object]] GetQueryParameters()": { "Type": "Method", "Attributes": [], From 69f820ed1b42d527ee02b14a63419fbe3b49ddf8 Mon Sep 17 00:00:00 2001 From: abhijitpai Date: Thu, 25 Mar 2021 22:58:10 +0530 Subject: [PATCH 09/19] Samples: Fixes exception logging in samples (#2329) Co-authored-by: j82w --- .../Usage/AzureFunctions/AzureFunctionsCosmosClient.cs | 1 + .../Usage/IndexManagement/Program.cs | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Microsoft.Azure.Cosmos.Samples/Usage/AzureFunctions/AzureFunctionsCosmosClient.cs b/Microsoft.Azure.Cosmos.Samples/Usage/AzureFunctions/AzureFunctionsCosmosClient.cs index 1f3688c440..c1ce809fff 100644 --- a/Microsoft.Azure.Cosmos.Samples/Usage/AzureFunctions/AzureFunctionsCosmosClient.cs +++ b/Microsoft.Azure.Cosmos.Samples/Usage/AzureFunctions/AzureFunctionsCosmosClient.cs @@ -61,6 +61,7 @@ public async Task Run( } catch (CosmosException cosmosException) { + log.LogError("Creating item failed with error {0}", cosmosException.ToString()); return new BadRequestObjectResult($"Failed to create item. Cosmos Status Code {cosmosException.StatusCode}, Sub Status Code {cosmosException.SubStatusCode}: {cosmosException.Message}."); } } diff --git a/Microsoft.Azure.Cosmos.Samples/Usage/IndexManagement/Program.cs b/Microsoft.Azure.Cosmos.Samples/Usage/IndexManagement/Program.cs index a2f7cbbe6c..c2a8e08014 100644 --- a/Microsoft.Azure.Cosmos.Samples/Usage/IndexManagement/Program.cs +++ b/Microsoft.Azure.Cosmos.Samples/Usage/IndexManagement/Program.cs @@ -94,7 +94,7 @@ public static async Task Main(string[] args) catch (Exception e) { Exception baseException = e.GetBaseException(); - Console.WriteLine("Error: {0}, Message: {1}", e.Message, baseException.Message); + Console.WriteLine("Error: {0}, Message: {1}", e.ToString(), baseException.Message); } finally { @@ -344,14 +344,14 @@ private static void LogException(Exception e) ConsoleColor color = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Red; - Exception baseException = e.GetBaseException(); if (e is CosmosException cosmosException) { - Console.WriteLine("{0} error occurred: {1}, Message: {2}", cosmosException.StatusCode, cosmosException.Message, baseException.Message); + Console.WriteLine("{0} error occurred: {1}", cosmosException.StatusCode, cosmosException.ToString()); } else { - Console.WriteLine("Error: {0}, Message: {1}", e.Message, baseException.Message); + Exception baseException = e.GetBaseException(); + Console.WriteLine("Error: {0}, Message: {1}", e.ToString(), baseException.Message); } Console.ForegroundColor = color; From 3b04f6e425dfcc1f105cf4a977b06ef67b37667d Mon Sep 17 00:00:00 2001 From: Matias Quaranta Date: Thu, 25 Mar 2021 12:47:34 -0700 Subject: [PATCH 10/19] [Internal] CTL: Adds configuration to use gateway mode (#2335) * Adding CTL config for gateway mode * Supporting -1 operations Co-authored-by: j82w --- .../Tools/CTL/CTLConfig.cs | 8 +++++ .../Tools/CTL/CTLOperationHandler.cs | 10 +++---- .../CTL/Scenarios/ReadWriteQueryScenario.cs | 30 +++++++++++++------ 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/Microsoft.Azure.Cosmos.Samples/Tools/CTL/CTLConfig.cs b/Microsoft.Azure.Cosmos.Samples/Tools/CTL/CTLConfig.cs index e2ac890fcf..dc7643e238 100644 --- a/Microsoft.Azure.Cosmos.Samples/Tools/CTL/CTLConfig.cs +++ b/Microsoft.Azure.Cosmos.Samples/Tools/CTL/CTLConfig.cs @@ -75,6 +75,9 @@ public string DiagnosticsThresholdDuration [Option("ctl_output_event_traces", Required = false, HelpText = "Outputs TraceSource to console")] public bool OutputEventTraces { get; set; } = false; + [Option("ctl_gateway_mode", Required = false, HelpText = "Uses gateway mode")] + public bool UseGatewayMode { get; set; } = false; + [Option("ctl_reporting_interval", Required = false, HelpText = "Reporting interval")] public int ReportingIntervalInSeconds { get; set; } = 10; @@ -113,6 +116,11 @@ internal CosmosClient CreateCosmosClient() ApplicationName = CTLConfig.UserAgentSuffix }; + if (this.UseGatewayMode) + { + clientOptions.ConnectionMode = ConnectionMode.Gateway; + } + if (!string.IsNullOrWhiteSpace(this.ConsistencyLevel)) { if (Enum.TryParse(this.ConsistencyLevel, out ConsistencyLevel consistencyLevel)) diff --git a/Microsoft.Azure.Cosmos.Samples/Tools/CTL/CTLOperationHandler.cs b/Microsoft.Azure.Cosmos.Samples/Tools/CTL/CTLOperationHandler.cs index 89b3f27d32..1336b2d380 100644 --- a/Microsoft.Azure.Cosmos.Samples/Tools/CTL/CTLOperationHandler.cs +++ b/Microsoft.Azure.Cosmos.Samples/Tools/CTL/CTLOperationHandler.cs @@ -5,7 +5,6 @@ namespace CosmosCTL { using System; - using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using App.Metrics.Timer; @@ -18,7 +17,6 @@ internal static class CTLOperationHandler /// /// Waits until the synchronization semaphore is available, creates a new operation and handles resolution. /// - /// Synchronization semaphore that defines maximum degree of parallelism. /// Latency threshold above which will be called. /// Creates a to measure operation latency. /// Producer to generate operation calls as a producer-consumer. @@ -28,7 +26,6 @@ internal static class CTLOperationHandler /// /// public static async Task PerformOperationAsync( - SemaphoreSlim semaphoreSlim, long diagnosticsLoggingThreshold, Func createTimerContext, ICTLResultProducer resultProducer, @@ -39,12 +36,10 @@ public static async Task PerformOperationAsync( { while (resultProducer.HasMoreResults) { - await semaphoreSlim.WaitAsync(cancellationToken); using (TimerContext timerContext = createTimerContext()) { await resultProducer.GetNextAsync().ContinueWith(task => { - semaphoreSlim.Release(); long latency = (long)timerContext.Elapsed.TotalMilliseconds; if (task.IsCompletedSuccessfully) { @@ -53,7 +48,10 @@ await resultProducer.GetNextAsync().ContinueWith(task => logDiagnostics(task.Result); } - onSuccess(); + if (!resultProducer.HasMoreResults) + { + onSuccess(); + } } else { diff --git a/Microsoft.Azure.Cosmos.Samples/Tools/CTL/Scenarios/ReadWriteQueryScenario.cs b/Microsoft.Azure.Cosmos.Samples/Tools/CTL/Scenarios/ReadWriteQueryScenario.cs index d408a4f0f5..2fc1388d6b 100644 --- a/Microsoft.Azure.Cosmos.Samples/Tools/CTL/Scenarios/ReadWriteQueryScenario.cs +++ b/Microsoft.Azure.Cosmos.Samples/Tools/CTL/Scenarios/ReadWriteQueryScenario.cs @@ -145,14 +145,14 @@ private async Task ExecuteOperationsAsync( Stopwatch stopwatch = Stopwatch.StartNew(); int writeRange = readWriteQueryPercentage.ReadPercentage + readWriteQueryPercentage.WritePercentage; long diagnosticsThresholdDuration = (long)config.DiagnosticsThresholdDurationAsTimespan.TotalMilliseconds; - List operations = new List((int)config.Operations); + List operations = new List(); for (long i = 0; ShouldContinue(stopwatch, i, config); i++) { + await concurrencyControlSemaphore.WaitAsync(cancellationToken); long index = (long)i % 100; if (index < readWriteQueryPercentage.ReadPercentage) { operations.Add(CTLOperationHandler>>.PerformOperationAsync( - semaphoreSlim: concurrencyControlSemaphore, diagnosticsLoggingThreshold: diagnosticsThresholdDuration, createTimerContext: () => metrics.Measure.Timer.Time(readLatencyTimer), resultProducer: new SingleExecutionResultProducer>>(() => this.CreateReadOperation( @@ -160,9 +160,13 @@ private async Task ExecuteOperationsAsync( partitionKeyAttributeName: config.CollectionPartitionKey, containers: initializationResult.Containers, createdDocumentsPerContainer: this.createdDocuments)), - onSuccess: () => metrics.Measure.Counter.Increment(readSuccessMeter), + onSuccess: () => { + concurrencyControlSemaphore.Release(); + metrics.Measure.Counter.Increment(readSuccessMeter); + }, onFailure: (Exception ex) => { + concurrencyControlSemaphore.Release(); metrics.Measure.Counter.Increment(readFailureMeter); logger.LogError(ex, "Failure during read operation"); }, @@ -172,7 +176,6 @@ private async Task ExecuteOperationsAsync( else if (index < writeRange) { operations.Add(CTLOperationHandler>>.PerformOperationAsync( - semaphoreSlim: concurrencyControlSemaphore, diagnosticsLoggingThreshold: diagnosticsThresholdDuration, createTimerContext: () => metrics.Measure.Timer.Time(writeLatencyTimer), resultProducer: new SingleExecutionResultProducer>>(() => this.CreateWriteOperation( @@ -180,9 +183,14 @@ private async Task ExecuteOperationsAsync( partitionKeyAttributeName: config.CollectionPartitionKey, containers: initializationResult.Containers, isContentResponseOnWriteEnabled: config.IsContentResponseOnWriteEnabled)), - onSuccess: () => metrics.Measure.Counter.Increment(writeSuccessMeter), + onSuccess: () => + { + concurrencyControlSemaphore.Release(); + metrics.Measure.Counter.Increment(writeSuccessMeter); + }, onFailure: (Exception ex) => { + concurrencyControlSemaphore.Release(); metrics.Measure.Counter.Increment(writeFailureMeter); logger.LogError(ex, "Failure during write operation"); }, @@ -193,15 +201,19 @@ private async Task ExecuteOperationsAsync( else { operations.Add(CTLOperationHandler>>.PerformOperationAsync( - semaphoreSlim: concurrencyControlSemaphore, diagnosticsLoggingThreshold: diagnosticsThresholdDuration, createTimerContext: () => metrics.Measure.Timer.Time(queryLatencyTimer), resultProducer: new IteratorResultProducer>(this.CreateQueryOperation( operation: i, containers: initializationResult.Containers)), - onSuccess: () => metrics.Measure.Counter.Increment(querySuccessMeter), + onSuccess: () => + { + concurrencyControlSemaphore.Release(); + metrics.Measure.Counter.Increment(querySuccessMeter); + }, onFailure: (Exception ex) => { + concurrencyControlSemaphore.Release(); metrics.Measure.Counter.Increment(queryFailureMeter); logger.LogError(ex, "Failure during query operation"); }, @@ -213,7 +225,7 @@ private async Task ExecuteOperationsAsync( await Task.WhenAll(operations); stopwatch.Stop(); logger.LogInformation("[{0}] operations performed in [{1}] seconds.", - config.Operations, stopwatch.Elapsed.TotalSeconds); + operations.Count, stopwatch.Elapsed.TotalSeconds); } private Task>> CreateReadOperation( @@ -333,7 +345,7 @@ private static IEnumerable> GenerateDocuments( long documentsToCreate, string partitionKeyPropertyName) { - List> createdDocuments = new List>((int)documentsToCreate); + List> createdDocuments = new List>(); for (long i = 0; i < documentsToCreate; i++) { createdDocuments.Add(GenerateDocument(partitionKeyPropertyName)); From c0da3e3d734c27de03f544345867e88875f8ba4d Mon Sep 17 00:00:00 2001 From: Matias Quaranta Date: Thu, 25 Mar 2021 14:09:01 -0700 Subject: [PATCH 11/19] [Internal] CTL: Fixes wiring of docker parameters into execution (#2339) --- .../Tools/CTL/run_ctl.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Microsoft.Azure.Cosmos.Samples/Tools/CTL/run_ctl.sh b/Microsoft.Azure.Cosmos.Samples/Tools/CTL/run_ctl.sh index afc91034d4..8088694349 100644 --- a/Microsoft.Azure.Cosmos.Samples/Tools/CTL/run_ctl.sh +++ b/Microsoft.Azure.Cosmos.Samples/Tools/CTL/run_ctl.sh @@ -114,6 +114,20 @@ else dotnetparameters="$dotnetparameters --ctl_output_event_traces $ctl_output_event_traces" fi +if [ -z "$ctl_gateway_mode" ] +then +dotnetparameters="$dotnetparameters" +else +dotnetparameters="$dotnetparameters --ctl_gateway_mode $ctl_gateway_mode" +fi + +if [ -z "$ctl_logging_context" ] +then +dotnetparameters="$dotnetparameters" +else +dotnetparameters="$dotnetparameters --ctl_logging_context $ctl_logging_context" +fi + log_filename="/tmp/dotnetctl.log" echo "Log file name is $log_filename" From 5e1bbe703d743095bedffbc85ee41647861c720b Mon Sep 17 00:00:00 2001 From: Santosh Kulkarni <66682828+kr-santosh@users.noreply.github.com> Date: Fri, 26 Mar 2021 17:18:07 +0530 Subject: [PATCH 12/19] Client Encryption: Adds integration with latest CosmosDb Preview Package - 3.18.0-preview. (#2340) * Throw NotImplementedException for new Methods in 3.18.0-preview. * Update changelog.md --- Directory.Build.props | 2 +- .../changelog.md | 5 +++++ .../src/Custom/EncryptionContainer.cs | 20 +++++++++++++++++++ .../Custom/EncryptionTransactionalBatch.cs | 8 ++++++++ .../src/EncryptionContainer.cs | 20 +++++++++++++++++++ .../src/EncryptionTransactionalBatch.cs | 8 ++++++++ .../Microsoft.Azure.Cosmos.Encryption.csproj | 2 +- 7 files changed, 63 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 32908fab38..c28e3aa475 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,7 +5,7 @@ 3.18.0 preview 3.17.2 - 1.0.0-previewV12 + 1.0.0-previewV13 1.1.0-preview1 $([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../')) $(DefineConstants);PREVIEW diff --git a/Microsoft.Azure.Cosmos.Encryption/changelog.md b/Microsoft.Azure.Cosmos.Encryption/changelog.md index 4ff5343011..6ddfdd45dc 100644 --- a/Microsoft.Azure.Cosmos.Encryption/changelog.md +++ b/Microsoft.Azure.Cosmos.Encryption/changelog.md @@ -3,6 +3,11 @@ Preview features are treated as a separate branch and will not be included in th The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +### [1.0.0-previewV13](https://www.nuget.org/packages/Microsoft.Azure.Cosmos.Encryption/1.0.0-previewV13) - 2021-03-26 + +#### Added +- [#2340](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/2340) Adds integration with latest CosmosDb Preview Package - 3.18.0-preview. + ### [1.0.0-previewV12](https://www.nuget.org/packages/Microsoft.Azure.Cosmos.Encryption/1.0.0-previewV12) - 2021-03-15 #### Added diff --git a/Microsoft.Azure.Cosmos.Encryption/src/Custom/EncryptionContainer.cs b/Microsoft.Azure.Cosmos.Encryption/src/Custom/EncryptionContainer.cs index 54f4268fb2..e484c50f34 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/Custom/EncryptionContainer.cs +++ b/Microsoft.Azure.Cosmos.Encryption/src/Custom/EncryptionContainer.cs @@ -873,5 +873,25 @@ public override FeedIterator GetChangeFeedIterator( changeFeedRequestOptions), this.ResponseFactory); } + + public override Task> PatchItemAsync( + string id, + PartitionKey partitionKey, + IReadOnlyList patchOperations, + PatchItemRequestOptions requestOptions = null, + CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public override Task PatchItemStreamAsync( + string id, + PartitionKey partitionKey, + IReadOnlyList patchOperations, + PatchItemRequestOptions requestOptions = null, + CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } } } \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos.Encryption/src/Custom/EncryptionTransactionalBatch.cs b/Microsoft.Azure.Cosmos.Encryption/src/Custom/EncryptionTransactionalBatch.cs index 1efb0b958a..0e9770ec90 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/Custom/EncryptionTransactionalBatch.cs +++ b/Microsoft.Azure.Cosmos.Encryption/src/Custom/EncryptionTransactionalBatch.cs @@ -252,5 +252,13 @@ private async Task DecryptTransactionalBatchResponse response, this.cosmosSerializer); } + + public override TransactionalBatch PatchItem( + string id, + IReadOnlyList patchOperations, + TransactionalBatchPatchItemRequestOptions requestOptions = null) + { + throw new NotImplementedException(); + } } } diff --git a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionContainer.cs b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionContainer.cs index 354b51365c..1c4f5802b5 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionContainer.cs +++ b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionContainer.cs @@ -741,5 +741,25 @@ public override FeedIterator GetChangeFeedIterator( changeFeedRequestOptions), this.ResponseFactory); } + + public override Task> PatchItemAsync( + string id, + PartitionKey partitionKey, + IReadOnlyList patchOperations, + PatchItemRequestOptions requestOptions = null, + CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public override Task PatchItemStreamAsync( + string id, + PartitionKey partitionKey, + IReadOnlyList patchOperations, + PatchItemRequestOptions requestOptions = null, + CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } } } \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionTransactionalBatch.cs b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionTransactionalBatch.cs index 0d31e244b2..e4839b7078 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionTransactionalBatch.cs +++ b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionTransactionalBatch.cs @@ -202,5 +202,13 @@ private async Task DecryptTransactionalBatchResponse response, this.cosmosSerializer); } + + public override TransactionalBatch PatchItem( + string id, + IReadOnlyList patchOperations, + TransactionalBatchPatchItemRequestOptions requestOptions = null) + { + throw new NotImplementedException(); + } } } diff --git a/Microsoft.Azure.Cosmos.Encryption/src/Microsoft.Azure.Cosmos.Encryption.csproj b/Microsoft.Azure.Cosmos.Encryption/src/Microsoft.Azure.Cosmos.Encryption.csproj index b3ae1babc0..6a0afb628c 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/Microsoft.Azure.Cosmos.Encryption.csproj +++ b/Microsoft.Azure.Cosmos.Encryption/src/Microsoft.Azure.Cosmos.Encryption.csproj @@ -26,7 +26,7 @@ - + From 53b706c473faa242f095d7f0e34e142353605ba9 Mon Sep 17 00:00:00 2001 From: j82w Date: Fri, 26 Mar 2021 11:28:53 -0700 Subject: [PATCH 13/19] CosmosBenchmarks: Adds additional percentages to summary output (#2342) --- .../Tools/Benchmark/Fx/ParallelExecutionStrategy.cs | 3 +++ Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/RunSummary.cs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/Fx/ParallelExecutionStrategy.cs b/Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/Fx/ParallelExecutionStrategy.cs index ecf28681f3..cc7d71d5fa 100644 --- a/Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/Fx/ParallelExecutionStrategy.cs +++ b/Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/Fx/ParallelExecutionStrategy.cs @@ -129,13 +129,16 @@ private async Task LogOutputStats(IExecutor[] executors) runSummary.Top80PercentAverageRps = Math.Round(summaryCounters.Take((int)(0.8 * summaryCounters.Length)).Average(), 0); runSummary.Top90PercentAverageRps = Math.Round(summaryCounters.Take((int)(0.9 * summaryCounters.Length)).Average(), 0); runSummary.Top95PercentAverageRps = Math.Round(summaryCounters.Take((int)(0.95 * summaryCounters.Length)).Average(), 0); + runSummary.Top99PercentAverageRps = Math.Round(summaryCounters.Take((int)(0.99 * summaryCounters.Length)).Average(), 0); runSummary.AverageRps = Math.Round(summaryCounters.Average(), 0); runSummary.Top50PercentLatencyInMs = TelemetrySpan.GetLatencyPercentile(50); runSummary.Top75PercentLatencyInMs = TelemetrySpan.GetLatencyPercentile(75); runSummary.Top90PercentLatencyInMs = TelemetrySpan.GetLatencyPercentile(90); runSummary.Top95PercentLatencyInMs = TelemetrySpan.GetLatencyPercentile(95); + runSummary.Top98PercentLatencyInMs = TelemetrySpan.GetLatencyPercentile(98); runSummary.Top99PercentLatencyInMs = TelemetrySpan.GetLatencyPercentile(99); + runSummary.MaxLatencyInMs = TelemetrySpan.GetLatencyPercentile(100); string summary = JsonConvert.SerializeObject(runSummary); Utility.TeeTraceInformation(summary); diff --git a/Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/RunSummary.cs b/Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/RunSummary.cs index 8aa4c16fbf..5ec49f8cbb 100644 --- a/Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/RunSummary.cs +++ b/Microsoft.Azure.Cosmos.Samples/Tools/Benchmark/RunSummary.cs @@ -57,12 +57,15 @@ public class RunSummary public double Top80PercentAverageRps { get; set; } public double Top90PercentAverageRps { get; set; } public double Top95PercentAverageRps { get; set; } + public double Top99PercentAverageRps { get; set; } public double? Top50PercentLatencyInMs { get; set; } public double? Top75PercentLatencyInMs { get; set; } public double? Top90PercentLatencyInMs { get; set; } public double? Top95PercentLatencyInMs { get; set; } + public double? Top98PercentLatencyInMs { get; set; } public double? Top99PercentLatencyInMs { get; set; } + public double? MaxLatencyInMs { get; set; } public double AverageRps { get; set; } From 624b744c957e3500c32a93cc068b0bf7de4d8d4e Mon Sep 17 00:00:00 2001 From: Asket Agarwal Date: Mon, 29 Mar 2021 19:05:49 +0530 Subject: [PATCH 14/19] Documentation: Fixes Code formatting in CosmosClientOptions (#2346) Co-authored-by: j82w --- Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs index 3a81a5f145..f3fe8d6813 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs @@ -400,6 +400,8 @@ public IWebProxy WebProxy /// /// /// An example on how to configure the serialization option to ignore null values + /// + /// + /// /// public CosmosSerializationOptions SerializerOptions { @@ -429,7 +433,9 @@ public CosmosSerializationOptions SerializerOptions /// SDK owned types such as DatabaseProperties and ContainerProperties will always use the SDK default serializer. /// /// - /// // An example on how to set a custom serializer. For basic serializer options look at CosmosSerializationOptions + /// An example on how to set a custom serializer. For basic serializer options look at CosmosSerializationOptions + /// + /// + /// /// [JsonConverter(typeof(ClientOptionJsonConverter))] public CosmosSerializer Serializer From 94914c41aad9b1996599a515168fee3e710eb7fc Mon Sep 17 00:00:00 2001 From: Asket Agarwal Date: Mon, 29 Mar 2021 22:01:28 +0530 Subject: [PATCH 15/19] Documentation: Fixes typo in Documentation of GetItemLinqQueryable (#2347) Co-authored-by: j82w --- Microsoft.Azure.Cosmos/src/Resource/Container/Container.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Container/Container.cs b/Microsoft.Azure.Cosmos/src/Resource/Container/Container.cs index 2b4f414e85..e8ed294b7f 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Container/Container.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Container/Container.cs @@ -1088,7 +1088,7 @@ public abstract FeedIterator GetItemQueryIterator( /// //Asynchronous query execution /// while (setIterator.HasMoreResults) /// { - /// foreach(var item in await feedIterator.ReadNextAsync()) + /// foreach(var item in await setIterator.ReadNextAsync()) /// { /// Console.WriteLine(item.Price); /// } From 42e597c4f1f3bd255bb04c2deeb6c8a93fd4bb35 Mon Sep 17 00:00:00 2001 From: Asket Agarwal Date: Tue, 30 Mar 2021 01:29:02 +0530 Subject: [PATCH 16/19] Gateway: Adds optimization to reduce gateway header size by scoping session token to specific partitions. (#2165) Currently in Gateway Mode, the entire session token from all Partitions is sent to the backend. With this change we try to resolve the partition of the request before sending to gateway and send only that session token. This will solve the issue of large headers leading to 400 errors. We first try to resolve the partition from PartitionKeyRangeCache. If we can't, we refresh the cache. If we still can't we send the GlobalSessionToken. --- Microsoft.Azure.Cosmos/src/DocumentClient.cs | 2 + .../src/GatewayStoreModel.cs | 154 +++++++++++++++++- .../src/Routing/AddressResolver.cs | 6 +- .../src/SessionContainer.cs | 32 ++++ .../GatewaySessionTokenTests.cs | 144 ++++++++++++++++ .../GatewayStoreModelTest.cs | 51 ++++-- 6 files changed, 365 insertions(+), 24 deletions(-) create mode 100644 Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/GatewaySessionTokenTests.cs diff --git a/Microsoft.Azure.Cosmos/src/DocumentClient.cs b/Microsoft.Azure.Cosmos/src/DocumentClient.cs index 932ea0c2d6..dd3c9463d1 100644 --- a/Microsoft.Azure.Cosmos/src/DocumentClient.cs +++ b/Microsoft.Azure.Cosmos/src/DocumentClient.cs @@ -949,6 +949,8 @@ private async Task GetInitializationTaskAsync(IStoreClientFactory storeClientFac this.partitionKeyRangeCache = new PartitionKeyRangeCache(this, this.GatewayStoreModel, this.collectionCache); this.ResetSessionTokenRetryPolicy = new ResetSessionTokenRetryPolicyFactory(this.sessionContainer, this.collectionCache, this.retryPolicy); + gatewayStoreModel.SetCaches(this.partitionKeyRangeCache, this.collectionCache); + if (this.ConnectionPolicy.ConnectionMode == ConnectionMode.Gateway) { this.StoreModel = this.GatewayStoreModel; diff --git a/Microsoft.Azure.Cosmos/src/GatewayStoreModel.cs b/Microsoft.Azure.Cosmos/src/GatewayStoreModel.cs index f6c34d1083..a0ecdfc258 100644 --- a/Microsoft.Azure.Cosmos/src/GatewayStoreModel.cs +++ b/Microsoft.Azure.Cosmos/src/GatewayStoreModel.cs @@ -10,10 +10,13 @@ namespace Microsoft.Azure.Cosmos using System.Linq; using System.Net; using System.Net.Http; + using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; + using Microsoft.Azure.Cosmos.Common; using Microsoft.Azure.Cosmos.Core.Trace; using Microsoft.Azure.Cosmos.Routing; + using Microsoft.Azure.Cosmos.Tracing; using Microsoft.Azure.Documents; using Microsoft.Azure.Documents.Collections; using Newtonsoft.Json; @@ -28,6 +31,10 @@ internal class GatewayStoreModel : IStoreModel, IDisposable private GatewayStoreClient gatewayStoreClient; + // Caches to resolve the PartitionKeyRange from request. For Session Token Optimization. + private ClientCollectionCache clientCollectionCache; + private PartitionKeyRangeCache partitionKeyRangeCache; + public GatewayStoreModel( GlobalEndpointManager endpointManager, ISessionContainer sessionContainer, @@ -49,10 +56,12 @@ public GatewayStoreModel( public virtual async Task ProcessMessageAsync(DocumentServiceRequest request, CancellationToken cancellationToken = default) { - GatewayStoreModel.ApplySessionToken( + await GatewayStoreModel.ApplySessionTokenAsync( request, this.defaultConsistencyLevel, - this.sessionContainer); + this.sessionContainer, + this.partitionKeyRangeCache, + this.clientCollectionCache); DocumentServiceResponse response; try @@ -143,6 +152,13 @@ public virtual async Task GetDatabaseAccountAsync(Func> TryResolveSessionTokenAsync(DocumentServiceRequest request, + ISessionContainer sessionContainer, + PartitionKeyRangeCache partitionKeyRangeCache, + ClientCollectionCache clientCollectionCache) + { + if (request == null) + { + throw new ArgumentNullException(nameof(request)); + } + + if (sessionContainer == null) + { + throw new ArgumentNullException(nameof(sessionContainer)); + } + + if (partitionKeyRangeCache == null) + { + throw new ArgumentNullException(nameof(partitionKeyRangeCache)); + } + + if (clientCollectionCache == null) + { + throw new ArgumentNullException(nameof(clientCollectionCache)); + } + + if (request.ResourceType.IsPartitioned()) + { + (bool isSuccess, PartitionKeyRange partitionKeyRange) = await TryResolvePartitionKeyRangeAsync(request: request, + sessionContainer: sessionContainer, + partitionKeyRangeCache: partitionKeyRangeCache, + clientCollectionCache: clientCollectionCache, + refreshCache: false); + + if (isSuccess && sessionContainer is SessionContainer gatewaySessionContainer) + { + request.RequestContext.ResolvedPartitionKeyRange = partitionKeyRange; + string localSessionToken = gatewaySessionContainer.ResolvePartitionLocalSessionTokenForGateway(request, partitionKeyRange.Id); + if (!string.IsNullOrEmpty(localSessionToken)) + { + return new Tuple(true, localSessionToken); + } + } + } + + return new Tuple(false, null); + } + + private static async Task> TryResolvePartitionKeyRangeAsync(DocumentServiceRequest request, + ISessionContainer sessionContainer, + PartitionKeyRangeCache partitionKeyRangeCache, + ClientCollectionCache clientCollectionCache, + bool refreshCache) + { + if (refreshCache) + { + request.ForceMasterRefresh = true; + request.ForceNameCacheRefresh = true; + } + + PartitionKeyRange partitonKeyRange = null; + ContainerProperties collection = await clientCollectionCache.ResolveCollectionAsync(request, CancellationToken.None, NoOpTrace.Singleton); + + string partitionKeyString = request.Headers[HttpConstants.HttpHeaders.PartitionKey]; + if (partitionKeyString != null) + { + CollectionRoutingMap collectionRoutingMap = await partitionKeyRangeCache.TryLookupAsync(collectionRid: collection.ResourceId, + previousValue: null, + request: request, + cancellationToken: CancellationToken.None, + NoOpTrace.Singleton); + + if (refreshCache && collectionRoutingMap != null) + { + collectionRoutingMap = await partitionKeyRangeCache.TryLookupAsync(collectionRid: collection.ResourceId, + previousValue: collectionRoutingMap, + request: request, + cancellationToken: CancellationToken.None, + NoOpTrace.Singleton); + } + + partitonKeyRange = AddressResolver.TryResolveServerPartitionByPartitionKey(request: request, + partitionKeyString: partitionKeyString, + collectionCacheUptoDate: false, + collection: collection, + routingMap: collectionRoutingMap); + } + else if (request.PartitionKeyRangeIdentity != null) + { + PartitionKeyRangeIdentity partitionKeyRangeId = request.PartitionKeyRangeIdentity; + partitonKeyRange = await partitionKeyRangeCache.TryGetPartitionKeyRangeByIdAsync(collection.ResourceId, + partitionKeyRangeId.ToString(), + NoOpTrace.Singleton, + refreshCache); + } + + if (partitonKeyRange == null) + { + if (refreshCache) + { + return new Tuple(false, null); + } + + // need to refresh cache. Maybe split happened. + return await GatewayStoreModel.TryResolvePartitionKeyRangeAsync(request: request, + sessionContainer: sessionContainer, + partitionKeyRangeCache: partitionKeyRangeCache, + clientCollectionCache: clientCollectionCache, + refreshCache: true); + } + + return new Tuple(true, partitonKeyRange); + } + // DEVNOTE: This can be replace with ReplicatedResourceClient.IsMasterOperation on next Direct sync internal static bool IsMasterOperation( ResourceType resourceType, diff --git a/Microsoft.Azure.Cosmos/src/Routing/AddressResolver.cs b/Microsoft.Azure.Cosmos/src/Routing/AddressResolver.cs index a423002b1f..271068302f 100644 --- a/Microsoft.Azure.Cosmos/src/Routing/AddressResolver.cs +++ b/Microsoft.Azure.Cosmos/src/Routing/AddressResolver.cs @@ -452,7 +452,7 @@ private async Task TryResolveServerPartitionAsync( object effectivePartitionKeyStringObject = null; if (partitionKeyString != null) { - range = this.TryResolveServerPartitionByPartitionKey( + range = AddressResolver.TryResolveServerPartitionByPartitionKey( request, partitionKeyString, collectionCacheIsUptodate, @@ -548,7 +548,7 @@ private PartitionKeyRange TryResolveSinglePartitionCollection( // due to parallel usage of V3 SDK and a possible storage or throughput split // The current client might be legacy and not aware of this. // In such case route the request to the first partition - return this.TryResolveServerPartitionByPartitionKey( + return AddressResolver.TryResolveServerPartitionByPartitionKey( request, "[]", // This corresponds to first partition collectionCacheIsUptoDate, @@ -629,7 +629,7 @@ private async Task TryResolveServerPartitionByPartitionKeyRang return new ResolutionResult(partitionKeyRange, addresses, identity); } - private PartitionKeyRange TryResolveServerPartitionByPartitionKey( + internal static PartitionKeyRange TryResolveServerPartitionByPartitionKey( DocumentServiceRequest request, string partitionKeyString, bool collectionCacheUptoDate, diff --git a/Microsoft.Azure.Cosmos/src/SessionContainer.cs b/Microsoft.Azure.Cosmos/src/SessionContainer.cs index 93f1de9fdc..9fbd3f88c8 100644 --- a/Microsoft.Azure.Cosmos/src/SessionContainer.cs +++ b/Microsoft.Azure.Cosmos/src/SessionContainer.cs @@ -49,6 +49,11 @@ public ISessionToken ResolvePartitionLocalSessionToken(DocumentServiceRequest re return SessionContainer.ResolvePartitionLocalSessionToken(this.state, request, partitionKeyRangeId); } + public string ResolvePartitionLocalSessionTokenForGateway(DocumentServiceRequest request, string partitionKeyRangeId) + { + return SessionContainer.ResolvePartitionLocalSessionTokenForGateway(this.state, request, partitionKeyRangeId); + } + public void ClearTokenByCollectionFullname(string collectionFullname) { SessionContainer.ClearTokenByCollectionFullname(this.state, collectionFullname); @@ -139,6 +144,33 @@ private static ISessionToken ResolvePartitionLocalSessionToken(SessionContainerS return SessionTokenHelper.ResolvePartitionLocalSessionToken(request, partitionKeyRangeId, SessionContainer.GetPartitionKeyRangeIdToTokenMap(self, request)); } + private static string ResolvePartitionLocalSessionTokenForGateway(SessionContainerState self, + DocumentServiceRequest request, + string partitionKeyRangeId) + { + ConcurrentDictionary partitionKeyRangeIdToTokenMap = SessionContainer.GetPartitionKeyRangeIdToTokenMap(self, request); + if (partitionKeyRangeIdToTokenMap != null) + { + if (partitionKeyRangeIdToTokenMap.TryGetValue(partitionKeyRangeId, out ISessionToken sessionToken)) + { + return partitionKeyRangeId + ":" + sessionToken.ConvertToString(); + } + else if (request.RequestContext.ResolvedPartitionKeyRange.Parents != null) + { + for (int parentIndex = request.RequestContext.ResolvedPartitionKeyRange.Parents.Count - 1; parentIndex >= 0; parentIndex--) + { + if (partitionKeyRangeIdToTokenMap.TryGetValue(request.RequestContext.ResolvedPartitionKeyRange.Parents[parentIndex], + out sessionToken)) + { + return partitionKeyRangeId + ":" + sessionToken.ConvertToString(); + } + } + } + } + + return null; + } + private static void ClearTokenByCollectionFullname(SessionContainerState self, string collectionFullname) { if (!string.IsNullOrEmpty(collectionFullname)) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/GatewaySessionTokenTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/GatewaySessionTokenTests.cs new file mode 100644 index 0000000000..94b1602675 --- /dev/null +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/GatewaySessionTokenTests.cs @@ -0,0 +1,144 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests +{ + using System; + using System.Collections.Generic; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + using Microsoft.Azure.Cosmos.Tracing; + using Microsoft.Azure.Documents; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class GatewaySessionTokenTests : BaseCosmosClientHelper + { + private ContainerInternal Container = null; + private const string PartitionKey = "/pk"; + + [TestInitialize] + public async Task TestInitialize() + { + this.cosmosClient = TestCommon.CreateCosmosClient(useGateway: true); + this.database = await this.cosmosClient.CreateDatabaseAsync( + id: Guid.NewGuid().ToString()); + ContainerResponse response = await this.database.CreateContainerAsync( + new ContainerProperties(id: Guid.NewGuid().ToString(), partitionKeyPath: PartitionKey), + throughput: 20000, + cancellationToken: this.cancellationToken); + Assert.IsNotNull(response); + Assert.IsNotNull(response.Container); + Assert.IsNotNull(response.Resource); + this.Container = (ContainerInlineCore)response; + + // Create items with different + for (int i = 0; i < 500; i++) + { + ToDoActivity item = ToDoActivity.CreateRandomToDoActivity(); + item.pk = "Status" + i.ToString(); + item.id = i.ToString(); + ItemResponse itemResponse = await this.Container.CreateItemAsync(item); + Assert.AreEqual(HttpStatusCode.Created, itemResponse.StatusCode); + } + } + + [TestCleanup] + public async Task Cleanup() + { + await base.TestCleanup(); + } + + [TestMethod] + public async Task TestGatewayModelSession() + { + ContainerProperties containerProperties = await this.Container.GetCachedContainerPropertiesAsync(false, NoOpTrace.Singleton, CancellationToken.None); + + ISessionContainer sessionContainer = this.cosmosClient.DocumentClient.sessionContainer; + string docLink = "dbs/" + this.database.Id + "/colls/" + containerProperties.Id + "/docs/3"; + Documents.Collections.INameValueCollection headers = new StoreRequestNameValueCollection(); + headers.Set(HttpConstants.HttpHeaders.PartitionKey, "[\"Status3\"]"); + + DocumentServiceRequest request = DocumentServiceRequest.Create(OperationType.Read, ResourceType.Document, docLink, AuthorizationTokenType.PrimaryMasterKey, headers); + string globalSessionToken = sessionContainer.ResolveGlobalSessionToken(request); + Assert.IsTrue(globalSessionToken.Split(',').Length > 1); + + await GatewayStoreModel.ApplySessionTokenAsync(request, + Cosmos.ConsistencyLevel.Session, + sessionContainer, + await this.cosmosClient.DocumentClient.GetPartitionKeyRangeCacheAsync(NoOpTrace.Singleton), + await this.cosmosClient.DocumentClient.GetCollectionCacheAsync(NoOpTrace.Singleton)); + + string sessionToken = request.Headers[HttpConstants.HttpHeaders.SessionToken]; + Assert.IsTrue(!string.IsNullOrEmpty(sessionToken) && sessionToken.Split(',').Length == 1); + } + + [TestMethod] + public async Task GatewaySameSessionTokenTest() + { + string createSessionToken = null; + GatewaySessionTokenTests.HttpClientHandlerHelper httpClientHandler = new HttpClientHandlerHelper + { + ResponseCallBack = (result) => + { + HttpResponseMessage response = result.Result; + if (response.StatusCode != HttpStatusCode.Created) + { + return response; + } + + response.Headers.TryGetValues("x-ms-session-token", out IEnumerable sessionTokens); + foreach (string singleToken in sessionTokens) + { + createSessionToken = singleToken; + break; + } + return response; + } + }; + + using (CosmosClient client = TestCommon.CreateCosmosClient(builder => builder + .WithConnectionModeGateway() + .WithConsistencyLevel(Cosmos.ConsistencyLevel.Session) + .WithHttpClientFactory(() => new HttpClient(httpClientHandler)))) + { + Container container = client.GetContainer(this.database.Id, this.Container.Id); + + ToDoActivity item = ToDoActivity.CreateRandomToDoActivity("Status1001", "1001"); + ItemResponse itemResponse = await container.CreateItemAsync(item); + + // Read back the created Item and check if the session token is identical. + string docLink = "dbs/" + this.database.Id + "/colls/" + this.Container.Id + "/docs/1001"; + Documents.Collections.INameValueCollection headers = new StoreRequestNameValueCollection(); + headers.Set(HttpConstants.HttpHeaders.PartitionKey, "[\"Status1001\"]"); + + DocumentServiceRequest request = DocumentServiceRequest.Create(OperationType.Read, ResourceType.Document, docLink, AuthorizationTokenType.PrimaryMasterKey, headers); + await GatewayStoreModel.ApplySessionTokenAsync(request, + Cosmos.ConsistencyLevel.Session, + client.DocumentClient.sessionContainer, + await client.DocumentClient.GetPartitionKeyRangeCacheAsync(NoOpTrace.Singleton), + await client.DocumentClient.GetCollectionCacheAsync(NoOpTrace.Singleton)); + + string readSessionToken = request.Headers[HttpConstants.HttpHeaders.SessionToken]; + Assert.AreEqual(readSessionToken, createSessionToken); + } + } + + private class HttpClientHandlerHelper : DelegatingHandler + { + public HttpClientHandlerHelper() : base(new HttpClientHandler()) + { + } + + public Func, HttpResponseMessage> ResponseCallBack { get; set; } + + protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + return base.SendAsync(request, cancellationToken).ContinueWith(this.ResponseCallBack); + } + } + } +} diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs index 503ee03f81..0bee04db2b 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs @@ -147,7 +147,7 @@ public async Task TestRetries() } [TestMethod] - public void TestApplySessionForMasterOperation() + public async Task TestApplySessionForMasterOperation() { List resourceTypes = new List() { @@ -190,10 +190,12 @@ public void TestApplySessionForMasterOperation() dsr.Headers.Add(HttpConstants.HttpHeaders.SessionToken, Guid.NewGuid().ToString()); - GatewayStoreModel.ApplySessionToken( + await GatewayStoreModel.ApplySessionTokenAsync( dsr, ConsistencyLevel.Session, - new Mock().Object); + new Mock().Object, + partitionKeyRangeCache: new Mock(null, null, null).Object, + clientCollectionCache: new Mock(new SessionContainer("testhost"), this.GetGatewayStoreModelForConsistencyTest(), null, null).Object); Assert.IsNull(dsr.Headers[HttpConstants.HttpHeaders.SessionToken]); } @@ -211,16 +213,19 @@ public void TestApplySessionForMasterOperation() dsrQueryPlan.Headers.Add(HttpConstants.HttpHeaders.SessionToken, Guid.NewGuid().ToString()); - GatewayStoreModel.ApplySessionToken( + await GatewayStoreModel.ApplySessionTokenAsync( dsrQueryPlan, ConsistencyLevel.Session, - new Mock().Object); + new Mock().Object, + partitionKeyRangeCache: new Mock(null, null, null).Object, + clientCollectionCache: new Mock(new SessionContainer("testhost"), this.GetGatewayStoreModelForConsistencyTest(), null, null).Object); + Assert.IsNull(dsrQueryPlan.Headers[HttpConstants.HttpHeaders.SessionToken]); } [TestMethod] - public void TestApplySessionForDataOperation() + public async Task TestApplySessionForDataOperation() { List resourceTypes = new List() { @@ -257,10 +262,13 @@ public void TestApplySessionForDataOperation() string dsrSessionToken = Guid.NewGuid().ToString(); dsr.Headers.Add(HttpConstants.HttpHeaders.SessionToken, dsrSessionToken); - GatewayStoreModel.ApplySessionToken( + await GatewayStoreModel.ApplySessionTokenAsync( dsr, ConsistencyLevel.Session, - new Mock().Object); + new Mock().Object, + partitionKeyRangeCache: new Mock(null, null, null).Object, + clientCollectionCache: new Mock(new SessionContainer("testhost"), this.GetGatewayStoreModelForConsistencyTest(), null, null).Object); + Assert.AreEqual(dsrSessionToken, dsr.Headers[HttpConstants.HttpHeaders.SessionToken]); @@ -274,12 +282,22 @@ public void TestApplySessionForDataOperation() Mock sMock = new Mock(); sMock.Setup(x => x.ResolveGlobalSessionToken(dsrNoSessionToken)).Returns(dsrSessionToken); - GatewayStoreModel.ApplySessionToken( + await GatewayStoreModel.ApplySessionTokenAsync( dsrNoSessionToken, ConsistencyLevel.Session, - sMock.Object); + sMock.Object, + partitionKeyRangeCache: new Mock(null, null, null).Object, + clientCollectionCache: new Mock(new SessionContainer("testhost"), this.GetGatewayStoreModelForConsistencyTest(), null, null).Object); + - Assert.AreEqual(dsrSessionToken, dsrNoSessionToken.Headers[HttpConstants.HttpHeaders.SessionToken]); + if (dsrNoSessionToken.IsReadOnlyRequest || dsrNoSessionToken.OperationType == OperationType.Batch) + { + Assert.AreEqual(dsrSessionToken, dsrNoSessionToken.Headers[HttpConstants.HttpHeaders.SessionToken]); + } + else + { + Assert.IsNull(dsrNoSessionToken.Headers[HttpConstants.HttpHeaders.SessionToken]); + } } } @@ -297,10 +315,13 @@ public void TestApplySessionForDataOperation() string sessionToken = Guid.NewGuid().ToString(); dsrSprocExecute.Headers.Add(HttpConstants.HttpHeaders.SessionToken, sessionToken); - GatewayStoreModel.ApplySessionToken( + await GatewayStoreModel.ApplySessionTokenAsync( dsrSprocExecute, ConsistencyLevel.Session, - new Mock().Object); + new Mock().Object, + partitionKeyRangeCache: new Mock(null, null, null).Object, + clientCollectionCache: new Mock(new SessionContainer("testhost"), this.GetGatewayStoreModelForConsistencyTest(), null, null).Object); + Assert.AreEqual(sessionToken, dsrSprocExecute.Headers[HttpConstants.HttpHeaders.SessionToken]); } @@ -751,6 +772,10 @@ private GatewayStoreModel GetGatewayStoreModelForConsistencyTest() null, MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(httpMessageHandler))); + ClientCollectionCache clientCollectionCache = new Mock(new SessionContainer("testhost"), storeModel, null, null).Object; + PartitionKeyRangeCache partitionKeyRangeCache = new Mock(null, storeModel, clientCollectionCache).Object; + storeModel.SetCaches(partitionKeyRangeCache, clientCollectionCache); + return storeModel; } From 4df54eeb5177e159a32574c3fc467f2e4efd3e6e Mon Sep 17 00:00:00 2001 From: Asket Agarwal Date: Wed, 31 Mar 2021 02:25:22 +0530 Subject: [PATCH 17/19] CosmosDiagnostics: Adds Client Configuration to CosmosDiagnostics (#2250) * Draft- Adding Client config to ITrace * Adding Tests * Refactoring Trace Datum * Adding more tests * Modifying Baseline Tests * adding lazy string * updating baseline tests * Fixing perf test * Fixing Tests * Making ToJsonString Lazy * Adding few properties * moving inline wrapper to containercoreinline * Renaming numberofclients * Caching the Serialization * updating baseline * classes in separate files * throwing exception if jsonwriter is not text Co-authored-by: j82w --- Microsoft.Azure.Cosmos/src/CosmosClient.cs | 17 + Microsoft.Azure.Cosmos/src/DocumentClient.cs | 11 + .../src/Handler/TransportHandler.cs | 2 - .../src/Resource/ClientContextCore.cs | 2 + .../Resource/Container/ContainerInlineCore.cs | 5 +- .../src/Tracing/ITraceDatumVisitor.cs | 1 + .../ClientConfigurationTraceDatum.cs | 104 + .../Tracing/TraceData/ConsistencyConfig.cs | 52 + .../TraceData/GatewayConnectionConfig.cs | 51 + .../TraceData/OtherConnectionConfig.cs | 41 + .../TraceData/RntbdConnectionConfig.cs | 57 + .../Tracing/TraceWriter.TraceJsonWriter.cs | 13 + .../Tracing/TraceWriter.TraceTextWriter.cs | 16 + ...iterBaselineTests.BatchOperationsAsync.xml | 11 +- ...riterBaselineTests.BulkOperationsAsync.xml | 1100 +++-- ...aceWriterBaselineTests.ChangeFeedAsync.xml | 4331 +++++++---------- ...eWriterBaselineTests.MiscellanousAsync.xml | 22 +- ...neTests.PointOperationsExceptionsAsync.xml | 91 +- ...EndTraceWriterBaselineTests.QueryAsync.xml | 2336 +++++---- ...TraceWriterBaselineTests.ReadFeedAsync.xml | 2126 ++++---- ...selineTests.StreamPointOperationsAsync.xml | 44 +- ...aselineTests.TypedPointOperationsAsync.xml | 44 +- .../ClientConfigurationDiagnosticTest.cs | 93 + .../EndToEndTraceWriterBaselineTests.cs | 104 +- 24 files changed, 5465 insertions(+), 5209 deletions(-) create mode 100644 Microsoft.Azure.Cosmos/src/Tracing/TraceData/ClientConfigurationTraceDatum.cs create mode 100644 Microsoft.Azure.Cosmos/src/Tracing/TraceData/ConsistencyConfig.cs create mode 100644 Microsoft.Azure.Cosmos/src/Tracing/TraceData/GatewayConnectionConfig.cs create mode 100644 Microsoft.Azure.Cosmos/src/Tracing/TraceData/OtherConnectionConfig.cs create mode 100644 Microsoft.Azure.Cosmos/src/Tracing/TraceData/RntbdConnectionConfig.cs create mode 100644 Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientConfigurationDiagnosticTest.cs diff --git a/Microsoft.Azure.Cosmos/src/CosmosClient.cs b/Microsoft.Azure.Cosmos/src/CosmosClient.cs index 647dc47bfa..9a1202655b 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosClient.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosClient.cs @@ -13,6 +13,7 @@ namespace Microsoft.Azure.Cosmos using global::Azure.Core; using Microsoft.Azure.Cosmos.Handlers; using Microsoft.Azure.Cosmos.Tracing; + using Microsoft.Azure.Cosmos.Tracing.TraceData; using Microsoft.Azure.Documents; /// @@ -98,6 +99,8 @@ public class CosmosClient : IDisposable private ConsistencyLevel? accountConsistencyLevel; private bool isDisposed = false; + internal static int numberOfClientsCreated; + static CosmosClient() { #if PREVIEW @@ -216,6 +219,9 @@ public CosmosClient( this.ClientContext = ClientContextCore.Create( this, clientOptions); + + this.IncrementNumberOfClientsCreated(); + this.ClientConfigurationTraceDatum = new ClientConfigurationTraceDatum(this.ClientContext, DateTime.UtcNow); } /// @@ -260,6 +266,9 @@ public CosmosClient( this.ClientContext = ClientContextCore.Create( this, clientOptions); + + this.IncrementNumberOfClientsCreated(); + this.ClientConfigurationTraceDatum = new ClientConfigurationTraceDatum(this.ClientContext, DateTime.UtcNow); } /// @@ -438,6 +447,8 @@ internal CosmosClient( this, documentClient, cosmosClientOptions); + + this.ClientConfigurationTraceDatum = new ClientConfigurationTraceDatum(this.ClientContext, DateTime.UtcNow); } /// @@ -485,6 +496,7 @@ internal CosmosClient( internal DocumentClient DocumentClient => this.ClientContext.DocumentClient; internal RequestInvokerHandler RequestHandler => this.ClientContext.RequestHandler; internal CosmosClientContext ClientContext { get; } + internal ClientConfigurationTraceDatum ClientConfigurationTraceDatum { get; } /// /// Reads the for the Azure Cosmos DB account. @@ -1198,6 +1210,11 @@ private Task InitializeContainersAsync(IReadOnlyList<(string databaseId, string } } + private void IncrementNumberOfClientsCreated() + { + Interlocked.Increment(ref numberOfClientsCreated); + } + private async Task InitializeContainerAsync(string databaseId, string containerId, CancellationToken cancellationToken = default) { ContainerInternal container = (ContainerInternal)this.GetContainer(databaseId, containerId); diff --git a/Microsoft.Azure.Cosmos/src/DocumentClient.cs b/Microsoft.Azure.Cosmos/src/DocumentClient.cs index dd3c9463d1..9a372e091e 100644 --- a/Microsoft.Azure.Cosmos/src/DocumentClient.cs +++ b/Microsoft.Azure.Cosmos/src/DocumentClient.cs @@ -25,6 +25,7 @@ namespace Microsoft.Azure.Cosmos using Microsoft.Azure.Cosmos.Query.Core.QueryPlan; using Microsoft.Azure.Cosmos.Routing; using Microsoft.Azure.Cosmos.Tracing; + using Microsoft.Azure.Cosmos.Tracing.TraceData; using Microsoft.Azure.Documents; using Microsoft.Azure.Documents.Client; using Microsoft.Azure.Documents.Collections; @@ -1361,6 +1362,16 @@ private static string NormalizeAuthorizationPayload(string input) return builder.ToString(); } + internal RntbdConnectionConfig RecordTcpSettings(ClientConfigurationTraceDatum clientConfigurationTraceDatum) + { + return new RntbdConnectionConfig(this.openConnectionTimeoutInSeconds, + this.idleConnectionTimeoutInSeconds, + this.maxRequestsPerRntbdChannel, + this.maxRntbdChannels, + this.ConnectionPolicy.EnableTcpConnectionEndpointRediscovery, + this.rntbdPortReuseMode); + } + private void ThrowIfDisposed() { if (this.isDisposed) diff --git a/Microsoft.Azure.Cosmos/src/Handler/TransportHandler.cs b/Microsoft.Azure.Cosmos/src/Handler/TransportHandler.cs index 4ab702d0b0..e4229c2504 100644 --- a/Microsoft.Azure.Cosmos/src/Handler/TransportHandler.cs +++ b/Microsoft.Azure.Cosmos/src/Handler/TransportHandler.cs @@ -91,8 +91,6 @@ internal async Task ProcessMessageAsync( { request.Trace = processMessageAsyncTrace; - processMessageAsyncTrace.AddDatum("User Agent", this.client.ClientContext.UserAgent); - DocumentServiceResponse response = request.OperationType == OperationType.Upsert ? await this.ProcessUpsertAsync(storeProxy, serviceRequest, cancellationToken) : await storeProxy.ProcessMessageAsync(serviceRequest, cancellationToken); diff --git a/Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs b/Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs index beb60b8d74..ef8d44d739 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs @@ -218,6 +218,8 @@ private async Task OperationHelperWithRootTraceAsync( using (ITrace trace = disableDiagnostics ? NoOpTrace.Singleton : (ITrace)Tracing.Trace.GetRootTrace(operationName, traceComponent, traceLevel)) { + trace.AddDatum("Client Configuration", this.client.ClientConfigurationTraceDatum); + return await this.RunWithDiagnosticsHelperAsync( trace, task); diff --git a/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerInlineCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerInlineCore.cs index 7a0b35d8da..9278cc286a 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerInlineCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerInlineCore.cs @@ -413,7 +413,10 @@ public override FeedIterator GetChangeFeedIterator( ChangeFeedMode changeFeedMode, ChangeFeedRequestOptions changeFeedRequestOptions = null) { - return base.GetChangeFeedIterator(changeFeedStartFrom, changeFeedMode, changeFeedRequestOptions); + return new FeedIteratorInlineCore(base.GetChangeFeedIterator(changeFeedStartFrom, + changeFeedMode, + changeFeedRequestOptions), + this.ClientContext); } public override Task> GetPartitionKeyRangesAsync( diff --git a/Microsoft.Azure.Cosmos/src/Tracing/ITraceDatumVisitor.cs b/Microsoft.Azure.Cosmos/src/Tracing/ITraceDatumVisitor.cs index ccb0113f0d..85db42440d 100644 --- a/Microsoft.Azure.Cosmos/src/Tracing/ITraceDatumVisitor.cs +++ b/Microsoft.Azure.Cosmos/src/Tracing/ITraceDatumVisitor.cs @@ -15,5 +15,6 @@ internal interface ITraceDatumVisitor void Visit(PointOperationStatisticsTraceDatum pointOperationStatisticsTraceDatum); void Visit(ClientSideRequestStatisticsTraceDatum clientSideRequestStatisticsTraceDatum); void Visit(CpuHistoryTraceDatum cpuHistoryTraceDatum); + void Visit(ClientConfigurationTraceDatum clientConfigurationTraceDatum); } } diff --git a/Microsoft.Azure.Cosmos/src/Tracing/TraceData/ClientConfigurationTraceDatum.cs b/Microsoft.Azure.Cosmos/src/Tracing/TraceData/ClientConfigurationTraceDatum.cs new file mode 100644 index 0000000000..353afccec3 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Tracing/TraceData/ClientConfigurationTraceDatum.cs @@ -0,0 +1,104 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Tracing.TraceData +{ + using System; + using System.Globalization; + using Microsoft.Azure.Cosmos.Json; + + internal sealed class ClientConfigurationTraceDatum : TraceDatum + { + public ClientConfigurationTraceDatum(CosmosClientContext cosmosClientContext, DateTime startTime) + { + this.ClientCreatedDateTimeUtc = startTime; + this.UserAgentContainer = cosmosClientContext.DocumentClient.ConnectionPolicy.UserAgentContainer; + this.GatewayConnectionConfig = new GatewayConnectionConfig(cosmosClientContext.ClientOptions.GatewayModeMaxConnectionLimit, + cosmosClientContext.ClientOptions.RequestTimeout, + cosmosClientContext.ClientOptions.WebProxy, + cosmosClientContext.ClientOptions.HttpClientFactory); + + this.RntbdConnectionConfig = cosmosClientContext.DocumentClient.RecordTcpSettings(this); + + this.OtherConnectionConfig = new OtherConnectionConfig(cosmosClientContext.ClientOptions.LimitToEndpoint, + cosmosClientContext.ClientOptions.AllowBulkExecution); + + this.ConsistencyConfig = new ConsistencyConfig(cosmosClientContext.ClientOptions.ConsistencyLevel, + cosmosClientContext.ClientOptions.ApplicationPreferredRegions); + + this.cachedNumberOfClientCreated = CosmosClient.numberOfClientsCreated; + this.cachedUserAgentString = this.UserAgentContainer.UserAgent; + this.cachedSerializedJson = this.GetSerializedDatum(); + } + + public DateTime ClientCreatedDateTimeUtc { get; } + + public GatewayConnectionConfig GatewayConnectionConfig { get; } + + public RntbdConnectionConfig RntbdConnectionConfig { get; } + + public OtherConnectionConfig OtherConnectionConfig { get; } + + public ConsistencyConfig ConsistencyConfig { get; } + + public ReadOnlyMemory SerializedJson + { + get + { + if ((this.cachedUserAgentString != this.UserAgentContainer.UserAgent) || + (this.cachedNumberOfClientCreated != CosmosClient.numberOfClientsCreated)) + { + this.cachedNumberOfClientCreated = CosmosClient.numberOfClientsCreated; + this.cachedUserAgentString = this.UserAgentContainer.UserAgent; + this.cachedSerializedJson = this.GetSerializedDatum(); + } + + return this.cachedSerializedJson; + } + } + + internal readonly UserAgentContainer UserAgentContainer; + + private ReadOnlyMemory cachedSerializedJson; + private int cachedNumberOfClientCreated; + private string cachedUserAgentString; + + internal override void Accept(ITraceDatumVisitor traceDatumVisitor) + { + traceDatumVisitor.Visit(this); + } + + private ReadOnlyMemory GetSerializedDatum() + { + IJsonWriter jsonTextWriter = JsonWriter.Create(JsonSerializationFormat.Text); + jsonTextWriter.WriteObjectStart(); + + jsonTextWriter.WriteFieldName("Client Created Time Utc"); + jsonTextWriter.WriteStringValue(this.ClientCreatedDateTimeUtc.ToString("o", CultureInfo.InvariantCulture)); + + jsonTextWriter.WriteFieldName("NumberOfClientsCreated"); + jsonTextWriter.WriteNumber64Value(this.cachedNumberOfClientCreated); + jsonTextWriter.WriteFieldName("User Agent"); + jsonTextWriter.WriteStringValue(this.cachedUserAgentString); + + jsonTextWriter.WriteFieldName("ConnectionConfig"); + jsonTextWriter.WriteObjectStart(); + + jsonTextWriter.WriteFieldName("gw"); + jsonTextWriter.WriteStringValue(this.GatewayConnectionConfig.ToString()); + jsonTextWriter.WriteFieldName("rntbd"); + jsonTextWriter.WriteStringValue(this.RntbdConnectionConfig.ToString()); + jsonTextWriter.WriteFieldName("other"); + jsonTextWriter.WriteStringValue(this.OtherConnectionConfig.ToString()); + + jsonTextWriter.WriteObjectEnd(); + + jsonTextWriter.WriteFieldName("ConsistencyConfig"); + jsonTextWriter.WriteStringValue(this.ConsistencyConfig.ToString()); + jsonTextWriter.WriteObjectEnd(); + + return jsonTextWriter.GetResult(); + } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Tracing/TraceData/ConsistencyConfig.cs b/Microsoft.Azure.Cosmos/src/Tracing/TraceData/ConsistencyConfig.cs new file mode 100644 index 0000000000..dfbffe8da3 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Tracing/TraceData/ConsistencyConfig.cs @@ -0,0 +1,52 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Tracing.TraceData +{ + using System; + using System.Collections.Generic; + using System.Globalization; + + internal class ConsistencyConfig + { + public ConsistencyConfig( + ConsistencyLevel? consistencyLevel, + IReadOnlyList preferredRegions) + { + this.ConsistencyLevel = consistencyLevel.GetValueOrDefault(); + this.PreferredRegions = preferredRegions; + this.lazyString = new Lazy(() => string.Format(CultureInfo.InvariantCulture, + "(consistency: {0}, prgns:[{1}])", + consistencyLevel.GetValueOrDefault(), + ConsistencyConfig.PreferredRegionsInternal(preferredRegions))); + this.lazyJsonString = new Lazy(() => Newtonsoft.Json.JsonConvert.SerializeObject(this)); + } + + public ConsistencyLevel ConsistencyLevel { get; } + public IReadOnlyList PreferredRegions { get; } + + private readonly Lazy lazyString; + private readonly Lazy lazyJsonString; + + public override string ToString() + { + return this.lazyString.Value; + } + + public string ToJsonString() + { + return this.lazyJsonString.Value; + } + + private static string PreferredRegionsInternal(IReadOnlyList applicationPreferredRegions) + { + if (applicationPreferredRegions == null) + { + return string.Empty; + } + + return string.Join(", ", applicationPreferredRegions); + } + } +} \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/src/Tracing/TraceData/GatewayConnectionConfig.cs b/Microsoft.Azure.Cosmos/src/Tracing/TraceData/GatewayConnectionConfig.cs new file mode 100644 index 0000000000..30bcd526eb --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Tracing/TraceData/GatewayConnectionConfig.cs @@ -0,0 +1,51 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Tracing.TraceData +{ + using System; + using System.Globalization; + using System.Net; + using System.Net.Http; + + internal class GatewayConnectionConfig + { + public GatewayConnectionConfig( + int maxConnectionLimit, + TimeSpan requestTimeout, + IWebProxy webProxy, + Func httpClientFactory) + { + this.MaxConnectionLimit = maxConnectionLimit; + this.UserRequestTimeout = (int)requestTimeout.TotalSeconds; + this.IsWebProxyConfigured = webProxy != null; + this.IsHttpClientFactoryConfigured = httpClientFactory != null; + this.lazyString = new Lazy(() => string.Format(CultureInfo.InvariantCulture, + "(cps:{0}, urto:{1}, p:{2}, httpf: {3})", + maxConnectionLimit, + (int)requestTimeout.TotalSeconds, + webProxy != null, + httpClientFactory != null)); + this.lazyJsonString = new Lazy(() => Newtonsoft.Json.JsonConvert.SerializeObject(this)); + } + + public int MaxConnectionLimit { get; } + public int UserRequestTimeout { get; } + public bool IsWebProxyConfigured { get; } + public bool IsHttpClientFactoryConfigured { get; } + + private readonly Lazy lazyString; + private readonly Lazy lazyJsonString; + + public override string ToString() + { + return this.lazyString.Value; + } + + public string ToJsonString() + { + return this.lazyJsonString.Value; + } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Tracing/TraceData/OtherConnectionConfig.cs b/Microsoft.Azure.Cosmos/src/Tracing/TraceData/OtherConnectionConfig.cs new file mode 100644 index 0000000000..2a37e6d579 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Tracing/TraceData/OtherConnectionConfig.cs @@ -0,0 +1,41 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Tracing.TraceData +{ + using System; + using System.Globalization; + + internal class OtherConnectionConfig + { + public OtherConnectionConfig( + bool limitToEndpoint, + bool allowBulkExecution) + { + this.LimitToEndpoint = limitToEndpoint; + this.AllowBulkExecution = allowBulkExecution; + this.lazyString = new Lazy(() => string.Format(CultureInfo.InvariantCulture, + "(ed:{0}, be:{1})", + limitToEndpoint, + allowBulkExecution)); + this.lazyJsonString = new Lazy(() => Newtonsoft.Json.JsonConvert.SerializeObject(this)); + } + + public bool LimitToEndpoint { get; } + public bool AllowBulkExecution { get; } + + private readonly Lazy lazyString; + private readonly Lazy lazyJsonString; + + public override string ToString() + { + return this.lazyString.Value; + } + + public string ToJsonString() + { + return this.lazyJsonString.Value; + } + } +} \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/src/Tracing/TraceData/RntbdConnectionConfig.cs b/Microsoft.Azure.Cosmos/src/Tracing/TraceData/RntbdConnectionConfig.cs new file mode 100644 index 0000000000..86b957cb30 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Tracing/TraceData/RntbdConnectionConfig.cs @@ -0,0 +1,57 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Tracing.TraceData +{ + using System; + using System.Globalization; + + internal class RntbdConnectionConfig + { + public RntbdConnectionConfig( + int connectionTimeout, + int idleConnectionTimeout, + int maxRequestsPerChannel, + int maxRequestsPerEndpoint, + bool tcpEndpointRediscovery, + PortReuseMode portReuseMode) + { + this.ConnectionTimeout = connectionTimeout; + this.IdleConnectionTimeout = idleConnectionTimeout; + this.MaxRequestsPerChannel = maxRequestsPerChannel; + this.MaxRequestsPerEndpoint = maxRequestsPerEndpoint; + this.TcpEndpointRediscovery = tcpEndpointRediscovery; + this.PortReuseMode = portReuseMode; + this.lazyString = new Lazy(() => string.Format(CultureInfo.InvariantCulture, + "(cto: {0}, icto: {1}, mrpc: {2}, mcpe: {3}, erd: {4}, pr: {5})", + connectionTimeout, + idleConnectionTimeout, + maxRequestsPerChannel, + maxRequestsPerEndpoint, + tcpEndpointRediscovery, + portReuseMode.ToString())); + this.lazyJsonString = new Lazy(() => Newtonsoft.Json.JsonConvert.SerializeObject(this)); + } + + public int ConnectionTimeout { get; } + public int IdleConnectionTimeout { get; } + public int MaxRequestsPerChannel { get; } + public int MaxRequestsPerEndpoint { get; } + public bool TcpEndpointRediscovery { get; } + public PortReuseMode PortReuseMode { get; } + + private readonly Lazy lazyString; + private readonly Lazy lazyJsonString; + + public override string ToString() + { + return this.lazyString.Value; + } + + public string ToJsonString() + { + return this.lazyJsonString.Value; + } + } +} \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/src/Tracing/TraceWriter.TraceJsonWriter.cs b/Microsoft.Azure.Cosmos/src/Tracing/TraceWriter.TraceJsonWriter.cs index 6a06f354ae..57e79e54e2 100644 --- a/Microsoft.Azure.Cosmos/src/Tracing/TraceWriter.TraceJsonWriter.cs +++ b/Microsoft.Azure.Cosmos/src/Tracing/TraceWriter.TraceJsonWriter.cs @@ -305,6 +305,19 @@ public void Visit(CpuHistoryTraceDatum cpuHistoryTraceDatum) this.jsonWriter.WriteObjectEnd(); } + public void Visit(ClientConfigurationTraceDatum clientConfigurationTraceDatum) + { + if (this.jsonWriter is IJsonTextWriterExtensions jsonTextWriter) + { + jsonTextWriter.WriteRawJsonValue(clientConfigurationTraceDatum.SerializedJson, + isFieldName: false); + } + else + { + throw new NotImplementedException("Writing Raw Json directly to the buffer is currently only supported for text and not for binary, hybridrow"); + } + } + private void WriteJsonUriArray(string propertyName, IEnumerable uris) { this.jsonWriter.WriteFieldName(propertyName); diff --git a/Microsoft.Azure.Cosmos/src/Tracing/TraceWriter.TraceTextWriter.cs b/Microsoft.Azure.Cosmos/src/Tracing/TraceWriter.TraceTextWriter.cs index 247496ed73..c88105aa21 100644 --- a/Microsoft.Azure.Cosmos/src/Tracing/TraceWriter.TraceTextWriter.cs +++ b/Microsoft.Azure.Cosmos/src/Tracing/TraceWriter.TraceTextWriter.cs @@ -453,6 +453,22 @@ public void Visit(CpuHistoryTraceDatum cpuHistoryTraceDatum) this.toStringValue = stringBuilder.ToString(); } + public void Visit(ClientConfigurationTraceDatum clientConfigurationTraceDatum) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.AppendLine("Client Configuration"); + stringBuilder.AppendLine($"Client Created Time: {clientConfigurationTraceDatum.ClientCreatedDateTimeUtc.ToString("o", CultureInfo.InvariantCulture)}"); + stringBuilder.AppendLine($"Number Of Clients Created: {CosmosClient.numberOfClientsCreated}"); + stringBuilder.AppendLine($"User Agent: {clientConfigurationTraceDatum.UserAgentContainer.UserAgent}"); + stringBuilder.AppendLine("Connection Config:"); + stringBuilder.AppendLine($"{space}'gw': {clientConfigurationTraceDatum.GatewayConnectionConfig}"); + stringBuilder.AppendLine($"{space}'rntbd': {clientConfigurationTraceDatum.RntbdConnectionConfig}"); + stringBuilder.AppendLine($"{space}'other': {clientConfigurationTraceDatum.OtherConnectionConfig}"); + stringBuilder.AppendLine($"Consistency Config: {clientConfigurationTraceDatum.ConsistencyConfig}"); + + this.toStringValue = stringBuilder.ToString(); + } + public override string ToString() { return this.toStringValue; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/EndToEndTraceWriterBaselineTests.BatchOperationsAsync.xml b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/EndToEndTraceWriterBaselineTests.BatchOperationsAsync.xml index 3e781482c1..1574453011 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/EndToEndTraceWriterBaselineTests.BatchOperationsAsync.xml +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/EndToEndTraceWriterBaselineTests.BatchOperationsAsync.xml @@ -35,6 +35,10 @@ traces = new List(); + while (feedIterator.HasMoreResults) { - while (feedIterator.HasMoreResults) + ResponseMessage responseMessage = await feedIterator.ReadNextAsync(cancellationToken: default); + ITrace trace = ((CosmosTraceDiagnostics)responseMessage.Diagnostics).Value; + traces.Add(trace); + if (responseMessage.StatusCode == System.Net.HttpStatusCode.NotModified) { - ResponseMessage responseMessage = await feedIterator.ReadNextAsync(rootTrace, cancellationToken: default); - if (responseMessage.StatusCode == System.Net.HttpStatusCode.NotModified) - { - break; - } + break; } } + + ITrace traceForest = TraceJoiner.JoinTraces(traces); ]]> - - - - - ChangeFeed Typed - feedIterator = (FeedIteratorInternal)containerInternal.GetChangeFeedIterator( - ChangeFeedStartFrom.Beginning(), - ChangeFeedMode.Incremental); - - TraceForBaselineTesting rootTrace; - using (rootTrace = TraceForBaselineTesting.GetRootTrace()) - { - while (feedIterator.HasMoreResults) - { - try - { - FeedResponse responseMessage = await feedIterator.ReadNextAsync(rootTrace, cancellationToken: default); - } - catch (CosmosException ce) when (ce.StatusCode == System.Net.HttpStatusCode.NotModified) - { - break; - } - } - } -]]> - - - - + + + + + ChangeFeed Typed + feedIterator = (FeedIteratorInternal)containerInternal.GetChangeFeedIterator( + ChangeFeedStartFrom.Beginning(), + ChangeFeedMode.Incremental); + + List traces = new List(); + while (feedIterator.HasMoreResults) { - "name": "Get Collection Cache", - "id": "00000000-0000-0000-0000-000000000000", - "component": "Routing", - "caller info": { - "member": "MemberName", - "file": "FilePath", - "line": 42 - }, - "start time": "12:00:00:000", - "duration in milliseconds": 0, - "data": {}, - "children": [] - }, + try + { + FeedResponse responseMessage = await feedIterator.ReadNextAsync(cancellationToken: default); + ITrace trace = ((CosmosTraceDiagnostics)responseMessage.Diagnostics).Value; + traces.Add(trace); + } + catch (CosmosException ce) when (ce.StatusCode == System.Net.HttpStatusCode.NotModified) + { + break; + } + } + + ITrace traceForest = TraceJoiner.JoinTraces(traces); +]]> + + + + @@ -4699,6 +3798,10 @@ traces = new List(); + while (feedIterator.HasMoreResults) { - while (feedIterator.HasMoreResults) - { - await feedIterator.ReadNextAsync(rootTrace, cancellationToken: default); - } + ResponseMessage responseMessage = await feedIterator.ReadNextAsync(cancellationToken: default); + ITrace trace = ((CosmosTraceDiagnostics)responseMessage.Diagnostics).Value; + traces.Add(trace); } + + ITrace traceForest = TraceJoiner.JoinTraces(traces); ]]> feedIterator = (FeedIteratorInternal)container.GetItemQueryIterator( queryText: "SELECT * FROM c"); - Trace rootTrace; - using (rootTrace = Trace.GetRootTrace("Root Trace")) + List traces = new List(); + while (feedIterator.HasMoreResults) { - while (feedIterator.HasMoreResults) - { - await feedIterator.ReadNextAsync(rootTrace, cancellationToken: default); - } + FeedResponse response = await feedIterator.ReadNextAsync(cancellationToken: default); + ITrace trace = ((CosmosTraceDiagnostics)response.Diagnostics).Value; + traces.Add(trace); } + + ITrace traceForest = TraceJoiner.JoinTraces(traces); ]]> @@ -2374,6 +2528,10 @@ traces = new List(); + while (feedIterator.HasMoreResults) { - while (feedIterator.HasMoreResults) - { - await feedIterator.ReadNextAsync(rootTrace, cancellationToken: default); - } + ResponseMessage responseMessage = await feedIterator.ReadNextAsync(cancellationToken: default); + ITrace trace = ((CosmosTraceDiagnostics)responseMessage.Diagnostics).Value; + traces.Add(trace); } + + ITrace traceForest = TraceJoiner.JoinTraces(traces); ]]> feedIterator = (FeedIteratorInternal)container .GetItemQueryIterator(queryText: null); - Trace rootTrace; - using (rootTrace = Trace.GetRootTrace("Root Trace")) + List traces = new List(); + while (feedIterator.HasMoreResults) { - while (feedIterator.HasMoreResults) - { - await feedIterator.ReadNextAsync(rootTrace, cancellationToken: default); - } + FeedResponse response = await feedIterator.ReadNextAsync(cancellationToken: default); + ITrace trace = ((CosmosTraceDiagnostics)response.Diagnostics).Value; + traces.Add(trace); } + + ITrace traceForest = TraceJoiner.JoinTraces(traces); ]]> @@ -2328,6 +2482,10 @@ response = await this.Container.CreateItemAsync(testItem, new Cosmos.PartitionKey(testItem.pk)); + Assert.IsNotNull(response.Diagnostics); + ITrace trace = ((CosmosTraceDiagnostics)response.Diagnostics).Value; + Assert.AreEqual(trace.Data.Count, 1); + ClientConfigurationTraceDatum clientConfigurationTraceDatum = (ClientConfigurationTraceDatum)trace.Data["Client Configuration"]; + Assert.IsNotNull(clientConfigurationTraceDatum.UserAgentContainer.UserAgent); + } + + [TestMethod] + public void CleintConfigWithOptionsTest() + { + CosmosClientOptions options = new CosmosClientOptions + { + RequestTimeout = TimeSpan.FromSeconds(50), + OpenTcpConnectionTimeout = TimeSpan.FromSeconds(30), + GatewayModeMaxConnectionLimit = 20, + MaxRequestsPerTcpConnection = 30, + MaxTcpConnectionsPerEndpoint = 30, + LimitToEndpoint = true, + ConsistencyLevel = ConsistencyLevel.Session + }; + + CosmosClient cosmosClient = TestCommon.CreateCosmosClient(options); + RntbdConnectionConfig tcpconfig = cosmosClient.ClientConfigurationTraceDatum.RntbdConnectionConfig; + Assert.AreEqual(tcpconfig.ConnectionTimeout, 30); + Assert.AreEqual(tcpconfig.IdleConnectionTimeout, -1); + Assert.AreEqual(tcpconfig.MaxRequestsPerChannel, 30); + Assert.AreEqual(tcpconfig.TcpEndpointRediscovery, false); + + GatewayConnectionConfig gwConfig = cosmosClient.ClientConfigurationTraceDatum.GatewayConnectionConfig; + Assert.AreEqual(gwConfig.UserRequestTimeout, 50); + Assert.AreEqual(gwConfig.MaxConnectionLimit, 20); + + ConsistencyConfig consistencyConfig = cosmosClient.ClientConfigurationTraceDatum.ConsistencyConfig; + Assert.AreEqual(consistencyConfig.ConsistencyLevel, ConsistencyLevel.Session); + } + + [TestMethod] + public async Task CachedSerializationTest() + { + ToDoActivity testItem = ToDoActivity.CreateRandomToDoActivity(); + ItemResponse response = await this.Container.CreateItemAsync(testItem, new Cosmos.PartitionKey(testItem.pk)); + ITrace trace = ((CosmosTraceDiagnostics)response.Diagnostics).Value; + ClientConfigurationTraceDatum clientConfigurationTraceDatum = (ClientConfigurationTraceDatum)trace.Data["Client Configuration"]; + Assert.IsNotNull(clientConfigurationTraceDatum.SerializedJson); + TestCommon.CreateCosmosClient(); + response = await this.Container.ReadItemAsync(testItem.id, new Cosmos.PartitionKey(testItem.pk)); + trace = ((CosmosTraceDiagnostics)response.Diagnostics).Value; + clientConfigurationTraceDatum = (ClientConfigurationTraceDatum)trace.Data["Client Configuration"]; + Assert.IsNotNull(clientConfigurationTraceDatum.SerializedJson); + } + } +} diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Tracing/EndToEndTraceWriterBaselineTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Tracing/EndToEndTraceWriterBaselineTests.cs index 67670c2ad9..c9b5cf6917 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Tracing/EndToEndTraceWriterBaselineTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Tracing/EndToEndTraceWriterBaselineTests.cs @@ -77,17 +77,18 @@ public async Task ReadFeedAsync() FeedIteratorInternal feedIterator = (FeedIteratorInternal)container.GetItemQueryStreamIterator( queryText: null); - Trace rootTrace; - using (rootTrace = Trace.GetRootTrace("Root Trace")) + List traces = new List(); + while (feedIterator.HasMoreResults) { - while (feedIterator.HasMoreResults) - { - await feedIterator.ReadNextAsync(rootTrace, cancellationToken: default); - } + ResponseMessage responseMessage = await feedIterator.ReadNextAsync(cancellationToken: default); + ITrace trace = ((CosmosTraceDiagnostics)responseMessage.Diagnostics).Value; + traces.Add(trace); } + + ITrace traceForest = TraceJoiner.JoinTraces(traces); endLineNumber = GetLineNumber(); - inputs.Add(new Input("ReadFeed", rootTrace, startLineNumber, endLineNumber)); + inputs.Add(new Input("ReadFeed", traceForest, startLineNumber, endLineNumber)); } //---------------------------------------------------------------- @@ -99,17 +100,18 @@ public async Task ReadFeedAsync() FeedIteratorInternal feedIterator = (FeedIteratorInternal)container .GetItemQueryIterator(queryText: null); - Trace rootTrace; - using (rootTrace = Trace.GetRootTrace("Root Trace")) + List traces = new List(); + while (feedIterator.HasMoreResults) { - while (feedIterator.HasMoreResults) - { - await feedIterator.ReadNextAsync(rootTrace, cancellationToken: default); - } + FeedResponse response = await feedIterator.ReadNextAsync(cancellationToken: default); + ITrace trace = ((CosmosTraceDiagnostics)response.Diagnostics).Value; + traces.Add(trace); } + + ITrace traceForest = TraceJoiner.JoinTraces(traces); endLineNumber = GetLineNumber(); - inputs.Add(new Input("ReadFeed Typed", rootTrace, startLineNumber, endLineNumber)); + inputs.Add(new Input("ReadFeed Typed", traceForest, startLineNumber, endLineNumber)); } //---------------------------------------------------------------- @@ -182,21 +184,22 @@ public async Task ChangeFeedAsync() ChangeFeedStartFrom.Beginning(), ChangeFeedMode.Incremental); - TraceForBaselineTesting rootTrace; - using (rootTrace = TraceForBaselineTesting.GetRootTrace()) + List traces = new List(); + while (feedIterator.HasMoreResults) { - while (feedIterator.HasMoreResults) + ResponseMessage responseMessage = await feedIterator.ReadNextAsync(cancellationToken: default); + ITrace trace = ((CosmosTraceDiagnostics)responseMessage.Diagnostics).Value; + traces.Add(trace); + if (responseMessage.StatusCode == System.Net.HttpStatusCode.NotModified) { - ResponseMessage responseMessage = await feedIterator.ReadNextAsync(rootTrace, cancellationToken: default); - if (responseMessage.StatusCode == System.Net.HttpStatusCode.NotModified) - { - break; - } + break; } } + + ITrace traceForest = TraceJoiner.JoinTraces(traces); endLineNumber = GetLineNumber(); - inputs.Add(new Input("ChangeFeed", rootTrace, startLineNumber, endLineNumber)); + inputs.Add(new Input("ChangeFeed", traceForest, startLineNumber, endLineNumber)); } //---------------------------------------------------------------- @@ -210,24 +213,25 @@ public async Task ChangeFeedAsync() ChangeFeedStartFrom.Beginning(), ChangeFeedMode.Incremental); - TraceForBaselineTesting rootTrace; - using (rootTrace = TraceForBaselineTesting.GetRootTrace()) + List traces = new List(); + while (feedIterator.HasMoreResults) { - while (feedIterator.HasMoreResults) + try { - try - { - FeedResponse responseMessage = await feedIterator.ReadNextAsync(rootTrace, cancellationToken: default); - } - catch (CosmosException ce) when (ce.StatusCode == System.Net.HttpStatusCode.NotModified) - { - break; - } + FeedResponse responseMessage = await feedIterator.ReadNextAsync(cancellationToken: default); + ITrace trace = ((CosmosTraceDiagnostics)responseMessage.Diagnostics).Value; + traces.Add(trace); + } + catch (CosmosException ce) when (ce.StatusCode == System.Net.HttpStatusCode.NotModified) + { + break; } } + + ITrace traceForest = TraceJoiner.JoinTraces(traces); endLineNumber = GetLineNumber(); - inputs.Add(new Input("ChangeFeed Typed", rootTrace, startLineNumber, endLineNumber)); + inputs.Add(new Input("ChangeFeed Typed", traceForest, startLineNumber, endLineNumber)); } //---------------------------------------------------------------- @@ -314,17 +318,18 @@ public async Task QueryAsync() FeedIteratorInternal feedIterator = (FeedIteratorInternal)container.GetItemQueryStreamIterator( queryText: "SELECT * FROM c"); - Trace rootTrace; - using (rootTrace = Trace.GetRootTrace("Root Trace")) + List traces = new List(); + while (feedIterator.HasMoreResults) { - while (feedIterator.HasMoreResults) - { - await feedIterator.ReadNextAsync(rootTrace, cancellationToken: default); - } + ResponseMessage responseMessage = await feedIterator.ReadNextAsync(cancellationToken: default); + ITrace trace = ((CosmosTraceDiagnostics)responseMessage.Diagnostics).Value; + traces.Add(trace); } + + ITrace traceForest = TraceJoiner.JoinTraces(traces); endLineNumber = GetLineNumber(); - inputs.Add(new Input("Query", rootTrace, startLineNumber, endLineNumber)); + inputs.Add(new Input("Query", traceForest, startLineNumber, endLineNumber)); } //---------------------------------------------------------------- @@ -336,17 +341,18 @@ public async Task QueryAsync() FeedIteratorInternal feedIterator = (FeedIteratorInternal)container.GetItemQueryIterator( queryText: "SELECT * FROM c"); - Trace rootTrace; - using (rootTrace = Trace.GetRootTrace("Root Trace")) + List traces = new List(); + while (feedIterator.HasMoreResults) { - while (feedIterator.HasMoreResults) - { - await feedIterator.ReadNextAsync(rootTrace, cancellationToken: default); - } + FeedResponse response = await feedIterator.ReadNextAsync(cancellationToken: default); + ITrace trace = ((CosmosTraceDiagnostics)response.Diagnostics).Value; + traces.Add(trace); } + + ITrace traceForest = TraceJoiner.JoinTraces(traces); endLineNumber = GetLineNumber(); - inputs.Add(new Input("Query Typed", rootTrace, startLineNumber, endLineNumber)); + inputs.Add(new Input("Query Typed", traceForest, startLineNumber, endLineNumber)); } //---------------------------------------------------------------- From 8bf3857ff0c6bbe5c4ce6197cc82aeca3c9e684d Mon Sep 17 00:00:00 2001 From: Jason Hunter Date: Tue, 30 Mar 2021 17:14:39 -0700 Subject: [PATCH 18/19] Dependencies: Adds dependency update to System.Threading.Tasks.Extensions and System.Memory to 4.5.4 and System.Runtime.CompilerServices.Unsafe 4.5.3 (#2348) * Update Microsoft.Azure.Cosmos.csproj * Update DirectContractTests.cs Update tests. * Update Microsoft.Azure.Cosmos.csproj Update Extensions as well. * Update DirectContractTests.cs Update extensions in test. * Update Directory.Build.props Update HybridRow package version. Co-authored-by: j82w Co-authored-by: Matias Quaranta --- Directory.Build.props | 2 +- Microsoft.Azure.Cosmos/src/Microsoft.Azure.Cosmos.csproj | 6 +++--- .../Contracts/DirectContractTests.cs | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index c28e3aa475..e1ece61d84 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -6,7 +6,7 @@ preview 3.17.2 1.0.0-previewV13 - 1.1.0-preview1 + 1.1.0-preview3 $([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../')) $(DefineConstants);PREVIEW diff --git a/Microsoft.Azure.Cosmos/src/Microsoft.Azure.Cosmos.csproj b/Microsoft.Azure.Cosmos/src/Microsoft.Azure.Cosmos.csproj index 68b3461260..8737300fd5 100644 --- a/Microsoft.Azure.Cosmos/src/Microsoft.Azure.Cosmos.csproj +++ b/Microsoft.Azure.Cosmos/src/Microsoft.Azure.Cosmos.csproj @@ -130,10 +130,10 @@ - + - - + + diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DirectContractTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DirectContractTests.cs index c93a0689a1..968ecc6823 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DirectContractTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DirectContractTests.cs @@ -102,10 +102,10 @@ public void ProjectPackageDependenciesTest() { "Newtonsoft.Json", new Version(10, 0, 2) }, { "Microsoft.Bcl.AsyncInterfaces", new Version(1, 0, 0) }, { "System.Configuration.ConfigurationManager", new Version(4, 5, 0) }, - { "System.Memory", new Version(4, 5, 3) }, + { "System.Memory", new Version(4, 5, 4) }, { "System.Buffers", new Version(4, 5, 1) }, - { "System.Runtime.CompilerServices.Unsafe", new Version(4, 5, 2) }, - { "System.Threading.Tasks.Extensions", new Version(4, 5, 2) }, + { "System.Runtime.CompilerServices.Unsafe", new Version(4, 5, 3) }, + { "System.Threading.Tasks.Extensions", new Version(4, 5, 4) }, { "System.ValueTuple", new Version(4, 5, 0) }, { "Microsoft.Bcl.HashCode", new Version(1, 1, 0) }, { "Azure.Core", new Version(1, 3, 0) }, From 95793b5d04bc4c717d91d4f8cfa84e002faefd93 Mon Sep 17 00:00:00 2001 From: Matias Quaranta Date: Thu, 1 Apr 2021 08:10:02 -0700 Subject: [PATCH 19/19] Samples: Adds change feed estimator detailed sample (#2358) * adding sample * text adjustment --- .../Usage/ChangeFeed/Program.cs | 89 ++++++++++++++++++- 1 file changed, 87 insertions(+), 2 deletions(-) diff --git a/Microsoft.Azure.Cosmos.Samples/Usage/ChangeFeed/Program.cs b/Microsoft.Azure.Cosmos.Samples/Usage/ChangeFeed/Program.cs index c9b480b4c2..a003ca73c5 100644 --- a/Microsoft.Azure.Cosmos.Samples/Usage/ChangeFeed/Program.cs +++ b/Microsoft.Azure.Cosmos.Samples/Usage/ChangeFeed/Program.cs @@ -68,9 +68,11 @@ static async Task Main(string[] args) await Program.RunStartTimeChangeFeed("changefeed-time", client); Console.WriteLine($"\n3. Listening for changes that happen since the container was created."); await Program.RunStartFromBeginningChangeFeed("changefeed-beginning", client); - Console.WriteLine($"\n4. Generate Estimator metrics to expose current Change Feed Processor progress."); + Console.WriteLine($"\n4. Generate Estimator metrics to expose current Change Feed Processor progress as a push notification."); await Program.RunEstimatorChangeFeed("changefeed-estimator", client); - Console.WriteLine($"\n5. Code migration template from existing Change Feed Processor library V2."); + Console.WriteLine($"\n5. Generate Estimator metrics to expose current Change Feed Processor progress on demand."); + await Program.RunEstimatorPullChangeFeed("changefeed-estimator-detailed", client); + Console.WriteLine($"\n6. Code migration template from existing Change Feed Processor library V2."); await Program.RunMigrationSample("changefeed-migration", client, configuration); } } @@ -249,6 +251,89 @@ public static async Task RunEstimatorChangeFeed( await changeFeedEstimator.StopAsync(); } + /// + /// Exposing progress with the Estimator with the detailed iterator. + /// + /// + /// The Estimator uses the same processorName and the same lease configuration as the existing processor to measure progress. + /// The iterator exposes detailed, per-lease, information on estimation and ownership. + /// + public static async Task RunEstimatorPullChangeFeed( + string databaseId, + CosmosClient client) + { + await Program.InitializeAsync(databaseId, client); + + // + Container leaseContainer = client.GetContainer(databaseId, Program.leasesContainer); + Container monitoredContainer = client.GetContainer(databaseId, Program.monitoredContainer); + ChangeFeedProcessor changeFeedProcessor = monitoredContainer + .GetChangeFeedProcessorBuilder("changeFeedEstimator", Program.HandleChangesAsync) + .WithInstanceName("consoleHost") + .WithLeaseContainer(leaseContainer) + .Build(); + // + + Console.WriteLine($"Starting Change Feed Processor..."); + await changeFeedProcessor.StartAsync(); + Console.WriteLine("Change Feed Processor started."); + + // Wait some seconds for instances to acquire leases + await Task.Delay(5000); + + Console.WriteLine("Generating 10 items that will be picked up by the delegate..."); + await Program.GenerateItems(10, client.GetContainer(databaseId, Program.monitoredContainer)); + + // Wait random time for the delegate to output all messages after initialization is done + await Task.Delay(5000); + + // + ChangeFeedEstimator changeFeedEstimator = monitoredContainer + .GetChangeFeedEstimator("changeFeedEstimator", leaseContainer); + // + + // + Console.WriteLine("Checking estimation..."); + using FeedIterator estimatorIterator = changeFeedEstimator.GetCurrentStateIterator(); + while (estimatorIterator.HasMoreResults) + { + FeedResponse states = await estimatorIterator.ReadNextAsync(); + foreach (ChangeFeedProcessorState leaseState in states) + { + string host = leaseState.InstanceName == null ? $"not owned by any host currently" : $"owned by host {leaseState.InstanceName}"; + Console.WriteLine($"Lease [{leaseState.LeaseToken}] {host} reports {leaseState.EstimatedLag} as estimated lag."); + } + } + // + + Console.WriteLine("Stopping processor to show how the lag increases if no processing is happening."); + await changeFeedProcessor.StopAsync(); + + // Wait for processor to shutdown completely so the next items generate lag + await Task.Delay(5000); + + Console.WriteLine("Generating 10 items that will be seen by the Estimator..."); + await Program.GenerateItems(10, client.GetContainer(databaseId, Program.monitoredContainer)); + + Console.WriteLine("Checking estimation..."); + using FeedIterator estimatorIteratorAfter = changeFeedEstimator.GetCurrentStateIterator(); + while (estimatorIteratorAfter.HasMoreResults) + { + FeedResponse states = await estimatorIteratorAfter.ReadNextAsync(); + foreach (ChangeFeedProcessorState leaseState in states) + { + // Host ownership should be empty as we have already stopped the estimator + string host = leaseState.InstanceName == null ? $"not owned by any host currently" : $"owned by host {leaseState.InstanceName}"; + Console.WriteLine($"Lease [{leaseState.LeaseToken}] {host} reports {leaseState.EstimatedLag} as estimated lag."); + } + } + + + + Console.WriteLine("Press any key to continue with the next demo..."); + Console.ReadKey(); + } + /// /// Example of a code migration template from Change Feed Processor V2 to SDK V3. ///