diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 5176442..4ba3267 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -14,7 +14,7 @@ jobs: matrix: # TODO: Test against latest previews too. This currently doesn't work because preview releases don't publish # a milvus-standalone-docker-compose.yml - milvus_version: [v2.3.0] + milvus_version: [v2.3.10] steps: - name: Checkout diff --git a/Milvus.Client.Tests/CollectionTests.cs b/Milvus.Client.Tests/CollectionTests.cs index 56dbd5c..d32a03f 100644 --- a/Milvus.Client.Tests/CollectionTests.cs +++ b/Milvus.Client.Tests/CollectionTests.cs @@ -308,8 +308,9 @@ public async Task Create_in_non_existing_database_fails() "foo", new[] { FieldSchema.Create("id", isPrimaryKey: true) })); - Assert.Equal(MilvusErrorCode.UnexpectedError, exception.ErrorCode); - Assert.Equal("ErrorCode: UnexpectedError Reason: database:non_existing_db not found", exception.Message); + // Expected: UnexpectedError, Actual: 65535 + // Assert.Equal(MilvusErrorCode.UnexpectedError, exception.ErrorCode); + Assert.Equal("ErrorCode: 65535 Reason: database:non_existing_db not found", exception.Message); } public CollectionTests(MilvusFixture milvusFixture) diff --git a/Milvus.Client.Tests/DataTests.cs b/Milvus.Client.Tests/DataTests.cs index 68311c4..6460fad 100644 --- a/Milvus.Client.Tests/DataTests.cs +++ b/Milvus.Client.Tests/DataTests.cs @@ -25,19 +25,15 @@ public async Task Insert_Drop() Assert.Equal(2, Assert.Single(result.Data)); mutationResult = await Collection.DeleteAsync("id in [2]"); - Assert.Collection(mutationResult.Ids.LongIds!, i => Assert.Equal(2, i)); + // Starting with Milvus 2.3.2, Delete no longer seems to return the deleted IDs + // Assert.Collection(mutationResult.Ids.LongIds!, i => Assert.Equal(2, i)); Assert.Equal(1, mutationResult.DeleteCount); Assert.Equal(0, mutationResult.InsertCount); Assert.Equal(0, mutationResult.UpsertCount); - ulong timestamp = mutationResult.Timestamp; results = await Collection.QueryAsync( "id in [2]", - new() - { - ConsistencyLevel = ConsistencyLevel.Customized, - GuaranteeTimestamp = timestamp - }); + new() { ConsistencyLevel = ConsistencyLevel.Strong }); result = Assert.IsType>(Assert.Single(results)); Assert.Empty(result.Data); } @@ -110,13 +106,6 @@ public async Task Collection_waitForFlush() [Fact] public async Task FlushAllAsync_and_wait() { - // Waiting for FlushAllAsync can take around a minute. - // To make the developer inner loop quicker, we run this test only on CI. - if (Environment.GetEnvironmentVariable("CI") == null) - { - return; - } - await InsertDataAsync(9, 10); // Flush all @@ -130,7 +119,7 @@ public async Task FlushAllAsync_and_wait() await Client.WaitForFlushAllAsync(timestamp); IEnumerable segmentInfos = await Collection.GetPersistentSegmentInfosAsync(); - Assert.True(segmentInfos.All(p => p.State == SegmentState.Flushed)); + Assert.True(segmentInfos.All(p => p.State is SegmentState.Flushed or SegmentState.Sealed)); } [Fact] diff --git a/Milvus.Client.Tests/IndexTests.cs b/Milvus.Client.Tests/IndexTests.cs index 7b2f105..2963383 100644 --- a/Milvus.Client.Tests/IndexTests.cs +++ b/Milvus.Client.Tests/IndexTests.cs @@ -170,7 +170,7 @@ await Collection.CreateIndexAsync( MilvusException exception = await Assert.ThrowsAsync( () => Collection.DescribeIndexAsync("float_vector")); - Assert.Equal(MilvusErrorCode.IndexNotExist, exception.ErrorCode); + Assert.Equal(MilvusErrorCode.IndexNotFound, exception.ErrorCode); } public async Task InitializeAsync() diff --git a/Milvus.Client.Tests/TestContainer/MilvusBuilder.cs b/Milvus.Client.Tests/TestContainer/MilvusBuilder.cs index 959df0e..b288cf9 100644 --- a/Milvus.Client.Tests/TestContainer/MilvusBuilder.cs +++ b/Milvus.Client.Tests/TestContainer/MilvusBuilder.cs @@ -8,7 +8,7 @@ namespace Milvus.Client.Tests.TestContainer; public class MilvusBuilder : ContainerBuilder { - public const string MilvusImage = "milvusdb/milvus:v2.3.0"; // TODO: Configurable + public const string MilvusImage = "milvusdb/milvus:v2.3.10"; // TODO: Configurable public const ushort MilvusGrpcPort = 19530; public const ushort MilvusManagementPort = 9091; diff --git a/Milvus.Client.sln.DotSettings b/Milvus.Client.sln.DotSettings index c58c0e2..b7ffb9a 100644 --- a/Milvus.Client.sln.DotSettings +++ b/Milvus.Client.sln.DotSettings @@ -1,6 +1,7 @@  True True + True True True True diff --git a/Milvus.Client/Milvus.Client.csproj b/Milvus.Client/Milvus.Client.csproj index 8b52e53..7972c88 100644 --- a/Milvus.Client/Milvus.Client.csproj +++ b/Milvus.Client/Milvus.Client.csproj @@ -31,6 +31,7 @@ + diff --git a/Milvus.Client/MilvusClient.Collection.cs b/Milvus.Client/MilvusClient.Collection.cs index e4da673..d37a354 100644 --- a/Milvus.Client/MilvusClient.Collection.cs +++ b/Milvus.Client/MilvusClient.Collection.cs @@ -114,7 +114,9 @@ public async Task CreateCollectionAsync( grpcCollectionSchema.Fields.Add(grpcField); } +#pragma warning disable CS0612 // Schema-level AutoID is obsolete, but still there in pymilvus grpcCollectionSchema.AutoID = schema.Fields.Any(static p => p.AutoId); +#pragma warning restore CS0612 // Type or member is obsolete var request = new CreateCollectionRequest { @@ -169,6 +171,8 @@ await InvokeAsync(GrpcClient.HasCollectionAsync, request, static r => r.Status, /// /// The token to monitor for cancellation requests. The default value is . /// + // ShowType and CollectionNames are obsolete, but seem required and is still used in pymilvus +#pragma warning disable CS0612 public async Task> ListCollectionsAsync( IReadOnlyList? collectionNames = null, CollectionFilter filter = CollectionFilter.All, @@ -200,6 +204,7 @@ await InvokeAsync(GrpcClient.ShowCollectionsAsync, request, static r => r.Status return collections; } +#pragma warning restore CS0612 /// /// Flushes collection data to disk, required only in order to get up-to-date statistics. diff --git a/Milvus.Client/MilvusClient.cs b/Milvus.Client/MilvusClient.cs index 750833b..91db86f 100644 --- a/Milvus.Client/MilvusClient.cs +++ b/Milvus.Client/MilvusClient.cs @@ -318,8 +318,7 @@ await GrpcClient.CheckHealthAsync(new CheckHealthRequest(), _log.HealthCheckFailed(response.Reasons); } - return new MilvusHealthState(response.IsHealthy, response.Status.Reason, - (MilvusErrorCode)response.Status.ErrorCode); + return new MilvusHealthState(response.IsHealthy, response.Status.Reason, (MilvusErrorCode)response.Status.Code); } /// @@ -378,12 +377,13 @@ internal async Task InvokeAsync( TResponse response = await func(request, _callOptions.WithCancellationToken(cancellationToken)).ConfigureAwait(false); Grpc.Status status = getStatus(response); + var code = (MilvusErrorCode)status.Code; - if (status.ErrorCode != Grpc.ErrorCode.Success) + if (code != MilvusErrorCode.Success) { - _log.OperationFailed(callerName, (MilvusErrorCode)status.ErrorCode, status.Reason); + _log.OperationFailed(callerName, code, status.Reason); - throw new MilvusException((MilvusErrorCode)status.ErrorCode, status.Reason); + throw new MilvusException(code, status.Reason); } return response; diff --git a/Milvus.Client/MilvusCollection.Entity.cs b/Milvus.Client/MilvusCollection.Entity.cs index acefa58..2084cd7 100644 --- a/Milvus.Client/MilvusCollection.Entity.cs +++ b/Milvus.Client/MilvusCollection.Entity.cs @@ -453,7 +453,7 @@ await _client.InvokeAsync(_client.GrpcClient.GetQuerySegmentInfoAsync, request, .ConfigureAwait(false); return response.Infos.Select(i => new QuerySegmentInfoResult( - i.CollectionID, i.IndexName, i.IndexID, i.MemSize, i.NodeID, i.NumRows, i.PartitionID, i.SegmentID, + i.CollectionID, i.IndexName, i.IndexID, i.MemSize, i.NodeIds, i.NumRows, i.PartitionID, i.SegmentID, (SegmentState)i.State)) .ToList(); } diff --git a/Milvus.Client/MilvusCollection.Partition.cs b/Milvus.Client/MilvusCollection.Partition.cs index 5f2d270..8e83d89 100644 --- a/Milvus.Client/MilvusCollection.Partition.cs +++ b/Milvus.Client/MilvusCollection.Partition.cs @@ -64,11 +64,11 @@ await _client.InvokeAsync(_client.GrpcClient.ShowPartitionsAsync, request, stati { for (int i = 0; i < response.PartitionIDs.Count; i++) { - partitions.Add(new MilvusPartition( - response.PartitionIDs[i], - response.PartitionNames[i], - response.CreatedUtcTimestamps[i], - response.InMemoryPercentages?.Count > 0 ? response.InMemoryPercentages[i] : -1)); + partitions.Add( + new MilvusPartition( + response.PartitionIDs[i], + response.PartitionNames[i], + response.CreatedUtcTimestamps[i])); } } diff --git a/Milvus.Client/MilvusErrorCode.cs b/Milvus.Client/MilvusErrorCode.cs index 243703c..8787ffe 100644 --- a/Milvus.Client/MilvusErrorCode.cs +++ b/Milvus.Client/MilvusErrorCode.cs @@ -7,76 +7,10 @@ namespace Milvus.Client; /// public enum MilvusErrorCode { - Success = Grpc.ErrorCode.Success, - UnexpectedError = Grpc.ErrorCode.UnexpectedError, - ConnectFailed = Grpc.ErrorCode.ConnectFailed, - PermissionDenied = Grpc.ErrorCode.PermissionDenied, - CollectionNotExists = Grpc.ErrorCode.CollectionNotExists, - IllegalArgument = Grpc.ErrorCode.IllegalArgument, - IllegalDimension = Grpc.ErrorCode.IllegalDimension, - IllegalIndexType = Grpc.ErrorCode.IllegalIndexType, - IllegalCollectionName = Grpc.ErrorCode.IllegalCollectionName, - IllegalTopk = Grpc.ErrorCode.IllegalTopk, - IllegalRowRecord = Grpc.ErrorCode.IllegalRowRecord, - IllegalVectorId = Grpc.ErrorCode.IllegalVectorId, - IllegalSearchResult = Grpc.ErrorCode.IllegalSearchResult, - FileNotFound = Grpc.ErrorCode.FileNotFound, - MetaFailed = Grpc.ErrorCode.MetaFailed, - CacheFailed = Grpc.ErrorCode.CacheFailed, - CannotCreateFolder = Grpc.ErrorCode.CannotCreateFolder, - CannotCreateFile = Grpc.ErrorCode.CannotCreateFile, - CannotDeleteFolder = Grpc.ErrorCode.CannotDeleteFolder, - CannotDeleteFile = Grpc.ErrorCode.CannotDeleteFile, - BuildIndexError = Grpc.ErrorCode.BuildIndexError, - IllegalNlist = Grpc.ErrorCode.IllegalNlist, - IllegalMetricType = Grpc.ErrorCode.IllegalMetricType, - OutOfMemory = Grpc.ErrorCode.OutOfMemory, - IndexNotExist = Grpc.ErrorCode.IndexNotExist, - EmptyCollection = Grpc.ErrorCode.EmptyCollection, - UpdateImportTaskFailure = Grpc.ErrorCode.UpdateImportTaskFailure, - CollectionNameNotFound = Grpc.ErrorCode.CollectionNameNotFound, - CreateCredentialFailure = Grpc.ErrorCode.CreateCredentialFailure, - UpdateCredentialFailure = Grpc.ErrorCode.UpdateCredentialFailure, - DeleteCredentialFailure = Grpc.ErrorCode.DeleteCredentialFailure, - GetCredentialFailure = Grpc.ErrorCode.GetCredentialFailure, - ListCredUsersFailure = Grpc.ErrorCode.ListCredUsersFailure, - GetUserFailure = Grpc.ErrorCode.GetUserFailure, - CreateRoleFailure = Grpc.ErrorCode.CreateRoleFailure, - DropRoleFailure = Grpc.ErrorCode.DropRoleFailure, - OperateUserRoleFailure = Grpc.ErrorCode.OperateUserRoleFailure, - SelectRoleFailure = Grpc.ErrorCode.SelectRoleFailure, - SelectUserFailure = Grpc.ErrorCode.SelectUserFailure, - SelectResourceFailure = Grpc.ErrorCode.SelectResourceFailure, - OperatePrivilegeFailure = Grpc.ErrorCode.OperatePrivilegeFailure, - SelectGrantFailure = Grpc.ErrorCode.SelectGrantFailure, - RefreshPolicyInfoCacheFailure = Grpc.ErrorCode.RefreshPolicyInfoCacheFailure, - ListPolicyFailure = Grpc.ErrorCode.ListPolicyFailure, - NotShardLeader = Grpc.ErrorCode.NotShardLeader, - NoReplicaAvailable = Grpc.ErrorCode.NoReplicaAvailable, - SegmentNotFound = Grpc.ErrorCode.SegmentNotFound, - ForceDeny = Grpc.ErrorCode.ForceDeny, - RateLimit = Grpc.ErrorCode.RateLimit, - NodeIdnotMatch = Grpc.ErrorCode.NodeIdnotMatch, - UpsertAutoIdtrue = Grpc.ErrorCode.UpsertAutoIdtrue, - InsufficientMemoryToLoad = Grpc.ErrorCode.InsufficientMemoryToLoad, - MemoryQuotaExhausted = Grpc.ErrorCode.MemoryQuotaExhausted, - DiskQuotaExhausted = Grpc.ErrorCode.DiskQuotaExhausted, - TimeTickLongDelay = Grpc.ErrorCode.TimeTickLongDelay, - NotReadyServe = Grpc.ErrorCode.NotReadyServe, - - /// - /// Coord is switching from standby mode to active mode - /// - NotReadyCoordActivating = Grpc.ErrorCode.NotReadyCoordActivating, - - /// - /// Service availability. - /// NA: Not Available. - /// - DataCoordNa = Grpc.ErrorCode.DataCoordNa, - - /// - /// Internal error code. - /// - DdrequestRace = Grpc.ErrorCode.DdrequestRace + Success = 0, + UnexpectedError = 1, + RateLimit = 8, + ForceDeny = 9, + CollectionNotFound = 100, + IndexNotFound = 700 } diff --git a/Milvus.Client/MilvusPartition.cs b/Milvus.Client/MilvusPartition.cs index 38a3c7a..6242c46 100644 --- a/Milvus.Client/MilvusPartition.cs +++ b/Milvus.Client/MilvusPartition.cs @@ -12,13 +12,11 @@ public sealed class MilvusPartition internal MilvusPartition( long partitionId, string partitionName, - ulong creationTimestamp, - long inMemoryPercentage) + ulong creationTimestamp) { PartitionId = partitionId; PartitionName = partitionName; CreationTimestamp = creationTimestamp; - InMemoryPercentage = inMemoryPercentage; } /// @@ -31,11 +29,6 @@ internal MilvusPartition( /// public string PartitionName { get; } - /// - /// Load percentage on query node. - /// - public long InMemoryPercentage { get; } - /// /// An opaque identifier for the point in time in which the partition was created. Can be passed to /// or as a guarantee @@ -50,5 +43,5 @@ internal MilvusPartition( /// Return string value of . /// public override string ToString() - => $"MilvusPartition: {{{nameof(PartitionName)}: {PartitionName}, {nameof(PartitionId)}: {PartitionId}, {nameof(CreationTimestamp)}:{CreationTimestamp}, {nameof(InMemoryPercentage)}: {InMemoryPercentage}}}"; + => $"MilvusPartition: {{{nameof(PartitionName)}: {PartitionName}, {nameof(PartitionId)}: {PartitionId}, {nameof(CreationTimestamp)}:{CreationTimestamp}}}"; } diff --git a/Milvus.Client/Protos b/Milvus.Client/Protos index 04a979a..9ed8fb4 160000 --- a/Milvus.Client/Protos +++ b/Milvus.Client/Protos @@ -1 +1 @@ -Subproject commit 04a979a79cdf370821d0c30a70828c995a3e781e +Subproject commit 9ed8fb405005c2a2cdb10d30276d8bec9334b023 diff --git a/Milvus.Client/QuerySegmentResult.cs b/Milvus.Client/QuerySegmentResult.cs index 1c4e1d7..b840e65 100644 --- a/Milvus.Client/QuerySegmentResult.cs +++ b/Milvus.Client/QuerySegmentResult.cs @@ -10,7 +10,7 @@ internal QuerySegmentInfoResult( string indexName, long indexId, long memSize, - long nodeId, + IReadOnlyList nodeIds, long numRows, long partitionId, long segmentId, @@ -20,7 +20,7 @@ internal QuerySegmentInfoResult( IndexName = indexName; IndexId = indexId; MemSize = memSize; - NodeId = nodeId; + NodeIds = nodeIds; NumRows = numRows; PartitionId = partitionId; SegmentId = segmentId; @@ -50,7 +50,7 @@ internal QuerySegmentInfoResult( /// /// Node id. /// - public long NodeId { get; } + public IReadOnlyList NodeIds { get; } /// /// Number of rows.