From 9011e5f72fa8f6e1410c44a5953aa8654a153ab7 Mon Sep 17 00:00:00 2001 From: Andrew Prudhomme Date: Mon, 30 Oct 2023 14:56:57 -0700 Subject: [PATCH] Remove legacy Archiver and backup api --- .../proto/yelp/nrtsearch/luceneserver.proto | 42 - .../lucene_server_configuration_primary.yaml | 2 - .../lucene_server_configuration_replica.yaml | 2 - docs/server_configuration.rst | 12 - grpc-gateway/luceneserver.pb.go | 2644 +++++++---------- grpc-gateway/luceneserver.pb.gw.go | 162 - grpc-gateway/luceneserver.swagger.json | 143 - .../com/yelp/nrtsearch/ArchiverModule.java | 32 +- .../nrtsearch/server/backup/ArchiverImpl.java | 408 --- .../server/backup/ContentDownloaderImpl.java | 63 +- .../server/cli/BackupIndexCommand.java | 89 - .../server/cli/DeleteIndexBackupCommand.java | 80 - .../server/cli/LuceneClientCommand.java | 2 - .../nrtsearch/server/cli/RestoreHelper.java | 24 +- .../config/LuceneServerConfiguration.java | 12 - .../nrtsearch/server/grpc/LuceneServer.java | 100 +- .../server/grpc/LuceneServerClient.java | 29 - .../BackupIndexRequestHandler.java | 392 --- .../luceneserver/CreateSnapshotHandler.java | 44 + .../DeleteIndexBackupHandler.java | 121 - .../server/luceneserver/GlobalState.java | 27 +- .../server/luceneserver/IndexState.java | 17 +- .../luceneserver/ReleaseSnapshotHandler.java | 19 + .../luceneserver/StartIndexHandler.java | 56 +- .../index/BackendStateManager.java | 2 +- .../index/ImmutableIndexState.java | 15 +- .../state/BackendGlobalState.java | 26 +- .../server/luceneserver/warming/Warmer.java | 33 +- .../nrtsearch/server/module/S3Module.java | 66 +- .../server/plugins/PluginDownloader.java | 64 - .../server/plugins/PluginsService.java | 12 +- .../server/remote/PluginDownloader.java | 33 + .../server/remote/RemoteBackend.java | 65 + .../s3/S3Backend.java} | 152 +- .../remote/s3/S3ProgressListenerImpl.java | 83 + .../nrtsearch/server/remote/s3/S3Util.java | 136 + .../yelp/nrtsearch/server/utils/S3Util.java | 60 - .../incremental/IncrementalCommandUtils.java | 4 +- .../nrtsearch/server/backup/ArchiverTest.java | 380 --- .../nrtsearch/server/grpc/AckedCopyTest.java | 19 +- .../BackupRestoreIndexRequestHandlerTest.java | 391 --- .../server/grpc/FailedBackupCleanupTest.java | 313 -- .../nrtsearch/server/grpc/GrpcServer.java | 26 +- .../server/grpc/LuceneServerTest.java | 49 +- .../grpc/ReplicationFailureScenariosTest.java | 290 ++ .../server/grpc/ReplicationServerTest.java | 20 +- .../grpc/ReplicationTestFailureScenarios.java | 506 ---- .../server/grpc/StateBackendServerTest.java | 7 +- .../nrtsearch/server/grpc/TestServer.java | 68 +- .../server/grpc/WarmingQueriesTest.java | 29 +- .../DeleteIndexBackupHandlerTest.java | 161 - .../server/luceneserver/GlobalStateTest.java | 6 +- .../index/BackendStateManagerTest.java | 13 +- .../index/ImmutableIndexStateTest.java | 2 +- .../state/BackendGlobalStateTest.java | 6 +- .../luceneserver/warming/WarmerTest.java | 65 +- .../server/remote/s3/S3BackendTest.java | 390 +++ .../{utils => remote/s3}/S3UtilTest.java | 6 +- .../server/utils/S3DownloaderTest.java | 88 - .../test_utils/AmazonS3Provider.java | 4 + 60 files changed, 2527 insertions(+), 5585 deletions(-) delete mode 100644 src/main/java/com/yelp/nrtsearch/server/backup/ArchiverImpl.java delete mode 100644 src/main/java/com/yelp/nrtsearch/server/cli/BackupIndexCommand.java delete mode 100644 src/main/java/com/yelp/nrtsearch/server/cli/DeleteIndexBackupCommand.java delete mode 100644 src/main/java/com/yelp/nrtsearch/server/luceneserver/BackupIndexRequestHandler.java delete mode 100644 src/main/java/com/yelp/nrtsearch/server/luceneserver/DeleteIndexBackupHandler.java delete mode 100644 src/main/java/com/yelp/nrtsearch/server/plugins/PluginDownloader.java create mode 100644 src/main/java/com/yelp/nrtsearch/server/remote/PluginDownloader.java create mode 100644 src/main/java/com/yelp/nrtsearch/server/remote/RemoteBackend.java rename src/main/java/com/yelp/nrtsearch/server/{utils/S3Downloader.java => remote/s3/S3Backend.java} (50%) create mode 100644 src/main/java/com/yelp/nrtsearch/server/remote/s3/S3ProgressListenerImpl.java create mode 100644 src/main/java/com/yelp/nrtsearch/server/remote/s3/S3Util.java delete mode 100644 src/main/java/com/yelp/nrtsearch/server/utils/S3Util.java delete mode 100644 src/test/java/com/yelp/nrtsearch/server/backup/ArchiverTest.java delete mode 100644 src/test/java/com/yelp/nrtsearch/server/grpc/BackupRestoreIndexRequestHandlerTest.java delete mode 100644 src/test/java/com/yelp/nrtsearch/server/grpc/FailedBackupCleanupTest.java create mode 100644 src/test/java/com/yelp/nrtsearch/server/grpc/ReplicationFailureScenariosTest.java delete mode 100644 src/test/java/com/yelp/nrtsearch/server/grpc/ReplicationTestFailureScenarios.java delete mode 100644 src/test/java/com/yelp/nrtsearch/server/luceneserver/DeleteIndexBackupHandlerTest.java create mode 100644 src/test/java/com/yelp/nrtsearch/server/remote/s3/S3BackendTest.java rename src/test/java/com/yelp/nrtsearch/server/{utils => remote/s3}/S3UtilTest.java (91%) delete mode 100644 src/test/java/com/yelp/nrtsearch/server/utils/S3DownloaderTest.java diff --git a/clientlib/src/main/proto/yelp/nrtsearch/luceneserver.proto b/clientlib/src/main/proto/yelp/nrtsearch/luceneserver.proto index 5e7901cd9..b85516fa0 100644 --- a/clientlib/src/main/proto/yelp/nrtsearch/luceneserver.proto +++ b/clientlib/src/main/proto/yelp/nrtsearch/luceneserver.proto @@ -282,21 +282,6 @@ service LuceneServer { } - /* backs up a resource (index) and it associated metadata e.g. settings, schema to s3 */ - rpc backupIndex (BackupIndexRequest) returns (BackupIndexResponse) { - option (google.api.http) = { - post: "/v1/backup_index" - body: "*" - }; - } - - rpc deleteIndexBackup (DeleteIndexBackupRequest) returns (DeleteIndexBackupResponse) { - option (google.api.http) = { - post: "/v1/delete_index_backup" - body: "*" - }; - } - /* Backup warming queries to S3 */ rpc backupWarmingQueries (BackupWarmingQueriesRequest) returns (BackupWarmingQueriesResponse) { option (google.api.http) = { @@ -830,19 +815,6 @@ message GetAllSnapshotGenResponse { repeated int64 indexGens = 1; // list of snapshotted index gens } -message BackupIndexRequest { - string indexName = 1; //name of the index to backup - string serviceName = 2; // remote storage namespace qualifier for service - string resourceName = 3; //remote storage namespace qualifier for resource e.g. indexName - bool completeDirectory = 4; // backup complete directory including all current snapshots if true (may backup corrupt segments if backup is created while indexing is happening), otherwise only backup the required segments and segment files - bool stream = 5; // if the built tar should be directly streamed to s3, instead of being written to a file first (experimental) -} - -message BackupIndexResponse { - string dataVersionHash = 1; //version identifier for data on s3 - string metadataVersionHash = 2; //version identifier for metadata on s3 -} - message BackupWarmingQueriesRequest { string index = 1; // Index whose warming queries to backup string serviceName = 2; // remote storage namespace qualifier for service @@ -853,20 +825,6 @@ message BackupWarmingQueriesRequest { message BackupWarmingQueriesResponse { } -message DeleteIndexBackupRequest { - string indexName = 1; //name of the index to backup - string serviceName = 2; // remote storage namespace qualifier for service - string resourceName = 3; //remote storage namespace qualifier for resource e.g. indexName - int32 nDays = 4; //backups older than nDays will be deleted from s3 -} - -message DeleteIndexBackupResponse { - repeated string deletedResourceDataHashes = 1; // version hashes of deleted backups from {resource}_data folder - repeated string deletedResourceMetadataHashes = 2; // version hashes of deleted metadata of backups from {resource}_metadata folder - repeated string deletedDataVersions = 3; // versions of deleted backup data from _version/{resource}_data folder - repeated string deletedMetadataVersions = 4; // versions of deleted backup data from _version/{resource}_metadata folder -} - message IndicesRequest { } diff --git a/docker-compose-config/lucene_server_configuration_primary.yaml b/docker-compose-config/lucene_server_configuration_primary.yaml index 9bd391b48..da4b24a0e 100644 --- a/docker-compose-config/lucene_server_configuration_primary.yaml +++ b/docker-compose-config/lucene_server_configuration_primary.yaml @@ -13,6 +13,4 @@ bucketName: "nrtsearch-bucket" archiveDirectory: "/user/app/primary_index_archiver" serviceName: "nrtsearch-service-test" restoreState: False -restoreFromIncArchiver: "true" -backupWithIncArchiver: "true" downloadAsStream: "true" \ No newline at end of file diff --git a/docker-compose-config/lucene_server_configuration_replica.yaml b/docker-compose-config/lucene_server_configuration_replica.yaml index 348f16fa5..b36c38529 100644 --- a/docker-compose-config/lucene_server_configuration_replica.yaml +++ b/docker-compose-config/lucene_server_configuration_replica.yaml @@ -12,6 +12,4 @@ bucketName: "nrtsearch-bucket" archiveDirectory: "/user/app/replica_index_archiver" serviceName: "nrtsearch-service-test" restoreState: False -restoreFromIncArchiver: "true" -backupWithIncArchiver: "true" downloadAsStream: "true" \ No newline at end of file diff --git a/docs/server_configuration.rst b/docs/server_configuration.rst index 41857da76..6e9697bf8 100644 --- a/docs/server_configuration.rst +++ b/docs/server_configuration.rst @@ -27,8 +27,6 @@ Example server configuration archiveDirectory: "/user/app/primary_index_archiver" serviceName: "nrtsearch-service-test" restoreState: False - restoreFromIncArchiver: "true" - backupWithIncArchiver: "true" downloadAsStream: "true" @@ -101,16 +99,6 @@ Example server configuration - Enables loading state from external storage on startup - false - * - restoreFromIncArchiver - - bool - - If enabled, uses the incremental archiver when restoring index data and state - - false - - * - backupWithIncArchiver - - bool - - If enabled, uses the incremental archiver for backups - - false - * - deadlineCancellation - bool - Enables gRPC deadline based cancellation of requests. A request is cancelled early if it exceeds the deadline. Currently only supported by the search endpoint. diff --git a/grpc-gateway/luceneserver.pb.go b/grpc-gateway/luceneserver.pb.go index 247346d2c..f885583d2 100644 --- a/grpc-gateway/luceneserver.pb.go +++ b/grpc-gateway/luceneserver.pb.go @@ -436,7 +436,7 @@ func (x ForceMergeResponse_Status) Number() protoreflect.EnumNumber { // Deprecated: Use ForceMergeResponse_Status.Descriptor instead. func (ForceMergeResponse_Status) EnumDescriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{77, 0} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{73, 0} } type ForceMergeDeletesResponse_Status int32 @@ -482,7 +482,7 @@ func (x ForceMergeDeletesResponse_Status) Number() protoreflect.EnumNumber { // Deprecated: Use ForceMergeDeletesResponse_Status.Descriptor instead. func (ForceMergeDeletesResponse_Status) EnumDescriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{79, 0} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{75, 0} } // Input to createIndex @@ -3329,140 +3329,6 @@ func (x *GetAllSnapshotGenResponse) GetIndexGens() []int64 { return nil } -type BackupIndexRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - IndexName string `protobuf:"bytes,1,opt,name=indexName,proto3" json:"indexName,omitempty"` //name of the index to backup - ServiceName string `protobuf:"bytes,2,opt,name=serviceName,proto3" json:"serviceName,omitempty"` // remote storage namespace qualifier for service - ResourceName string `protobuf:"bytes,3,opt,name=resourceName,proto3" json:"resourceName,omitempty"` //remote storage namespace qualifier for resource e.g. indexName - CompleteDirectory bool `protobuf:"varint,4,opt,name=completeDirectory,proto3" json:"completeDirectory,omitempty"` // backup complete directory including all current snapshots if true (may backup corrupt segments if backup is created while indexing is happening), otherwise only backup the required segments and segment files - Stream bool `protobuf:"varint,5,opt,name=stream,proto3" json:"stream,omitempty"` // if the built tar should be directly streamed to s3, instead of being written to a file first (experimental) -} - -func (x *BackupIndexRequest) Reset() { - *x = BackupIndexRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[43] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *BackupIndexRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*BackupIndexRequest) ProtoMessage() {} - -func (x *BackupIndexRequest) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[43] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use BackupIndexRequest.ProtoReflect.Descriptor instead. -func (*BackupIndexRequest) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{43} -} - -func (x *BackupIndexRequest) GetIndexName() string { - if x != nil { - return x.IndexName - } - return "" -} - -func (x *BackupIndexRequest) GetServiceName() string { - if x != nil { - return x.ServiceName - } - return "" -} - -func (x *BackupIndexRequest) GetResourceName() string { - if x != nil { - return x.ResourceName - } - return "" -} - -func (x *BackupIndexRequest) GetCompleteDirectory() bool { - if x != nil { - return x.CompleteDirectory - } - return false -} - -func (x *BackupIndexRequest) GetStream() bool { - if x != nil { - return x.Stream - } - return false -} - -type BackupIndexResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - DataVersionHash string `protobuf:"bytes,1,opt,name=dataVersionHash,proto3" json:"dataVersionHash,omitempty"` //version identifier for data on s3 - MetadataVersionHash string `protobuf:"bytes,2,opt,name=metadataVersionHash,proto3" json:"metadataVersionHash,omitempty"` //version identifier for metadata on s3 -} - -func (x *BackupIndexResponse) Reset() { - *x = BackupIndexResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[44] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *BackupIndexResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*BackupIndexResponse) ProtoMessage() {} - -func (x *BackupIndexResponse) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[44] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use BackupIndexResponse.ProtoReflect.Descriptor instead. -func (*BackupIndexResponse) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{44} -} - -func (x *BackupIndexResponse) GetDataVersionHash() string { - if x != nil { - return x.DataVersionHash - } - return "" -} - -func (x *BackupIndexResponse) GetMetadataVersionHash() string { - if x != nil { - return x.MetadataVersionHash - } - return "" -} - type BackupWarmingQueriesRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3477,7 +3343,7 @@ type BackupWarmingQueriesRequest struct { func (x *BackupWarmingQueriesRequest) Reset() { *x = BackupWarmingQueriesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[45] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3490,7 +3356,7 @@ func (x *BackupWarmingQueriesRequest) String() string { func (*BackupWarmingQueriesRequest) ProtoMessage() {} func (x *BackupWarmingQueriesRequest) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[45] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[43] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3503,7 +3369,7 @@ func (x *BackupWarmingQueriesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BackupWarmingQueriesRequest.ProtoReflect.Descriptor instead. func (*BackupWarmingQueriesRequest) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{45} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{43} } func (x *BackupWarmingQueriesRequest) GetIndex() string { @@ -3543,7 +3409,7 @@ type BackupWarmingQueriesResponse struct { func (x *BackupWarmingQueriesResponse) Reset() { *x = BackupWarmingQueriesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[46] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3556,7 +3422,7 @@ func (x *BackupWarmingQueriesResponse) String() string { func (*BackupWarmingQueriesResponse) ProtoMessage() {} func (x *BackupWarmingQueriesResponse) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[46] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[44] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3569,149 +3435,7 @@ func (x *BackupWarmingQueriesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use BackupWarmingQueriesResponse.ProtoReflect.Descriptor instead. func (*BackupWarmingQueriesResponse) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{46} -} - -type DeleteIndexBackupRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - IndexName string `protobuf:"bytes,1,opt,name=indexName,proto3" json:"indexName,omitempty"` //name of the index to backup - ServiceName string `protobuf:"bytes,2,opt,name=serviceName,proto3" json:"serviceName,omitempty"` // remote storage namespace qualifier for service - ResourceName string `protobuf:"bytes,3,opt,name=resourceName,proto3" json:"resourceName,omitempty"` //remote storage namespace qualifier for resource e.g. indexName - NDays int32 `protobuf:"varint,4,opt,name=nDays,proto3" json:"nDays,omitempty"` //backups older than nDays will be deleted from s3 -} - -func (x *DeleteIndexBackupRequest) Reset() { - *x = DeleteIndexBackupRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[47] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *DeleteIndexBackupRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DeleteIndexBackupRequest) ProtoMessage() {} - -func (x *DeleteIndexBackupRequest) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[47] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DeleteIndexBackupRequest.ProtoReflect.Descriptor instead. -func (*DeleteIndexBackupRequest) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{47} -} - -func (x *DeleteIndexBackupRequest) GetIndexName() string { - if x != nil { - return x.IndexName - } - return "" -} - -func (x *DeleteIndexBackupRequest) GetServiceName() string { - if x != nil { - return x.ServiceName - } - return "" -} - -func (x *DeleteIndexBackupRequest) GetResourceName() string { - if x != nil { - return x.ResourceName - } - return "" -} - -func (x *DeleteIndexBackupRequest) GetNDays() int32 { - if x != nil { - return x.NDays - } - return 0 -} - -type DeleteIndexBackupResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - DeletedResourceDataHashes []string `protobuf:"bytes,1,rep,name=deletedResourceDataHashes,proto3" json:"deletedResourceDataHashes,omitempty"` // version hashes of deleted backups from {resource}_data folder - DeletedResourceMetadataHashes []string `protobuf:"bytes,2,rep,name=deletedResourceMetadataHashes,proto3" json:"deletedResourceMetadataHashes,omitempty"` // version hashes of deleted metadata of backups from {resource}_metadata folder - DeletedDataVersions []string `protobuf:"bytes,3,rep,name=deletedDataVersions,proto3" json:"deletedDataVersions,omitempty"` // versions of deleted backup data from _version/{resource}_data folder - DeletedMetadataVersions []string `protobuf:"bytes,4,rep,name=deletedMetadataVersions,proto3" json:"deletedMetadataVersions,omitempty"` // versions of deleted backup data from _version/{resource}_metadata folder -} - -func (x *DeleteIndexBackupResponse) Reset() { - *x = DeleteIndexBackupResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[48] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *DeleteIndexBackupResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DeleteIndexBackupResponse) ProtoMessage() {} - -func (x *DeleteIndexBackupResponse) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[48] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DeleteIndexBackupResponse.ProtoReflect.Descriptor instead. -func (*DeleteIndexBackupResponse) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{48} -} - -func (x *DeleteIndexBackupResponse) GetDeletedResourceDataHashes() []string { - if x != nil { - return x.DeletedResourceDataHashes - } - return nil -} - -func (x *DeleteIndexBackupResponse) GetDeletedResourceMetadataHashes() []string { - if x != nil { - return x.DeletedResourceMetadataHashes - } - return nil -} - -func (x *DeleteIndexBackupResponse) GetDeletedDataVersions() []string { - if x != nil { - return x.DeletedDataVersions - } - return nil -} - -func (x *DeleteIndexBackupResponse) GetDeletedMetadataVersions() []string { - if x != nil { - return x.DeletedMetadataVersions - } - return nil + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{44} } type IndicesRequest struct { @@ -3723,7 +3447,7 @@ type IndicesRequest struct { func (x *IndicesRequest) Reset() { *x = IndicesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[49] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3736,7 +3460,7 @@ func (x *IndicesRequest) String() string { func (*IndicesRequest) ProtoMessage() {} func (x *IndicesRequest) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[49] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[45] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3749,7 +3473,7 @@ func (x *IndicesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use IndicesRequest.ProtoReflect.Descriptor instead. func (*IndicesRequest) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{49} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{45} } type IndicesResponse struct { @@ -3763,7 +3487,7 @@ type IndicesResponse struct { func (x *IndicesResponse) Reset() { *x = IndicesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[50] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3776,7 +3500,7 @@ func (x *IndicesResponse) String() string { func (*IndicesResponse) ProtoMessage() {} func (x *IndicesResponse) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[50] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[46] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3789,7 +3513,7 @@ func (x *IndicesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use IndicesResponse.ProtoReflect.Descriptor instead. func (*IndicesResponse) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{50} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{46} } func (x *IndicesResponse) GetIndicesResponse() []*IndexStatsResponse { @@ -3811,7 +3535,7 @@ type IndexStatsResponse struct { func (x *IndexStatsResponse) Reset() { *x = IndexStatsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[51] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3824,7 +3548,7 @@ func (x *IndexStatsResponse) String() string { func (*IndexStatsResponse) ProtoMessage() {} func (x *IndexStatsResponse) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[51] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[47] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3837,7 +3561,7 @@ func (x *IndexStatsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use IndexStatsResponse.ProtoReflect.Descriptor instead. func (*IndexStatsResponse) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{51} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{47} } func (x *IndexStatsResponse) GetIndexName() string { @@ -3867,7 +3591,7 @@ type RestoreIndex struct { func (x *RestoreIndex) Reset() { *x = RestoreIndex{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[52] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3880,7 +3604,7 @@ func (x *RestoreIndex) String() string { func (*RestoreIndex) ProtoMessage() {} func (x *RestoreIndex) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[52] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[48] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3893,7 +3617,7 @@ func (x *RestoreIndex) ProtoReflect() protoreflect.Message { // Deprecated: Use RestoreIndex.ProtoReflect.Descriptor instead. func (*RestoreIndex) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{52} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{48} } func (x *RestoreIndex) GetServiceName() string { @@ -3928,7 +3652,7 @@ type StateRequest struct { func (x *StateRequest) Reset() { *x = StateRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[53] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3941,7 +3665,7 @@ func (x *StateRequest) String() string { func (*StateRequest) ProtoMessage() {} func (x *StateRequest) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[53] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[49] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3954,7 +3678,7 @@ func (x *StateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StateRequest.ProtoReflect.Descriptor instead. func (*StateRequest) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{53} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{49} } func (x *StateRequest) GetIndexName() string { @@ -3975,7 +3699,7 @@ type StateResponse struct { func (x *StateResponse) Reset() { *x = StateResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[54] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3988,7 +3712,7 @@ func (x *StateResponse) String() string { func (*StateResponse) ProtoMessage() {} func (x *StateResponse) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[54] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[50] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4001,7 +3725,7 @@ func (x *StateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StateResponse.ProtoReflect.Descriptor instead. func (*StateResponse) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{54} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{50} } func (x *StateResponse) GetResponse() string { @@ -4026,7 +3750,7 @@ type AddReplicaRequest struct { func (x *AddReplicaRequest) Reset() { *x = AddReplicaRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[55] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4039,7 +3763,7 @@ func (x *AddReplicaRequest) String() string { func (*AddReplicaRequest) ProtoMessage() {} func (x *AddReplicaRequest) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[55] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[51] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4052,7 +3776,7 @@ func (x *AddReplicaRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AddReplicaRequest.ProtoReflect.Descriptor instead. func (*AddReplicaRequest) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{55} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{51} } func (x *AddReplicaRequest) GetMagicNumber() int32 { @@ -4101,7 +3825,7 @@ type AddReplicaResponse struct { func (x *AddReplicaResponse) Reset() { *x = AddReplicaResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[56] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4114,7 +3838,7 @@ func (x *AddReplicaResponse) String() string { func (*AddReplicaResponse) ProtoMessage() {} func (x *AddReplicaResponse) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[56] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[52] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4127,7 +3851,7 @@ func (x *AddReplicaResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AddReplicaResponse.ProtoReflect.Descriptor instead. func (*AddReplicaResponse) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{56} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{52} } func (x *AddReplicaResponse) GetOk() string { @@ -4156,7 +3880,7 @@ type CopyState struct { func (x *CopyState) Reset() { *x = CopyState{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[57] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4169,7 +3893,7 @@ func (x *CopyState) String() string { func (*CopyState) ProtoMessage() {} func (x *CopyState) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[57] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[53] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4182,7 +3906,7 @@ func (x *CopyState) ProtoReflect() protoreflect.Message { // Deprecated: Use CopyState.ProtoReflect.Descriptor instead. func (*CopyState) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{57} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{53} } func (x *CopyState) GetInfoBytesLength() int32 { @@ -4253,7 +3977,7 @@ type FilesMetadata struct { func (x *FilesMetadata) Reset() { *x = FilesMetadata{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[58] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4266,7 +3990,7 @@ func (x *FilesMetadata) String() string { func (*FilesMetadata) ProtoMessage() {} func (x *FilesMetadata) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[58] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[54] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4279,7 +4003,7 @@ func (x *FilesMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use FilesMetadata.ProtoReflect.Descriptor instead. func (*FilesMetadata) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{58} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{54} } func (x *FilesMetadata) GetNumFiles() int32 { @@ -4313,7 +4037,7 @@ type FileMetadata struct { func (x *FileMetadata) Reset() { *x = FileMetadata{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[59] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4326,7 +4050,7 @@ func (x *FileMetadata) String() string { func (*FileMetadata) ProtoMessage() {} func (x *FileMetadata) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[59] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[55] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4339,7 +4063,7 @@ func (x *FileMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use FileMetadata.ProtoReflect.Descriptor instead. func (*FileMetadata) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{59} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{55} } func (x *FileMetadata) GetFileName() string { @@ -4406,7 +4130,7 @@ type CopyFiles struct { func (x *CopyFiles) Reset() { *x = CopyFiles{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[60] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4419,7 +4143,7 @@ func (x *CopyFiles) String() string { func (*CopyFiles) ProtoMessage() {} func (x *CopyFiles) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[60] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[56] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4432,7 +4156,7 @@ func (x *CopyFiles) ProtoReflect() protoreflect.Message { // Deprecated: Use CopyFiles.ProtoReflect.Descriptor instead. func (*CopyFiles) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{60} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{56} } func (x *CopyFiles) GetMagicNumber() int32 { @@ -4477,7 +4201,7 @@ type CopyStateRequest struct { func (x *CopyStateRequest) Reset() { *x = CopyStateRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[61] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4490,7 +4214,7 @@ func (x *CopyStateRequest) String() string { func (*CopyStateRequest) ProtoMessage() {} func (x *CopyStateRequest) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[61] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[57] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4503,7 +4227,7 @@ func (x *CopyStateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CopyStateRequest.ProtoReflect.Descriptor instead. func (*CopyStateRequest) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{61} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{57} } func (x *CopyStateRequest) GetMagicNumber() int32 { @@ -4541,7 +4265,7 @@ type FilesInfo struct { func (x *FilesInfo) Reset() { *x = FilesInfo{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[62] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4554,7 +4278,7 @@ func (x *FilesInfo) String() string { func (*FilesInfo) ProtoMessage() {} func (x *FilesInfo) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[62] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[58] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4567,7 +4291,7 @@ func (x *FilesInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use FilesInfo.ProtoReflect.Descriptor instead. func (*FilesInfo) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{62} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{58} } func (x *FilesInfo) GetMagicNumber() int32 { @@ -4613,7 +4337,7 @@ type FileInfo struct { func (x *FileInfo) Reset() { *x = FileInfo{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[63] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4626,7 +4350,7 @@ func (x *FileInfo) String() string { func (*FileInfo) ProtoMessage() {} func (x *FileInfo) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[63] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[59] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4639,7 +4363,7 @@ func (x *FileInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use FileInfo.ProtoReflect.Descriptor instead. func (*FileInfo) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{63} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{59} } func (x *FileInfo) GetFileName() string { @@ -4685,7 +4409,7 @@ type RawFileChunk struct { func (x *RawFileChunk) Reset() { *x = RawFileChunk{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[64] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4698,7 +4422,7 @@ func (x *RawFileChunk) String() string { func (*RawFileChunk) ProtoMessage() {} func (x *RawFileChunk) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[64] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[60] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4711,7 +4435,7 @@ func (x *RawFileChunk) ProtoReflect() protoreflect.Message { // Deprecated: Use RawFileChunk.ProtoReflect.Descriptor instead. func (*RawFileChunk) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{64} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{60} } func (x *RawFileChunk) GetContent() []byte { @@ -4746,7 +4470,7 @@ type HealthCheckRequest struct { func (x *HealthCheckRequest) Reset() { *x = HealthCheckRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[65] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4759,7 +4483,7 @@ func (x *HealthCheckRequest) String() string { func (*HealthCheckRequest) ProtoMessage() {} func (x *HealthCheckRequest) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[65] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[61] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4772,7 +4496,7 @@ func (x *HealthCheckRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use HealthCheckRequest.ProtoReflect.Descriptor instead. func (*HealthCheckRequest) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{65} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{61} } func (x *HealthCheckRequest) GetCheck() bool { @@ -4793,7 +4517,7 @@ type HealthCheckResponse struct { func (x *HealthCheckResponse) Reset() { *x = HealthCheckResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[66] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4806,7 +4530,7 @@ func (x *HealthCheckResponse) String() string { func (*HealthCheckResponse) ProtoMessage() {} func (x *HealthCheckResponse) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[66] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[62] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4819,7 +4543,7 @@ func (x *HealthCheckResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use HealthCheckResponse.ProtoReflect.Descriptor instead. func (*HealthCheckResponse) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{66} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{62} } func (x *HealthCheckResponse) GetHealth() TransferStatusCode { @@ -4840,7 +4564,7 @@ type ReadyCheckRequest struct { func (x *ReadyCheckRequest) Reset() { *x = ReadyCheckRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[67] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4853,7 +4577,7 @@ func (x *ReadyCheckRequest) String() string { func (*ReadyCheckRequest) ProtoMessage() {} func (x *ReadyCheckRequest) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[67] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[63] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4866,7 +4590,7 @@ func (x *ReadyCheckRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReadyCheckRequest.ProtoReflect.Descriptor instead. func (*ReadyCheckRequest) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{67} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{63} } func (x *ReadyCheckRequest) GetIndexNames() string { @@ -4888,7 +4612,7 @@ type TransferStatus struct { func (x *TransferStatus) Reset() { *x = TransferStatus{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[68] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4901,7 +4625,7 @@ func (x *TransferStatus) String() string { func (*TransferStatus) ProtoMessage() {} func (x *TransferStatus) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[68] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[64] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4914,7 +4638,7 @@ func (x *TransferStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use TransferStatus.ProtoReflect.Descriptor instead. func (*TransferStatus) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{68} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{64} } func (x *TransferStatus) GetMessage() string { @@ -4945,7 +4669,7 @@ type NewNRTPoint struct { func (x *NewNRTPoint) Reset() { *x = NewNRTPoint{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[69] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4958,7 +4682,7 @@ func (x *NewNRTPoint) String() string { func (*NewNRTPoint) ProtoMessage() {} func (x *NewNRTPoint) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[69] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[65] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4971,7 +4695,7 @@ func (x *NewNRTPoint) ProtoReflect() protoreflect.Message { // Deprecated: Use NewNRTPoint.ProtoReflect.Descriptor instead. func (*NewNRTPoint) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{69} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{65} } func (x *NewNRTPoint) GetMagicNumber() int32 { @@ -5014,7 +4738,7 @@ type IndexName struct { func (x *IndexName) Reset() { *x = IndexName{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[70] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5027,7 +4751,7 @@ func (x *IndexName) String() string { func (*IndexName) ProtoMessage() {} func (x *IndexName) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[70] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[66] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5040,7 +4764,7 @@ func (x *IndexName) ProtoReflect() protoreflect.Message { // Deprecated: Use IndexName.ProtoReflect.Descriptor instead. func (*IndexName) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{70} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{66} } func (x *IndexName) GetMagicNumber() int32 { @@ -5069,7 +4793,7 @@ type SearcherVersion struct { func (x *SearcherVersion) Reset() { *x = SearcherVersion{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[71] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5082,7 +4806,7 @@ func (x *SearcherVersion) String() string { func (*SearcherVersion) ProtoMessage() {} func (x *SearcherVersion) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[71] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[67] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5095,7 +4819,7 @@ func (x *SearcherVersion) ProtoReflect() protoreflect.Message { // Deprecated: Use SearcherVersion.ProtoReflect.Descriptor instead. func (*SearcherVersion) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{71} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{67} } func (x *SearcherVersion) GetVersion() int64 { @@ -5123,7 +4847,7 @@ type GetNodesRequest struct { func (x *GetNodesRequest) Reset() { *x = GetNodesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[72] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5136,7 +4860,7 @@ func (x *GetNodesRequest) String() string { func (*GetNodesRequest) ProtoMessage() {} func (x *GetNodesRequest) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[72] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[68] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5149,7 +4873,7 @@ func (x *GetNodesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetNodesRequest.ProtoReflect.Descriptor instead. func (*GetNodesRequest) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{72} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{68} } func (x *GetNodesRequest) GetIndexName() string { @@ -5170,7 +4894,7 @@ type GetNodesResponse struct { func (x *GetNodesResponse) Reset() { *x = GetNodesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[73] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5183,7 +4907,7 @@ func (x *GetNodesResponse) String() string { func (*GetNodesResponse) ProtoMessage() {} func (x *GetNodesResponse) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[73] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[69] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5196,7 +4920,7 @@ func (x *GetNodesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetNodesResponse.ProtoReflect.Descriptor instead. func (*GetNodesResponse) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{73} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{69} } func (x *GetNodesResponse) GetNodes() []*NodeInfo { @@ -5218,7 +4942,7 @@ type NodeInfo struct { func (x *NodeInfo) Reset() { *x = NodeInfo{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[74] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5231,7 +4955,7 @@ func (x *NodeInfo) String() string { func (*NodeInfo) ProtoMessage() {} func (x *NodeInfo) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[74] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[70] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5244,7 +4968,7 @@ func (x *NodeInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use NodeInfo.ProtoReflect.Descriptor instead. func (*NodeInfo) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{74} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{70} } func (x *NodeInfo) GetHostname() string { @@ -5273,7 +4997,7 @@ type DeleteByQueryRequest struct { func (x *DeleteByQueryRequest) Reset() { *x = DeleteByQueryRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[75] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5286,7 +5010,7 @@ func (x *DeleteByQueryRequest) String() string { func (*DeleteByQueryRequest) ProtoMessage() {} func (x *DeleteByQueryRequest) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[75] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[71] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5299,7 +5023,7 @@ func (x *DeleteByQueryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteByQueryRequest.ProtoReflect.Descriptor instead. func (*DeleteByQueryRequest) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{75} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{71} } func (x *DeleteByQueryRequest) GetIndexName() string { @@ -5329,7 +5053,7 @@ type ForceMergeRequest struct { func (x *ForceMergeRequest) Reset() { *x = ForceMergeRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[76] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5342,7 +5066,7 @@ func (x *ForceMergeRequest) String() string { func (*ForceMergeRequest) ProtoMessage() {} func (x *ForceMergeRequest) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[76] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[72] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5355,7 +5079,7 @@ func (x *ForceMergeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ForceMergeRequest.ProtoReflect.Descriptor instead. func (*ForceMergeRequest) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{76} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{72} } func (x *ForceMergeRequest) GetIndexName() string { @@ -5390,7 +5114,7 @@ type ForceMergeResponse struct { func (x *ForceMergeResponse) Reset() { *x = ForceMergeResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[77] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5403,7 +5127,7 @@ func (x *ForceMergeResponse) String() string { func (*ForceMergeResponse) ProtoMessage() {} func (x *ForceMergeResponse) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[77] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[73] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5416,7 +5140,7 @@ func (x *ForceMergeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ForceMergeResponse.ProtoReflect.Descriptor instead. func (*ForceMergeResponse) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{77} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{73} } func (x *ForceMergeResponse) GetStatus() ForceMergeResponse_Status { @@ -5438,7 +5162,7 @@ type ForceMergeDeletesRequest struct { func (x *ForceMergeDeletesRequest) Reset() { *x = ForceMergeDeletesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[78] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5451,7 +5175,7 @@ func (x *ForceMergeDeletesRequest) String() string { func (*ForceMergeDeletesRequest) ProtoMessage() {} func (x *ForceMergeDeletesRequest) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[78] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[74] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5464,7 +5188,7 @@ func (x *ForceMergeDeletesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ForceMergeDeletesRequest.ProtoReflect.Descriptor instead. func (*ForceMergeDeletesRequest) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{78} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{74} } func (x *ForceMergeDeletesRequest) GetIndexName() string { @@ -5492,7 +5216,7 @@ type ForceMergeDeletesResponse struct { func (x *ForceMergeDeletesResponse) Reset() { *x = ForceMergeDeletesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[79] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5505,7 +5229,7 @@ func (x *ForceMergeDeletesResponse) String() string { func (*ForceMergeDeletesResponse) ProtoMessage() {} func (x *ForceMergeDeletesResponse) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[79] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[75] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5518,7 +5242,7 @@ func (x *ForceMergeDeletesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ForceMergeDeletesResponse.ProtoReflect.Descriptor instead. func (*ForceMergeDeletesResponse) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{79} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{75} } func (x *ForceMergeDeletesResponse) GetStatus() ForceMergeDeletesResponse_Status { @@ -5552,7 +5276,7 @@ type IndexSettings struct { func (x *IndexSettings) Reset() { *x = IndexSettings{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[80] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5565,7 +5289,7 @@ func (x *IndexSettings) String() string { func (*IndexSettings) ProtoMessage() {} func (x *IndexSettings) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[80] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[76] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5578,7 +5302,7 @@ func (x *IndexSettings) ProtoReflect() protoreflect.Message { // Deprecated: Use IndexSettings.ProtoReflect.Descriptor instead. func (*IndexSettings) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{80} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{76} } func (x *IndexSettings) GetNrtCachingDirectoryMaxMergeSizeMB() *wrapperspb.DoubleValue { @@ -5668,7 +5392,7 @@ type IndexLiveSettings struct { func (x *IndexLiveSettings) Reset() { *x = IndexLiveSettings{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[81] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5681,7 +5405,7 @@ func (x *IndexLiveSettings) String() string { func (*IndexLiveSettings) ProtoMessage() {} func (x *IndexLiveSettings) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[81] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[77] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5694,7 +5418,7 @@ func (x *IndexLiveSettings) ProtoReflect() protoreflect.Message { // Deprecated: Use IndexLiveSettings.ProtoReflect.Descriptor instead. func (*IndexLiveSettings) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{81} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{77} } func (x *IndexLiveSettings) GetMaxRefreshSec() *wrapperspb.DoubleValue { @@ -5817,7 +5541,7 @@ type IndexStateInfo struct { func (x *IndexStateInfo) Reset() { *x = IndexStateInfo{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[82] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5830,7 +5554,7 @@ func (x *IndexStateInfo) String() string { func (*IndexStateInfo) ProtoMessage() {} func (x *IndexStateInfo) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[82] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[78] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5843,7 +5567,7 @@ func (x *IndexStateInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use IndexStateInfo.ProtoReflect.Descriptor instead. func (*IndexStateInfo) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{82} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{78} } func (x *IndexStateInfo) GetIndexName() string { @@ -5902,7 +5626,7 @@ type IndexGlobalState struct { func (x *IndexGlobalState) Reset() { *x = IndexGlobalState{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[83] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5915,7 +5639,7 @@ func (x *IndexGlobalState) String() string { func (*IndexGlobalState) ProtoMessage() {} func (x *IndexGlobalState) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[83] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[79] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5928,7 +5652,7 @@ func (x *IndexGlobalState) ProtoReflect() protoreflect.Message { // Deprecated: Use IndexGlobalState.ProtoReflect.Descriptor instead. func (*IndexGlobalState) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{83} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{79} } func (x *IndexGlobalState) GetId() string { @@ -5959,7 +5683,7 @@ type GlobalStateInfo struct { func (x *GlobalStateInfo) Reset() { *x = GlobalStateInfo{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[84] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5972,7 +5696,7 @@ func (x *GlobalStateInfo) String() string { func (*GlobalStateInfo) ProtoMessage() {} func (x *GlobalStateInfo) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[84] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[80] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5985,7 +5709,7 @@ func (x *GlobalStateInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use GlobalStateInfo.ProtoReflect.Descriptor instead. func (*GlobalStateInfo) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{84} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{80} } func (x *GlobalStateInfo) GetGen() int64 { @@ -6015,7 +5739,7 @@ type CustomRequest struct { func (x *CustomRequest) Reset() { *x = CustomRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[85] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6028,7 +5752,7 @@ func (x *CustomRequest) String() string { func (*CustomRequest) ProtoMessage() {} func (x *CustomRequest) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[85] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[81] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6041,7 +5765,7 @@ func (x *CustomRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CustomRequest.ProtoReflect.Descriptor instead. func (*CustomRequest) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{85} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{81} } func (x *CustomRequest) GetId() string { @@ -6076,7 +5800,7 @@ type CustomResponse struct { func (x *CustomResponse) Reset() { *x = CustomResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[86] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6089,7 +5813,7 @@ func (x *CustomResponse) String() string { func (*CustomResponse) ProtoMessage() {} func (x *CustomResponse) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[86] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[82] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6102,7 +5826,7 @@ func (x *CustomResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CustomResponse.ProtoReflect.Descriptor instead. func (*CustomResponse) Descriptor() ([]byte, []int) { - return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{86} + return file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP(), []int{82} } func (x *CustomResponse) GetResponse() map[string]string { @@ -6126,7 +5850,7 @@ type AddDocumentRequest_MultiValuedField struct { func (x *AddDocumentRequest_MultiValuedField) Reset() { *x = AddDocumentRequest_MultiValuedField{} if protoimpl.UnsafeEnabled { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[87] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6139,7 +5863,7 @@ func (x *AddDocumentRequest_MultiValuedField) String() string { func (*AddDocumentRequest_MultiValuedField) ProtoMessage() {} func (x *AddDocumentRequest_MultiValuedField) ProtoReflect() protoreflect.Message { - mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[87] + mi := &file_yelp_nrtsearch_luceneserver_proto_msgTypes[83] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6606,821 +6330,759 @@ var file_yelp_nrtsearch_luceneserver_proto_rawDesc = []byte{ 0x6c, 0x6c, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x47, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x47, 0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x03, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x47, - 0x65, 0x6e, 0x73, 0x22, 0xbe, 0x01, 0x0a, 0x12, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, - 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2c, - 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, - 0x6f, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x63, 0x6f, 0x6d, 0x70, 0x6c, - 0x65, 0x74, 0x65, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, - 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x73, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x22, 0x71, 0x0a, 0x13, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x64, - 0x61, 0x74, 0x61, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x48, 0x61, 0x73, 0x68, 0x12, 0x30, 0x0a, 0x13, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x13, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x22, 0xbf, 0x01, 0x0a, 0x1b, 0x42, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x57, 0x61, 0x72, 0x6d, 0x69, 0x6e, 0x67, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x20, 0x0a, - 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x30, 0x0a, 0x13, 0x6e, 0x75, 0x6d, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x54, 0x68, 0x72, - 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x6e, 0x75, - 0x6d, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, - 0x64, 0x12, 0x36, 0x0a, 0x16, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x6e, 0x75, 0x74, - 0x65, 0x73, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x16, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x6e, 0x75, 0x74, 0x65, 0x73, - 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x22, 0x1e, 0x0a, 0x1c, 0x42, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x57, 0x61, 0x72, 0x6d, 0x69, 0x6e, 0x67, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x94, 0x01, 0x0a, 0x18, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, - 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, - 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x44, - 0x61, 0x79, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6e, 0x44, 0x61, 0x79, 0x73, - 0x22, 0x8b, 0x02, 0x0a, 0x19, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, - 0x0a, 0x19, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x44, 0x61, 0x74, 0x61, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x19, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x44, 0x0a, 0x1d, - 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x1d, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x61, 0x73, 0x68, - 0x65, 0x73, 0x12, 0x30, 0x0a, 0x13, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, - 0x61, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x13, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x38, 0x0a, 0x17, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x17, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x10, - 0x0a, 0x0e, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x22, 0x5d, 0x0a, 0x0f, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x0f, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6c, - 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x64, 0x65, - 0x78, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0f, - 0x69, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x75, 0x0a, 0x12, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x41, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6c, 0x75, 0x63, - 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x84, 0x01, 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x74, 0x6f, - 0x72, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, - 0x12, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x44, - 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x64, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x61, 0x74, 0x61, 0x22, 0x2c, 0x0a, - 0x0c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, - 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x2b, 0x0a, 0x0d, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, - 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xa1, 0x01, 0x0a, 0x11, 0x41, 0x64, 0x64, - 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, - 0x0a, 0x0b, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, - 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, - 0x0a, 0x09, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x09, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, - 0x68, 0x6f, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x68, 0x6f, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x24, 0x0a, 0x12, - 0x41, 0x64, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, - 0x6f, 0x6b, 0x22, 0xce, 0x02, 0x0a, 0x09, 0x43, 0x6f, 0x70, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x12, 0x28, 0x0a, 0x0f, 0x69, 0x6e, 0x66, 0x6f, 0x42, 0x79, 0x74, 0x65, 0x73, 0x4c, 0x65, 0x6e, - 0x67, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x69, 0x6e, 0x66, 0x6f, 0x42, - 0x79, 0x74, 0x65, 0x73, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, - 0x66, 0x6f, 0x42, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x69, - 0x6e, 0x66, 0x6f, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x65, 0x6e, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x67, 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x41, 0x0a, 0x0d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6c, 0x75, - 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x73, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x38, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x70, 0x6c, - 0x65, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x53, 0x69, - 0x7a, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x17, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, - 0x74, 0x65, 0x64, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x53, 0x69, 0x7a, - 0x65, 0x12, 0x30, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4d, 0x65, - 0x72, 0x67, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, - 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x46, 0x69, - 0x6c, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x47, 0x65, - 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, - 0x47, 0x65, 0x6e, 0x22, 0x6b, 0x0a, 0x0d, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x75, 0x6d, 0x46, 0x69, 0x6c, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x6e, 0x75, 0x6d, 0x46, 0x69, 0x6c, 0x65, 0x73, - 0x12, 0x3e, 0x0a, 0x0c, 0x66, 0x69, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x52, 0x0c, 0x66, 0x69, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x22, 0xd0, 0x01, 0x0a, 0x0c, 0x46, 0x69, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, - 0x03, 0x6c, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6c, 0x65, 0x6e, 0x12, - 0x1a, 0x0a, 0x08, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x08, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x12, 0x22, 0x0a, 0x0c, 0x68, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x0c, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, - 0x16, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0c, 0x66, 0x6f, 0x6f, 0x74, 0x65, - 0x72, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x66, - 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x66, - 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x6f, 0x6f, - 0x74, 0x65, 0x72, 0x22, 0xae, 0x01, 0x0a, 0x09, 0x43, 0x6f, 0x70, 0x79, 0x46, 0x69, 0x6c, 0x65, - 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x4e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x47, 0x65, 0x6e, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x47, 0x65, - 0x6e, 0x12, 0x41, 0x0a, 0x0d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, - 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x22, 0x70, 0x0a, 0x10, 0x43, 0x6f, 0x70, 0x79, 0x53, 0x74, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x61, 0x67, 0x69, + 0x65, 0x6e, 0x73, 0x22, 0xbf, 0x01, 0x0a, 0x1b, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x57, 0x61, + 0x72, 0x6d, 0x69, 0x6e, 0x67, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x6e, + 0x75, 0x6d, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, + 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x6e, 0x75, 0x6d, 0x51, 0x75, 0x65, + 0x72, 0x69, 0x65, 0x73, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x36, 0x0a, + 0x16, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x6e, 0x75, 0x74, 0x65, 0x73, 0x54, 0x68, + 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x16, 0x75, + 0x70, 0x74, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x6e, 0x75, 0x74, 0x65, 0x73, 0x54, 0x68, 0x72, 0x65, + 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x22, 0x1e, 0x0a, 0x1c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x57, + 0x61, 0x72, 0x6d, 0x69, 0x6e, 0x67, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x10, 0x0a, 0x0e, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x5d, 0x0a, 0x0f, 0x49, 0x6e, 0x64, 0x69, 0x63, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x0f, 0x69, 0x6e, + 0x64, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0f, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x75, 0x0a, 0x12, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, + 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x41, 0x0a, 0x0d, 0x73, 0x74, + 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0d, + 0x73, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x84, 0x01, + 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x20, + 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x78, + 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x12, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, + 0x44, 0x61, 0x74, 0x61, 0x22, 0x2c, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, + 0x6d, 0x65, 0x22, 0x2b, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0xa1, 0x01, 0x0a, 0x11, 0x41, 0x64, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x4e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6d, 0x61, 0x67, 0x69, + 0x63, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, + 0x6f, 0x72, 0x74, 0x22, 0x24, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x6b, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x6f, 0x6b, 0x22, 0xce, 0x02, 0x0a, 0x09, 0x43, 0x6f, + 0x70, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x69, 0x6e, 0x66, 0x6f, 0x42, + 0x79, 0x74, 0x65, 0x73, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x0f, 0x69, 0x6e, 0x66, 0x6f, 0x42, 0x79, 0x74, 0x65, 0x73, 0x4c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x66, 0x6f, 0x42, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x69, 0x6e, 0x66, 0x6f, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, + 0x10, 0x0a, 0x03, 0x67, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x67, 0x65, + 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x41, 0x0a, 0x0d, 0x66, + 0x69, 0x6c, 0x65, 0x73, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, + 0x0d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x38, + 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x72, 0x67, 0x65, + 0x46, 0x69, 0x6c, 0x65, 0x73, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x17, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x46, + 0x69, 0x6c, 0x65, 0x73, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x18, + 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, + 0x4d, 0x65, 0x72, 0x67, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, + 0x69, 0x6d, 0x61, 0x72, 0x79, 0x47, 0x65, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, + 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x47, 0x65, 0x6e, 0x22, 0x6b, 0x0a, 0x0d, 0x46, 0x69, + 0x6c, 0x65, 0x73, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x6e, + 0x75, 0x6d, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x6e, + 0x75, 0x6d, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x3e, 0x0a, 0x0c, 0x66, 0x69, 0x6c, 0x65, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x69, 0x6c, + 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0c, 0x66, 0x69, 0x6c, 0x65, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0xd0, 0x01, 0x0a, 0x0c, 0x46, 0x69, 0x6c, 0x65, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, + 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6c, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x03, 0x6c, 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, + 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, + 0x75, 0x6d, 0x12, 0x22, 0x0a, 0x0c, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4c, 0x65, 0x6e, 0x67, + 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x22, + 0x0a, 0x0c, 0x66, 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x66, 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x4c, 0x65, 0x6e, 0x67, + 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x06, 0x66, 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x22, 0xae, 0x01, 0x0a, 0x09, 0x43, + 0x6f, 0x70, 0x79, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, - 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x70, 0x6c, - 0x69, 0x63, 0x61, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x72, 0x65, 0x70, - 0x6c, 0x69, 0x63, 0x61, 0x49, 0x64, 0x22, 0x9d, 0x01, 0x0a, 0x09, 0x46, 0x69, 0x6c, 0x65, 0x73, - 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x4e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6d, 0x61, 0x67, 0x69, 0x63, - 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, - 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x49, - 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, - 0x49, 0x64, 0x12, 0x32, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x04, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x66, 0x69, - 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x7c, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, - 0x66, 0x6f, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x66, 0x70, 0x53, 0x74, 0x61, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x07, 0x66, 0x70, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x64, - 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x63, 0x6b, 0x53, 0x65, 0x71, - 0x4e, 0x75, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x61, 0x63, 0x6b, 0x53, 0x65, - 0x71, 0x4e, 0x75, 0x6d, 0x22, 0x52, 0x0a, 0x0c, 0x52, 0x61, 0x77, 0x46, 0x69, 0x6c, 0x65, 0x43, - 0x68, 0x75, 0x6e, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x16, - 0x0a, 0x06, 0x73, 0x65, 0x71, 0x4e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, - 0x73, 0x65, 0x71, 0x4e, 0x75, 0x6d, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x6b, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x03, 0x61, 0x63, 0x6b, 0x22, 0x2a, 0x0a, 0x12, 0x48, 0x65, 0x61, 0x6c, - 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, - 0x0a, 0x05, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x63, - 0x68, 0x65, 0x63, 0x6b, 0x22, 0x4f, 0x0a, 0x13, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, - 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x06, 0x68, - 0x65, 0x61, 0x6c, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x6c, 0x75, + 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x69, 0x6d, + 0x61, 0x72, 0x79, 0x47, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x70, 0x72, + 0x69, 0x6d, 0x61, 0x72, 0x79, 0x47, 0x65, 0x6e, 0x12, 0x41, 0x0a, 0x0d, 0x66, 0x69, 0x6c, 0x65, + 0x73, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, + 0x69, 0x6c, 0x65, 0x73, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x66, 0x69, + 0x6c, 0x65, 0x73, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x70, 0x0a, 0x10, 0x43, + 0x6f, 0x70, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x20, 0x0a, 0x0b, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x4e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x09, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x49, 0x64, 0x22, 0x9d, 0x01, + 0x0a, 0x09, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x0a, 0x0b, 0x6d, + 0x61, 0x67, 0x69, 0x63, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x0b, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a, + 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x72, + 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, + 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x08, 0x66, 0x69, 0x6c, + 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x75, + 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x7c, 0x0a, + 0x08, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x70, 0x53, 0x74, 0x61, 0x72, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x66, 0x70, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, + 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, + 0x09, 0x61, 0x63, 0x6b, 0x53, 0x65, 0x71, 0x4e, 0x75, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x09, 0x61, 0x63, 0x6b, 0x53, 0x65, 0x71, 0x4e, 0x75, 0x6d, 0x22, 0x52, 0x0a, 0x0c, 0x52, + 0x61, 0x77, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x71, 0x4e, 0x75, 0x6d, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x65, 0x71, 0x4e, 0x75, 0x6d, 0x12, 0x10, 0x0a, + 0x03, 0x61, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x61, 0x63, 0x6b, 0x22, + 0x2a, 0x0a, 0x12, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x22, 0x4f, 0x0a, 0x13, 0x48, + 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x38, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x43, 0x6f, 0x64, 0x65, 0x52, 0x06, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x22, 0x33, 0x0a, 0x11, + 0x52, 0x65, 0x61, 0x64, 0x79, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, + 0x73, 0x22, 0x60, 0x0a, 0x0e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x34, 0x0a, + 0x04, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x66, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x06, 0x68, - 0x65, 0x61, 0x6c, 0x74, 0x68, 0x22, 0x33, 0x0a, 0x11, 0x52, 0x65, 0x61, 0x64, 0x79, 0x43, 0x68, - 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x60, 0x0a, 0x0e, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x34, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x87, 0x01, 0x0a, - 0x0b, 0x4e, 0x65, 0x77, 0x4e, 0x52, 0x54, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, - 0x6d, 0x61, 0x67, 0x69, 0x63, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x0b, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, - 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, - 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x47, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x47, 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x4b, 0x0a, 0x09, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x4e, 0x75, 0x6d, 0x62, + 0x66, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x43, + 0x6f, 0x64, 0x65, 0x22, 0x87, 0x01, 0x0a, 0x0b, 0x4e, 0x65, 0x77, 0x4e, 0x52, 0x54, 0x50, 0x6f, + 0x69, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, - 0x61, 0x6d, 0x65, 0x22, 0x4b, 0x0a, 0x0f, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x72, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x64, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, 0x69, 0x64, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, - 0x22, 0x2f, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, - 0x65, 0x22, 0x40, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x6e, 0x6f, - 0x64, 0x65, 0x73, 0x22, 0x3a, 0x0a, 0x08, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, - 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, - 0x5f, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x79, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, - 0x22, 0x71, 0x0a, 0x11, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x4e, 0x75, 0x6d, 0x53, 0x65, 0x67, - 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x6d, 0x61, 0x78, - 0x4e, 0x75, 0x6d, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x64, - 0x6f, 0x57, 0x61, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x64, 0x6f, 0x57, - 0x61, 0x69, 0x74, 0x22, 0x95, 0x01, 0x0a, 0x12, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x72, - 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x06, 0x73, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x6c, 0x75, 0x63, - 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x4d, - 0x65, 0x72, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3e, 0x0a, 0x06, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, 0x15, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x4d, - 0x45, 0x52, 0x47, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x00, - 0x12, 0x19, 0x0a, 0x15, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x4d, 0x45, 0x52, 0x47, 0x45, 0x5f, - 0x53, 0x55, 0x42, 0x4d, 0x49, 0x54, 0x54, 0x45, 0x44, 0x10, 0x01, 0x22, 0x50, 0x0a, 0x18, 0x46, - 0x6f, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x57, 0x61, 0x69, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x64, 0x6f, 0x57, 0x61, 0x69, 0x74, 0x22, 0xb3, 0x01, - 0x0a, 0x19, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x06, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x6c, 0x75, - 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x6f, 0x72, 0x63, 0x65, - 0x4d, 0x65, 0x72, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x22, 0x4e, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x21, 0x0a, - 0x1d, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x4d, 0x45, 0x52, 0x47, 0x45, 0x5f, 0x44, 0x45, 0x4c, - 0x45, 0x54, 0x45, 0x53, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x00, - 0x12, 0x21, 0x0a, 0x1d, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x4d, 0x45, 0x52, 0x47, 0x45, 0x5f, - 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x53, 0x5f, 0x53, 0x55, 0x42, 0x4d, 0x49, 0x54, 0x54, 0x45, - 0x44, 0x10, 0x01, 0x22, 0x9f, 0x05, 0x0a, 0x0d, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x6a, 0x0a, 0x21, 0x6e, 0x72, 0x74, 0x43, 0x61, 0x63, 0x68, - 0x69, 0x6e, 0x67, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x61, 0x78, 0x4d, - 0x65, 0x72, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x4d, 0x42, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x21, + 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x47, 0x65, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, + 0x47, 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x4b, 0x0a, + 0x09, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x61, + 0x67, 0x69, 0x63, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x0b, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x4b, 0x0a, 0x0f, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x64, 0x52, 0x65, + 0x66, 0x72, 0x65, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, 0x69, 0x64, + 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x22, 0x2f, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4e, 0x6f, + 0x64, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x40, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4e, + 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x05, + 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x75, + 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x3a, 0x0a, 0x08, 0x4e, 0x6f, + 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x5f, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x42, 0x79, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, + 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x05, + 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x75, + 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0x71, 0x0a, 0x11, 0x46, 0x6f, 0x72, 0x63, 0x65, + 0x4d, 0x65, 0x72, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x6d, 0x61, + 0x78, 0x4e, 0x75, 0x6d, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x4e, 0x75, 0x6d, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x57, 0x61, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x06, 0x64, 0x6f, 0x57, 0x61, 0x69, 0x74, 0x22, 0x95, 0x01, 0x0a, 0x12, 0x46, + 0x6f, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x3f, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x27, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x2e, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x22, 0x3e, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, 0x15, + 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x4d, 0x45, 0x52, 0x47, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, + 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x46, 0x4f, 0x52, 0x43, 0x45, + 0x5f, 0x4d, 0x45, 0x52, 0x47, 0x45, 0x5f, 0x53, 0x55, 0x42, 0x4d, 0x49, 0x54, 0x54, 0x45, 0x44, + 0x10, 0x01, 0x22, 0x50, 0x0a, 0x18, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x72, 0x67, 0x65, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, + 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, + 0x64, 0x6f, 0x57, 0x61, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x64, 0x6f, + 0x57, 0x61, 0x69, 0x74, 0x22, 0xb3, 0x01, 0x0a, 0x19, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x4d, 0x65, + 0x72, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x46, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2e, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x4e, 0x0a, 0x06, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x21, 0x0a, 0x1d, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x4d, 0x45, + 0x52, 0x47, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x53, 0x5f, 0x43, 0x4f, 0x4d, 0x50, + 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x21, 0x0a, 0x1d, 0x46, 0x4f, 0x52, 0x43, 0x45, + 0x5f, 0x4d, 0x45, 0x52, 0x47, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x53, 0x5f, 0x53, + 0x55, 0x42, 0x4d, 0x49, 0x54, 0x54, 0x45, 0x44, 0x10, 0x01, 0x22, 0x9f, 0x05, 0x0a, 0x0d, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x6a, 0x0a, 0x21, 0x6e, 0x72, 0x74, 0x43, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x61, 0x78, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x4d, - 0x42, 0x12, 0x60, 0x0a, 0x1c, 0x6e, 0x72, 0x74, 0x43, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x44, - 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x61, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x4d, - 0x42, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x42, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x1c, 0x6e, 0x72, 0x74, 0x43, 0x61, 0x63, 0x68, 0x69, 0x6e, - 0x67, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x61, 0x78, 0x53, 0x69, 0x7a, - 0x65, 0x4d, 0x42, 0x12, 0x73, 0x0a, 0x26, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, - 0x74, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x4d, - 0x61, 0x78, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x52, 0x26, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x72, 0x67, - 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x4d, 0x61, 0x78, 0x54, 0x68, 0x72, - 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x71, 0x0a, 0x25, 0x63, 0x6f, 0x6e, 0x63, - 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, - 0x75, 0x6c, 0x65, 0x72, 0x4d, 0x61, 0x78, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x43, 0x6f, 0x75, 0x6e, - 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x52, 0x25, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, - 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x4d, 0x61, - 0x78, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x36, 0x0a, 0x09, 0x69, - 0x6e, 0x64, 0x65, 0x78, 0x53, 0x6f, 0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, - 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x6f, - 0x72, 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x53, - 0x6f, 0x72, 0x74, 0x12, 0x64, 0x0a, 0x1f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4d, 0x65, 0x72, 0x67, - 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x41, 0x75, 0x74, 0x6f, 0x54, 0x68, - 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, - 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x1f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4d, - 0x65, 0x72, 0x67, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x41, 0x75, 0x74, - 0x6f, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x12, 0x3a, 0x0a, 0x09, 0x64, 0x69, 0x72, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, - 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x79, 0x22, 0xe1, 0x08, 0x0a, 0x11, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4c, - 0x69, 0x76, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x42, 0x0a, 0x0d, 0x6d, - 0x61, 0x78, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x53, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x53, 0x65, 0x63, 0x12, - 0x42, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x53, 0x65, 0x63, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0d, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, - 0x53, 0x65, 0x63, 0x12, 0x4a, 0x0a, 0x11, 0x6d, 0x61, 0x78, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x65, 0x72, 0x41, 0x67, 0x65, 0x53, 0x65, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x21, 0x6e, 0x72, 0x74, 0x43, 0x61, 0x63, 0x68, 0x69, 0x6e, + 0x67, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x61, 0x78, 0x4d, 0x65, 0x72, + 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x4d, 0x42, 0x12, 0x60, 0x0a, 0x1c, 0x6e, 0x72, 0x74, 0x43, + 0x61, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x4d, + 0x61, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x4d, 0x42, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x6d, 0x61, - 0x78, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x72, 0x41, 0x67, 0x65, 0x53, 0x65, 0x63, 0x12, - 0x50, 0x0a, 0x14, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x61, 0x6d, 0x42, 0x75, 0x66, 0x66, 0x65, - 0x72, 0x53, 0x69, 0x7a, 0x65, 0x4d, 0x42, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x14, 0x69, 0x6e, 0x64, - 0x65, 0x78, 0x52, 0x61, 0x6d, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x4d, - 0x42, 0x12, 0x57, 0x0a, 0x18, 0x61, 0x64, 0x64, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, - 0x73, 0x4d, 0x61, 0x78, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x4c, 0x65, 0x6e, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x52, 0x18, 0x61, 0x64, 0x64, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, - 0x78, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x4c, 0x65, 0x6e, 0x12, 0x3f, 0x0a, 0x0c, 0x73, 0x6c, - 0x69, 0x63, 0x65, 0x4d, 0x61, 0x78, 0x44, 0x6f, 0x63, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x73, - 0x6c, 0x69, 0x63, 0x65, 0x4d, 0x61, 0x78, 0x44, 0x6f, 0x63, 0x73, 0x12, 0x47, 0x0a, 0x10, 0x73, - 0x6c, 0x69, 0x63, 0x65, 0x4d, 0x61, 0x78, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x52, 0x10, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x4d, 0x61, 0x78, 0x53, 0x65, 0x67, 0x6d, - 0x65, 0x6e, 0x74, 0x73, 0x12, 0x41, 0x0a, 0x0d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x68, 0x61, 0x72, 0x64, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, - 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x12, 0x4b, 0x0a, 0x12, 0x6d, 0x61, 0x78, 0x4d, 0x65, - 0x72, 0x67, 0x65, 0x64, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x42, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x52, 0x12, 0x6d, 0x61, 0x78, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x64, 0x53, 0x65, 0x67, 0x6d, 0x65, - 0x6e, 0x74, 0x4d, 0x42, 0x12, 0x45, 0x0a, 0x0f, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, - 0x50, 0x65, 0x72, 0x54, 0x69, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, + 0x2e, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x1c, 0x6e, 0x72, + 0x74, 0x43, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, + 0x79, 0x4d, 0x61, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x4d, 0x42, 0x12, 0x73, 0x0a, 0x26, 0x63, 0x6f, + 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x63, 0x68, + 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x4d, 0x61, 0x78, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, + 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x26, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, + 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, + 0x72, 0x4d, 0x61, 0x78, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x71, 0x0a, 0x25, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x72, + 0x67, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x4d, 0x61, 0x78, 0x4d, 0x65, + 0x72, 0x67, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x25, 0x63, 0x6f, 0x6e, + 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x63, 0x68, 0x65, + 0x64, 0x75, 0x6c, 0x65, 0x72, 0x4d, 0x61, 0x78, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x36, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x6f, 0x72, 0x74, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x6f, 0x72, 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x52, + 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x6f, 0x72, 0x74, 0x12, 0x64, 0x0a, 0x1f, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, + 0x72, 0x41, 0x75, 0x74, 0x6f, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, + 0x1f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, + 0x75, 0x6c, 0x65, 0x72, 0x41, 0x75, 0x74, 0x6f, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, + 0x12, 0x3a, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x22, 0xe1, 0x08, 0x0a, + 0x11, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x12, 0x42, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, + 0x53, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x6f, 0x75, 0x62, + 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x52, 0x65, 0x66, 0x72, + 0x65, 0x73, 0x68, 0x53, 0x65, 0x63, 0x12, 0x42, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x66, + 0x72, 0x65, 0x73, 0x68, 0x53, 0x65, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x73, 0x65, 0x67, 0x6d, - 0x65, 0x6e, 0x74, 0x73, 0x50, 0x65, 0x72, 0x54, 0x69, 0x65, 0x72, 0x12, 0x56, 0x0a, 0x17, 0x64, - 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x54, 0x69, 0x6d, 0x65, - 0x6f, 0x75, 0x74, 0x53, 0x65, 0x63, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, - 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x17, 0x64, 0x65, 0x66, 0x61, - 0x75, 0x6c, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, - 0x53, 0x65, 0x63, 0x12, 0x63, 0x0a, 0x1e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, - 0x45, 0x76, 0x65, 0x72, 0x79, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, - 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x1e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x43, 0x68, - 0x65, 0x63, 0x6b, 0x45, 0x76, 0x65, 0x72, 0x79, 0x12, 0x51, 0x0a, 0x15, 0x64, 0x65, 0x66, 0x61, - 0x75, 0x6c, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x41, 0x66, 0x74, 0x65, - 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0d, 0x6d, 0x69, 0x6e, + 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x53, 0x65, 0x63, 0x12, 0x4a, 0x0a, 0x11, 0x6d, 0x61, + 0x78, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x72, 0x41, 0x67, 0x65, 0x53, 0x65, 0x63, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x52, 0x11, 0x6d, 0x61, 0x78, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x72, + 0x41, 0x67, 0x65, 0x53, 0x65, 0x63, 0x12, 0x50, 0x0a, 0x14, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x52, + 0x61, 0x6d, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x4d, 0x42, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x14, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x61, 0x6d, 0x42, 0x75, 0x66, 0x66, + 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x4d, 0x42, 0x12, 0x57, 0x0a, 0x18, 0x61, 0x64, 0x64, 0x44, + 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x78, 0x42, 0x75, 0x66, 0x66, 0x65, + 0x72, 0x4c, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, + 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x18, 0x61, 0x64, 0x64, 0x44, 0x6f, 0x63, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x78, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x4c, 0x65, + 0x6e, 0x12, 0x3f, 0x0a, 0x0c, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x4d, 0x61, 0x78, 0x44, 0x6f, 0x63, + 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x52, 0x15, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x54, 0x65, 0x72, - 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x41, 0x66, 0x74, 0x65, 0x72, 0x12, 0x5c, 0x0a, 0x1a, 0x6d, - 0x61, 0x78, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x65, 0x43, 0x6f, 0x70, 0x79, 0x44, 0x75, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x63, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x1a, 0x6d, - 0x61, 0x78, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x65, 0x43, 0x6f, 0x70, 0x79, 0x44, 0x75, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x63, 0x22, 0xee, 0x02, 0x0a, 0x0e, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x53, 0x74, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x65, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x67, 0x65, 0x6e, 0x12, 0x1c, 0x0a, 0x09, - 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x12, 0x37, 0x0a, 0x08, 0x73, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6c, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x4d, 0x61, 0x78, 0x44, 0x6f, + 0x63, 0x73, 0x12, 0x47, 0x0a, 0x10, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x4d, 0x61, 0x78, 0x53, 0x65, + 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, + 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x10, 0x73, 0x6c, 0x69, 0x63, 0x65, + 0x4d, 0x61, 0x78, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x41, 0x0a, 0x0d, 0x76, + 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, + 0x0d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x12, 0x4b, + 0x0a, 0x12, 0x6d, 0x61, 0x78, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x64, 0x53, 0x65, 0x67, 0x6d, 0x65, + 0x6e, 0x74, 0x4d, 0x42, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, + 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x6d, 0x61, 0x78, 0x4d, 0x65, 0x72, 0x67, + 0x65, 0x64, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x42, 0x12, 0x45, 0x0a, 0x0f, 0x73, + 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x50, 0x65, 0x72, 0x54, 0x69, 0x65, 0x72, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x0f, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x50, 0x65, 0x72, 0x54, 0x69, + 0x65, 0x72, 0x12, 0x56, 0x0a, 0x17, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x53, 0x65, 0x63, 0x18, 0x0b, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x17, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x53, 0x65, 0x63, 0x12, 0x63, 0x0a, 0x1e, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x6f, + 0x75, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x45, 0x76, 0x65, 0x72, 0x79, 0x18, 0x0c, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, + 0x1e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x54, 0x69, + 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x45, 0x76, 0x65, 0x72, 0x79, 0x12, + 0x51, 0x0a, 0x15, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, + 0x61, 0x74, 0x65, 0x41, 0x66, 0x74, 0x65, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x15, 0x64, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x41, 0x66, 0x74, + 0x65, 0x72, 0x12, 0x5c, 0x0a, 0x1a, 0x6d, 0x61, 0x78, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, + 0x65, 0x43, 0x6f, 0x70, 0x79, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x63, + 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x1a, 0x6d, 0x61, 0x78, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, + 0x65, 0x43, 0x6f, 0x70, 0x79, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x63, + 0x22, 0xee, 0x02, 0x0a, 0x0e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x74, 0x61, 0x74, 0x65, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, + 0x67, 0x65, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, + 0x64, 0x12, 0x37, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x43, 0x0a, 0x0c, 0x6c, 0x69, + 0x76, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1f, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x52, 0x0c, 0x6c, 0x69, 0x76, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, + 0x40, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x28, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x53, 0x74, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x46, 0x69, + 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x73, 0x1a, 0x4e, 0x0a, 0x0b, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x29, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0x3c, 0x0a, 0x10, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x22, + 0xc5, 0x01, 0x0a, 0x0f, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x03, 0x67, 0x65, 0x6e, 0x12, 0x44, 0x0a, 0x07, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x07, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x1a, 0x5a, 0x0a, 0x0c, 0x49, + 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x34, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x64, 0x65, - 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, - 0x6e, 0x67, 0x73, 0x12, 0x43, 0x0a, 0x0c, 0x6c, 0x69, 0x76, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, - 0x6e, 0x67, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6c, 0x75, 0x63, 0x65, - 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4c, 0x69, - 0x76, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0c, 0x6c, 0x69, 0x76, 0x65, - 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x40, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, - 0x64, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, - 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x1a, 0x4e, 0x0a, 0x0b, 0x46, 0x69, - 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x75, 0x63, - 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x3c, 0x0a, 0x10, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, - 0x0a, 0x07, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x07, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x22, 0xc5, 0x01, 0x0a, 0x0f, 0x47, 0x6c, 0x6f, - 0x62, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, - 0x67, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x67, 0x65, 0x6e, 0x12, 0x44, - 0x0a, 0x07, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x2a, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, - 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x49, - 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x69, 0x6e, 0x64, - 0x69, 0x63, 0x65, 0x73, 0x1a, 0x5a, 0x0a, 0x0c, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x34, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, - 0x22, 0xaf, 0x01, 0x0a, 0x0d, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, - 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x3f, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, - 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x50, 0x61, 0x72, 0x61, 0x6d, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, - 0x38, 0x01, 0x22, 0x95, 0x01, 0x0a, 0x0e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x3b, 0x0a, - 0x0d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x2a, 0xdc, 0x01, 0x0a, 0x09, 0x46, - 0x69, 0x65, 0x6c, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x54, 0x4f, 0x4d, - 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x54, 0x45, 0x58, 0x54, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, - 0x42, 0x4f, 0x4f, 0x4c, 0x45, 0x41, 0x4e, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x4c, 0x4f, 0x4e, - 0x47, 0x10, 0x03, 0x12, 0x07, 0x0a, 0x03, 0x49, 0x4e, 0x54, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, - 0x44, 0x4f, 0x55, 0x42, 0x4c, 0x45, 0x10, 0x05, 0x12, 0x09, 0x0a, 0x05, 0x46, 0x4c, 0x4f, 0x41, - 0x54, 0x10, 0x06, 0x12, 0x0b, 0x0a, 0x07, 0x4c, 0x41, 0x54, 0x5f, 0x4c, 0x4f, 0x4e, 0x10, 0x07, - 0x12, 0x0d, 0x0a, 0x09, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x10, 0x08, 0x12, - 0x0b, 0x0a, 0x07, 0x56, 0x49, 0x52, 0x54, 0x55, 0x41, 0x4c, 0x10, 0x09, 0x12, 0x0c, 0x0a, 0x08, - 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x10, 0x0a, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x55, - 0x53, 0x54, 0x4f, 0x4d, 0x10, 0x0b, 0x12, 0x07, 0x0a, 0x03, 0x5f, 0x49, 0x44, 0x10, 0x0c, 0x12, - 0x0b, 0x0a, 0x07, 0x50, 0x4f, 0x4c, 0x59, 0x47, 0x4f, 0x4e, 0x10, 0x0d, 0x12, 0x0a, 0x0a, 0x06, - 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x10, 0x0e, 0x12, 0x0a, 0x0a, 0x06, 0x56, 0x45, 0x43, 0x54, - 0x4f, 0x52, 0x10, 0x0f, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x4f, 0x4e, 0x54, 0x45, 0x58, 0x54, 0x5f, - 0x53, 0x55, 0x47, 0x47, 0x45, 0x53, 0x54, 0x10, 0x10, 0x2a, 0x64, 0x0a, 0x0c, 0x49, 0x6e, 0x64, - 0x65, 0x78, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x18, 0x0a, 0x14, 0x44, 0x4f, 0x43, - 0x53, 0x5f, 0x46, 0x52, 0x45, 0x51, 0x53, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, - 0x53, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x4f, 0x43, 0x53, 0x10, 0x01, 0x12, 0x0e, 0x0a, - 0x0a, 0x44, 0x4f, 0x43, 0x53, 0x5f, 0x46, 0x52, 0x45, 0x51, 0x53, 0x10, 0x02, 0x12, 0x20, 0x0a, - 0x1c, 0x44, 0x4f, 0x43, 0x53, 0x5f, 0x46, 0x52, 0x45, 0x51, 0x53, 0x5f, 0x50, 0x4f, 0x53, 0x49, - 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, 0x53, 0x10, 0x03, 0x2a, - 0x84, 0x01, 0x0a, 0x0b, 0x54, 0x65, 0x72, 0x6d, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, - 0x12, 0x0a, 0x0e, 0x4e, 0x4f, 0x5f, 0x54, 0x45, 0x52, 0x4d, 0x56, 0x45, 0x43, 0x54, 0x4f, 0x52, - 0x53, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x45, 0x52, 0x4d, 0x53, 0x10, 0x01, 0x12, 0x13, - 0x0a, 0x0f, 0x54, 0x45, 0x52, 0x4d, 0x53, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, - 0x53, 0x10, 0x02, 0x12, 0x1b, 0x0a, 0x17, 0x54, 0x45, 0x52, 0x4d, 0x53, 0x5f, 0x50, 0x4f, 0x53, - 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, 0x53, 0x10, 0x03, - 0x12, 0x24, 0x0a, 0x20, 0x54, 0x45, 0x52, 0x4d, 0x53, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, - 0x4f, 0x4e, 0x53, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, 0x53, 0x5f, 0x50, 0x41, 0x59, 0x4c, - 0x4f, 0x41, 0x44, 0x53, 0x10, 0x04, 0x2a, 0x61, 0x0a, 0x09, 0x46, 0x61, 0x63, 0x65, 0x74, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f, 0x46, 0x41, 0x43, 0x45, 0x54, 0x53, - 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x4c, 0x41, 0x54, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, - 0x48, 0x49, 0x45, 0x52, 0x41, 0x52, 0x43, 0x48, 0x59, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4e, - 0x55, 0x4d, 0x45, 0x52, 0x49, 0x43, 0x5f, 0x52, 0x41, 0x4e, 0x47, 0x45, 0x10, 0x03, 0x12, 0x19, - 0x0a, 0x15, 0x53, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x5f, 0x53, 0x45, 0x54, 0x5f, 0x44, 0x4f, 0x43, - 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x53, 0x10, 0x04, 0x2a, 0x30, 0x0a, 0x04, 0x4d, 0x6f, 0x64, - 0x65, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x54, 0x41, 0x4e, 0x44, 0x41, 0x4c, 0x4f, 0x4e, 0x45, 0x10, - 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x52, 0x49, 0x4d, 0x41, 0x52, 0x59, 0x10, 0x01, 0x12, 0x0b, - 0x0a, 0x07, 0x52, 0x45, 0x50, 0x4c, 0x49, 0x43, 0x41, 0x10, 0x02, 0x2a, 0x44, 0x0a, 0x12, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, - 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x08, - 0x0a, 0x04, 0x44, 0x6f, 0x6e, 0x65, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x61, 0x69, 0x6c, - 0x65, 0x64, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x4f, 0x6e, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x10, - 0x03, 0x32, 0x9f, 0x22, 0x0a, 0x0c, 0x4c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x12, 0x6f, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, - 0x78, 0x12, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x22, 0x10, - 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x3a, 0x01, 0x2a, 0x12, 0x73, 0x0a, 0x0c, 0x6c, 0x69, 0x76, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, - 0x6e, 0x67, 0x73, 0x12, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, - 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x16, 0x22, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x5f, 0x73, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x9a, 0x01, 0x0a, 0x0e, 0x6c, 0x69, 0x76, - 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x56, 0x32, 0x12, 0x23, 0x2e, 0x6c, 0x75, - 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x76, 0x65, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x56, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x24, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, - 0x4c, 0x69, 0x76, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x56, 0x32, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x37, 0x22, 0x11, - 0x2f, 0x76, 0x32, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, - 0x73, 0x3a, 0x01, 0x2a, 0x5a, 0x1f, 0x12, 0x1d, 0x2f, 0x76, 0x32, 0x2f, 0x6c, 0x69, 0x76, 0x65, - 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x4e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x6f, 0x0a, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, - 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x44, 0x65, 0x66, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x44, 0x65, 0x66, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x22, 0x13, - 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x66, 0x69, 0x65, - 0x6c, 0x64, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x6b, 0x0a, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x44, 0x65, 0x66, 0x52, 0x65, + 0x78, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xaf, 0x01, 0x0a, 0x0d, 0x43, 0x75, 0x73, 0x74, + 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, + 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x3f, 0x0a, + 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, + 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x75, 0x73, + 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x39, + 0x0a, 0x0b, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x95, 0x01, 0x0a, 0x0e, 0x43, 0x75, + 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x08, + 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, + 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x75, + 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x3b, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x2a, 0xdc, 0x01, 0x0a, 0x09, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x08, 0x0a, 0x04, 0x41, 0x54, 0x4f, 0x4d, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x54, 0x45, 0x58, + 0x54, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x42, 0x4f, 0x4f, 0x4c, 0x45, 0x41, 0x4e, 0x10, 0x02, + 0x12, 0x08, 0x0a, 0x04, 0x4c, 0x4f, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x07, 0x0a, 0x03, 0x49, 0x4e, + 0x54, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x4f, 0x55, 0x42, 0x4c, 0x45, 0x10, 0x05, 0x12, + 0x09, 0x0a, 0x05, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x10, 0x06, 0x12, 0x0b, 0x0a, 0x07, 0x4c, 0x41, + 0x54, 0x5f, 0x4c, 0x4f, 0x4e, 0x10, 0x07, 0x12, 0x0d, 0x0a, 0x09, 0x44, 0x41, 0x54, 0x45, 0x5f, + 0x54, 0x49, 0x4d, 0x45, 0x10, 0x08, 0x12, 0x0b, 0x0a, 0x07, 0x56, 0x49, 0x52, 0x54, 0x55, 0x41, + 0x4c, 0x10, 0x09, 0x12, 0x0c, 0x0a, 0x08, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x10, + 0x0a, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x55, 0x53, 0x54, 0x4f, 0x4d, 0x10, 0x0b, 0x12, 0x07, 0x0a, + 0x03, 0x5f, 0x49, 0x44, 0x10, 0x0c, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x4f, 0x4c, 0x59, 0x47, 0x4f, + 0x4e, 0x10, 0x0d, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x10, 0x0e, 0x12, + 0x0a, 0x0a, 0x06, 0x56, 0x45, 0x43, 0x54, 0x4f, 0x52, 0x10, 0x0f, 0x12, 0x13, 0x0a, 0x0f, 0x43, + 0x4f, 0x4e, 0x54, 0x45, 0x58, 0x54, 0x5f, 0x53, 0x55, 0x47, 0x47, 0x45, 0x53, 0x54, 0x10, 0x10, + 0x2a, 0x64, 0x0a, 0x0c, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x18, 0x0a, 0x14, 0x44, 0x4f, 0x43, 0x53, 0x5f, 0x46, 0x52, 0x45, 0x51, 0x53, 0x5f, 0x50, + 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x4f, + 0x43, 0x53, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x44, 0x4f, 0x43, 0x53, 0x5f, 0x46, 0x52, 0x45, + 0x51, 0x53, 0x10, 0x02, 0x12, 0x20, 0x0a, 0x1c, 0x44, 0x4f, 0x43, 0x53, 0x5f, 0x46, 0x52, 0x45, + 0x51, 0x53, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x4f, 0x46, 0x46, + 0x53, 0x45, 0x54, 0x53, 0x10, 0x03, 0x2a, 0x84, 0x01, 0x0a, 0x0b, 0x54, 0x65, 0x72, 0x6d, 0x56, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x12, 0x0a, 0x0e, 0x4e, 0x4f, 0x5f, 0x54, 0x45, 0x52, + 0x4d, 0x56, 0x45, 0x43, 0x54, 0x4f, 0x52, 0x53, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x45, + 0x52, 0x4d, 0x53, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x54, 0x45, 0x52, 0x4d, 0x53, 0x5f, 0x50, + 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x10, 0x02, 0x12, 0x1b, 0x0a, 0x17, 0x54, 0x45, + 0x52, 0x4d, 0x53, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x4f, 0x46, + 0x46, 0x53, 0x45, 0x54, 0x53, 0x10, 0x03, 0x12, 0x24, 0x0a, 0x20, 0x54, 0x45, 0x52, 0x4d, 0x53, + 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, + 0x54, 0x53, 0x5f, 0x50, 0x41, 0x59, 0x4c, 0x4f, 0x41, 0x44, 0x53, 0x10, 0x04, 0x2a, 0x61, 0x0a, + 0x09, 0x46, 0x61, 0x63, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, + 0x5f, 0x46, 0x41, 0x43, 0x45, 0x54, 0x53, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x4c, 0x41, + 0x54, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x48, 0x49, 0x45, 0x52, 0x41, 0x52, 0x43, 0x48, 0x59, + 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4e, 0x55, 0x4d, 0x45, 0x52, 0x49, 0x43, 0x5f, 0x52, 0x41, + 0x4e, 0x47, 0x45, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x5f, + 0x53, 0x45, 0x54, 0x5f, 0x44, 0x4f, 0x43, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x53, 0x10, 0x04, + 0x2a, 0x30, 0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x54, 0x41, 0x4e, + 0x44, 0x41, 0x4c, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x52, 0x49, 0x4d, + 0x41, 0x52, 0x59, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x45, 0x50, 0x4c, 0x49, 0x43, 0x41, + 0x10, 0x02, 0x2a, 0x44, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, + 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x6f, 0x6e, 0x65, 0x10, 0x01, 0x12, + 0x0a, 0x0a, 0x06, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x4f, + 0x6e, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x10, 0x03, 0x32, 0xa3, 0x20, 0x0a, 0x0c, 0x4c, 0x75, 0x63, + 0x65, 0x6e, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x6f, 0x0a, 0x0b, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, + 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, + 0x64, 0x65, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6c, 0x75, 0x63, + 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x22, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x01, 0x2a, 0x12, 0x73, 0x0a, 0x0c, 0x6c, 0x69, + 0x76, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x21, 0x2e, 0x6c, 0x75, 0x63, + 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, + 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x76, + 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x22, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x6c, + 0x69, 0x76, 0x65, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x3a, 0x01, 0x2a, 0x12, + 0x9a, 0x01, 0x0a, 0x0e, 0x6c, 0x69, 0x76, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x56, 0x32, 0x12, 0x23, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2e, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x56, 0x32, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x73, 0x56, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3d, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x37, 0x22, 0x11, 0x2f, 0x76, 0x32, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x5f, + 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x3a, 0x01, 0x2a, 0x5a, 0x1f, 0x12, 0x1d, 0x2f, + 0x76, 0x32, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x2f, 0x7b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x6f, 0x0a, 0x0e, + 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x1d, + 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x69, + 0x65, 0x6c, 0x64, 0x44, 0x65, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, + 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x69, 0x65, + 0x6c, 0x64, 0x44, 0x65, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x22, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x6b, 0x0a, + 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x1d, 0x2e, + 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x69, 0x65, + 0x6c, 0x64, 0x44, 0x65, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, + 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x69, 0x65, 0x6c, + 0x64, 0x44, 0x65, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x16, 0x22, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x62, 0x0a, 0x08, 0x73, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x44, 0x65, 0x66, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x22, 0x11, 0x2f, - 0x76, 0x31, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, - 0x3a, 0x01, 0x2a, 0x12, 0x62, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, - 0x1d, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, - 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x22, 0x0c, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x74, 0x74, - 0x69, 0x6e, 0x67, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x84, 0x01, 0x0a, 0x0a, 0x73, 0x65, 0x74, 0x74, - 0x69, 0x6e, 0x67, 0x73, 0x56, 0x32, 0x12, 0x1f, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x56, 0x32, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x56, - 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x33, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x2d, 0x22, 0x0c, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x3a, - 0x01, 0x2a, 0x5a, 0x1a, 0x12, 0x18, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, - 0x67, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x6b, - 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1f, 0x2e, 0x6c, - 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x72, - 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, - 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, - 0x72, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x22, 0x0f, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x01, 0x2a, 0x12, 0x6f, 0x0a, 0x0c, 0x73, - 0x74, 0x61, 0x72, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, 0x32, 0x12, 0x21, 0x2e, 0x6c, 0x75, - 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, - 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, - 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, - 0x61, 0x72, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x22, 0x0f, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x01, 0x2a, 0x12, 0x63, 0x0a, 0x09, - 0x73, 0x74, 0x6f, 0x70, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1e, 0x2e, 0x6c, 0x75, 0x63, 0x65, - 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x49, 0x6e, 0x64, - 0x65, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x75, 0x63, 0x65, - 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x44, 0x75, 0x6d, 0x6d, 0x79, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x22, 0x0e, - 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, 0x6f, 0x70, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x01, - 0x2a, 0x12, 0x6f, 0x0a, 0x0b, 0x72, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x12, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, - 0x52, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x2e, 0x52, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x22, 0x10, 0x2f, - 0x76, 0x31, 0x2f, 0x72, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x3a, - 0x01, 0x2a, 0x12, 0x73, 0x0a, 0x0c, 0x61, 0x64, 0x64, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, - 0x74, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x22, - 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x64, 0x64, 0x5f, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, - 0x74, 0x73, 0x3a, 0x01, 0x2a, 0x28, 0x01, 0x12, 0x5e, 0x0a, 0x07, 0x72, 0x65, 0x66, 0x72, 0x65, - 0x73, 0x68, 0x12, 0x1c, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x2e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1d, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, - 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x22, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x66, - 0x72, 0x65, 0x73, 0x68, 0x3a, 0x01, 0x2a, 0x12, 0x5a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, - 0x74, 0x12, 0x1b, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, - 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, - 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x15, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x0f, 0x22, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x3a, 0x01, 0x2a, 0x12, 0x6f, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6c, - 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, - 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x27, 0x22, 0x09, 0x2f, - 0x76, 0x31, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x3a, 0x01, 0x2a, 0x5a, 0x17, 0x12, 0x15, 0x2f, - 0x76, 0x31, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, - 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x5a, 0x0a, 0x06, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1b, + 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x22, 0x0c, 0x2f, + 0x76, 0x31, 0x2f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x84, + 0x01, 0x0a, 0x0a, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x56, 0x32, 0x12, 0x1f, 0x2e, + 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x56, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x75, - 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x0f, 0x22, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x3a, 0x01, 0x2a, - 0x12, 0x54, 0x0a, 0x08, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x56, 0x32, 0x12, 0x1b, 0x2e, 0x6c, - 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x22, - 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x22, 0x0a, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x3a, 0x01, 0x2a, 0x12, 0x64, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x12, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, - 0x41, 0x64, 0x64, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x22, 0x0a, 0x2f, - 0x76, 0x31, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x76, 0x0a, 0x0d, - 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x79, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x22, 0x2e, - 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x42, 0x79, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x41, 0x64, 0x64, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x22, 0x13, 0x2f, 0x76, - 0x31, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x62, 0x79, 0x5f, 0x71, 0x75, 0x65, 0x72, - 0x79, 0x3a, 0x01, 0x2a, 0x12, 0x79, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, - 0x6c, 0x12, 0x27, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x56, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x33, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x22, 0x0c, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x3a, 0x01, 0x2a, 0x5a, 0x1a, 0x12, 0x18, 0x2f, 0x76, 0x32, + 0x2f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x4e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x6b, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x49, 0x6e, + 0x64, 0x65, 0x78, 0x12, 0x1f, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x22, 0x0f, + 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, + 0x01, 0x2a, 0x12, 0x6f, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x72, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x56, 0x32, 0x12, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, 0x32, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x22, + 0x0f, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x3a, 0x01, 0x2a, 0x12, 0x63, 0x0a, 0x09, 0x73, 0x74, 0x6f, 0x70, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x12, 0x1e, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, + 0x53, 0x74, 0x6f, 0x70, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1b, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, + 0x44, 0x75, 0x6d, 0x6d, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x22, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, 0x6f, 0x70, 0x5f, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x01, 0x2a, 0x12, 0x6f, 0x0a, 0x0b, 0x72, 0x65, 0x6c, 0x6f, + 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x65, + 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x15, 0x22, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x6c, 0x6f, 0x61, 0x64, + 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x73, 0x0a, 0x0c, 0x61, 0x64, 0x64, + 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, + 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x6f, 0x63, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6c, 0x75, + 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x6f, + 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x22, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x64, 0x64, 0x5f, + 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x3a, 0x01, 0x2a, 0x28, 0x01, 0x12, 0x5e, + 0x0a, 0x07, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x1c, 0x2e, 0x6c, 0x75, 0x63, 0x65, + 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x22, 0x0b, + 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x3a, 0x01, 0x2a, 0x12, 0x5a, + 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x1b, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, + 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x22, 0x0a, 0x2f, 0x76, 0x31, + 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x6f, 0x0a, 0x05, 0x73, 0x74, + 0x61, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1b, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2d, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x27, 0x22, 0x09, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x3a, + 0x01, 0x2a, 0x5a, 0x17, 0x12, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2f, + 0x7b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x5a, 0x0a, 0x06, 0x73, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1b, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x22, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x3a, 0x01, 0x2a, 0x12, 0x54, 0x0a, 0x08, 0x73, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x56, 0x32, 0x12, 0x1b, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x22, 0x0a, + 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x3a, 0x01, 0x2a, 0x12, 0x64, 0x0a, + 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x65, + 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x6f, 0x63, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x15, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x0f, 0x22, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x3a, 0x01, 0x2a, 0x12, 0x76, 0x0a, 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x79, 0x51, + 0x75, 0x65, 0x72, 0x79, 0x12, 0x22, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x79, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, + 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x6f, 0x63, 0x75, 0x6d, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x18, 0x22, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, + 0x62, 0x79, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0x79, 0x0a, 0x09, 0x64, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x12, 0x27, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, + 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, + 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x28, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, - 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x6c, 0x75, 0x63, - 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x41, 0x6c, 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x22, 0x0e, 0x2f, 0x76, - 0x31, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x61, 0x6c, 0x6c, 0x3a, 0x01, 0x2a, 0x12, - 0x6f, 0x0a, 0x0b, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x20, - 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x22, 0x10, 0x2f, 0x76, 0x31, - 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x01, 0x2a, - 0x12, 0x73, 0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, - 0x12, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, - 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x22, - 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x5f, 0x62, 0x75, 0x69, - 0x6c, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0x77, 0x0a, 0x0d, 0x73, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, - 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x12, 0x22, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x4c, 0x6f, 0x6f, - 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6c, 0x75, 0x63, - 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, - 0x74, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x22, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x75, 0x67, - 0x67, 0x65, 0x73, 0x74, 0x5f, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x3a, 0x01, 0x2a, 0x12, 0x75, - 0x0a, 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x12, - 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x52, 0x65, + 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x13, 0x22, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, + 0x61, 0x6c, 0x6c, 0x3a, 0x01, 0x2a, 0x12, 0x6f, 0x0a, 0x0b, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x64, + 0x65, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x15, 0x22, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x01, 0x2a, 0x12, 0x73, 0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, + 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x12, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x75, 0x67, 0x67, + 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6c, 0x75, 0x63, + 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, + 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x22, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x75, 0x67, 0x67, + 0x65, 0x73, 0x74, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0x77, 0x0a, 0x0d, + 0x73, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x12, 0x22, 0x2e, + 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x75, 0x67, + 0x67, 0x65, 0x73, 0x74, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x23, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x2e, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x22, 0x12, - 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x7b, 0x0a, 0x0e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x23, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6c, - 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x22, 0x13, 0x2f, 0x76, 0x31, 0x2f, - 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x3a, - 0x01, 0x2a, 0x12, 0x7f, 0x0a, 0x0f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x24, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x6e, 0x61, 0x70, - 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x6c, 0x75, - 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, - 0x73, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, - 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, - 0x3a, 0x01, 0x2a, 0x12, 0x9d, 0x01, 0x0a, 0x16, 0x67, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x6e, - 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x47, 0x65, 0x6e, 0x12, 0x26, - 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x65, - 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x47, 0x65, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x6e, 0x61, 0x70, - 0x73, 0x68, 0x6f, 0x74, 0x47, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x32, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x12, 0x2a, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, - 0x5f, 0x61, 0x6c, 0x6c, 0x5f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x5f, 0x67, 0x65, 0x6e, 0x2f, 0x7b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, - 0x6d, 0x65, 0x7d, 0x12, 0x6f, 0x0a, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x6e, 0x64, - 0x65, 0x78, 0x12, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x22, - 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x3a, 0x01, 0x2a, 0x12, 0x88, 0x01, 0x0a, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, - 0x6e, 0x64, 0x65, 0x78, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x26, 0x2e, 0x6c, 0x75, 0x63, - 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x1c, 0x22, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x3a, 0x01, 0x2a, 0x12, - 0x94, 0x01, 0x0a, 0x14, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x57, 0x61, 0x72, 0x6d, 0x69, 0x6e, - 0x67, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x29, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, - 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x57, 0x61, - 0x72, 0x6d, 0x69, 0x6e, 0x67, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x5f, 0x6c, 0x6f, 0x6f, 0x6b, + 0x75, 0x70, 0x3a, 0x01, 0x2a, 0x12, 0x75, 0x0a, 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, + 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x12, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x75, 0x67, 0x67, 0x65, + 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6c, 0x75, 0x63, 0x65, + 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x75, + 0x67, 0x67, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x22, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x75, 0x67, 0x67, 0x65, + 0x73, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x7b, 0x0a, 0x0e, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x23, + 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x18, 0x22, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x6e, + 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x7f, 0x0a, 0x0f, 0x72, 0x65, 0x6c, + 0x65, 0x61, 0x73, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x24, 0x2e, 0x6c, + 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x6c, 0x65, + 0x61, 0x73, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x19, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x73, + 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x9d, 0x01, 0x0a, 0x16, 0x67, + 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x49, 0x6e, 0x64, + 0x65, 0x78, 0x47, 0x65, 0x6e, 0x12, 0x26, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x6e, 0x61, 0x70, 0x73, + 0x68, 0x6f, 0x74, 0x47, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, + 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, + 0x41, 0x6c, 0x6c, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x47, 0x65, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x32, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x12, 0x2a, + 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x6c, 0x5f, 0x73, 0x6e, 0x61, 0x70, + 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x67, 0x65, 0x6e, 0x2f, 0x7b, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x94, 0x01, 0x0a, 0x14, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x57, 0x61, 0x72, 0x6d, 0x69, 0x6e, 0x67, 0x51, 0x75, 0x65, 0x72, + 0x69, 0x65, 0x73, 0x12, 0x29, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x57, 0x61, 0x72, 0x6d, 0x69, 0x6e, 0x67, - 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x5f, 0x77, 0x61, 0x72, 0x6d, 0x69, 0x6e, 0x67, 0x5f, 0x71, 0x75, 0x65, 0x72, - 0x69, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x6f, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, - 0x1a, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x75, - 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x27, - 0x22, 0x09, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x5a, 0x17, - 0x12, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2f, 0x7b, 0x69, 0x6e, 0x64, - 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x61, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12, 0x0a, - 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x78, 0x0a, 0x05, 0x72, 0x65, - 0x61, 0x64, 0x79, 0x12, 0x1f, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x79, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x12, - 0x09, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x79, 0x5a, 0x18, 0x12, 0x16, 0x2f, 0x76, - 0x31, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x79, 0x2f, 0x7b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, - 0x6d, 0x65, 0x73, 0x7d, 0x12, 0x50, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, - 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x17, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2f, 0x6d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x5b, 0x0a, 0x07, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x65, - 0x73, 0x12, 0x1c, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1d, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x49, - 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x13, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0d, 0x12, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x64, 0x69, - 0x63, 0x65, 0x73, 0x12, 0x6b, 0x0a, 0x0a, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x72, 0x67, - 0x65, 0x12, 0x1f, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x2e, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x22, 0x0f, 0x2f, 0x76, - 0x31, 0x2f, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x3a, 0x01, 0x2a, - 0x12, 0x88, 0x01, 0x0a, 0x11, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x12, 0x26, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x72, 0x67, 0x65, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, - 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x6f, - 0x72, 0x63, 0x65, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, - 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x72, 0x67, 0x65, - 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x66, 0x0a, 0x06, 0x63, - 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x12, 0x1b, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x22, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x75, - 0x73, 0x74, 0x6f, 0x6d, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x70, 0x61, 0x74, 0x68, 0x7d, - 0x3a, 0x01, 0x2a, 0x32, 0x9c, 0x06, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x52, 0x0a, 0x0b, 0x61, 0x64, 0x64, - 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, 0x12, 0x1f, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, - 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, - 0x63, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, - 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x70, 0x6c, - 0x69, 0x63, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4a, 0x0a, - 0x0d, 0x72, 0x65, 0x63, 0x76, 0x43, 0x6f, 0x70, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1e, - 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, - 0x70, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, - 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, - 0x70, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x0b, 0x73, 0x65, 0x6e, - 0x64, 0x52, 0x61, 0x77, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1a, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, + 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, + 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x42, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x57, 0x61, 0x72, 0x6d, 0x69, 0x6e, 0x67, 0x51, 0x75, 0x65, 0x72, 0x69, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x1f, 0x22, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x77, + 0x61, 0x72, 0x6d, 0x69, 0x6e, 0x67, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x3a, 0x01, + 0x2a, 0x12, 0x6f, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1a, 0x2e, 0x6c, 0x75, 0x63, + 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x2d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x27, 0x22, 0x09, 0x2f, 0x76, 0x31, + 0x2f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x5a, 0x17, 0x12, 0x15, 0x2f, 0x76, 0x31, + 0x2f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2f, 0x7b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, + 0x65, 0x7d, 0x12, 0x61, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x20, 0x2e, 0x6c, + 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x61, 0x6c, + 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, + 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x65, + 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x78, 0x0a, 0x05, 0x72, 0x65, 0x61, 0x64, 0x79, 0x12, 0x1f, + 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x52, 0x65, + 0x61, 0x64, 0x79, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, + 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x12, 0x09, 0x2f, 0x76, 0x31, 0x2f, + 0x72, 0x65, 0x61, 0x64, 0x79, 0x5a, 0x18, 0x12, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x61, + 0x64, 0x79, 0x2f, 0x7b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x7d, 0x12, + 0x50, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x48, 0x74, 0x74, 0x70, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, + 0x12, 0x0f, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x12, 0x5b, 0x0a, 0x07, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x6c, + 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x64, 0x69, + 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x75, 0x63, + 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x13, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x0d, 0x12, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x12, 0x6b, + 0x0a, 0x0a, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x12, 0x1f, 0x2e, 0x6c, + 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x6f, 0x72, 0x63, + 0x65, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, + 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x6f, 0x72, + 0x63, 0x65, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x22, 0x0f, 0x2f, 0x76, 0x31, 0x2f, 0x66, 0x6f, 0x72, + 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x88, 0x01, 0x0a, 0x11, + 0x66, 0x6f, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x73, 0x12, 0x26, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x2e, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x6c, 0x75, 0x63, 0x65, + 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x4d, 0x65, + 0x72, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x17, 0x2f, 0x76, 0x31, 0x2f, + 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x66, 0x0a, 0x06, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, + 0x12, 0x1b, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, + 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, + 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x75, 0x73, + 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x1b, 0x22, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2f, + 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x70, 0x61, 0x74, 0x68, 0x7d, 0x3a, 0x01, 0x2a, 0x32, 0x9c, + 0x06, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x12, 0x52, 0x0a, 0x0b, 0x61, 0x64, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x73, 0x12, 0x1f, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x2e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0d, 0x72, 0x65, 0x63, 0x76, + 0x43, 0x6f, 0x70, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1e, 0x2e, 0x6c, 0x75, 0x63, 0x65, + 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x70, 0x79, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6c, 0x75, 0x63, 0x65, + 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x70, 0x79, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x0b, 0x73, 0x65, 0x6e, 0x64, 0x52, 0x61, 0x77, 0x46, + 0x69, 0x6c, 0x65, 0x12, 0x1a, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x52, 0x61, 0x77, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x1a, + 0x1c, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x28, + 0x01, 0x12, 0x45, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x76, 0x52, 0x61, 0x77, 0x46, 0x69, 0x6c, 0x65, + 0x12, 0x16, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, + 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x1a, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x52, 0x61, 0x77, 0x46, 0x69, 0x6c, 0x65, 0x43, - 0x68, 0x75, 0x6e, 0x6b, 0x1a, 0x1c, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x22, 0x00, 0x28, 0x01, 0x12, 0x45, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x76, 0x52, 0x61, - 0x77, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x16, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x1a, 0x2e, - 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x52, 0x61, 0x77, - 0x46, 0x69, 0x6c, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x22, 0x00, 0x30, 0x01, 0x12, 0x49, 0x0a, - 0x0d, 0x72, 0x65, 0x63, 0x76, 0x52, 0x61, 0x77, 0x46, 0x69, 0x6c, 0x65, 0x56, 0x32, 0x12, 0x16, - 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x69, - 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x1a, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x52, 0x61, 0x77, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x68, 0x75, - 0x6e, 0x6b, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x46, 0x0a, 0x09, 0x63, 0x6f, 0x70, 0x79, - 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x17, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x70, 0x79, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x1a, 0x1c, - 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x30, 0x01, - 0x12, 0x48, 0x0a, 0x0b, 0x6e, 0x65, 0x77, 0x4e, 0x52, 0x54, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, - 0x19, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4e, - 0x65, 0x77, 0x4e, 0x52, 0x54, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x75, 0x63, - 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, - 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x49, 0x0a, 0x0d, 0x77, 0x72, - 0x69, 0x74, 0x65, 0x4e, 0x52, 0x54, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x17, 0x2e, 0x6c, 0x75, - 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, - 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0x1d, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12, 0x55, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, - 0x65, 0x6e, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x17, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0x1d, 0x2e, 0x6c, 0x75, - 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x11, - 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4e, 0x6f, 0x64, 0x65, - 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1e, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, - 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x42, 0x56, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x79, 0x65, 0x6c, 0x70, 0x2e, 0x6e, - 0x72, 0x74, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, - 0x67, 0x72, 0x70, 0x63, 0x42, 0x11, 0x4c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x19, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x59, 0x65, 0x6c, 0x70, 0x2f, 0x6e, 0x72, 0x74, 0x73, 0x65, - 0x61, 0x72, 0x63, 0x68, 0xa2, 0x02, 0x03, 0x48, 0x4c, 0x57, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x68, 0x75, 0x6e, 0x6b, 0x22, 0x00, 0x30, 0x01, 0x12, 0x49, 0x0a, 0x0d, 0x72, 0x65, 0x63, 0x76, + 0x52, 0x61, 0x77, 0x46, 0x69, 0x6c, 0x65, 0x56, 0x32, 0x12, 0x16, 0x2e, 0x6c, 0x75, 0x63, 0x65, + 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, + 0x6f, 0x1a, 0x1a, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x2e, 0x52, 0x61, 0x77, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x22, 0x00, 0x28, + 0x01, 0x30, 0x01, 0x12, 0x46, 0x0a, 0x09, 0x63, 0x6f, 0x70, 0x79, 0x46, 0x69, 0x6c, 0x65, 0x73, + 0x12, 0x17, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, + 0x43, 0x6f, 0x70, 0x79, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x1a, 0x1c, 0x2e, 0x6c, 0x75, 0x63, 0x65, + 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, + 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x30, 0x01, 0x12, 0x48, 0x0a, 0x0b, 0x6e, + 0x65, 0x77, 0x4e, 0x52, 0x54, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x19, 0x2e, 0x6c, 0x75, 0x63, + 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4e, 0x65, 0x77, 0x4e, 0x52, 0x54, + 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x49, 0x0a, 0x0d, 0x77, 0x72, 0x69, 0x74, 0x65, 0x4e, 0x52, + 0x54, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x17, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x1a, + 0x1d, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x00, + 0x12, 0x55, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x2e, + 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x64, + 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0x1d, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x72, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x6c, + 0x75, 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x4e, + 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x75, + 0x63, 0x65, 0x6e, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, + 0x64, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x56, 0x0a, + 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x79, 0x65, 0x6c, 0x70, 0x2e, 0x6e, 0x72, 0x74, 0x73, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x42, + 0x11, 0x4c, 0x75, 0x63, 0x65, 0x6e, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x19, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x59, 0x65, 0x6c, 0x70, 0x2f, 0x6e, 0x72, 0x74, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0xa2, + 0x02, 0x03, 0x48, 0x4c, 0x57, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -7436,7 +7098,7 @@ func file_yelp_nrtsearch_luceneserver_proto_rawDescGZIP() []byte { } var file_yelp_nrtsearch_luceneserver_proto_enumTypes = make([]protoimpl.EnumInfo, 8) -var file_yelp_nrtsearch_luceneserver_proto_msgTypes = make([]protoimpl.MessageInfo, 93) +var file_yelp_nrtsearch_luceneserver_proto_msgTypes = make([]protoimpl.MessageInfo, 89) var file_yelp_nrtsearch_luceneserver_proto_goTypes = []interface{}{ (FieldType)(0), // 0: luceneserver.FieldType (IndexOptions)(0), // 1: luceneserver.IndexOptions @@ -7489,149 +7151,145 @@ var file_yelp_nrtsearch_luceneserver_proto_goTypes = []interface{}{ (*ReleaseSnapshotResponse)(nil), // 48: luceneserver.ReleaseSnapshotResponse (*GetAllSnapshotGenRequest)(nil), // 49: luceneserver.GetAllSnapshotGenRequest (*GetAllSnapshotGenResponse)(nil), // 50: luceneserver.GetAllSnapshotGenResponse - (*BackupIndexRequest)(nil), // 51: luceneserver.BackupIndexRequest - (*BackupIndexResponse)(nil), // 52: luceneserver.BackupIndexResponse - (*BackupWarmingQueriesRequest)(nil), // 53: luceneserver.BackupWarmingQueriesRequest - (*BackupWarmingQueriesResponse)(nil), // 54: luceneserver.BackupWarmingQueriesResponse - (*DeleteIndexBackupRequest)(nil), // 55: luceneserver.DeleteIndexBackupRequest - (*DeleteIndexBackupResponse)(nil), // 56: luceneserver.DeleteIndexBackupResponse - (*IndicesRequest)(nil), // 57: luceneserver.IndicesRequest - (*IndicesResponse)(nil), // 58: luceneserver.IndicesResponse - (*IndexStatsResponse)(nil), // 59: luceneserver.IndexStatsResponse - (*RestoreIndex)(nil), // 60: luceneserver.RestoreIndex - (*StateRequest)(nil), // 61: luceneserver.StateRequest - (*StateResponse)(nil), // 62: luceneserver.StateResponse - (*AddReplicaRequest)(nil), // 63: luceneserver.AddReplicaRequest - (*AddReplicaResponse)(nil), // 64: luceneserver.AddReplicaResponse - (*CopyState)(nil), // 65: luceneserver.CopyState - (*FilesMetadata)(nil), // 66: luceneserver.FilesMetadata - (*FileMetadata)(nil), // 67: luceneserver.FileMetadata - (*CopyFiles)(nil), // 68: luceneserver.CopyFiles - (*CopyStateRequest)(nil), // 69: luceneserver.CopyStateRequest - (*FilesInfo)(nil), // 70: luceneserver.FilesInfo - (*FileInfo)(nil), // 71: luceneserver.FileInfo - (*RawFileChunk)(nil), // 72: luceneserver.RawFileChunk - (*HealthCheckRequest)(nil), // 73: luceneserver.HealthCheckRequest - (*HealthCheckResponse)(nil), // 74: luceneserver.HealthCheckResponse - (*ReadyCheckRequest)(nil), // 75: luceneserver.ReadyCheckRequest - (*TransferStatus)(nil), // 76: luceneserver.TransferStatus - (*NewNRTPoint)(nil), // 77: luceneserver.NewNRTPoint - (*IndexName)(nil), // 78: luceneserver.IndexName - (*SearcherVersion)(nil), // 79: luceneserver.SearcherVersion - (*GetNodesRequest)(nil), // 80: luceneserver.GetNodesRequest - (*GetNodesResponse)(nil), // 81: luceneserver.GetNodesResponse - (*NodeInfo)(nil), // 82: luceneserver.NodeInfo - (*DeleteByQueryRequest)(nil), // 83: luceneserver.DeleteByQueryRequest - (*ForceMergeRequest)(nil), // 84: luceneserver.ForceMergeRequest - (*ForceMergeResponse)(nil), // 85: luceneserver.ForceMergeResponse - (*ForceMergeDeletesRequest)(nil), // 86: luceneserver.ForceMergeDeletesRequest - (*ForceMergeDeletesResponse)(nil), // 87: luceneserver.ForceMergeDeletesResponse - (*IndexSettings)(nil), // 88: luceneserver.IndexSettings - (*IndexLiveSettings)(nil), // 89: luceneserver.IndexLiveSettings - (*IndexStateInfo)(nil), // 90: luceneserver.IndexStateInfo - (*IndexGlobalState)(nil), // 91: luceneserver.IndexGlobalState - (*GlobalStateInfo)(nil), // 92: luceneserver.GlobalStateInfo - (*CustomRequest)(nil), // 93: luceneserver.CustomRequest - (*CustomResponse)(nil), // 94: luceneserver.CustomResponse - (*AddDocumentRequest_MultiValuedField)(nil), // 95: luceneserver.AddDocumentRequest.MultiValuedField - nil, // 96: luceneserver.AddDocumentRequest.FieldsEntry - nil, // 97: luceneserver.IndexStateInfo.FieldsEntry - nil, // 98: luceneserver.GlobalStateInfo.IndicesEntry - nil, // 99: luceneserver.CustomRequest.ParamsEntry - nil, // 100: luceneserver.CustomResponse.ResponseEntry - (*Script)(nil), // 101: luceneserver.Script - (*Analyzer)(nil), // 102: luceneserver.Analyzer - (*structpb.Struct)(nil), // 103: google.protobuf.Struct - (*SortFields)(nil), // 104: luceneserver.SortFields - (*Query)(nil), // 105: luceneserver.Query - (*wrapperspb.DoubleValue)(nil), // 106: google.protobuf.DoubleValue - (*wrapperspb.Int32Value)(nil), // 107: google.protobuf.Int32Value - (*wrapperspb.BoolValue)(nil), // 108: google.protobuf.BoolValue - (*wrapperspb.StringValue)(nil), // 109: google.protobuf.StringValue - (*wrapperspb.UInt64Value)(nil), // 110: google.protobuf.UInt64Value - (*SearchRequest)(nil), // 111: luceneserver.SearchRequest - (*BuildSuggestRequest)(nil), // 112: luceneserver.BuildSuggestRequest - (*SuggestLookupRequest)(nil), // 113: luceneserver.SuggestLookupRequest - (*emptypb.Empty)(nil), // 114: google.protobuf.Empty - (*SearchResponse)(nil), // 115: luceneserver.SearchResponse - (*anypb.Any)(nil), // 116: google.protobuf.Any - (*BuildSuggestResponse)(nil), // 117: luceneserver.BuildSuggestResponse - (*SuggestLookupResponse)(nil), // 118: luceneserver.SuggestLookupResponse - (*httpbody.HttpBody)(nil), // 119: google.api.HttpBody + (*BackupWarmingQueriesRequest)(nil), // 51: luceneserver.BackupWarmingQueriesRequest + (*BackupWarmingQueriesResponse)(nil), // 52: luceneserver.BackupWarmingQueriesResponse + (*IndicesRequest)(nil), // 53: luceneserver.IndicesRequest + (*IndicesResponse)(nil), // 54: luceneserver.IndicesResponse + (*IndexStatsResponse)(nil), // 55: luceneserver.IndexStatsResponse + (*RestoreIndex)(nil), // 56: luceneserver.RestoreIndex + (*StateRequest)(nil), // 57: luceneserver.StateRequest + (*StateResponse)(nil), // 58: luceneserver.StateResponse + (*AddReplicaRequest)(nil), // 59: luceneserver.AddReplicaRequest + (*AddReplicaResponse)(nil), // 60: luceneserver.AddReplicaResponse + (*CopyState)(nil), // 61: luceneserver.CopyState + (*FilesMetadata)(nil), // 62: luceneserver.FilesMetadata + (*FileMetadata)(nil), // 63: luceneserver.FileMetadata + (*CopyFiles)(nil), // 64: luceneserver.CopyFiles + (*CopyStateRequest)(nil), // 65: luceneserver.CopyStateRequest + (*FilesInfo)(nil), // 66: luceneserver.FilesInfo + (*FileInfo)(nil), // 67: luceneserver.FileInfo + (*RawFileChunk)(nil), // 68: luceneserver.RawFileChunk + (*HealthCheckRequest)(nil), // 69: luceneserver.HealthCheckRequest + (*HealthCheckResponse)(nil), // 70: luceneserver.HealthCheckResponse + (*ReadyCheckRequest)(nil), // 71: luceneserver.ReadyCheckRequest + (*TransferStatus)(nil), // 72: luceneserver.TransferStatus + (*NewNRTPoint)(nil), // 73: luceneserver.NewNRTPoint + (*IndexName)(nil), // 74: luceneserver.IndexName + (*SearcherVersion)(nil), // 75: luceneserver.SearcherVersion + (*GetNodesRequest)(nil), // 76: luceneserver.GetNodesRequest + (*GetNodesResponse)(nil), // 77: luceneserver.GetNodesResponse + (*NodeInfo)(nil), // 78: luceneserver.NodeInfo + (*DeleteByQueryRequest)(nil), // 79: luceneserver.DeleteByQueryRequest + (*ForceMergeRequest)(nil), // 80: luceneserver.ForceMergeRequest + (*ForceMergeResponse)(nil), // 81: luceneserver.ForceMergeResponse + (*ForceMergeDeletesRequest)(nil), // 82: luceneserver.ForceMergeDeletesRequest + (*ForceMergeDeletesResponse)(nil), // 83: luceneserver.ForceMergeDeletesResponse + (*IndexSettings)(nil), // 84: luceneserver.IndexSettings + (*IndexLiveSettings)(nil), // 85: luceneserver.IndexLiveSettings + (*IndexStateInfo)(nil), // 86: luceneserver.IndexStateInfo + (*IndexGlobalState)(nil), // 87: luceneserver.IndexGlobalState + (*GlobalStateInfo)(nil), // 88: luceneserver.GlobalStateInfo + (*CustomRequest)(nil), // 89: luceneserver.CustomRequest + (*CustomResponse)(nil), // 90: luceneserver.CustomResponse + (*AddDocumentRequest_MultiValuedField)(nil), // 91: luceneserver.AddDocumentRequest.MultiValuedField + nil, // 92: luceneserver.AddDocumentRequest.FieldsEntry + nil, // 93: luceneserver.IndexStateInfo.FieldsEntry + nil, // 94: luceneserver.GlobalStateInfo.IndicesEntry + nil, // 95: luceneserver.CustomRequest.ParamsEntry + nil, // 96: luceneserver.CustomResponse.ResponseEntry + (*Script)(nil), // 97: luceneserver.Script + (*Analyzer)(nil), // 98: luceneserver.Analyzer + (*structpb.Struct)(nil), // 99: google.protobuf.Struct + (*SortFields)(nil), // 100: luceneserver.SortFields + (*Query)(nil), // 101: luceneserver.Query + (*wrapperspb.DoubleValue)(nil), // 102: google.protobuf.DoubleValue + (*wrapperspb.Int32Value)(nil), // 103: google.protobuf.Int32Value + (*wrapperspb.BoolValue)(nil), // 104: google.protobuf.BoolValue + (*wrapperspb.StringValue)(nil), // 105: google.protobuf.StringValue + (*wrapperspb.UInt64Value)(nil), // 106: google.protobuf.UInt64Value + (*SearchRequest)(nil), // 107: luceneserver.SearchRequest + (*BuildSuggestRequest)(nil), // 108: luceneserver.BuildSuggestRequest + (*SuggestLookupRequest)(nil), // 109: luceneserver.SuggestLookupRequest + (*emptypb.Empty)(nil), // 110: google.protobuf.Empty + (*SearchResponse)(nil), // 111: luceneserver.SearchResponse + (*anypb.Any)(nil), // 112: google.protobuf.Any + (*BuildSuggestResponse)(nil), // 113: luceneserver.BuildSuggestResponse + (*SuggestLookupResponse)(nil), // 114: luceneserver.SuggestLookupResponse + (*httpbody.HttpBody)(nil), // 115: google.api.HttpBody } var file_yelp_nrtsearch_luceneserver_proto_depIdxs = []int32{ - 88, // 0: luceneserver.CreateIndexRequest.settings:type_name -> luceneserver.IndexSettings - 89, // 1: luceneserver.CreateIndexRequest.liveSettings:type_name -> luceneserver.IndexLiveSettings + 84, // 0: luceneserver.CreateIndexRequest.settings:type_name -> luceneserver.IndexSettings + 85, // 1: luceneserver.CreateIndexRequest.liveSettings:type_name -> luceneserver.IndexLiveSettings 14, // 2: luceneserver.CreateIndexRequest.fields:type_name -> luceneserver.Field - 89, // 3: luceneserver.LiveSettingsV2Request.liveSettings:type_name -> luceneserver.IndexLiveSettings - 89, // 4: luceneserver.LiveSettingsV2Response.liveSettings:type_name -> luceneserver.IndexLiveSettings + 85, // 3: luceneserver.LiveSettingsV2Request.liveSettings:type_name -> luceneserver.IndexLiveSettings + 85, // 4: luceneserver.LiveSettingsV2Response.liveSettings:type_name -> luceneserver.IndexLiveSettings 0, // 5: luceneserver.Field.type:type_name -> luceneserver.FieldType 1, // 6: luceneserver.Field.indexOptions:type_name -> luceneserver.IndexOptions - 101, // 7: luceneserver.Field.script:type_name -> luceneserver.Script - 102, // 8: luceneserver.Field.analyzer:type_name -> luceneserver.Analyzer - 102, // 9: luceneserver.Field.indexAnalyzer:type_name -> luceneserver.Analyzer - 102, // 10: luceneserver.Field.searchAnalyzer:type_name -> luceneserver.Analyzer + 97, // 7: luceneserver.Field.script:type_name -> luceneserver.Script + 98, // 8: luceneserver.Field.analyzer:type_name -> luceneserver.Analyzer + 98, // 9: luceneserver.Field.indexAnalyzer:type_name -> luceneserver.Analyzer + 98, // 10: luceneserver.Field.searchAnalyzer:type_name -> luceneserver.Analyzer 2, // 11: luceneserver.Field.termVectors:type_name -> luceneserver.TermVectors 3, // 12: luceneserver.Field.facet:type_name -> luceneserver.FacetType - 103, // 13: luceneserver.Field.additionalProperties:type_name -> google.protobuf.Struct - 103, // 14: luceneserver.Field.similarityParams:type_name -> google.protobuf.Struct + 99, // 13: luceneserver.Field.additionalProperties:type_name -> google.protobuf.Struct + 99, // 14: luceneserver.Field.similarityParams:type_name -> google.protobuf.Struct 14, // 15: luceneserver.Field.childFields:type_name -> luceneserver.Field 15, // 16: luceneserver.Field.vectorIndexingOptions:type_name -> luceneserver.VectorIndexingOptions 14, // 17: luceneserver.FieldDefRequest.field:type_name -> luceneserver.Field - 104, // 18: luceneserver.SettingsRequest.indexSort:type_name -> luceneserver.SortFields - 88, // 19: luceneserver.SettingsV2Request.settings:type_name -> luceneserver.IndexSettings - 88, // 20: luceneserver.SettingsV2Response.settings:type_name -> luceneserver.IndexSettings + 100, // 18: luceneserver.SettingsRequest.indexSort:type_name -> luceneserver.SortFields + 84, // 19: luceneserver.SettingsV2Request.settings:type_name -> luceneserver.IndexSettings + 84, // 20: luceneserver.SettingsV2Response.settings:type_name -> luceneserver.IndexSettings 4, // 21: luceneserver.StartIndexRequest.mode:type_name -> luceneserver.Mode - 60, // 22: luceneserver.StartIndexRequest.restore:type_name -> luceneserver.RestoreIndex - 96, // 23: luceneserver.AddDocumentRequest.fields:type_name -> luceneserver.AddDocumentRequest.FieldsEntry + 56, // 22: luceneserver.StartIndexRequest.restore:type_name -> luceneserver.RestoreIndex + 92, // 23: luceneserver.AddDocumentRequest.fields:type_name -> luceneserver.AddDocumentRequest.FieldsEntry 34, // 24: luceneserver.StatsResponse.taxonomy:type_name -> luceneserver.Taxonomy 35, // 25: luceneserver.StatsResponse.searchers:type_name -> luceneserver.Searcher 35, // 26: luceneserver.StatsResponse.currentSearcher:type_name -> luceneserver.Searcher 46, // 27: luceneserver.CreateSnapshotResponse.snapshotId:type_name -> luceneserver.SnapshotId 46, // 28: luceneserver.ReleaseSnapshotRequest.snapshotId:type_name -> luceneserver.SnapshotId - 59, // 29: luceneserver.IndicesResponse.indicesResponse:type_name -> luceneserver.IndexStatsResponse + 55, // 29: luceneserver.IndicesResponse.indicesResponse:type_name -> luceneserver.IndexStatsResponse 33, // 30: luceneserver.IndexStatsResponse.statsResponse:type_name -> luceneserver.StatsResponse - 66, // 31: luceneserver.CopyState.filesMetadata:type_name -> luceneserver.FilesMetadata - 67, // 32: luceneserver.FilesMetadata.fileMetadata:type_name -> luceneserver.FileMetadata - 66, // 33: luceneserver.CopyFiles.filesMetadata:type_name -> luceneserver.FilesMetadata - 71, // 34: luceneserver.FilesInfo.fileInfo:type_name -> luceneserver.FileInfo + 62, // 31: luceneserver.CopyState.filesMetadata:type_name -> luceneserver.FilesMetadata + 63, // 32: luceneserver.FilesMetadata.fileMetadata:type_name -> luceneserver.FileMetadata + 62, // 33: luceneserver.CopyFiles.filesMetadata:type_name -> luceneserver.FilesMetadata + 67, // 34: luceneserver.FilesInfo.fileInfo:type_name -> luceneserver.FileInfo 5, // 35: luceneserver.HealthCheckResponse.health:type_name -> luceneserver.TransferStatusCode 5, // 36: luceneserver.TransferStatus.Code:type_name -> luceneserver.TransferStatusCode - 82, // 37: luceneserver.GetNodesResponse.nodes:type_name -> luceneserver.NodeInfo - 105, // 38: luceneserver.DeleteByQueryRequest.query:type_name -> luceneserver.Query + 78, // 37: luceneserver.GetNodesResponse.nodes:type_name -> luceneserver.NodeInfo + 101, // 38: luceneserver.DeleteByQueryRequest.query:type_name -> luceneserver.Query 6, // 39: luceneserver.ForceMergeResponse.status:type_name -> luceneserver.ForceMergeResponse.Status 7, // 40: luceneserver.ForceMergeDeletesResponse.status:type_name -> luceneserver.ForceMergeDeletesResponse.Status - 106, // 41: luceneserver.IndexSettings.nrtCachingDirectoryMaxMergeSizeMB:type_name -> google.protobuf.DoubleValue - 106, // 42: luceneserver.IndexSettings.nrtCachingDirectoryMaxSizeMB:type_name -> google.protobuf.DoubleValue - 107, // 43: luceneserver.IndexSettings.concurrentMergeSchedulerMaxThreadCount:type_name -> google.protobuf.Int32Value - 107, // 44: luceneserver.IndexSettings.concurrentMergeSchedulerMaxMergeCount:type_name -> google.protobuf.Int32Value - 104, // 45: luceneserver.IndexSettings.indexSort:type_name -> luceneserver.SortFields - 108, // 46: luceneserver.IndexSettings.indexMergeSchedulerAutoThrottle:type_name -> google.protobuf.BoolValue - 109, // 47: luceneserver.IndexSettings.directory:type_name -> google.protobuf.StringValue - 106, // 48: luceneserver.IndexLiveSettings.maxRefreshSec:type_name -> google.protobuf.DoubleValue - 106, // 49: luceneserver.IndexLiveSettings.minRefreshSec:type_name -> google.protobuf.DoubleValue - 106, // 50: luceneserver.IndexLiveSettings.maxSearcherAgeSec:type_name -> google.protobuf.DoubleValue - 106, // 51: luceneserver.IndexLiveSettings.indexRamBufferSizeMB:type_name -> google.protobuf.DoubleValue - 107, // 52: luceneserver.IndexLiveSettings.addDocumentsMaxBufferLen:type_name -> google.protobuf.Int32Value - 107, // 53: luceneserver.IndexLiveSettings.sliceMaxDocs:type_name -> google.protobuf.Int32Value - 107, // 54: luceneserver.IndexLiveSettings.sliceMaxSegments:type_name -> google.protobuf.Int32Value - 107, // 55: luceneserver.IndexLiveSettings.virtualShards:type_name -> google.protobuf.Int32Value - 107, // 56: luceneserver.IndexLiveSettings.maxMergedSegmentMB:type_name -> google.protobuf.Int32Value - 107, // 57: luceneserver.IndexLiveSettings.segmentsPerTier:type_name -> google.protobuf.Int32Value - 106, // 58: luceneserver.IndexLiveSettings.defaultSearchTimeoutSec:type_name -> google.protobuf.DoubleValue - 107, // 59: luceneserver.IndexLiveSettings.defaultSearchTimeoutCheckEvery:type_name -> google.protobuf.Int32Value - 107, // 60: luceneserver.IndexLiveSettings.defaultTerminateAfter:type_name -> google.protobuf.Int32Value - 110, // 61: luceneserver.IndexLiveSettings.maxMergePreCopyDurationSec:type_name -> google.protobuf.UInt64Value - 88, // 62: luceneserver.IndexStateInfo.settings:type_name -> luceneserver.IndexSettings - 89, // 63: luceneserver.IndexStateInfo.liveSettings:type_name -> luceneserver.IndexLiveSettings - 97, // 64: luceneserver.IndexStateInfo.fields:type_name -> luceneserver.IndexStateInfo.FieldsEntry - 98, // 65: luceneserver.GlobalStateInfo.indices:type_name -> luceneserver.GlobalStateInfo.IndicesEntry - 99, // 66: luceneserver.CustomRequest.params:type_name -> luceneserver.CustomRequest.ParamsEntry - 100, // 67: luceneserver.CustomResponse.response:type_name -> luceneserver.CustomResponse.ResponseEntry + 102, // 41: luceneserver.IndexSettings.nrtCachingDirectoryMaxMergeSizeMB:type_name -> google.protobuf.DoubleValue + 102, // 42: luceneserver.IndexSettings.nrtCachingDirectoryMaxSizeMB:type_name -> google.protobuf.DoubleValue + 103, // 43: luceneserver.IndexSettings.concurrentMergeSchedulerMaxThreadCount:type_name -> google.protobuf.Int32Value + 103, // 44: luceneserver.IndexSettings.concurrentMergeSchedulerMaxMergeCount:type_name -> google.protobuf.Int32Value + 100, // 45: luceneserver.IndexSettings.indexSort:type_name -> luceneserver.SortFields + 104, // 46: luceneserver.IndexSettings.indexMergeSchedulerAutoThrottle:type_name -> google.protobuf.BoolValue + 105, // 47: luceneserver.IndexSettings.directory:type_name -> google.protobuf.StringValue + 102, // 48: luceneserver.IndexLiveSettings.maxRefreshSec:type_name -> google.protobuf.DoubleValue + 102, // 49: luceneserver.IndexLiveSettings.minRefreshSec:type_name -> google.protobuf.DoubleValue + 102, // 50: luceneserver.IndexLiveSettings.maxSearcherAgeSec:type_name -> google.protobuf.DoubleValue + 102, // 51: luceneserver.IndexLiveSettings.indexRamBufferSizeMB:type_name -> google.protobuf.DoubleValue + 103, // 52: luceneserver.IndexLiveSettings.addDocumentsMaxBufferLen:type_name -> google.protobuf.Int32Value + 103, // 53: luceneserver.IndexLiveSettings.sliceMaxDocs:type_name -> google.protobuf.Int32Value + 103, // 54: luceneserver.IndexLiveSettings.sliceMaxSegments:type_name -> google.protobuf.Int32Value + 103, // 55: luceneserver.IndexLiveSettings.virtualShards:type_name -> google.protobuf.Int32Value + 103, // 56: luceneserver.IndexLiveSettings.maxMergedSegmentMB:type_name -> google.protobuf.Int32Value + 103, // 57: luceneserver.IndexLiveSettings.segmentsPerTier:type_name -> google.protobuf.Int32Value + 102, // 58: luceneserver.IndexLiveSettings.defaultSearchTimeoutSec:type_name -> google.protobuf.DoubleValue + 103, // 59: luceneserver.IndexLiveSettings.defaultSearchTimeoutCheckEvery:type_name -> google.protobuf.Int32Value + 103, // 60: luceneserver.IndexLiveSettings.defaultTerminateAfter:type_name -> google.protobuf.Int32Value + 106, // 61: luceneserver.IndexLiveSettings.maxMergePreCopyDurationSec:type_name -> google.protobuf.UInt64Value + 84, // 62: luceneserver.IndexStateInfo.settings:type_name -> luceneserver.IndexSettings + 85, // 63: luceneserver.IndexStateInfo.liveSettings:type_name -> luceneserver.IndexLiveSettings + 93, // 64: luceneserver.IndexStateInfo.fields:type_name -> luceneserver.IndexStateInfo.FieldsEntry + 94, // 65: luceneserver.GlobalStateInfo.indices:type_name -> luceneserver.GlobalStateInfo.IndicesEntry + 95, // 66: luceneserver.CustomRequest.params:type_name -> luceneserver.CustomRequest.ParamsEntry + 96, // 67: luceneserver.CustomResponse.response:type_name -> luceneserver.CustomResponse.ResponseEntry 26, // 68: luceneserver.AddDocumentRequest.MultiValuedField.faceHierarchyPaths:type_name -> luceneserver.FacetHierarchyPath - 95, // 69: luceneserver.AddDocumentRequest.FieldsEntry.value:type_name -> luceneserver.AddDocumentRequest.MultiValuedField + 91, // 69: luceneserver.AddDocumentRequest.FieldsEntry.value:type_name -> luceneserver.AddDocumentRequest.MultiValuedField 14, // 70: luceneserver.IndexStateInfo.FieldsEntry.value:type_name -> luceneserver.Field - 91, // 71: luceneserver.GlobalStateInfo.IndicesEntry.value:type_name -> luceneserver.IndexGlobalState + 87, // 71: luceneserver.GlobalStateInfo.IndicesEntry.value:type_name -> luceneserver.IndexGlobalState 8, // 72: luceneserver.LuceneServer.createIndex:input_type -> luceneserver.CreateIndexRequest 10, // 73: luceneserver.LuceneServer.liveSettings:input_type -> luceneserver.LiveSettingsRequest 12, // 74: luceneserver.LuceneServer.liveSettingsV2:input_type -> luceneserver.LiveSettingsV2Request @@ -7647,89 +7305,85 @@ var file_yelp_nrtsearch_luceneserver_proto_depIdxs = []int32{ 28, // 84: luceneserver.LuceneServer.refresh:input_type -> luceneserver.RefreshRequest 30, // 85: luceneserver.LuceneServer.commit:input_type -> luceneserver.CommitRequest 32, // 86: luceneserver.LuceneServer.stats:input_type -> luceneserver.StatsRequest - 111, // 87: luceneserver.LuceneServer.search:input_type -> luceneserver.SearchRequest - 111, // 88: luceneserver.LuceneServer.searchV2:input_type -> luceneserver.SearchRequest + 107, // 87: luceneserver.LuceneServer.search:input_type -> luceneserver.SearchRequest + 107, // 88: luceneserver.LuceneServer.searchV2:input_type -> luceneserver.SearchRequest 25, // 89: luceneserver.LuceneServer.delete:input_type -> luceneserver.AddDocumentRequest - 83, // 90: luceneserver.LuceneServer.deleteByQuery:input_type -> luceneserver.DeleteByQueryRequest + 79, // 90: luceneserver.LuceneServer.deleteByQuery:input_type -> luceneserver.DeleteByQueryRequest 36, // 91: luceneserver.LuceneServer.deleteAll:input_type -> luceneserver.DeleteAllDocumentsRequest 38, // 92: luceneserver.LuceneServer.deleteIndex:input_type -> luceneserver.DeleteIndexRequest - 112, // 93: luceneserver.LuceneServer.buildSuggest:input_type -> luceneserver.BuildSuggestRequest - 113, // 94: luceneserver.LuceneServer.suggestLookup:input_type -> luceneserver.SuggestLookupRequest - 112, // 95: luceneserver.LuceneServer.updateSuggest:input_type -> luceneserver.BuildSuggestRequest + 108, // 93: luceneserver.LuceneServer.buildSuggest:input_type -> luceneserver.BuildSuggestRequest + 109, // 94: luceneserver.LuceneServer.suggestLookup:input_type -> luceneserver.SuggestLookupRequest + 108, // 95: luceneserver.LuceneServer.updateSuggest:input_type -> luceneserver.BuildSuggestRequest 44, // 96: luceneserver.LuceneServer.createSnapshot:input_type -> luceneserver.CreateSnapshotRequest 47, // 97: luceneserver.LuceneServer.releaseSnapshot:input_type -> luceneserver.ReleaseSnapshotRequest 49, // 98: luceneserver.LuceneServer.getAllSnapshotIndexGen:input_type -> luceneserver.GetAllSnapshotGenRequest - 51, // 99: luceneserver.LuceneServer.backupIndex:input_type -> luceneserver.BackupIndexRequest - 55, // 100: luceneserver.LuceneServer.deleteIndexBackup:input_type -> luceneserver.DeleteIndexBackupRequest - 53, // 101: luceneserver.LuceneServer.backupWarmingQueries:input_type -> luceneserver.BackupWarmingQueriesRequest - 61, // 102: luceneserver.LuceneServer.state:input_type -> luceneserver.StateRequest - 73, // 103: luceneserver.LuceneServer.status:input_type -> luceneserver.HealthCheckRequest - 75, // 104: luceneserver.LuceneServer.ready:input_type -> luceneserver.ReadyCheckRequest - 114, // 105: luceneserver.LuceneServer.metrics:input_type -> google.protobuf.Empty - 57, // 106: luceneserver.LuceneServer.indices:input_type -> luceneserver.IndicesRequest - 84, // 107: luceneserver.LuceneServer.forceMerge:input_type -> luceneserver.ForceMergeRequest - 86, // 108: luceneserver.LuceneServer.forceMergeDeletes:input_type -> luceneserver.ForceMergeDeletesRequest - 93, // 109: luceneserver.LuceneServer.custom:input_type -> luceneserver.CustomRequest - 63, // 110: luceneserver.ReplicationServer.addReplicas:input_type -> luceneserver.AddReplicaRequest - 69, // 111: luceneserver.ReplicationServer.recvCopyState:input_type -> luceneserver.CopyStateRequest - 72, // 112: luceneserver.ReplicationServer.sendRawFile:input_type -> luceneserver.RawFileChunk - 71, // 113: luceneserver.ReplicationServer.recvRawFile:input_type -> luceneserver.FileInfo - 71, // 114: luceneserver.ReplicationServer.recvRawFileV2:input_type -> luceneserver.FileInfo - 68, // 115: luceneserver.ReplicationServer.copyFiles:input_type -> luceneserver.CopyFiles - 77, // 116: luceneserver.ReplicationServer.newNRTPoint:input_type -> luceneserver.NewNRTPoint - 78, // 117: luceneserver.ReplicationServer.writeNRTPoint:input_type -> luceneserver.IndexName - 78, // 118: luceneserver.ReplicationServer.getCurrentSearcherVersion:input_type -> luceneserver.IndexName - 80, // 119: luceneserver.ReplicationServer.getConnectedNodes:input_type -> luceneserver.GetNodesRequest - 9, // 120: luceneserver.LuceneServer.createIndex:output_type -> luceneserver.CreateIndexResponse - 11, // 121: luceneserver.LuceneServer.liveSettings:output_type -> luceneserver.LiveSettingsResponse - 13, // 122: luceneserver.LuceneServer.liveSettingsV2:output_type -> luceneserver.LiveSettingsV2Response - 17, // 123: luceneserver.LuceneServer.registerFields:output_type -> luceneserver.FieldDefResponse - 17, // 124: luceneserver.LuceneServer.updateFields:output_type -> luceneserver.FieldDefResponse - 19, // 125: luceneserver.LuceneServer.settings:output_type -> luceneserver.SettingsResponse - 21, // 126: luceneserver.LuceneServer.settingsV2:output_type -> luceneserver.SettingsV2Response - 24, // 127: luceneserver.LuceneServer.startIndex:output_type -> luceneserver.StartIndexResponse - 24, // 128: luceneserver.LuceneServer.startIndexV2:output_type -> luceneserver.StartIndexResponse - 40, // 129: luceneserver.LuceneServer.stopIndex:output_type -> luceneserver.DummyResponse - 43, // 130: luceneserver.LuceneServer.reloadState:output_type -> luceneserver.ReloadStateResponse - 27, // 131: luceneserver.LuceneServer.addDocuments:output_type -> luceneserver.AddDocumentResponse - 29, // 132: luceneserver.LuceneServer.refresh:output_type -> luceneserver.RefreshResponse - 31, // 133: luceneserver.LuceneServer.commit:output_type -> luceneserver.CommitResponse - 33, // 134: luceneserver.LuceneServer.stats:output_type -> luceneserver.StatsResponse - 115, // 135: luceneserver.LuceneServer.search:output_type -> luceneserver.SearchResponse - 116, // 136: luceneserver.LuceneServer.searchV2:output_type -> google.protobuf.Any - 27, // 137: luceneserver.LuceneServer.delete:output_type -> luceneserver.AddDocumentResponse - 27, // 138: luceneserver.LuceneServer.deleteByQuery:output_type -> luceneserver.AddDocumentResponse - 37, // 139: luceneserver.LuceneServer.deleteAll:output_type -> luceneserver.DeleteAllDocumentsResponse - 39, // 140: luceneserver.LuceneServer.deleteIndex:output_type -> luceneserver.DeleteIndexResponse - 117, // 141: luceneserver.LuceneServer.buildSuggest:output_type -> luceneserver.BuildSuggestResponse - 118, // 142: luceneserver.LuceneServer.suggestLookup:output_type -> luceneserver.SuggestLookupResponse - 117, // 143: luceneserver.LuceneServer.updateSuggest:output_type -> luceneserver.BuildSuggestResponse - 45, // 144: luceneserver.LuceneServer.createSnapshot:output_type -> luceneserver.CreateSnapshotResponse - 48, // 145: luceneserver.LuceneServer.releaseSnapshot:output_type -> luceneserver.ReleaseSnapshotResponse - 50, // 146: luceneserver.LuceneServer.getAllSnapshotIndexGen:output_type -> luceneserver.GetAllSnapshotGenResponse - 52, // 147: luceneserver.LuceneServer.backupIndex:output_type -> luceneserver.BackupIndexResponse - 56, // 148: luceneserver.LuceneServer.deleteIndexBackup:output_type -> luceneserver.DeleteIndexBackupResponse - 54, // 149: luceneserver.LuceneServer.backupWarmingQueries:output_type -> luceneserver.BackupWarmingQueriesResponse - 62, // 150: luceneserver.LuceneServer.state:output_type -> luceneserver.StateResponse - 74, // 151: luceneserver.LuceneServer.status:output_type -> luceneserver.HealthCheckResponse - 74, // 152: luceneserver.LuceneServer.ready:output_type -> luceneserver.HealthCheckResponse - 119, // 153: luceneserver.LuceneServer.metrics:output_type -> google.api.HttpBody - 58, // 154: luceneserver.LuceneServer.indices:output_type -> luceneserver.IndicesResponse - 85, // 155: luceneserver.LuceneServer.forceMerge:output_type -> luceneserver.ForceMergeResponse - 87, // 156: luceneserver.LuceneServer.forceMergeDeletes:output_type -> luceneserver.ForceMergeDeletesResponse - 94, // 157: luceneserver.LuceneServer.custom:output_type -> luceneserver.CustomResponse - 64, // 158: luceneserver.ReplicationServer.addReplicas:output_type -> luceneserver.AddReplicaResponse - 65, // 159: luceneserver.ReplicationServer.recvCopyState:output_type -> luceneserver.CopyState - 76, // 160: luceneserver.ReplicationServer.sendRawFile:output_type -> luceneserver.TransferStatus - 72, // 161: luceneserver.ReplicationServer.recvRawFile:output_type -> luceneserver.RawFileChunk - 72, // 162: luceneserver.ReplicationServer.recvRawFileV2:output_type -> luceneserver.RawFileChunk - 76, // 163: luceneserver.ReplicationServer.copyFiles:output_type -> luceneserver.TransferStatus - 76, // 164: luceneserver.ReplicationServer.newNRTPoint:output_type -> luceneserver.TransferStatus - 79, // 165: luceneserver.ReplicationServer.writeNRTPoint:output_type -> luceneserver.SearcherVersion - 79, // 166: luceneserver.ReplicationServer.getCurrentSearcherVersion:output_type -> luceneserver.SearcherVersion - 81, // 167: luceneserver.ReplicationServer.getConnectedNodes:output_type -> luceneserver.GetNodesResponse - 120, // [120:168] is the sub-list for method output_type - 72, // [72:120] is the sub-list for method input_type + 51, // 99: luceneserver.LuceneServer.backupWarmingQueries:input_type -> luceneserver.BackupWarmingQueriesRequest + 57, // 100: luceneserver.LuceneServer.state:input_type -> luceneserver.StateRequest + 69, // 101: luceneserver.LuceneServer.status:input_type -> luceneserver.HealthCheckRequest + 71, // 102: luceneserver.LuceneServer.ready:input_type -> luceneserver.ReadyCheckRequest + 110, // 103: luceneserver.LuceneServer.metrics:input_type -> google.protobuf.Empty + 53, // 104: luceneserver.LuceneServer.indices:input_type -> luceneserver.IndicesRequest + 80, // 105: luceneserver.LuceneServer.forceMerge:input_type -> luceneserver.ForceMergeRequest + 82, // 106: luceneserver.LuceneServer.forceMergeDeletes:input_type -> luceneserver.ForceMergeDeletesRequest + 89, // 107: luceneserver.LuceneServer.custom:input_type -> luceneserver.CustomRequest + 59, // 108: luceneserver.ReplicationServer.addReplicas:input_type -> luceneserver.AddReplicaRequest + 65, // 109: luceneserver.ReplicationServer.recvCopyState:input_type -> luceneserver.CopyStateRequest + 68, // 110: luceneserver.ReplicationServer.sendRawFile:input_type -> luceneserver.RawFileChunk + 67, // 111: luceneserver.ReplicationServer.recvRawFile:input_type -> luceneserver.FileInfo + 67, // 112: luceneserver.ReplicationServer.recvRawFileV2:input_type -> luceneserver.FileInfo + 64, // 113: luceneserver.ReplicationServer.copyFiles:input_type -> luceneserver.CopyFiles + 73, // 114: luceneserver.ReplicationServer.newNRTPoint:input_type -> luceneserver.NewNRTPoint + 74, // 115: luceneserver.ReplicationServer.writeNRTPoint:input_type -> luceneserver.IndexName + 74, // 116: luceneserver.ReplicationServer.getCurrentSearcherVersion:input_type -> luceneserver.IndexName + 76, // 117: luceneserver.ReplicationServer.getConnectedNodes:input_type -> luceneserver.GetNodesRequest + 9, // 118: luceneserver.LuceneServer.createIndex:output_type -> luceneserver.CreateIndexResponse + 11, // 119: luceneserver.LuceneServer.liveSettings:output_type -> luceneserver.LiveSettingsResponse + 13, // 120: luceneserver.LuceneServer.liveSettingsV2:output_type -> luceneserver.LiveSettingsV2Response + 17, // 121: luceneserver.LuceneServer.registerFields:output_type -> luceneserver.FieldDefResponse + 17, // 122: luceneserver.LuceneServer.updateFields:output_type -> luceneserver.FieldDefResponse + 19, // 123: luceneserver.LuceneServer.settings:output_type -> luceneserver.SettingsResponse + 21, // 124: luceneserver.LuceneServer.settingsV2:output_type -> luceneserver.SettingsV2Response + 24, // 125: luceneserver.LuceneServer.startIndex:output_type -> luceneserver.StartIndexResponse + 24, // 126: luceneserver.LuceneServer.startIndexV2:output_type -> luceneserver.StartIndexResponse + 40, // 127: luceneserver.LuceneServer.stopIndex:output_type -> luceneserver.DummyResponse + 43, // 128: luceneserver.LuceneServer.reloadState:output_type -> luceneserver.ReloadStateResponse + 27, // 129: luceneserver.LuceneServer.addDocuments:output_type -> luceneserver.AddDocumentResponse + 29, // 130: luceneserver.LuceneServer.refresh:output_type -> luceneserver.RefreshResponse + 31, // 131: luceneserver.LuceneServer.commit:output_type -> luceneserver.CommitResponse + 33, // 132: luceneserver.LuceneServer.stats:output_type -> luceneserver.StatsResponse + 111, // 133: luceneserver.LuceneServer.search:output_type -> luceneserver.SearchResponse + 112, // 134: luceneserver.LuceneServer.searchV2:output_type -> google.protobuf.Any + 27, // 135: luceneserver.LuceneServer.delete:output_type -> luceneserver.AddDocumentResponse + 27, // 136: luceneserver.LuceneServer.deleteByQuery:output_type -> luceneserver.AddDocumentResponse + 37, // 137: luceneserver.LuceneServer.deleteAll:output_type -> luceneserver.DeleteAllDocumentsResponse + 39, // 138: luceneserver.LuceneServer.deleteIndex:output_type -> luceneserver.DeleteIndexResponse + 113, // 139: luceneserver.LuceneServer.buildSuggest:output_type -> luceneserver.BuildSuggestResponse + 114, // 140: luceneserver.LuceneServer.suggestLookup:output_type -> luceneserver.SuggestLookupResponse + 113, // 141: luceneserver.LuceneServer.updateSuggest:output_type -> luceneserver.BuildSuggestResponse + 45, // 142: luceneserver.LuceneServer.createSnapshot:output_type -> luceneserver.CreateSnapshotResponse + 48, // 143: luceneserver.LuceneServer.releaseSnapshot:output_type -> luceneserver.ReleaseSnapshotResponse + 50, // 144: luceneserver.LuceneServer.getAllSnapshotIndexGen:output_type -> luceneserver.GetAllSnapshotGenResponse + 52, // 145: luceneserver.LuceneServer.backupWarmingQueries:output_type -> luceneserver.BackupWarmingQueriesResponse + 58, // 146: luceneserver.LuceneServer.state:output_type -> luceneserver.StateResponse + 70, // 147: luceneserver.LuceneServer.status:output_type -> luceneserver.HealthCheckResponse + 70, // 148: luceneserver.LuceneServer.ready:output_type -> luceneserver.HealthCheckResponse + 115, // 149: luceneserver.LuceneServer.metrics:output_type -> google.api.HttpBody + 54, // 150: luceneserver.LuceneServer.indices:output_type -> luceneserver.IndicesResponse + 81, // 151: luceneserver.LuceneServer.forceMerge:output_type -> luceneserver.ForceMergeResponse + 83, // 152: luceneserver.LuceneServer.forceMergeDeletes:output_type -> luceneserver.ForceMergeDeletesResponse + 90, // 153: luceneserver.LuceneServer.custom:output_type -> luceneserver.CustomResponse + 60, // 154: luceneserver.ReplicationServer.addReplicas:output_type -> luceneserver.AddReplicaResponse + 61, // 155: luceneserver.ReplicationServer.recvCopyState:output_type -> luceneserver.CopyState + 72, // 156: luceneserver.ReplicationServer.sendRawFile:output_type -> luceneserver.TransferStatus + 68, // 157: luceneserver.ReplicationServer.recvRawFile:output_type -> luceneserver.RawFileChunk + 68, // 158: luceneserver.ReplicationServer.recvRawFileV2:output_type -> luceneserver.RawFileChunk + 72, // 159: luceneserver.ReplicationServer.copyFiles:output_type -> luceneserver.TransferStatus + 72, // 160: luceneserver.ReplicationServer.newNRTPoint:output_type -> luceneserver.TransferStatus + 75, // 161: luceneserver.ReplicationServer.writeNRTPoint:output_type -> luceneserver.SearcherVersion + 75, // 162: luceneserver.ReplicationServer.getCurrentSearcherVersion:output_type -> luceneserver.SearcherVersion + 77, // 163: luceneserver.ReplicationServer.getConnectedNodes:output_type -> luceneserver.GetNodesResponse + 118, // [118:164] is the sub-list for method output_type + 72, // [72:118] is the sub-list for method input_type 72, // [72:72] is the sub-list for extension type_name 72, // [72:72] is the sub-list for extension extendee 0, // [0:72] is the sub-list for field type_name @@ -8261,30 +7915,6 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { } } file_yelp_nrtsearch_luceneserver_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BackupIndexRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BackupIndexResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BackupWarmingQueriesRequest); i { case 0: return &v.state @@ -8296,7 +7926,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BackupWarmingQueriesResponse); i { case 0: return &v.state @@ -8308,31 +7938,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteIndexBackupRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteIndexBackupResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*IndicesRequest); i { case 0: return &v.state @@ -8344,7 +7950,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*IndicesResponse); i { case 0: return &v.state @@ -8356,7 +7962,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*IndexStatsResponse); i { case 0: return &v.state @@ -8368,7 +7974,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RestoreIndex); i { case 0: return &v.state @@ -8380,7 +7986,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*StateRequest); i { case 0: return &v.state @@ -8392,7 +7998,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*StateResponse); i { case 0: return &v.state @@ -8404,7 +8010,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AddReplicaRequest); i { case 0: return &v.state @@ -8416,7 +8022,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AddReplicaResponse); i { case 0: return &v.state @@ -8428,7 +8034,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CopyState); i { case 0: return &v.state @@ -8440,7 +8046,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*FilesMetadata); i { case 0: return &v.state @@ -8452,7 +8058,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*FileMetadata); i { case 0: return &v.state @@ -8464,7 +8070,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CopyFiles); i { case 0: return &v.state @@ -8476,7 +8082,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CopyStateRequest); i { case 0: return &v.state @@ -8488,7 +8094,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*FilesInfo); i { case 0: return &v.state @@ -8500,7 +8106,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*FileInfo); i { case 0: return &v.state @@ -8512,7 +8118,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RawFileChunk); i { case 0: return &v.state @@ -8524,7 +8130,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*HealthCheckRequest); i { case 0: return &v.state @@ -8536,7 +8142,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*HealthCheckResponse); i { case 0: return &v.state @@ -8548,7 +8154,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ReadyCheckRequest); i { case 0: return &v.state @@ -8560,7 +8166,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TransferStatus); i { case 0: return &v.state @@ -8572,7 +8178,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*NewNRTPoint); i { case 0: return &v.state @@ -8584,7 +8190,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*IndexName); i { case 0: return &v.state @@ -8596,7 +8202,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SearcherVersion); i { case 0: return &v.state @@ -8608,7 +8214,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetNodesRequest); i { case 0: return &v.state @@ -8620,7 +8226,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetNodesResponse); i { case 0: return &v.state @@ -8632,7 +8238,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*NodeInfo); i { case 0: return &v.state @@ -8644,7 +8250,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DeleteByQueryRequest); i { case 0: return &v.state @@ -8656,7 +8262,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ForceMergeRequest); i { case 0: return &v.state @@ -8668,7 +8274,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ForceMergeResponse); i { case 0: return &v.state @@ -8680,7 +8286,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ForceMergeDeletesRequest); i { case 0: return &v.state @@ -8692,7 +8298,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ForceMergeDeletesResponse); i { case 0: return &v.state @@ -8704,7 +8310,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*IndexSettings); i { case 0: return &v.state @@ -8716,7 +8322,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[81].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*IndexLiveSettings); i { case 0: return &v.state @@ -8728,7 +8334,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[82].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*IndexStateInfo); i { case 0: return &v.state @@ -8740,7 +8346,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[83].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*IndexGlobalState); i { case 0: return &v.state @@ -8752,7 +8358,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[84].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GlobalStateInfo); i { case 0: return &v.state @@ -8764,7 +8370,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[85].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[81].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CustomRequest); i { case 0: return &v.state @@ -8776,7 +8382,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[86].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[82].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CustomResponse); i { case 0: return &v.state @@ -8788,7 +8394,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { return nil } } - file_yelp_nrtsearch_luceneserver_proto_msgTypes[87].Exporter = func(v interface{}, i int) interface{} { + file_yelp_nrtsearch_luceneserver_proto_msgTypes[83].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AddDocumentRequest_MultiValuedField); i { case 0: return &v.state @@ -8807,7 +8413,7 @@ func file_yelp_nrtsearch_luceneserver_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_yelp_nrtsearch_luceneserver_proto_rawDesc, NumEnums: 8, - NumMessages: 93, + NumMessages: 89, NumExtensions: 0, NumServices: 2, }, @@ -8910,9 +8516,6 @@ type LuceneServerClient interface { ReleaseSnapshot(ctx context.Context, in *ReleaseSnapshotRequest, opts ...grpc.CallOption) (*ReleaseSnapshotResponse, error) // Gets all unreleased index gens of snapshots previously created with @createSnapshot. GetAllSnapshotIndexGen(ctx context.Context, in *GetAllSnapshotGenRequest, opts ...grpc.CallOption) (*GetAllSnapshotGenResponse, error) - // backs up a resource (index) and it associated metadata e.g. settings, schema to s3 - BackupIndex(ctx context.Context, in *BackupIndexRequest, opts ...grpc.CallOption) (*BackupIndexResponse, error) - DeleteIndexBackup(ctx context.Context, in *DeleteIndexBackupRequest, opts ...grpc.CallOption) (*DeleteIndexBackupResponse, error) // Backup warming queries to S3 BackupWarmingQueries(ctx context.Context, in *BackupWarmingQueriesRequest, opts ...grpc.CallOption) (*BackupWarmingQueriesResponse, error) // Gets the state of a started index, includes settings, live_settings, search schema, suggest schema @@ -9218,24 +8821,6 @@ func (c *luceneServerClient) GetAllSnapshotIndexGen(ctx context.Context, in *Get return out, nil } -func (c *luceneServerClient) BackupIndex(ctx context.Context, in *BackupIndexRequest, opts ...grpc.CallOption) (*BackupIndexResponse, error) { - out := new(BackupIndexResponse) - err := c.cc.Invoke(ctx, "/luceneserver.LuceneServer/backupIndex", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *luceneServerClient) DeleteIndexBackup(ctx context.Context, in *DeleteIndexBackupRequest, opts ...grpc.CallOption) (*DeleteIndexBackupResponse, error) { - out := new(DeleteIndexBackupResponse) - err := c.cc.Invoke(ctx, "/luceneserver.LuceneServer/deleteIndexBackup", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *luceneServerClient) BackupWarmingQueries(ctx context.Context, in *BackupWarmingQueriesRequest, opts ...grpc.CallOption) (*BackupWarmingQueriesResponse, error) { out := new(BackupWarmingQueriesResponse) err := c.cc.Invoke(ctx, "/luceneserver.LuceneServer/backupWarmingQueries", in, out, opts...) @@ -9395,9 +8980,6 @@ type LuceneServerServer interface { ReleaseSnapshot(context.Context, *ReleaseSnapshotRequest) (*ReleaseSnapshotResponse, error) // Gets all unreleased index gens of snapshots previously created with @createSnapshot. GetAllSnapshotIndexGen(context.Context, *GetAllSnapshotGenRequest) (*GetAllSnapshotGenResponse, error) - // backs up a resource (index) and it associated metadata e.g. settings, schema to s3 - BackupIndex(context.Context, *BackupIndexRequest) (*BackupIndexResponse, error) - DeleteIndexBackup(context.Context, *DeleteIndexBackupRequest) (*DeleteIndexBackupResponse, error) // Backup warming queries to S3 BackupWarmingQueries(context.Context, *BackupWarmingQueriesRequest) (*BackupWarmingQueriesResponse, error) // Gets the state of a started index, includes settings, live_settings, search schema, suggest schema @@ -9512,12 +9094,6 @@ func (*UnimplementedLuceneServerServer) ReleaseSnapshot(context.Context, *Releas func (*UnimplementedLuceneServerServer) GetAllSnapshotIndexGen(context.Context, *GetAllSnapshotGenRequest) (*GetAllSnapshotGenResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetAllSnapshotIndexGen not implemented") } -func (*UnimplementedLuceneServerServer) BackupIndex(context.Context, *BackupIndexRequest) (*BackupIndexResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method BackupIndex not implemented") -} -func (*UnimplementedLuceneServerServer) DeleteIndexBackup(context.Context, *DeleteIndexBackupRequest) (*DeleteIndexBackupResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method DeleteIndexBackup not implemented") -} func (*UnimplementedLuceneServerServer) BackupWarmingQueries(context.Context, *BackupWarmingQueriesRequest) (*BackupWarmingQueriesResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method BackupWarmingQueries not implemented") } @@ -10044,42 +9620,6 @@ func _LuceneServer_GetAllSnapshotIndexGen_Handler(srv interface{}, ctx context.C return interceptor(ctx, in, info, handler) } -func _LuceneServer_BackupIndex_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(BackupIndexRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(LuceneServerServer).BackupIndex(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/luceneserver.LuceneServer/BackupIndex", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(LuceneServerServer).BackupIndex(ctx, req.(*BackupIndexRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _LuceneServer_DeleteIndexBackup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(DeleteIndexBackupRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(LuceneServerServer).DeleteIndexBackup(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/luceneserver.LuceneServer/DeleteIndexBackup", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(LuceneServerServer).DeleteIndexBackup(ctx, req.(*DeleteIndexBackupRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _LuceneServer_BackupWarmingQueries_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(BackupWarmingQueriesRequest) if err := dec(in); err != nil { @@ -10350,14 +9890,6 @@ var _LuceneServer_serviceDesc = grpc.ServiceDesc{ MethodName: "getAllSnapshotIndexGen", Handler: _LuceneServer_GetAllSnapshotIndexGen_Handler, }, - { - MethodName: "backupIndex", - Handler: _LuceneServer_BackupIndex_Handler, - }, - { - MethodName: "deleteIndexBackup", - Handler: _LuceneServer_DeleteIndexBackup_Handler, - }, { MethodName: "backupWarmingQueries", Handler: _LuceneServer_BackupWarmingQueries_Handler, diff --git a/grpc-gateway/luceneserver.pb.gw.go b/grpc-gateway/luceneserver.pb.gw.go index 9da9f00b6..c62a5a97f 100644 --- a/grpc-gateway/luceneserver.pb.gw.go +++ b/grpc-gateway/luceneserver.pb.gw.go @@ -1180,74 +1180,6 @@ func local_request_LuceneServer_GetAllSnapshotIndexGen_0(ctx context.Context, ma } -func request_LuceneServer_BackupIndex_0(ctx context.Context, marshaler runtime.Marshaler, client LuceneServerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq BackupIndexRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := client.BackupIndex(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_LuceneServer_BackupIndex_0(ctx context.Context, marshaler runtime.Marshaler, server LuceneServerServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq BackupIndexRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.BackupIndex(ctx, &protoReq) - return msg, metadata, err - -} - -func request_LuceneServer_DeleteIndexBackup_0(ctx context.Context, marshaler runtime.Marshaler, client LuceneServerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq DeleteIndexBackupRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := client.DeleteIndexBackup(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_LuceneServer_DeleteIndexBackup_0(ctx context.Context, marshaler runtime.Marshaler, server LuceneServerServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq DeleteIndexBackupRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.DeleteIndexBackup(ctx, &protoReq) - return msg, metadata, err - -} - func request_LuceneServer_BackupWarmingQueries_0(ctx context.Context, marshaler runtime.Marshaler, client LuceneServerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq BackupWarmingQueriesRequest var metadata runtime.ServerMetadata @@ -2372,52 +2304,6 @@ func RegisterLuceneServerHandlerServer(ctx context.Context, mux *runtime.ServeMu }) - mux.Handle("POST", pattern_LuceneServer_BackupIndex_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_LuceneServer_BackupIndex_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_LuceneServer_BackupIndex_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_LuceneServer_DeleteIndexBackup_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_LuceneServer_DeleteIndexBackup_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_LuceneServer_DeleteIndexBackup_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - mux.Handle("POST", pattern_LuceneServer_BackupWarmingQueries_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -3312,46 +3198,6 @@ func RegisterLuceneServerHandlerClient(ctx context.Context, mux *runtime.ServeMu }) - mux.Handle("POST", pattern_LuceneServer_BackupIndex_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_LuceneServer_BackupIndex_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_LuceneServer_BackupIndex_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_LuceneServer_DeleteIndexBackup_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_LuceneServer_DeleteIndexBackup_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_LuceneServer_DeleteIndexBackup_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - mux.Handle("POST", pattern_LuceneServer_BackupWarmingQueries_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -3636,10 +3482,6 @@ var ( pattern_LuceneServer_GetAllSnapshotIndexGen_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "get_all_snapshot_index_gen", "indexName"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_LuceneServer_BackupIndex_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "backup_index"}, "", runtime.AssumeColonVerbOpt(true))) - - pattern_LuceneServer_DeleteIndexBackup_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "delete_index_backup"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_LuceneServer_BackupWarmingQueries_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "backup_warming_queries"}, "", runtime.AssumeColonVerbOpt(true))) pattern_LuceneServer_State_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "state"}, "", runtime.AssumeColonVerbOpt(true))) @@ -3724,10 +3566,6 @@ var ( forward_LuceneServer_GetAllSnapshotIndexGen_0 = runtime.ForwardResponseMessage - forward_LuceneServer_BackupIndex_0 = runtime.ForwardResponseMessage - - forward_LuceneServer_DeleteIndexBackup_0 = runtime.ForwardResponseMessage - forward_LuceneServer_BackupWarmingQueries_0 = runtime.ForwardResponseMessage forward_LuceneServer_State_0 = runtime.ForwardResponseMessage diff --git a/grpc-gateway/luceneserver.swagger.json b/grpc-gateway/luceneserver.swagger.json index 7f2b086bd..572ac9546 100644 --- a/grpc-gateway/luceneserver.swagger.json +++ b/grpc-gateway/luceneserver.swagger.json @@ -68,39 +68,6 @@ ] } }, - "/v1/backup_index": { - "post": { - "summary": "backs up a resource (index) and it associated metadata e.g. settings, schema to s3", - "operationId": "LuceneServer_backupIndex", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/luceneserverBackupIndexResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/runtimeError" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/luceneserverBackupIndexRequest" - } - } - ], - "tags": [ - "LuceneServer" - ] - } - }, "/v1/backup_warming_queries": { "post": { "summary": "Backup warming queries to S3", @@ -410,38 +377,6 @@ ] } }, - "/v1/delete_index_backup": { - "post": { - "operationId": "LuceneServer_deleteIndexBackup", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/luceneserverDeleteIndexBackupResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/runtimeError" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/luceneserverDeleteIndexBackupRequest" - } - } - ], - "tags": [ - "LuceneServer" - ] - } - }, "/v1/force_merge": { "post": { "summary": "Forces merge policy to merge segments until there are \u003c= maxNumSegments. The actual\nmerges to be executed are determined by the MergePolicy. This call will merge those\nsegments present in the index when the call started. If other threads are still\nadding documents and flushing segments, those newly created segments will not be\nmerged unless you call forceMerge again.", @@ -2313,37 +2248,6 @@ }, "title": "Suggester that first analyzes the surface form, adds the analyzed form to a weighted FST, and then does the same thing at lookup time (see @lucene:suggest:org.apache.lucene.search.suggest.analyzing.AnalyzingSuggester" }, - "luceneserverBackupIndexRequest": { - "type": "object", - "properties": { - "indexName": { - "type": "string" - }, - "serviceName": { - "type": "string" - }, - "resourceName": { - "type": "string" - }, - "completeDirectory": { - "type": "boolean" - }, - "stream": { - "type": "boolean" - } - } - }, - "luceneserverBackupIndexResponse": { - "type": "object", - "properties": { - "dataVersionHash": { - "type": "string" - }, - "metadataVersionHash": { - "type": "string" - } - } - }, "luceneserverBackupWarmingQueriesRequest": { "type": "object", "properties": { @@ -2843,53 +2747,6 @@ } } }, - "luceneserverDeleteIndexBackupRequest": { - "type": "object", - "properties": { - "indexName": { - "type": "string" - }, - "serviceName": { - "type": "string" - }, - "resourceName": { - "type": "string" - }, - "nDays": { - "type": "integer", - "format": "int32" - } - } - }, - "luceneserverDeleteIndexBackupResponse": { - "type": "object", - "properties": { - "deletedResourceDataHashes": { - "type": "array", - "items": { - "type": "string" - } - }, - "deletedResourceMetadataHashes": { - "type": "array", - "items": { - "type": "string" - } - }, - "deletedDataVersions": { - "type": "array", - "items": { - "type": "string" - } - }, - "deletedMetadataVersions": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, "luceneserverDeleteIndexRequest": { "type": "object", "properties": { diff --git a/src/main/java/com/yelp/nrtsearch/ArchiverModule.java b/src/main/java/com/yelp/nrtsearch/ArchiverModule.java index 8d774e245..7a4a863ae 100644 --- a/src/main/java/com/yelp/nrtsearch/ArchiverModule.java +++ b/src/main/java/com/yelp/nrtsearch/ArchiverModule.java @@ -22,7 +22,8 @@ import com.google.inject.name.Names; import com.yelp.nrtsearch.server.backup.*; import com.yelp.nrtsearch.server.config.LuceneServerConfiguration; -import java.nio.file.Path; +import com.yelp.nrtsearch.server.remote.RemoteBackend; +import com.yelp.nrtsearch.server.remote.s3.S3Backend; import java.nio.file.Paths; import java.util.concurrent.*; @@ -46,10 +47,6 @@ protected void configure() { .annotatedWith(Names.named("fileCompressAndUploaderWithTar")) .toProvider(FileCompressAndUploaderWithTar.class) .asEagerSingleton(); - bind(Archiver.class) - .annotatedWith(Names.named("legacyArchiver")) - .toProvider(LegacyArchiverProvider.class) - .asEagerSingleton(); bind(BackupDiffManager.class).toProvider(BackupDiffManagerProvider.class).asEagerSingleton(); bind(Archiver.class) .annotatedWith(Names.named("incArchiver")) @@ -160,23 +157,6 @@ public BackupDiffManager get() { } } - private static class LegacyArchiverProvider implements Provider { - @Inject AmazonS3 s3; - @Inject LuceneServerConfiguration luceneServerConfiguration; - @Inject Tar tar; - - @Override - public Archiver get() { - Path archiveDir = Paths.get(luceneServerConfiguration.getArchiveDirectory()); - return new ArchiverImpl( - s3, - luceneServerConfiguration.getBucketName(), - archiveDir, - tar, - luceneServerConfiguration.getDownloadAsStream()); - } - } - private static class IncArchiverProvider implements Provider { @Inject BackupDiffManager backupDiffManager; @@ -201,4 +181,12 @@ public Archiver get() { Paths.get(luceneServerConfiguration.getArchiveDirectory())); } } + + @Inject + @Singleton + @Provides + protected RemoteBackend providesRemoteBackend( + LuceneServerConfiguration configuration, AmazonS3 s3) { + return new S3Backend(configuration, s3); + } } diff --git a/src/main/java/com/yelp/nrtsearch/server/backup/ArchiverImpl.java b/src/main/java/com/yelp/nrtsearch/server/backup/ArchiverImpl.java deleted file mode 100644 index 053d7520f..000000000 --- a/src/main/java/com/yelp/nrtsearch/server/backup/ArchiverImpl.java +++ /dev/null @@ -1,408 +0,0 @@ -/* - * Copyright 2020 Yelp Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yelp.nrtsearch.server.backup; - -import static com.yelp.nrtsearch.server.utils.S3Downloader.NUM_S3_THREADS; - -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.model.*; -import com.amazonaws.services.s3.transfer.*; -import com.google.inject.Inject; -import com.yelp.nrtsearch.server.utils.S3Downloader; -import java.io.*; -import java.nio.file.*; -import java.util.*; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadPoolExecutor; -import net.jpountz.lz4.LZ4FrameInputStream; -import org.apache.commons.codec.DecoderException; -import org.apache.commons.codec.binary.Hex; -import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; -import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This implementation is deprecated. IndexArchiver is the current implementation that facilitates - * incremental backups and faster downloads. - */ -@Deprecated -public class ArchiverImpl implements Archiver { - public static final String DELIMITER = "/"; - private static final Logger logger = LoggerFactory.getLogger(ArchiverImpl.class); - private static final String CURRENT_VERSION_NAME = "current"; - private static final String TMP_SUFFIX = ".tmp"; - - private final AmazonS3 s3; - private final String bucketName; - private final Path archiverDirectory; - private final Tar tar; - private final VersionManager versionManger; - private final TransferManager transferManager; - private final ThreadPoolExecutor executor = - (ThreadPoolExecutor) Executors.newFixedThreadPool(NUM_S3_THREADS); - private final S3Downloader s3Downloader; - private final boolean downloadAsStream; - - @Inject - public ArchiverImpl( - final AmazonS3 s3, - final String bucketName, - final Path archiverDirectory, - final Tar tar, - final boolean downloadAsStream) { - this.s3 = s3; - this.transferManager = - TransferManagerBuilder.standard() - .withS3Client(s3) - .withExecutorFactory(() -> executor) - .withShutDownThreadPools(false) - .build(); - this.bucketName = bucketName; - this.archiverDirectory = archiverDirectory; - this.tar = tar; - this.versionManger = new VersionManager(s3, bucketName); - this.s3Downloader = new S3Downloader(s3, executor); - this.downloadAsStream = downloadAsStream; - } - - public ArchiverImpl( - final AmazonS3 s3, final String bucketName, final Path archiverDirectory, final Tar tar) { - this(s3, bucketName, archiverDirectory, tar, false); - } - - @Override - public Path download(String serviceName, String resource) throws IOException { - if (!Files.exists(archiverDirectory)) { - logger.info("Archiver directory doesn't exist: " + archiverDirectory + " creating new "); - Files.createDirectories(archiverDirectory); - } - - final String latestVersion = getVersionString(serviceName, resource, "_latest_version"); - final String versionHash = getVersionString(serviceName, resource, latestVersion); - final Path resourceDestDirectory = archiverDirectory.resolve(resource); - final Path versionDirectory = resourceDestDirectory.resolve(versionHash); - final Path currentDirectory = resourceDestDirectory.resolve("current"); - final Path tempCurrentLink = resourceDestDirectory.resolve(getTmpName()); - final Path relativeVersionDirectory = Paths.get(versionHash); - logger.info( - "Downloading resource {} for service {} version {} to directory {}", - resource, - serviceName, - versionHash, - versionDirectory); - getVersionContent(serviceName, resource, versionHash, versionDirectory); - try { - logger.info("Point current version symlink to new resource {}", resource); - Files.createSymbolicLink(tempCurrentLink, relativeVersionDirectory); - Files.move(tempCurrentLink, currentDirectory, StandardCopyOption.REPLACE_EXISTING); - } finally { - if (Files.exists(tempCurrentLink)) { - FileUtils.deleteDirectory(tempCurrentLink.toFile()); - } - } - cleanupFiles(versionHash, resourceDestDirectory); - return currentDirectory; - } - - @Override - public List getResources(String serviceName) { - List resources = new ArrayList<>(); - ListObjectsRequest listObjectsRequest = - new ListObjectsRequest() - .withBucketName(bucketName) - .withPrefix(serviceName + DELIMITER) - .withDelimiter(DELIMITER); - List resourcePrefixes = s3.listObjects(listObjectsRequest).getCommonPrefixes(); - for (String resource : resourcePrefixes) { - String[] prefix = resource.split(DELIMITER); - String potentialResourceName = prefix[prefix.length - 1]; - if (!potentialResourceName.equals("_version")) { - resources.add(potentialResourceName); - } - } - return resources; - } - - @Override - public List getVersionedResource(String serviceName, String resource) { - List resources = new ArrayList<>(); - ListObjectsRequest listObjectsRequest = - new ListObjectsRequest() - .withBucketName(bucketName) - .withPrefix(serviceName + DELIMITER + resource + DELIMITER) - .withDelimiter(DELIMITER); - - List objects = s3.listObjects(listObjectsRequest).getObjectSummaries(); - - for (S3ObjectSummary object : objects) { - String key = object.getKey(); - String[] prefix = key.split(DELIMITER); - String versionHash = prefix[prefix.length - 1]; - VersionedResource versionedResource = - VersionedResource.builder() - .setServiceName(serviceName) - .setResourceName(resource) - .setVersionHash(versionHash) - .setCreationTimestamp(object.getLastModified().toInstant()) - .createVersionedResource(); - resources.add(versionedResource); - } - return resources; - } - - @Override - public String upload( - final String serviceName, - final String resource, - Path sourceDir, - Collection filesToInclude, - Collection parentDirectoriesToInclude, - boolean stream) - throws IOException { - if (!Files.exists(sourceDir)) { - throw new IOException( - String.format( - "Source directory %s, for service %s, and resource %s does not exist", - sourceDir, serviceName, resource)); - } - if (stream) { - return uploadAsStream( - serviceName, resource, sourceDir, filesToInclude, parentDirectoriesToInclude); - } else { - return uploadAsFile( - serviceName, resource, sourceDir, filesToInclude, parentDirectoriesToInclude); - } - } - - private String uploadAsFile( - final String serviceName, - final String resource, - Path sourceDir, - Collection filesToInclude, - Collection parentDirectoriesToInclude) - throws IOException { - if (!Files.exists(archiverDirectory)) { - logger.info("Archiver directory doesn't exist: " + archiverDirectory + " creating new "); - Files.createDirectories(archiverDirectory); - } - Path destPath = archiverDirectory.resolve(getTmpName()); - try { - tar.buildTar(sourceDir, destPath, filesToInclude, parentDirectoriesToInclude); - String versionHash = UUID.randomUUID().toString(); - uploadTarWithMetadata(serviceName, resource, versionHash, destPath); - return versionHash; - } finally { - Files.deleteIfExists(destPath); - } - } - - private void uploadTarWithMetadata( - String serviceName, String resource, String versionHash, Path path) throws IOException { - final String absoluteResourcePath = - String.format("%s/%s/%s", serviceName, resource, versionHash); - PutObjectRequest request = - new PutObjectRequest(bucketName, absoluteResourcePath, path.toFile()); - request.setGeneralProgressListener( - new ContentDownloaderImpl.S3ProgressListenerImpl(serviceName, resource, "upload")); - Upload upload = transferManager.upload(request); - try { - upload.waitForUploadResult(); - logger.info("Upload completed "); - } catch (InterruptedException e) { - throw new IOException("Error while uploading to s3. ", e); - } - } - - private String uploadAsStream( - final String serviceName, - final String resource, - Path sourceDir, - Collection filesToInclude, - Collection parentDirectoriesToInclude) - throws IOException { - String versionHash = UUID.randomUUID().toString(); - final String absoluteResourcePath = - String.format("%s/%s/%s", serviceName, resource, versionHash); - long uncompressedSize = - getTotalSize(sourceDir.toString(), filesToInclude, parentDirectoriesToInclude); - logger.info("Uploading: " + absoluteResourcePath); - logger.info("Uncompressed total size: " + uncompressedSize); - TarUploadOutputStream uploadStream = null; - try { - uploadStream = - new TarUploadOutputStream( - bucketName, - absoluteResourcePath, - uncompressedSize, - transferManager.getAmazonS3Client(), - executor); - tar.buildTar(sourceDir, uploadStream, filesToInclude, parentDirectoriesToInclude); - uploadStream.complete(); - } catch (Exception e) { - if (uploadStream != null) { - uploadStream.cancel(); - } - throw new IOException("Error uploading tar to s3", e); - } - return versionHash; - } - - private long getTotalSize( - String filePath, - Collection filesToInclude, - Collection parentDirectoriesToInclude) { - File file = new File(filePath); - long totalSize = 0; - if (file.isFile() - && TarImpl.shouldIncludeFile(file, filesToInclude, parentDirectoriesToInclude)) { - totalSize += file.length(); - } else if (file.isDirectory()) { - for (File f : file.listFiles()) { - totalSize += getTotalSize(f.getAbsolutePath(), filesToInclude, parentDirectoriesToInclude); - } - } - return totalSize; - } - - @Override - public boolean blessVersion(String serviceName, String resource, String resourceHash) - throws IOException { - return versionManger.blessVersion(serviceName, resource, resourceHash); - } - - private String getVersionString( - final String serviceName, final String resource, final String version) throws IOException { - final String absoluteResourcePath = - String.format("%s/_version/%s/%s", serviceName, resource, version); - try (final S3Object s3Object = s3.getObject(bucketName, absoluteResourcePath)) { - return IOUtils.toString(s3Object.getObjectContent()); - } - } - - private void getVersionContent( - final String serviceName, final String resource, final String hash, final Path destDirectory) - throws IOException { - final String absoluteResourcePath = String.format("%s/%s/%s", serviceName, resource, hash); - final Path parentDirectory = destDirectory.getParent(); - final Path tmpFile = parentDirectory.resolve(getTmpName()); - - final InputStream s3InputStream; - if (downloadAsStream) { - // Stream the file download from s3 instead of writing to a file first - s3InputStream = s3Downloader.downloadFromS3Path(bucketName, absoluteResourcePath); - } else { - Download download = - transferManager.download( - new GetObjectRequest(bucketName, absoluteResourcePath), - tmpFile.toFile(), - new ContentDownloaderImpl.S3ProgressListenerImpl(serviceName, resource, "download")); - try { - download.waitForCompletion(); - logger.info("S3 Download complete"); - } catch (InterruptedException e) { - throw new IOException("S3 Download failed", e); - } - - s3InputStream = new FileInputStream(tmpFile.toFile()); - } - - final InputStream compressorInputStream; - if (tar.getCompressionMode().equals(Tar.CompressionMode.LZ4)) { - compressorInputStream = new LZ4FrameInputStream(s3InputStream); - } else { - compressorInputStream = new GzipCompressorInputStream(s3InputStream, true); - } - try (final TarArchiveInputStream tarArchiveInputStream = - new TarArchiveInputStream(compressorInputStream); ) { - if (Files.exists(destDirectory)) { - logger.info("Directory {} already exists, not re-downloading from Archiver", destDirectory); - return; - } - final Path tmpDirectory = parentDirectory.resolve(getTmpName()); - try { - long tarBefore = System.nanoTime(); - logger.info("Extract tar started..."); - tar.extractTar(tarArchiveInputStream, tmpDirectory); - long tarAfter = System.nanoTime(); - logger.info( - "Extract tar time " + (tarAfter - tarBefore) / (1000 * 1000 * 1000) + " seconds"); - Files.move(tmpDirectory, destDirectory); - } finally { - if (Files.exists(tmpDirectory)) { - FileUtils.deleteDirectory(tmpDirectory.toFile()); - } - if (Files.exists(tmpFile)) { - Files.delete(tmpFile); - } - } - } - } - - @Override - public boolean deleteVersion(String serviceName, String resource, String versionHash) - throws IOException { - return versionManger.deleteVersion(serviceName, resource, versionHash); - } - - @Override - public boolean deleteLocalFiles(String resource) { - return IndexArchiver.deleteLocalResourceFiles(resource, archiverDirectory); - } - - private String getTmpName() { - return UUID.randomUUID().toString() + TMP_SUFFIX; - } - - private void cleanupFiles(final String versionHash, final Path resourceDestDirectory) - throws IOException { - final DirectoryStream.Filter filter = - entry -> { - final String fileName = entry.getFileName().toString(); - // Ignore the current version - if (CURRENT_VERSION_NAME.equals(fileName)) { - return false; - } - // Ignore the current version hash - if (versionHash.equals(fileName)) { - return false; - } - // Ignore non-directories - if (!Files.isDirectory(entry)) { - logger.warn("Unexpected non-directory entry found while cleaning up: {}", fileName); - return false; - } - // Ignore version names that aren't hex encoded - try { - Hex.decodeHex(fileName.toCharArray()); - } catch (DecoderException e) { - logger.warn( - "Not cleaning up directory because name doesn't match pattern: {}", fileName); - return false; - } - return true; - }; - try (final DirectoryStream stream = - Files.newDirectoryStream(resourceDestDirectory, filter)) { - for (final Path entry : stream) { - logger.info("Cleaning up old directory: {}", entry); - FileUtils.deleteDirectory(entry.toFile()); - } - } - } -} diff --git a/src/main/java/com/yelp/nrtsearch/server/backup/ContentDownloaderImpl.java b/src/main/java/com/yelp/nrtsearch/server/backup/ContentDownloaderImpl.java index 229390d64..d0082f4a7 100644 --- a/src/main/java/com/yelp/nrtsearch/server/backup/ContentDownloaderImpl.java +++ b/src/main/java/com/yelp/nrtsearch/server/backup/ContentDownloaderImpl.java @@ -15,33 +15,27 @@ */ package com.yelp.nrtsearch.server.backup; -import com.amazonaws.event.ProgressEvent; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.model.GetObjectMetadataRequest; import com.amazonaws.services.s3.model.GetObjectRequest; import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.model.S3Object; import com.amazonaws.services.s3.transfer.Download; -import com.amazonaws.services.s3.transfer.PersistableTransfer; import com.amazonaws.services.s3.transfer.TransferManager; -import com.amazonaws.services.s3.transfer.internal.S3ProgressListener; import com.google.inject.Inject; +import com.yelp.nrtsearch.server.remote.s3.S3ProgressListenerImpl; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.SequenceInputStream; import java.nio.file.Files; import java.nio.file.Path; -import java.time.Duration; -import java.time.LocalDateTime; import java.util.Enumeration; import java.util.LinkedList; import java.util.UUID; import java.util.concurrent.Executors; import java.util.concurrent.Future; -import java.util.concurrent.Semaphore; import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.atomic.AtomicLong; import net.jpountz.lz4.LZ4FrameInputStream; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; @@ -98,7 +92,7 @@ public void getVersionContent( transferManager.download( new GetObjectRequest(bucketName, absoluteResourcePath), tmpFile.toFile(), - new ContentDownloaderImpl.S3ProgressListenerImpl(serviceName, resource, "download")); + new S3ProgressListenerImpl(serviceName, resource, "download")); try { download.waitForCompletion(); logger.debug("S3 Download complete"); @@ -245,57 +239,4 @@ public InputStream nextElement() { private String getTmpName() { return UUID.randomUUID().toString() + TMP_SUFFIX; } - - public static class S3ProgressListenerImpl implements S3ProgressListener { - private static final Logger logger = - LoggerFactory.getLogger(ContentDownloaderImpl.S3ProgressListenerImpl.class); - - private static final long LOG_THRESHOLD_BYTES = 1024 * 1024 * 500; // 500 MB - private static final long LOG_THRESHOLD_SECONDS = 30; - - private final String serviceName; - private final String resource; - private final String operation; - - private final Semaphore lock = new Semaphore(1); - private final AtomicLong totalBytesTransferred = new AtomicLong(); - private long bytesTransferredSinceLastLog = 0; - private LocalDateTime lastLoggedTime = LocalDateTime.now(); - - public S3ProgressListenerImpl(String serviceName, String resource, String operation) { - this.serviceName = serviceName; - this.resource = resource; - this.operation = operation; - } - - @Override - public void onPersistableTransfer(PersistableTransfer persistableTransfer) {} - - @Override - public void progressChanged(ProgressEvent progressEvent) { - long totalBytes = totalBytesTransferred.addAndGet(progressEvent.getBytesTransferred()); - - boolean acquired = lock.tryAcquire(); - - if (acquired) { - try { - bytesTransferredSinceLastLog += progressEvent.getBytesTransferred(); - long secondsSinceLastLog = - Duration.between(lastLoggedTime, LocalDateTime.now()).getSeconds(); - - if (bytesTransferredSinceLastLog > LOG_THRESHOLD_BYTES - || secondsSinceLastLog > LOG_THRESHOLD_SECONDS) { - logger.info( - String.format( - "service: %s, resource: %s, %s transferred bytes: %s", - serviceName, resource, operation, totalBytes)); - bytesTransferredSinceLastLog = 0; - lastLoggedTime = LocalDateTime.now(); - } - } finally { - lock.release(); - } - } - } - } } diff --git a/src/main/java/com/yelp/nrtsearch/server/cli/BackupIndexCommand.java b/src/main/java/com/yelp/nrtsearch/server/cli/BackupIndexCommand.java deleted file mode 100644 index bab3be43a..000000000 --- a/src/main/java/com/yelp/nrtsearch/server/cli/BackupIndexCommand.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2020 Yelp Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yelp.nrtsearch.server.cli; - -import com.yelp.nrtsearch.server.grpc.LuceneServerClient; -import java.util.concurrent.Callable; -import picocli.CommandLine; - -@CommandLine.Command(name = BackupIndexCommand.BACKUP_INDEX, description = "Backup index") -public class BackupIndexCommand implements Callable { - public static final String BACKUP_INDEX = "backupIndex"; - - @CommandLine.ParentCommand private LuceneClientCommand baseCmd; - - @CommandLine.Option( - names = {"-i", "--indexName"}, - description = "Name of the index which is to be backed up", - required = true) - private String indexName; - - public String getIndexName() { - return indexName; - } - - @CommandLine.Option( - names = {"-s", "--serviceName"}, - description = "Name of the service which is to be backed up", - required = true) - private String serviceName; - - public String getServiceName() { - return serviceName; - } - - @CommandLine.Option( - names = {"-r", "--resourceName"}, - description = "Name of the resource which is to be backed up", - required = true) - private String resourceName; - - public String getResourceName() { - return resourceName; - } - - @CommandLine.Option( - names = {"-c", "--completeDirectory"}, - description = - "Backup complete directory including all current snapshots if true (may backup corrupt segments if backup is created while indexing is happening), otherwise only backup the required segments and segment files") - private boolean completeDirectory; - - public boolean getCompleteDirectory() { - return completeDirectory; - } - - @CommandLine.Option( - names = {"--stream"}, - description = - "Stream the index archive directly to s3, instead of writing to a file first (experimental)") - private boolean stream; - - public boolean getStream() { - return stream; - } - - @Override - public Integer call() throws Exception { - LuceneServerClient client = baseCmd.getClient(); - try { - client.backupIndex( - getIndexName(), getServiceName(), getResourceName(), getCompleteDirectory(), getStream()); - } finally { - client.shutdown(); - } - return 0; - } -} diff --git a/src/main/java/com/yelp/nrtsearch/server/cli/DeleteIndexBackupCommand.java b/src/main/java/com/yelp/nrtsearch/server/cli/DeleteIndexBackupCommand.java deleted file mode 100644 index db01aae12..000000000 --- a/src/main/java/com/yelp/nrtsearch/server/cli/DeleteIndexBackupCommand.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2020 Yelp Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yelp.nrtsearch.server.cli; - -import static com.yelp.nrtsearch.server.cli.DeleteIndexBackupCommand.DELETE_INDEX_BACKUP; - -import com.yelp.nrtsearch.server.grpc.LuceneServerClient; -import java.util.concurrent.Callable; -import picocli.CommandLine; - -@CommandLine.Command(name = DELETE_INDEX_BACKUP, description = "Delete index backups") -public class DeleteIndexBackupCommand implements Callable { - public static final String DELETE_INDEX_BACKUP = "deleteIndexBackup"; - - @CommandLine.ParentCommand private LuceneClientCommand baseCmd; - - @CommandLine.Option( - names = {"-i", "--indexName"}, - description = "Name of the index which is to be backed up", - required = true) - private String indexName; - - public String getIndexName() { - return indexName; - } - - @CommandLine.Option( - names = {"-s", "--serviceName"}, - description = "Name of the service which is to be backed up", - required = true) - private String serviceName; - - public String getServiceName() { - return serviceName; - } - - @CommandLine.Option( - names = {"-r", "--resourceName"}, - description = "Name of the resource which is to be backed up", - required = true) - private String resourceName; - - public String getResourceName() { - return resourceName; - } - - @CommandLine.Option( - names = {"-n", "--nDays"}, - description = "Backups older than these many days will be deleted from s3", - required = true) - private int nDays; - - public int getNDays() { - return nDays; - } - - @Override - public Integer call() throws Exception { - LuceneServerClient client = baseCmd.getClient(); - try { - client.deleteIndexBackup(getIndexName(), getServiceName(), getResourceName(), getNDays()); - } finally { - client.shutdown(); - } - return 0; - } -} diff --git a/src/main/java/com/yelp/nrtsearch/server/cli/LuceneClientCommand.java b/src/main/java/com/yelp/nrtsearch/server/cli/LuceneClientCommand.java index eae124623..cc73f23b8 100644 --- a/src/main/java/com/yelp/nrtsearch/server/cli/LuceneClientCommand.java +++ b/src/main/java/com/yelp/nrtsearch/server/cli/LuceneClientCommand.java @@ -27,14 +27,12 @@ synopsisSubcommandLabel = "COMMAND", subcommands = { AddDocumentsCommand.class, - BackupIndexCommand.class, BackupWarmingQueriesCommand.class, CommitCommand.class, CreateIndexCommand.class, GetCurrentSearcherVersion.class, DeleteDocumentsCommand.class, DeleteAllDocumentsCommand.class, - DeleteIndexBackupCommand.class, DeleteIndexCommand.class, ForceMergeCommand.class, ForceMergeDeletesCommand.class, diff --git a/src/main/java/com/yelp/nrtsearch/server/cli/RestoreHelper.java b/src/main/java/com/yelp/nrtsearch/server/cli/RestoreHelper.java index 58af413ed..9a35c95aa 100644 --- a/src/main/java/com/yelp/nrtsearch/server/cli/RestoreHelper.java +++ b/src/main/java/com/yelp/nrtsearch/server/cli/RestoreHelper.java @@ -15,13 +15,10 @@ */ package com.yelp.nrtsearch.server.cli; -import com.amazonaws.services.s3.AmazonS3; import com.yelp.nrtsearch.server.backup.*; import com.yelp.nrtsearch.server.luceneserver.IndexBackupUtils; import java.io.IOException; import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.UUID; import java.util.concurrent.Callable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,27 +30,10 @@ public class RestoreHelper implements Callable { @CommandLine.ParentCommand private BackupRestoreCommand baseCmd; private static final Logger logger = LoggerFactory.getLogger(RestoreHelper.class.getName()); - @CommandLine.Option( - names = {"-l", "--legacy"}, - description = "Use legacy version for restore") - private boolean legacy; - @Override public Integer call() throws Exception { - if (legacy) { - AmazonS3 amazonS3 = baseCmd.getAmazonS3(); - Archiver archiver = - new ArchiverImpl( - amazonS3, - baseCmd.getBucket(), - Paths.get(baseCmd.getArchiveDir(), UUID.randomUUID().toString()), - new TarImpl(Tar.CompressionMode.LZ4), - true); - restore(archiver); - } else { - Archiver archiver = baseCmd.getArchiver(); - restore(archiver); - } + Archiver archiver = baseCmd.getArchiver(); + restore(archiver); return 0; } diff --git a/src/main/java/com/yelp/nrtsearch/server/config/LuceneServerConfiguration.java b/src/main/java/com/yelp/nrtsearch/server/config/LuceneServerConfiguration.java index c899b8dc6..8b4c5adf4 100644 --- a/src/main/java/com/yelp/nrtsearch/server/config/LuceneServerConfiguration.java +++ b/src/main/java/com/yelp/nrtsearch/server/config/LuceneServerConfiguration.java @@ -79,8 +79,6 @@ public class LuceneServerConfiguration { private final String pluginSearchPath; private final String serviceName; private final boolean restoreState; - private final boolean restoreFromIncArchiver; - private final boolean backupWithIncArchiver; private final ThreadPoolConfiguration threadPoolConfiguration; private final IndexPreloadConfig preloadConfig; private final QueryCacheConfig queryCacheConfig; @@ -151,8 +149,6 @@ public LuceneServerConfiguration(InputStream yamlStream) { configReader.getString("pluginSearchPath", DEFAULT_PLUGIN_SEARCH_PATH.toString()); serviceName = configReader.getString("serviceName", DEFAULT_SERVICE_NAME); restoreState = configReader.getBoolean("restoreState", false); - restoreFromIncArchiver = configReader.getBoolean("restoreFromIncArchiver", false); - backupWithIncArchiver = configReader.getBoolean("backupWithIncArchiver", false); preloadConfig = IndexPreloadConfig.fromConfig(configReader); queryCacheConfig = QueryCacheConfig.fromConfig(configReader); warmerConfig = WarmerConfig.fromConfig(configReader); @@ -260,14 +256,6 @@ public boolean getRestoreState() { return restoreState; } - public boolean getRestoreFromIncArchiver() { - return restoreFromIncArchiver; - } - - public boolean getBackupWithInArchiver() { - return backupWithIncArchiver; - } - public IndexPreloadConfig getPreloadConfig() { return preloadConfig; } diff --git a/src/main/java/com/yelp/nrtsearch/server/grpc/LuceneServer.java b/src/main/java/com/yelp/nrtsearch/server/grpc/LuceneServer.java index 1ef910608..6e223c93a 100644 --- a/src/main/java/com/yelp/nrtsearch/server/grpc/LuceneServer.java +++ b/src/main/java/com/yelp/nrtsearch/server/grpc/LuceneServer.java @@ -17,7 +17,6 @@ import static com.yelp.nrtsearch.server.grpc.ReplicationServerClient.MAX_MESSAGE_BYTES_SIZE; -import com.amazonaws.services.s3.AmazonS3; import com.google.api.HttpBody; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Splitter; @@ -59,6 +58,7 @@ import com.yelp.nrtsearch.server.monitoring.ThreadPoolCollector.RejectionCounterWrapper; import com.yelp.nrtsearch.server.plugins.Plugin; import com.yelp.nrtsearch.server.plugins.PluginsService; +import com.yelp.nrtsearch.server.remote.RemoteBackend; import com.yelp.nrtsearch.server.utils.ThreadPoolExecutorFactory; import io.grpc.Context; import io.grpc.Server; @@ -93,8 +93,8 @@ public class LuceneServer { private static final Logger logger = LoggerFactory.getLogger(LuceneServer.class.getName()); private static final Splitter COMMA_SPLITTER = Splitter.on(","); - private final Archiver archiver; private final Archiver incArchiver; + private final RemoteBackend remoteBackend; private final CollectorRegistry collectorRegistry; private final PluginsService pluginsService; @@ -105,16 +105,15 @@ public class LuceneServer { @Inject public LuceneServer( LuceneServerConfiguration luceneServerConfiguration, - @Named("legacyArchiver") Archiver archiver, @Named("incArchiver") Archiver incArchiver, - AmazonS3 amazonS3, + RemoteBackend remoteBackend, CollectorRegistry collectorRegistry) { this.luceneServerConfiguration = luceneServerConfiguration; - this.archiver = archiver; this.incArchiver = incArchiver; + this.remoteBackend = remoteBackend; this.collectorRegistry = collectorRegistry; this.pluginsService = - new PluginsService(luceneServerConfiguration, amazonS3, collectorRegistry); + new PluginsService(luceneServerConfiguration, remoteBackend, collectorRegistry); } @VisibleForTesting @@ -125,7 +124,7 @@ public void start() throws IOException { LuceneServerImpl serverImpl = new LuceneServerImpl( - luceneServerConfiguration, archiver, incArchiver, collectorRegistry, plugins); + luceneServerConfiguration, incArchiver, remoteBackend, collectorRegistry, plugins); GlobalState globalState = serverImpl.getGlobalState(); registerMetrics(globalState); @@ -289,36 +288,28 @@ static class LuceneServerImpl extends LuceneServerGrpc.LuceneServerImplBase { private final JsonFormat.Printer protoMessagePrinter = JsonFormat.printer().omittingInsignificantWhitespace(); private final GlobalState globalState; - private final Archiver archiver; - private final Archiver incArchiver; private final CollectorRegistry collectorRegistry; private final ThreadPoolExecutor searchThreadPoolExecutor; - private final String archiveDirectory; - private final boolean backupFromIncArchiver; /** * Constructor used with newer state handling. Defers initialization of global state until after * extendable components. * * @param configuration server configuration - * @param archiver archiver for external file transfer * @param incArchiver archiver for incremental index data copy + * @param remoteBackend backend for persistent remote storage * @param collectorRegistry metrics collector registry * @param plugins loaded plugins * @throws IOException */ LuceneServerImpl( LuceneServerConfiguration configuration, - Archiver archiver, Archiver incArchiver, + RemoteBackend remoteBackend, CollectorRegistry collectorRegistry, List plugins) throws IOException { - this.archiver = archiver; - this.incArchiver = incArchiver; - this.archiveDirectory = configuration.getArchiveDirectory(); this.collectorRegistry = collectorRegistry; - this.backupFromIncArchiver = configuration.getBackupWithInArchiver(); DeadlineUtils.setCancellationEnabled(configuration.getDeadlineCancellation()); CompletionPostingsFormatUtil.setCompletionCodecLoadMode( @@ -327,7 +318,7 @@ static class LuceneServerImpl extends LuceneServerGrpc.LuceneServerImplBase { initQueryCache(configuration); initExtendableComponents(configuration, plugins); - this.globalState = GlobalState.createState(configuration, incArchiver, archiver); + this.globalState = GlobalState.createState(configuration, incArchiver, remoteBackend); this.searchThreadPoolExecutor = globalState.getSearchThreadPoolExecutor(); } @@ -955,7 +946,7 @@ public void commit( () -> { try { IndexState indexState = globalState.getIndex(commitRequest.getIndexName()); - long gen = indexState.commit(backupFromIncArchiver); + long gen = indexState.commit(); CommitResponse reply = CommitResponse.newBuilder() .setGen(gen) @@ -1538,77 +1529,6 @@ public void getAllSnapshotIndexGen( } } - @Override - public void backupIndex( - BackupIndexRequest backupIndexRequest, - StreamObserver responseObserver) { - logger.info("Received backup index request: {}", backupIndexRequest); - try { - IndexState indexState = globalState.getIndex(backupIndexRequest.getIndexName()); - BackupIndexRequestHandler backupIndexRequestHandler = - new BackupIndexRequestHandler( - archiver, incArchiver, archiveDirectory, backupFromIncArchiver); - BackupIndexResponse reply = - backupIndexRequestHandler.handle(indexState, backupIndexRequest); - logger.info(String.format("BackupRequestHandler returned results %s", reply.toString())); - responseObserver.onNext(reply); - responseObserver.onCompleted(); - } catch (Exception e) { - logger.warn( - String.format( - "error while trying to backupIndex for index: %s for service: %s, resource: %s", - backupIndexRequest.getIndexName(), - backupIndexRequest.getServiceName(), - backupIndexRequest.getResourceName()), - e); - responseObserver.onError( - Status.UNKNOWN - .withCause(e) - .withDescription( - String.format( - "error while trying to backupIndex for index %s for service: %s, resource: %s", - backupIndexRequest.getIndexName(), - backupIndexRequest.getServiceName(), - backupIndexRequest.getResourceName())) - .augmentDescription(e.getMessage()) - .asRuntimeException()); - } - } - - @Override - public void deleteIndexBackup( - DeleteIndexBackupRequest request, - StreamObserver responseObserver) { - try { - IndexState indexState = globalState.getIndex(request.getIndexName()); - DeleteIndexBackupHandler backupIndexRequestHandler = new DeleteIndexBackupHandler(archiver); - DeleteIndexBackupResponse reply = backupIndexRequestHandler.handle(indexState, request); - logger.info("DeleteIndexBackupHandler returned results {}", reply.toString()); - responseObserver.onNext(reply); - responseObserver.onCompleted(); - } catch (Exception e) { - logger.warn( - "error while trying to deleteIndexBackup for index: {} for service: {}, resource: {}, nDays: {}", - request.getIndexName(), - request.getServiceName(), - request.getResourceName(), - request.getNDays(), - e); - responseObserver.onError( - Status.UNKNOWN - .withCause(e) - .withDescription( - String.format( - "error while trying to deleteIndexBackup for index %s for service: %s, resource: %s, nDays: %s", - request.getIndexName(), - request.getServiceName(), - request.getResourceName(), - request.getNDays())) - .augmentDescription(e.getMessage()) - .asRuntimeException()); - } - } - @Override public void backupWarmingQueries( BackupWarmingQueriesRequest request, diff --git a/src/main/java/com/yelp/nrtsearch/server/grpc/LuceneServerClient.java b/src/main/java/com/yelp/nrtsearch/server/grpc/LuceneServerClient.java index cacd0d026..61ab82cc5 100644 --- a/src/main/java/com/yelp/nrtsearch/server/grpc/LuceneServerClient.java +++ b/src/main/java/com/yelp/nrtsearch/server/grpc/LuceneServerClient.java @@ -434,22 +434,6 @@ public void stopIndex(String indexName) { blockingStub.stopIndex(StopIndexRequest.newBuilder().setIndexName(indexName).build()); } - public void backupIndex( - String indexName, - String serviceName, - String resourceName, - boolean completeDirectory, - boolean stream) { - blockingStub.backupIndex( - BackupIndexRequest.newBuilder() - .setServiceName(serviceName) - .setResourceName(resourceName) - .setIndexName(indexName) - .setCompleteDirectory(completeDirectory) - .setStream(stream) - .build()); - } - public void backupWarmingQueries( String index, String service, int numQueriesThreshold, int uptimeMinutesThreshold) { blockingStub.backupWarmingQueries( @@ -476,19 +460,6 @@ public void status() throws InterruptedException { System.exit(1); } - public void deleteIndexBackup( - String indexName, String serviceName, String resourceName, int nDays) { - DeleteIndexBackupRequest request = - DeleteIndexBackupRequest.newBuilder() - .setIndexName(indexName) - .setServiceName(serviceName) - .setResourceName(resourceName) - .setNDays(nDays) - .build(); - DeleteIndexBackupResponse deleteIndexBackupResponse = blockingStub.deleteIndexBackup(request); - logger.info("Response: {}", deleteIndexBackupResponse); - } - public List getIndices() { return blockingStub .indices(IndicesRequest.newBuilder().build()) diff --git a/src/main/java/com/yelp/nrtsearch/server/luceneserver/BackupIndexRequestHandler.java b/src/main/java/com/yelp/nrtsearch/server/luceneserver/BackupIndexRequestHandler.java deleted file mode 100644 index 2cdcf7f07..000000000 --- a/src/main/java/com/yelp/nrtsearch/server/luceneserver/BackupIndexRequestHandler.java +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Copyright 2020 Yelp Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yelp.nrtsearch.server.luceneserver; - -import com.google.gson.Gson; -import com.yelp.nrtsearch.server.backup.Archiver; -import com.yelp.nrtsearch.server.grpc.BackupIndexRequest; -import com.yelp.nrtsearch.server.grpc.BackupIndexResponse; -import com.yelp.nrtsearch.server.grpc.CreateSnapshotRequest; -import com.yelp.nrtsearch.server.grpc.ReleaseSnapshotRequest; -import com.yelp.nrtsearch.server.grpc.ReleaseSnapshotResponse; -import com.yelp.nrtsearch.server.grpc.SnapshotId; -import java.io.IOException; -import java.io.Writer; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.*; -import java.util.concurrent.locks.ReentrantLock; -import org.apache.lucene.facet.taxonomy.SearcherTaxonomyManager; -import org.apache.lucene.index.DirectoryReader; -import org.apache.lucene.index.IndexReader; -import org.apache.lucene.index.StandardDirectoryReader; -import org.apache.lucene.util.IOUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/* The functionality of this class will be used only within the scope of Commit. Where commit will take care of uploading - * files to remote storage*/ -@Deprecated -public class BackupIndexRequestHandler implements Handler { - private static final String BACKUP_INDICATOR_FILE_NAME = "backup.txt"; - private static final ReentrantLock LOCK = new ReentrantLock(); - private static String lastBackedUpIndex = ""; - private final boolean disableLegacy; - private final Archiver incrementalArchiver; - Logger logger = LoggerFactory.getLogger(BackupIndexRequestHandler.class); - private final Archiver archiver; - private final Path archiveDirectory; - private final Path backupIndicatorFilePath; - - public BackupIndexRequestHandler( - Archiver archiver, - Archiver incrementalArchiver, - String archiveDirectory, - boolean disableLegacy) { - this.archiver = archiver; - this.incrementalArchiver = incrementalArchiver; - this.archiveDirectory = Paths.get(archiveDirectory); - this.disableLegacy = disableLegacy; - this.backupIndicatorFilePath = Paths.get(archiveDirectory, BACKUP_INDICATOR_FILE_NAME); - } - - @Override - public BackupIndexResponse handle(IndexState indexState, BackupIndexRequest backupIndexRequest) - throws HandlerException { - BackupIndexResponse.Builder backupIndexResponseBuilder = BackupIndexResponse.newBuilder(); - if (!LOCK.tryLock()) { - throw new IllegalStateException( - String.format( - "A backup is ongoing for index %s, please try again after the current backup is finished", - lastBackedUpIndex)); - } - String indexName = backupIndexRequest.getIndexName(); - SnapshotId snapshotId = null; - try { - if (wasBackupPotentiallyInterrupted()) { - LOCK.unlock(); - throw new IllegalStateException( - String.format( - "A backup is ongoing for index %s, please try again after the current backup is finished", - readBackupIndicatorDetails().indexName)); - } - - lastBackedUpIndex = indexName; - - // only upload metadata in case we are replica - if (indexState.getShard(0).isReplica()) { - uploadMetadata( - backupIndexRequest.getServiceName(), - backupIndexRequest.getResourceName(), - indexState, - backupIndexResponseBuilder, - backupIndexRequest.getStream()); - } else { - indexState.commit(false); - - CreateSnapshotRequest createSnapshotRequest = - CreateSnapshotRequest.newBuilder().setIndexName(indexName).build(); - - snapshotId = - new CreateSnapshotHandler() - .createSnapshot(indexState, createSnapshotRequest) - .getSnapshotId(); - - createBackupIndicator(indexName, snapshotId); - LOCK.unlock(); - - Collection segmentFiles; - List stateDirectory; - - if (backupIndexRequest.getCompleteDirectory()) { - segmentFiles = Collections.emptyList(); - stateDirectory = Collections.emptyList(); - } else { - segmentFiles = getSegmentFilesInSnapshot(indexState, snapshotId); - stateDirectory = Collections.singletonList(indexState.getStateDirectoryPath().toString()); - } - - uploadArtifacts( - backupIndexRequest.getServiceName(), - backupIndexRequest.getResourceName(), - indexState, - backupIndexResponseBuilder, - segmentFiles, - stateDirectory, - backupIndexRequest.getStream(), - snapshotId); - } - - } catch (IOException e) { - logger.error( - String.format( - "Error while trying to backup index %s with serviceName %s, resourceName %s", - indexName, backupIndexRequest.getServiceName(), backupIndexRequest.getResourceName()), - e); - return backupIndexResponseBuilder.build(); - } finally { - if (LOCK.isHeldByCurrentThread()) { - LOCK.unlock(); - } - if (snapshotId != null) { - releaseSnapshot(indexState, indexName, snapshotId); - deleteBackupIndicator(); - } - } - - return backupIndexResponseBuilder.build(); - } - - public static Collection getSegmentFilesInSnapshot( - IndexState indexState, SnapshotId snapshotId) throws IOException { - String snapshotIdAsString = CreateSnapshotHandler.getSnapshotIdAsString(snapshotId); - IndexState.Gens snapshot = new IndexState.Gens(snapshotIdAsString); - if (indexState.getShards().size() != 1) { - throw new IllegalStateException( - String.format( - "%s shards found index %s instead of exactly 1", - indexState.getShards().size(), indexState.getName())); - } - ShardState state = indexState.getShards().entrySet().iterator().next().getValue(); - SearcherTaxonomyManager.SearcherAndTaxonomy searcherAndTaxonomy = null; - IndexReader indexReader = null; - try { - searcherAndTaxonomy = state.acquire(); - indexReader = - DirectoryReader.openIfChanged( - (DirectoryReader) searcherAndTaxonomy.searcher.getIndexReader(), - state.snapshots.getIndexCommit(snapshot.indexGen)); - if (!(indexReader instanceof StandardDirectoryReader)) { - throw new IllegalStateException("Unable to find segments to backup"); - } - StandardDirectoryReader standardDirectoryReader = (StandardDirectoryReader) indexReader; - return standardDirectoryReader.getSegmentInfos().files(true); - } finally { - if (searcherAndTaxonomy != null) { - state.release(searcherAndTaxonomy); - } - if (indexReader != null) { - indexReader.close(); - } - } - } - - public boolean wasBackupPotentiallyInterrupted() { - return Files.exists(backupIndicatorFilePath); - } - - public String getIndexNameOfInterruptedBackup() { - return readBackupIndicatorDetails().indexName; - } - - private void createBackupIndicator(String indexName, SnapshotId snapshotId) { - if (wasBackupPotentiallyInterrupted()) { - throw new IllegalStateException( - String.format( - "A backup is ongoing for index %s, please try again after the current backup is finished", - getIndexNameOfInterruptedBackup())); - } - - if (!Files.exists(backupIndicatorFilePath.getParent())) { - try { - Files.createDirectories(backupIndicatorFilePath.getParent()); - } catch (IOException e) { - throw new IllegalStateException( - "Unable to create parent directories for backup indicator file " - + backupIndicatorFilePath, - e); - } - } - - try (Writer writer = Files.newBufferedWriter(backupIndicatorFilePath)) { - BackupIndicatorDetails backupInfo = - new BackupIndicatorDetails( - indexName, - snapshotId.getIndexGen(), - snapshotId.getStateGen(), - snapshotId.getTaxonomyGen()); - writer.write(new Gson().toJson(backupInfo)); - writer.flush(); - IOUtils.fsync(backupIndicatorFilePath, false); - IOUtils.fsync(backupIndicatorFilePath.getParent(), true); - } catch (IOException e) { - throw new IllegalStateException("Unable to create backup indicator file", e); - } - } - - private void deleteBackupIndicator() { - if (Files.exists(backupIndicatorFilePath)) { - try { - Files.delete(backupIndicatorFilePath); - } catch (IOException e) { - throw new IllegalStateException("Unable to delete backup indicator file", e); - } - } - } - - public void interruptedBackupCleanup(IndexState indexState, Set allSnapshotIndexGen) { - BackupIndicatorDetails details = readBackupIndicatorDetails(); - releaseLeftoverSnapshot(indexState, allSnapshotIndexGen, details); - deleteTemporaryBackupFilesIfAny(); - deleteBackupIndicator(); - } - - private BackupIndicatorDetails readBackupIndicatorDetails() { - try { - return new Gson() - .fromJson(Files.readString(backupIndicatorFilePath), BackupIndicatorDetails.class); - } catch (IOException e) { - throw new IllegalStateException("Unable to read backup indicator file", e); - } - } - - private void releaseLeftoverSnapshot( - IndexState indexState, - Set allSnapshotIndexGen, - BackupIndicatorDetails backupIndicatorDetails) { - if (allSnapshotIndexGen.contains(backupIndicatorDetails.indexGen)) { - String indexName = backupIndicatorDetails.indexName; - SnapshotId snapshotId = - SnapshotId.newBuilder() - .setIndexGen(backupIndicatorDetails.indexGen) - .setStateGen(backupIndicatorDetails.stateGen) - .setTaxonomyGen(backupIndicatorDetails.taxonomyGen) - .build(); - logger.info("Releasing snapshot: {} for index: {}", snapshotId, indexName); - releaseSnapshot(indexState, indexName, snapshotId); - } - } - - private void deleteTemporaryBackupFilesIfAny() { - try { - Files.walk(archiveDirectory) - .filter(file -> file.startsWith(archiveDirectory)) - .filter(file -> file.toString().endsWith(".tmp")) - .forEach( - file -> { - try { - logger.info("Deleting temporary file: {}", file); - Files.delete(file); - } catch (IOException e) { - logger.error("Unable to delete temporary file: {}", file, e); - } - }); - } catch (IOException e) { - throw new IllegalStateException("Unable to read files in archive directory", e); - } - } - - public void uploadArtifacts( - String serviceName, - String resourceName, - IndexState indexState, - BackupIndexResponse.Builder backupIndexResponseBuilder, - Collection filesToInclude, - Collection parentDirectoriesToInclude, - boolean stream, - SnapshotId snapshotId) - throws IOException { - String resourceData = IndexBackupUtils.getResourceData(resourceName); - String versionHash; - if (!disableLegacy) { - versionHash = - archiver.upload( - serviceName, - resourceData, - indexState.getRootDir(), - filesToInclude, - parentDirectoriesToInclude, - stream); - archiver.blessVersion(serviceName, resourceData, versionHash); - } else { - // incremental backup needs to know current files/segments on disk - if (filesToInclude.isEmpty()) { - filesToInclude = getSegmentFilesInSnapshot(indexState, snapshotId); - } - versionHash = - incrementalArchiver.upload( - serviceName, - resourceData, - indexState.getRootDir(), - filesToInclude, - parentDirectoriesToInclude, - stream); - incrementalArchiver.blessVersion(serviceName, resourceData, versionHash); - } - backupIndexResponseBuilder.setDataVersionHash(versionHash); - } - - public void uploadMetadata( - String serviceName, - String resourceName, - IndexState indexState, - BackupIndexResponse.Builder backupIndexResponseBuilder, - boolean stream) - throws IOException { - String resourceMetadata = IndexBackupUtils.getResourceMetadata(resourceName); - String versionHash; - if (!disableLegacy) { - versionHash = - archiver.upload( - serviceName, - resourceMetadata, - indexState.getGlobalState().getStateDir(), - Collections.emptyList(), - Collections.emptyList(), - stream); - archiver.blessVersion(serviceName, resourceMetadata, versionHash); - - } else { - versionHash = - incrementalArchiver.upload( - serviceName, - resourceMetadata, - indexState.getGlobalState().getStateDir(), - Collections.emptyList(), - Collections.emptyList(), - stream); - incrementalArchiver.blessVersion(serviceName, resourceMetadata, versionHash); - } - backupIndexResponseBuilder.setMetadataVersionHash(versionHash); - } - - public static void releaseSnapshot( - IndexState indexState, String indexName, SnapshotId snapshotId) { - ReleaseSnapshotRequest releaseSnapshotRequest = - ReleaseSnapshotRequest.newBuilder() - .setIndexName(indexName) - .setSnapshotId(snapshotId) - .build(); - ReleaseSnapshotResponse releaseSnapshotResponse = - new ReleaseSnapshotHandler().handle(indexState, releaseSnapshotRequest); - } - - private static class BackupIndicatorDetails { - String indexName; - long indexGen; - long stateGen; - long taxonomyGen; - - public BackupIndicatorDetails( - String indexName, long indexGen, long stateGen, long taxonomyGen) { - this.indexName = indexName; - this.indexGen = indexGen; - this.stateGen = stateGen; - this.taxonomyGen = taxonomyGen; - } - } -} diff --git a/src/main/java/com/yelp/nrtsearch/server/luceneserver/CreateSnapshotHandler.java b/src/main/java/com/yelp/nrtsearch/server/luceneserver/CreateSnapshotHandler.java index d7d0bc624..126cfcd6e 100644 --- a/src/main/java/com/yelp/nrtsearch/server/luceneserver/CreateSnapshotHandler.java +++ b/src/main/java/com/yelp/nrtsearch/server/luceneserver/CreateSnapshotHandler.java @@ -20,11 +20,13 @@ import com.yelp.nrtsearch.server.grpc.CreateSnapshotResponse; import com.yelp.nrtsearch.server.grpc.SnapshotId; import java.io.IOException; +import java.util.Collection; import org.apache.lucene.facet.taxonomy.SearcherTaxonomyManager; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.IndexCommit; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.SegmentInfos; +import org.apache.lucene.index.StandardDirectoryReader; import org.apache.lucene.search.IndexSearcher; public class CreateSnapshotHandler @@ -118,4 +120,46 @@ public static String getSnapshotIdAsString(SnapshotId snapshotId) { + ":" + snapshotId.getStateGen(); } + + /** + * Get names of all index files in a given snapshot. + * + * @param indexState index state + * @param snapshotId snapshot id + * @return collection of file names + * @throws IOException + */ + public static Collection getSegmentFilesInSnapshot( + IndexState indexState, SnapshotId snapshotId) throws IOException { + String snapshotIdAsString = CreateSnapshotHandler.getSnapshotIdAsString(snapshotId); + IndexState.Gens snapshot = new IndexState.Gens(snapshotIdAsString); + if (indexState.getShards().size() != 1) { + throw new IllegalStateException( + String.format( + "%s shards found index %s instead of exactly 1", + indexState.getShards().size(), indexState.getName())); + } + ShardState state = indexState.getShards().entrySet().iterator().next().getValue(); + SearcherTaxonomyManager.SearcherAndTaxonomy searcherAndTaxonomy = null; + IndexReader indexReader = null; + try { + searcherAndTaxonomy = state.acquire(); + indexReader = + DirectoryReader.openIfChanged( + (DirectoryReader) searcherAndTaxonomy.searcher.getIndexReader(), + state.snapshots.getIndexCommit(snapshot.indexGen)); + if (!(indexReader instanceof StandardDirectoryReader)) { + throw new IllegalStateException("Unable to find segments to backup"); + } + StandardDirectoryReader standardDirectoryReader = (StandardDirectoryReader) indexReader; + return standardDirectoryReader.getSegmentInfos().files(true); + } finally { + if (searcherAndTaxonomy != null) { + state.release(searcherAndTaxonomy); + } + if (indexReader != null) { + indexReader.close(); + } + } + } } diff --git a/src/main/java/com/yelp/nrtsearch/server/luceneserver/DeleteIndexBackupHandler.java b/src/main/java/com/yelp/nrtsearch/server/luceneserver/DeleteIndexBackupHandler.java deleted file mode 100644 index 1946503d4..000000000 --- a/src/main/java/com/yelp/nrtsearch/server/luceneserver/DeleteIndexBackupHandler.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2020 Yelp Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yelp.nrtsearch.server.luceneserver; - -import com.yelp.nrtsearch.server.backup.Archiver; -import com.yelp.nrtsearch.server.backup.VersionedResource; -import com.yelp.nrtsearch.server.grpc.DeleteIndexBackupRequest; -import com.yelp.nrtsearch.server.grpc.DeleteIndexBackupResponse; -import java.io.IOException; -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class DeleteIndexBackupHandler - implements Handler { - private static final Logger logger = LoggerFactory.getLogger(DeleteIndexBackupHandler.class); - private final Archiver archiver; - - public DeleteIndexBackupHandler(Archiver archiver) { - this.archiver = archiver; - } - - @Override - public DeleteIndexBackupResponse handle( - IndexState indexState, DeleteIndexBackupRequest deleteIndexBackupRequest) - throws HandlerException { - - DeleteIndexBackupResponse.Builder deleteIndexBackupResponseBuilder = - DeleteIndexBackupResponse.newBuilder(); - - String indexName = deleteIndexBackupRequest.getIndexName(); - String serviceName = deleteIndexBackupRequest.getServiceName(); - String resourceName = deleteIndexBackupRequest.getResourceName(); - String resourceData = IndexBackupUtils.getResourceData(resourceName); - String resourceMetadata = IndexBackupUtils.getResourceMetadata(resourceName); - String resourceVersionData = IndexBackupUtils.getResourceVersionData(resourceName); - String resourceVersionMetadata = IndexBackupUtils.getResourceVersionMetadata(resourceName); - int nDays = deleteIndexBackupRequest.getNDays(); - - try { - List versionedResourceData = - archiver.getVersionedResource(serviceName, resourceData); - List versionedResourceMetadata = - archiver.getVersionedResource(serviceName, resourceMetadata); - List versionedResourceVersionData = - archiver.getVersionedResource(serviceName, resourceVersionData); - List versionedResourceVersionMetadata = - archiver.getVersionedResource(serviceName, resourceVersionMetadata); - - Instant now = Instant.now(); - - List deletedResourceDataHashes = - deleteOlderThanNDays(versionedResourceData, now, nDays); - List deletedResourceMetadataHashes = - deleteOlderThanNDays(versionedResourceMetadata, now, nDays); - List deletedDataVersions = - deleteOlderThanNDays(versionedResourceVersionData, now, nDays); - List deletedMetadataVersions = - deleteOlderThanNDays(versionedResourceVersionMetadata, now, nDays); - - return deleteIndexBackupResponseBuilder - .addAllDeletedResourceDataHashes(deletedResourceDataHashes) - .addAllDeletedResourceMetadataHashes(deletedResourceMetadataHashes) - .addAllDeletedDataVersions(deletedDataVersions) - .addAllDeletedMetadataVersions(deletedMetadataVersions) - .build(); - - } catch (IOException e) { - logger.error( - "Error while trying to delete backup of index {} with serviceName {}, resourceName {}, nDays: {}", - indexName, - serviceName, - resourceName, - nDays, - e); - return deleteIndexBackupResponseBuilder.build(); - } - } - - private List deleteOlderThanNDays( - List versionedResources, Instant now, int nDays) throws IOException { - - List deletedVersions = new ArrayList<>(); - - List resourcesOlderThanNDays = - versionedResources.stream() - .filter(resourceObject -> isOlderThanNDays(resourceObject, now, nDays)) - .collect(Collectors.toList()); - - for (VersionedResource objectToDelete : resourcesOlderThanNDays) { - archiver.deleteVersion( - objectToDelete.getServiceName(), - objectToDelete.getResourceName(), - objectToDelete.getVersionHash()); - deletedVersions.add(objectToDelete.getVersionHash()); - } - - return deletedVersions; - } - - public static boolean isOlderThanNDays(VersionedResource resource, Instant now, int nDays) { - return now.minus(nDays, ChronoUnit.DAYS).isAfter(resource.getCreationTimestamp()); - } -} diff --git a/src/main/java/com/yelp/nrtsearch/server/luceneserver/GlobalState.java b/src/main/java/com/yelp/nrtsearch/server/luceneserver/GlobalState.java index 31bed6536..d546bcdfa 100644 --- a/src/main/java/com/yelp/nrtsearch/server/luceneserver/GlobalState.java +++ b/src/main/java/com/yelp/nrtsearch/server/luceneserver/GlobalState.java @@ -26,6 +26,7 @@ import com.yelp.nrtsearch.server.grpc.StopIndexRequest; import com.yelp.nrtsearch.server.luceneserver.index.IndexStateManager; import com.yelp.nrtsearch.server.luceneserver.state.BackendGlobalState; +import com.yelp.nrtsearch.server.remote.RemoteBackend; import com.yelp.nrtsearch.server.utils.ThreadPoolExecutorFactory; import java.io.Closeable; import java.io.IOException; @@ -48,6 +49,7 @@ public abstract class GlobalState implements Closeable { private final int port; private final ThreadPoolConfiguration threadPoolConfiguration; private final Archiver incArchiver; + private final RemoteBackend remoteBackend; private int replicaReplicationPortPingInterval; private final String ephemeralId = UUID.randomUUID().toString(); private final long generation = System.currentTimeMillis(); @@ -66,32 +68,29 @@ public abstract class GlobalState implements Closeable { private final ExecutorService fetchService; private final ThreadPoolExecutor searchThreadPoolExecutor; - public static GlobalState createState(LuceneServerConfiguration luceneServerConfiguration) - throws IOException { - return createState(luceneServerConfiguration, null); - } - - public static GlobalState createState( - LuceneServerConfiguration luceneServerConfiguration, Archiver incArchiver) - throws IOException { - return createState(luceneServerConfiguration, incArchiver, null); - } - public static GlobalState createState( LuceneServerConfiguration luceneServerConfiguration, Archiver incArchiver, - Archiver legacyArchiver) + RemoteBackend remoteBackend) throws IOException { - return new BackendGlobalState(luceneServerConfiguration, incArchiver, legacyArchiver); + return new BackendGlobalState(luceneServerConfiguration, incArchiver, remoteBackend); } public Optional getIncArchiver() { return Optional.ofNullable(incArchiver); } - protected GlobalState(LuceneServerConfiguration luceneServerConfiguration, Archiver incArchiver) + public RemoteBackend getRemoteBackend() { + return remoteBackend; + } + + protected GlobalState( + LuceneServerConfiguration luceneServerConfiguration, + Archiver incArchiver, + RemoteBackend remoteBackend) throws IOException { this.incArchiver = incArchiver; + this.remoteBackend = remoteBackend; this.nodeName = luceneServerConfiguration.getNodeName(); this.stateDir = Paths.get(luceneServerConfiguration.getStateDir()); this.indexDirBase = Paths.get(luceneServerConfiguration.getIndexDir()); diff --git a/src/main/java/com/yelp/nrtsearch/server/luceneserver/IndexState.java b/src/main/java/com/yelp/nrtsearch/server/luceneserver/IndexState.java index 03e4c11eb..d72c16981 100644 --- a/src/main/java/com/yelp/nrtsearch/server/luceneserver/IndexState.java +++ b/src/main/java/com/yelp/nrtsearch/server/luceneserver/IndexState.java @@ -17,7 +17,6 @@ import com.google.common.collect.ImmutableMap; import com.google.gson.JsonObject; -import com.yelp.nrtsearch.server.backup.Archiver; import com.yelp.nrtsearch.server.config.LuceneServerConfiguration; import com.yelp.nrtsearch.server.config.ThreadPoolConfiguration; import com.yelp.nrtsearch.server.grpc.*; @@ -32,6 +31,7 @@ import com.yelp.nrtsearch.server.luceneserver.index.IndexSimilarity; import com.yelp.nrtsearch.server.luceneserver.warming.Warmer; import com.yelp.nrtsearch.server.luceneserver.warming.WarmerConfig; +import com.yelp.nrtsearch.server.remote.RemoteBackend; import com.yelp.nrtsearch.server.utils.FileUtil; import java.io.Closeable; import java.io.IOException; @@ -244,17 +244,17 @@ public Path getRootDir() { return rootDir; } - public void initWarmer(Archiver archiver) { - initWarmer(archiver, name); + public void initWarmer(RemoteBackend remoteBackend) { + initWarmer(remoteBackend, name); } - public void initWarmer(Archiver archiver, String indexName) { + public void initWarmer(RemoteBackend remoteBackend, String indexName) { LuceneServerConfiguration configuration = globalState.getConfiguration(); WarmerConfig warmerConfig = configuration.getWarmerConfig(); if (warmerConfig.isWarmOnStartup() || warmerConfig.getMaxWarmingQueries() > 0) { this.warmer = new Warmer( - archiver, + remoteBackend, configuration.getServiceName(), indexName, warmerConfig.getMaxWarmingQueries()); @@ -390,11 +390,8 @@ public abstract void start( /** Get mapping of ordinal to shard state. */ public abstract Map getShards(); - /** - * Commit all state and shards. If backupFromIncArchiver is passed in it will also attempt to use - * IndexArchiver to upload files to remote storage - */ - public abstract long commit(boolean backupFromIncArchiver) throws IOException; + /** Commit all state and shards */ + public abstract long commit() throws IOException; /** True if this index has at least one commit. */ public abstract boolean hasCommit() throws IOException; diff --git a/src/main/java/com/yelp/nrtsearch/server/luceneserver/ReleaseSnapshotHandler.java b/src/main/java/com/yelp/nrtsearch/server/luceneserver/ReleaseSnapshotHandler.java index 2655319f3..75d1edb9a 100644 --- a/src/main/java/com/yelp/nrtsearch/server/luceneserver/ReleaseSnapshotHandler.java +++ b/src/main/java/com/yelp/nrtsearch/server/luceneserver/ReleaseSnapshotHandler.java @@ -17,6 +17,7 @@ import com.yelp.nrtsearch.server.grpc.ReleaseSnapshotRequest; import com.yelp.nrtsearch.server.grpc.ReleaseSnapshotResponse; +import com.yelp.nrtsearch.server.grpc.SnapshotId; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -55,4 +56,22 @@ public ReleaseSnapshotResponse handle( } return ReleaseSnapshotResponse.newBuilder().setSuccess(true).build(); } + + /** + * Release resources held by the given snapshot. + * + * @param indexState index state + * @param indexName index name + * @param snapshotId snapshot id + */ + public static void releaseSnapshot( + IndexState indexState, String indexName, SnapshotId snapshotId) { + ReleaseSnapshotRequest releaseSnapshotRequest = + ReleaseSnapshotRequest.newBuilder() + .setIndexName(indexName) + .setSnapshotId(snapshotId) + .build(); + ReleaseSnapshotResponse releaseSnapshotResponse = + new ReleaseSnapshotHandler().handle(indexState, releaseSnapshotRequest); + } } diff --git a/src/main/java/com/yelp/nrtsearch/server/luceneserver/StartIndexHandler.java b/src/main/java/com/yelp/nrtsearch/server/luceneserver/StartIndexHandler.java index 01d35db9b..17017aa22 100644 --- a/src/main/java/com/yelp/nrtsearch/server/luceneserver/StartIndexHandler.java +++ b/src/main/java/com/yelp/nrtsearch/server/luceneserver/StartIndexHandler.java @@ -23,6 +23,7 @@ import com.yelp.nrtsearch.server.grpc.StartIndexRequest; import com.yelp.nrtsearch.server.grpc.StartIndexResponse; import com.yelp.nrtsearch.server.luceneserver.index.IndexStateManager; +import com.yelp.nrtsearch.server.remote.RemoteBackend; import com.yelp.nrtsearch.server.utils.FileUtil; import java.io.IOException; import java.nio.file.Files; @@ -39,28 +40,22 @@ public enum INDEXED_DATA_TYPE { STATE } - private final Archiver archiver; private final Archiver incArchiver; + private final RemoteBackend remoteBackend; private final String archiveDirectory; private final IndexStateManager indexStateManager; - private final boolean backupFromIncArchiver; - private final boolean restoreFromIncArchiver; private final int discoveryFileUpdateIntervalMs; private static final Logger logger = LoggerFactory.getLogger(StartIndexHandler.class); public StartIndexHandler( - Archiver archiver, Archiver incArchiver, + RemoteBackend remoteBackend, String archiveDirectory, - boolean backupFromIncArchiver, - boolean restoreFromIncArchiver, IndexStateManager indexStateManager, int discoveryFileUpdateIntervalMs) { - this.archiver = archiver; this.incArchiver = incArchiver; + this.remoteBackend = remoteBackend; this.archiveDirectory = archiveDirectory; - this.backupFromIncArchiver = backupFromIncArchiver; - this.restoreFromIncArchiver = restoreFromIncArchiver; this.indexStateManager = indexStateManager; this.discoveryFileUpdateIntervalMs = discoveryFileUpdateIntervalMs; } @@ -95,8 +90,7 @@ public StartIndexResponse handle(IndexState indexState, StartIndexRequest startI downloadArtifact( restoreIndex.getServiceName(), restoreIndex.getResourceName(), - INDEXED_DATA_TYPE.DATA, - restoreFromIncArchiver); + INDEXED_DATA_TYPE.DATA); } else { throw new IllegalStateException( "Index " + indexState.getName() + " already restored"); @@ -121,24 +115,10 @@ public StartIndexResponse handle(IndexState indexState, StartIndexRequest startI long t0 = System.nanoTime(); try { if (mode.equals(Mode.REPLICA)) { - indexState.initWarmer(archiver); + indexState.initWarmer(remoteBackend); } indexStateManager.start(mode, dataPath, primaryGen, primaryClient); - - if (mode.equals(Mode.PRIMARY)) { - BackupIndexRequestHandler backupIndexRequestHandler = - new BackupIndexRequestHandler( - archiver, incArchiver, archiveDirectory, backupFromIncArchiver); - if (backupIndexRequestHandler.wasBackupPotentiallyInterrupted()) { - if (backupIndexRequestHandler - .getIndexNameOfInterruptedBackup() - .equals(indexState.getName())) { - backupIndexRequestHandler.interruptedBackupCleanup( - indexState, shardState.snapshotGenToVersion.keySet()); - } - } - } } catch (Exception e) { logger.error("Cannot start IndexState/ShardState", e); throw new StartIndexHandlerException(e); @@ -171,9 +151,7 @@ public StartIndexResponse handle(IndexState indexState, StartIndexRequest startI } finally { if (startIndexRequest.hasRestore()) { cleanupDownloadedArtifacts( - startIndexRequest.getRestore().getResourceName(), - INDEXED_DATA_TYPE.DATA, - restoreFromIncArchiver); + startIndexRequest.getRestore().getResourceName(), INDEXED_DATA_TYPE.DATA); } } } @@ -201,10 +179,7 @@ private void deleteDownloadedBackupDirectories(String resourceName) throws IOExc * index data */ public Path downloadArtifact( - String serviceName, - String resourceName, - INDEXED_DATA_TYPE indexDataType, - boolean disableLegacyArchiver) { + String serviceName, String resourceName, INDEXED_DATA_TYPE indexDataType) { String resource; if (indexDataType.equals(INDEXED_DATA_TYPE.DATA)) { resource = IndexBackupUtils.getResourceData(resourceName); @@ -214,18 +189,13 @@ public Path downloadArtifact( throw new RuntimeException("Invalid INDEXED_DATA_TYPE " + indexDataType); } try { - if (!disableLegacyArchiver) { - return archiver.download(serviceName, resource); - } else { - return incArchiver.download(serviceName, resource); - } + return incArchiver.download(serviceName, resource); } catch (IOException e) { throw new RuntimeException(e); } } - void cleanupDownloadedArtifacts( - String resourceName, INDEXED_DATA_TYPE indexDataType, boolean disableLegacyArchiver) { + void cleanupDownloadedArtifacts(String resourceName, INDEXED_DATA_TYPE indexDataType) { String resource; if (indexDataType.equals(INDEXED_DATA_TYPE.DATA)) { resource = IndexBackupUtils.getResourceData(resourceName); @@ -235,11 +205,7 @@ void cleanupDownloadedArtifacts( throw new RuntimeException("Invalid INDEXED_DATA_TYPE " + indexDataType); } logger.info("Cleaning up local index resource: " + resource); - if (!disableLegacyArchiver) { - archiver.deleteLocalFiles(resource); - } else { - incArchiver.deleteLocalFiles(resource); - } + incArchiver.deleteLocalFiles(resource); } public static class StartIndexHandlerException extends HandlerException { diff --git a/src/main/java/com/yelp/nrtsearch/server/luceneserver/index/BackendStateManager.java b/src/main/java/com/yelp/nrtsearch/server/luceneserver/index/BackendStateManager.java index 48bd6771b..88371e9f0 100644 --- a/src/main/java/com/yelp/nrtsearch/server/luceneserver/index/BackendStateManager.java +++ b/src/main/java/com/yelp/nrtsearch/server/luceneserver/index/BackendStateManager.java @@ -206,7 +206,7 @@ public synchronized void start( currentState.start(serverMode, dataPath, primaryGen, primaryClient); if (serverMode != Mode.REPLICA && !currentState.getCurrentStateInfo().getCommitted()) { logger.info("Doing initial commit for index: " + indexName); - currentState.commit(globalState.getConfiguration().getBackupWithInArchiver()); + currentState.commit(); IndexStateInfo updatedStateInfo = currentState.getCurrentStateInfo().toBuilder() .setCommitted(true) diff --git a/src/main/java/com/yelp/nrtsearch/server/luceneserver/index/ImmutableIndexState.java b/src/main/java/com/yelp/nrtsearch/server/luceneserver/index/ImmutableIndexState.java index 65e22388e..17459c928 100644 --- a/src/main/java/com/yelp/nrtsearch/server/luceneserver/index/ImmutableIndexState.java +++ b/src/main/java/com/yelp/nrtsearch/server/luceneserver/index/ImmutableIndexState.java @@ -15,8 +15,8 @@ */ package com.yelp.nrtsearch.server.luceneserver.index; -import static com.yelp.nrtsearch.server.luceneserver.BackupIndexRequestHandler.getSegmentFilesInSnapshot; -import static com.yelp.nrtsearch.server.luceneserver.BackupIndexRequestHandler.releaseSnapshot; +import static com.yelp.nrtsearch.server.luceneserver.CreateSnapshotHandler.getSegmentFilesInSnapshot; +import static com.yelp.nrtsearch.server.luceneserver.ReleaseSnapshotHandler.releaseSnapshot; import com.google.common.collect.ImmutableMap; import com.google.gson.JsonElement; @@ -53,6 +53,7 @@ import com.yelp.nrtsearch.server.luceneserver.field.properties.GlobalOrdinalable; import com.yelp.nrtsearch.server.luceneserver.search.sort.SortParser; import com.yelp.nrtsearch.server.luceneserver.state.StateUtils; +import com.yelp.nrtsearch.server.remote.RemoteBackend; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -579,7 +580,7 @@ public Map getShards() { } @Override - public long commit(boolean backupFromIncArchiver) throws IOException { + public long commit() throws IOException { // the shards map is created once and passed to all subsequent instance synchronized (shards) { long gen = -1; @@ -589,9 +590,7 @@ public long commit(boolean backupFromIncArchiver) throws IOException { SnapshotId snapshotId = null; try { - if (this.getShard(0).isPrimary() - && getGlobalState().getIncArchiver().isPresent() - && backupFromIncArchiver) { + if (this.getShard(0).isPrimary() && getGlobalState().getIncArchiver().isPresent()) { CreateSnapshotRequest createSnapshotRequest = CreateSnapshotRequest.newBuilder().setIndexName(getName()).build(); @@ -831,8 +830,8 @@ public Map getSuggesters() { } @Override - public void initWarmer(Archiver archiver) { - initWarmer(archiver, uniqueName); + public void initWarmer(RemoteBackend remoteBackend) { + initWarmer(remoteBackend, uniqueName); } @Override diff --git a/src/main/java/com/yelp/nrtsearch/server/luceneserver/state/BackendGlobalState.java b/src/main/java/com/yelp/nrtsearch/server/luceneserver/state/BackendGlobalState.java index 209955932..7fd792493 100644 --- a/src/main/java/com/yelp/nrtsearch/server/luceneserver/state/BackendGlobalState.java +++ b/src/main/java/com/yelp/nrtsearch/server/luceneserver/state/BackendGlobalState.java @@ -39,6 +39,7 @@ import com.yelp.nrtsearch.server.luceneserver.state.backend.LocalStateBackend; import com.yelp.nrtsearch.server.luceneserver.state.backend.RemoteStateBackend; import com.yelp.nrtsearch.server.luceneserver.state.backend.StateBackend; +import com.yelp.nrtsearch.server.remote.RemoteBackend; import java.io.IOException; import java.nio.file.Path; import java.util.Collections; @@ -80,7 +81,6 @@ private static class ImmutableState { // volatile for atomic replacement private volatile ImmutableState immutableState; private final StateBackend stateBackend; - private final Archiver legacyArchiver; /** * Build unique index name from index name and instance id (UUID). @@ -101,29 +101,15 @@ public static String getUniqueIndexName(String indexName, String id) { * * @param luceneServerConfiguration server config * @param incArchiver archiver for remote backends - * @throws IOException on filesystem error - */ - public BackendGlobalState( - LuceneServerConfiguration luceneServerConfiguration, Archiver incArchiver) - throws IOException { - this(luceneServerConfiguration, incArchiver, null); - } - - /** - * Constructor. - * - * @param luceneServerConfiguration server config - * @param incArchiver archiver for remote backends - * @param legacyArchiver legacy archiver + * @param remoteBackend backend for persistent remote storage * @throws IOException on filesystem error */ public BackendGlobalState( LuceneServerConfiguration luceneServerConfiguration, Archiver incArchiver, - Archiver legacyArchiver) + RemoteBackend remoteBackend) throws IOException { - super(luceneServerConfiguration, incArchiver); - this.legacyArchiver = legacyArchiver; + super(luceneServerConfiguration, incArchiver, remoteBackend); stateBackend = createStateBackend(); GlobalStateInfo globalStateInfo = stateBackend.loadOrCreateGlobalState(); // init index state managers @@ -427,11 +413,9 @@ private StartIndexResponse startIndex( IndexStateManager indexStateManager, StartIndexRequest startIndexRequest) throws IOException { StartIndexHandler startIndexHandler = new StartIndexHandler( - legacyArchiver, getIncArchiver().orElse(null), + getRemoteBackend(), getConfiguration().getArchiveDirectory(), - getConfiguration().getBackupWithInArchiver(), - getConfiguration().getRestoreFromIncArchiver(), indexStateManager, getConfiguration().getDiscoveryFileUpdateIntervalMs()); try { diff --git a/src/main/java/com/yelp/nrtsearch/server/luceneserver/warming/Warmer.java b/src/main/java/com/yelp/nrtsearch/server/luceneserver/warming/Warmer.java index 3bfe0f219..c29883dae 100644 --- a/src/main/java/com/yelp/nrtsearch/server/luceneserver/warming/Warmer.java +++ b/src/main/java/com/yelp/nrtsearch/server/luceneserver/warming/Warmer.java @@ -19,13 +19,15 @@ import com.google.common.base.Strings; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.util.JsonFormat; -import com.yelp.nrtsearch.server.backup.Archiver; import com.yelp.nrtsearch.server.grpc.SearchRequest; import com.yelp.nrtsearch.server.luceneserver.IndexState; import com.yelp.nrtsearch.server.luceneserver.SearchHandler; +import com.yelp.nrtsearch.server.remote.RemoteBackend; +import com.yelp.nrtsearch.server.remote.RemoteBackend.IndexResourceType; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; +import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -41,23 +43,20 @@ public class Warmer { private static final Logger logger = LoggerFactory.getLogger(Warmer.class); - public static final String WARMING_QUERIES_RESOURCE = "_warming_queries"; public static final String WARMING_QUERIES_DIR = "warming_queries"; private static final String WARMING_QUERIES_FILE = "warming_queries.txt"; - private final Archiver archiver; + private final RemoteBackend remoteBackend; private final String service; - private final String resource; private final List warmingRequests; private final ReservoirSampler reservoirSampler; private final String index; private final int maxWarmingQueries; - public Warmer(Archiver archiver, String service, String index, int maxWarmingQueries) { - this.archiver = archiver; + public Warmer(RemoteBackend remoteBackend, String service, String index, int maxWarmingQueries) { + this.remoteBackend = remoteBackend; this.service = service; this.index = index; - this.resource = index + WARMING_QUERIES_RESOURCE; this.warmingRequests = Collections.synchronizedList(new ArrayList<>(maxWarmingQueries)); this.reservoirSampler = new ReservoirSampler(maxWarmingQueries); this.maxWarmingQueries = maxWarmingQueries; @@ -101,15 +100,14 @@ public synchronized void backupWarmingQueriesToS3(String service) throws IOExcep } writer.close(); writer = null; - String versionHash = - archiver.upload(service, resource, warmingQueriesDir, List.of(), List.of(), true); - archiver.blessVersion(service, resource, versionHash); + remoteBackend.uploadFile( + service, index, IndexResourceType.WARMING_QUERIES, warmingQueriesFile); logger.info( - "Backed up {} warming queries for index: {} to service: {}, resource: {}", + "Backed up {} warming queries for index: {} to service: {}, type: {}", count, index, service, - resource); + IndexResourceType.WARMING_QUERIES); } finally { if (writer != null) { writer.close(); @@ -132,9 +130,8 @@ public void warmFromS3(IndexState indexState, int parallelism) @VisibleForTesting void warmFromS3(IndexState indexState, int parallelism, SearchHandler searchHandler) throws IOException, SearchHandler.SearchHandlerException, InterruptedException { - if (archiver.getVersionedResource(service, resource).isEmpty()) { - logger.info( - "No warming queries found in S3 for service: {} and resource: {}", service, resource); + if (!remoteBackend.exists(service, index, IndexResourceType.WARMING_QUERIES)) { + logger.info("No warming queries found in S3 for service: {} and index: {}", service, index); return; } ThreadPoolExecutor threadPoolExecutor = null; @@ -150,10 +147,10 @@ void warmFromS3(IndexState indexState, int parallelism, SearchHandler searchHand new NamedThreadFactory("warming-"), new ThreadPoolExecutor.CallerRunsPolicy()); } - Path downloadDir = archiver.download(service, resource); - Path warmingRequestsDir = downloadDir.resolve(WARMING_QUERIES_DIR); try (BufferedReader reader = - Files.newBufferedReader(warmingRequestsDir.resolve(WARMING_QUERIES_FILE))) { + new BufferedReader( + new InputStreamReader( + remoteBackend.downloadStream(service, index, IndexResourceType.WARMING_QUERIES)))) { String line; int count = 0; while ((line = reader.readLine()) != null) { diff --git a/src/main/java/com/yelp/nrtsearch/server/module/S3Module.java b/src/main/java/com/yelp/nrtsearch/server/module/S3Module.java index 1456a340c..55c5a961f 100644 --- a/src/main/java/com/yelp/nrtsearch/server/module/S3Module.java +++ b/src/main/java/com/yelp/nrtsearch/server/module/S3Module.java @@ -15,81 +15,19 @@ */ package com.yelp.nrtsearch.server.module; -import com.amazonaws.ClientConfiguration; -import com.amazonaws.auth.AWSCredentialsProvider; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.AnonymousAWSCredentials; -import com.amazonaws.auth.profile.ProfileCredentialsProvider; -import com.amazonaws.auth.profile.ProfilesConfigFile; -import com.amazonaws.client.builder.AwsClientBuilder; -import com.amazonaws.client.builder.AwsClientBuilder.EndpointConfiguration; -import com.amazonaws.retry.PredefinedRetryPolicies; -import com.amazonaws.retry.RetryPolicy; import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.google.inject.AbstractModule; import com.google.inject.Inject; import com.google.inject.Provides; import com.google.inject.Singleton; import com.yelp.nrtsearch.server.config.LuceneServerConfiguration; -import java.nio.file.Path; -import java.nio.file.Paths; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.yelp.nrtsearch.server.remote.s3.S3Util; public class S3Module extends AbstractModule { - private static final Logger logger = LoggerFactory.getLogger(S3Module.class); - @Inject @Singleton @Provides protected AmazonS3 providesAmazonS3(LuceneServerConfiguration luceneServerConfiguration) { - if (luceneServerConfiguration - .getBotoCfgPath() - .equals(LuceneServerConfiguration.DEFAULT_BOTO_CFG_PATH.toString())) { - return AmazonS3ClientBuilder.standard() - .withCredentials(new AWSStaticCredentialsProvider(new AnonymousAWSCredentials())) - .withEndpointConfiguration( - new AwsClientBuilder.EndpointConfiguration("dummyService", "dummyRegion")) - .build(); - } else { - Path botoCfgPath = Paths.get(luceneServerConfiguration.getBotoCfgPath()); - final ProfilesConfigFile profilesConfigFile = new ProfilesConfigFile(botoCfgPath.toFile()); - final AWSCredentialsProvider awsCredentialsProvider = - new ProfileCredentialsProvider(profilesConfigFile, "default"); - AmazonS3 s3ClientInterim = - AmazonS3ClientBuilder.standard().withCredentials(awsCredentialsProvider).build(); - String region = s3ClientInterim.getBucketLocation(luceneServerConfiguration.getBucketName()); - // In useast-1, the region is returned as "US" which is an equivalent to "us-east-1" - // https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/model/Region.html#US_Standard - // However, this causes an UnknownHostException so we override it to the full region name - if (region.equals("US")) { - region = "us-east-1"; - } - String serviceEndpoint = String.format("s3.%s.amazonaws.com", region); - logger.info(String.format("S3 ServiceEndpoint: %s", serviceEndpoint)); - AmazonS3ClientBuilder clientBuilder = - AmazonS3ClientBuilder.standard() - .withCredentials(awsCredentialsProvider) - .withEndpointConfiguration(new EndpointConfiguration(serviceEndpoint, region)); - - int maxRetries = luceneServerConfiguration.getMaxS3ClientRetries(); - if (maxRetries > 0) { - RetryPolicy retryPolicy = - new RetryPolicy( - PredefinedRetryPolicies.DEFAULT_RETRY_CONDITION, - PredefinedRetryPolicies.DEFAULT_BACKOFF_STRATEGY, - maxRetries, - true); - ClientConfiguration clientConfiguration = - new ClientConfiguration().withRetryPolicy(retryPolicy); - clientBuilder.setClientConfiguration(clientConfiguration); - } - - if (luceneServerConfiguration.getEnableGlobalBucketAccess()) { - clientBuilder.enableForceGlobalBucketAccess(); - } - return clientBuilder.build(); - } + return S3Util.buildS3Client(luceneServerConfiguration); } } diff --git a/src/main/java/com/yelp/nrtsearch/server/plugins/PluginDownloader.java b/src/main/java/com/yelp/nrtsearch/server/plugins/PluginDownloader.java deleted file mode 100644 index f2ac742dd..000000000 --- a/src/main/java/com/yelp/nrtsearch/server/plugins/PluginDownloader.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2023 Yelp Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yelp.nrtsearch.server.plugins; - -import com.amazonaws.services.s3.AmazonS3; -import com.yelp.nrtsearch.server.config.LuceneServerConfiguration; -import com.yelp.nrtsearch.server.utils.S3Downloader; -import com.yelp.nrtsearch.server.utils.S3Util; -import com.yelp.nrtsearch.server.utils.ZipUtil; -import java.io.Closeable; -import java.nio.file.Path; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** Download plugins from external sources. */ -public class PluginDownloader implements Closeable { - - private static final Logger logger = LoggerFactory.getLogger(PluginDownloader.class); - private static final String ZIP_EXTENSION = ".zip"; - - private final S3Downloader s3Downloader; - private final boolean saveBeforeUnzip; - - public PluginDownloader(AmazonS3 amazonS3, LuceneServerConfiguration configuration) { - this.s3Downloader = new S3Downloader(amazonS3); - this.saveBeforeUnzip = configuration.getSavePluginBeforeUnzip(); - } - - /** - * If the plugin name is an external URI, download the plugin from the URI. Currently only S3 URI - * containing a zip file is supported. - * - * @param pluginName Plugin name from configuration - * @param searchPath Path of local storage where plugin files must be located to be loaded - * @return Updated file name - */ - public String downloadPluginIfNeeded(String pluginName, Path searchPath) { - if (S3Util.isValidS3FilePath(pluginName) && pluginName.endsWith(ZIP_EXTENSION)) { - logger.info("Downloading plugin: {}", pluginName); - ZipUtil.extractZip(s3Downloader.downloadFromS3Path(pluginName), searchPath, saveBeforeUnzip); - // Assuming that the plugin directory is same as the name of the file - return S3Util.getS3FileName(pluginName).split(".zip")[0]; - } - return pluginName; - } - - @Override - public void close() { - s3Downloader.close(); - } -} diff --git a/src/main/java/com/yelp/nrtsearch/server/plugins/PluginsService.java b/src/main/java/com/yelp/nrtsearch/server/plugins/PluginsService.java index 0eb233b61..861164478 100644 --- a/src/main/java/com/yelp/nrtsearch/server/plugins/PluginsService.java +++ b/src/main/java/com/yelp/nrtsearch/server/plugins/PluginsService.java @@ -15,8 +15,8 @@ */ package com.yelp.nrtsearch.server.plugins; -import com.amazonaws.services.s3.AmazonS3; import com.yelp.nrtsearch.server.config.LuceneServerConfiguration; +import com.yelp.nrtsearch.server.remote.PluginDownloader; import io.prometheus.client.CollectorRegistry; import java.io.File; import java.net.MalformedURLException; @@ -47,13 +47,15 @@ public class PluginsService { private final CollectorRegistry collectorRegistry; private final List loadedPluginDescriptors = new ArrayList<>(); - private final AmazonS3 amazonS3; + private final PluginDownloader pluginDownloader; public PluginsService( - LuceneServerConfiguration config, AmazonS3 amazonS3, CollectorRegistry collectorRegistry) { + LuceneServerConfiguration config, + PluginDownloader pluginDownloader, + CollectorRegistry collectorRegistry) { this.config = config; this.collectorRegistry = collectorRegistry; - this.amazonS3 = amazonS3; + this.pluginDownloader = pluginDownloader; } /** @@ -67,14 +69,12 @@ public List loadPlugins() { List pluginSearchPath = getPluginSearchPath(); logger.debug("Plugin search path: " + pluginSearchPath); List loadedPlugins = new ArrayList<>(); - PluginDownloader pluginDownloader = new PluginDownloader(amazonS3, config); for (String plugin : config.getPlugins()) { logger.info("Loading plugin: " + plugin); PluginDescriptor descriptor = loadPlugin(plugin, pluginSearchPath, pluginDownloader); loadedPluginDescriptors.add(descriptor); loadedPlugins.add(descriptor.getPlugin()); } - pluginDownloader.close(); return loadedPlugins; } diff --git a/src/main/java/com/yelp/nrtsearch/server/remote/PluginDownloader.java b/src/main/java/com/yelp/nrtsearch/server/remote/PluginDownloader.java new file mode 100644 index 000000000..73f4e095d --- /dev/null +++ b/src/main/java/com/yelp/nrtsearch/server/remote/PluginDownloader.java @@ -0,0 +1,33 @@ +/* + * Copyright 2023 Yelp Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.yelp.nrtsearch.server.remote; + +import java.io.Closeable; +import java.nio.file.Path; + +/** Interface for downloading plugins from an external source. */ +public interface PluginDownloader extends Closeable { + + /** + * If the plugin name is a path supported by this downloader, download the plugin to the specified + * directory. + * + * @param pluginNameOrPath potential plugin path to download + * @param destPath directory to store downloaded plugin folder + * @return resolved plugin name + */ + String downloadPluginIfNeeded(String pluginNameOrPath, Path destPath); +} diff --git a/src/main/java/com/yelp/nrtsearch/server/remote/RemoteBackend.java b/src/main/java/com/yelp/nrtsearch/server/remote/RemoteBackend.java new file mode 100644 index 000000000..01efade9f --- /dev/null +++ b/src/main/java/com/yelp/nrtsearch/server/remote/RemoteBackend.java @@ -0,0 +1,65 @@ +/* + * Copyright 2023 Yelp Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.yelp.nrtsearch.server.remote; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; + +/** Interface for interacting with service resources stored in a persistent backend. */ +public interface RemoteBackend extends PluginDownloader { + enum IndexResourceType { + WARMING_QUERIES + } + + /** + * Get if a given index resource exists in the backend. + * + * @param service service name + * @param indexIdentifier unique index identifier + * @param resourceType type of index resource + * @return if resource exists + * @throws IOException + */ + boolean exists(String service, String indexIdentifier, IndexResourceType resourceType) + throws IOException; + + /** + * Download index resource data from backend through an {@link InputStream}. + * + * @param service service name + * @param indexIdentifier unique index identifier + * @param resourceType type of index resource + * @return input stream to process downloaded resource + * @throws IllegalArgumentException if resource does not exist + * @throws IOException + */ + InputStream downloadStream(String service, String indexIdentifier, IndexResourceType resourceType) + throws IOException; + + /** + * Upload file contents to the specified index resource, replacing any existing version. + * + * @param service service name + * @param indexIdentifier unique index identifier + * @param resourceType type of index resource + * @param file file data to upload + * @throws IllegalArgumentException if file does not exist, or is not a regular file + * @throws IOException on error uploading file + */ + void uploadFile(String service, String indexIdentifier, IndexResourceType resourceType, Path file) + throws IOException; +} diff --git a/src/main/java/com/yelp/nrtsearch/server/utils/S3Downloader.java b/src/main/java/com/yelp/nrtsearch/server/remote/s3/S3Backend.java similarity index 50% rename from src/main/java/com/yelp/nrtsearch/server/utils/S3Downloader.java rename to src/main/java/com/yelp/nrtsearch/server/remote/s3/S3Backend.java index a344e0ece..393bce629 100644 --- a/src/main/java/com/yelp/nrtsearch/server/utils/S3Downloader.java +++ b/src/main/java/com/yelp/nrtsearch/server/remote/s3/S3Backend.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.yelp.nrtsearch.server.utils; +package com.yelp.nrtsearch.server.remote.s3; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3URI; @@ -21,40 +21,79 @@ import com.amazonaws.services.s3.model.GetObjectMetadataRequest; import com.amazonaws.services.s3.model.GetObjectRequest; import com.amazonaws.services.s3.model.ObjectMetadata; +import com.amazonaws.services.s3.model.PutObjectRequest; import com.amazonaws.services.s3.model.S3Object; -import java.io.Closeable; +import com.amazonaws.services.s3.transfer.TransferManager; +import com.amazonaws.services.s3.transfer.TransferManagerBuilder; +import com.amazonaws.services.s3.transfer.Upload; +import com.google.common.annotations.VisibleForTesting; +import com.yelp.nrtsearch.server.backup.VersionManager; +import com.yelp.nrtsearch.server.config.LuceneServerConfiguration; +import com.yelp.nrtsearch.server.remote.RemoteBackend; +import com.yelp.nrtsearch.server.utils.ZipUtil; +import java.io.IOException; import java.io.InputStream; import java.io.SequenceInputStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Enumeration; import java.util.LinkedList; +import java.util.UUID; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class S3Downloader implements Closeable { - private static final Logger logger = LoggerFactory.getLogger(S3Downloader.class); +/** Backend implementation that stored data in amazon s3 object storage. */ +public class S3Backend implements RemoteBackend { + public static final String WARMING_QUERIES_RESOURCE_SUFFIX = "_warming_queries"; + public static final String LATEST_VERSION = "_latest_version"; + static final String VERSION_STRING_FORMAT = "%s/_version/%s/%s"; + static final String RESOURCE_KEY_FORMAT = "%s/%s/%s"; + private static final Logger logger = LoggerFactory.getLogger(S3Backend.class); + private static final String ZIP_EXTENSION = ".zip"; public static final int NUM_S3_THREADS = 20; private final ThreadPoolExecutor executor; + private final boolean saveBeforeUnzip; private final AmazonS3 s3; + private final String serviceBucket; + private final VersionManager versionManger; + private final TransferManager transferManager; - public S3Downloader(AmazonS3 s3) { + /** + * Constructor. + * + * @param configuration configuration + * @param s3 s3 client + */ + public S3Backend(LuceneServerConfiguration configuration, AmazonS3 s3) { this.s3 = s3; this.executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(NUM_S3_THREADS); + this.saveBeforeUnzip = configuration.getSavePluginBeforeUnzip(); + this.serviceBucket = configuration.getBucketName(); + this.versionManger = new VersionManager(s3, serviceBucket); + this.transferManager = + TransferManagerBuilder.standard() + .withS3Client(s3) + .withExecutorFactory(() -> executor) + .withShutDownThreadPools(false) + .build(); } - public S3Downloader(AmazonS3 s3, int numS3Threads) { - this.s3 = s3; - this.executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(numS3Threads); - } - - public S3Downloader(AmazonS3 s3, ThreadPoolExecutor executor) { - this.s3 = s3; - this.executor = executor; + @Override + public String downloadPluginIfNeeded(String pluginNameOrPath, Path destPath) { + if (S3Util.isValidS3FilePath(pluginNameOrPath) && pluginNameOrPath.endsWith(ZIP_EXTENSION)) { + logger.info("Downloading plugin: {}", pluginNameOrPath); + ZipUtil.extractZip(downloadFromS3Path(pluginNameOrPath), destPath, saveBeforeUnzip); + // Assuming that the plugin directory is same as the name of the file + return S3Util.getS3FileName(pluginNameOrPath).split(".zip")[0]; + } + return pluginNameOrPath; } /** @@ -87,7 +126,7 @@ public InputStream downloadFromS3Path(String bucketName, String absoluteResource ObjectMetadata fullMetadata = s3.getObjectMetadata(metadataRequest); logger.info("Full object size: " + fullMetadata.getContentLength()); } catch (AmazonS3Exception e) { - if (e.getStatusCode() == 404) { + if (isNotFoundException(e)) { String error = String.format("Object s3://%s/%s not found", bucketName, absoluteResourcePath); throw new IllegalArgumentException(error, e); @@ -162,11 +201,96 @@ public InputStream nextElement() { @Override public void close() { + transferManager.shutdownNow(false); try { executor.shutdown(); executor.awaitTermination(1, TimeUnit.SECONDS); } catch (InterruptedException e) { throw new RuntimeException(e); } + s3.shutdown(); + } + + @Override + public boolean exists(String service, String indexIdentifier, IndexResourceType resourceType) + throws IOException { + String resource = getResourceName(indexIdentifier, resourceType); + try { + getVersionString(service, resource, LATEST_VERSION); + return true; + } catch (IllegalArgumentException e) { + return false; + } + } + + @Override + public InputStream downloadStream( + String service, String indexIdentifier, IndexResourceType resourceType) throws IOException { + String resource = getResourceName(indexIdentifier, resourceType); + String latestVersion = getVersionString(service, resource, LATEST_VERSION); + String versionHash = getVersionString(service, resource, latestVersion); + String resourceKey = getResourceKey(service, resource, versionHash); + return downloadFromS3Path(serviceBucket, resourceKey); + } + + @Override + public void uploadFile( + String service, String indexIdentifier, IndexResourceType resourceType, Path file) + throws IOException { + if (!Files.exists(file)) { + throw new IllegalArgumentException("File does not exist: " + file); + } + if (!Files.isRegularFile(file)) { + throw new IllegalArgumentException("Is not regular file: " + file); + } + String resource = getResourceName(indexIdentifier, resourceType); + String versionHash = UUID.randomUUID().toString(); + String resourceKey = getResourceKey(service, resource, versionHash); + PutObjectRequest request = new PutObjectRequest(serviceBucket, resourceKey, file.toFile()); + request.setGeneralProgressListener(new S3ProgressListenerImpl(service, resource, "upload")); + Upload upload = transferManager.upload(request); + try { + upload.waitForUploadResult(); + logger.info("Upload completed "); + } catch (InterruptedException e) { + throw new IOException("Error while uploading to s3. ", e); + } + versionManger.blessVersion(service, resource, versionHash); + } + + @VisibleForTesting + static String getResourceName(String indexIdentifier, IndexResourceType resourceType) { + return switch (resourceType) { + case WARMING_QUERIES -> indexIdentifier + WARMING_QUERIES_RESOURCE_SUFFIX; + }; + } + + @VisibleForTesting + static String getResourceKey(String service, String resource, String versionHash) { + return String.format(RESOURCE_KEY_FORMAT, service, resource, versionHash); + } + + @VisibleForTesting + static String getVersionKey(String service, String resource, String version) { + return String.format(VERSION_STRING_FORMAT, service, resource, version); + } + + private String getVersionString( + final String serviceName, final String resource, final String version) throws IOException { + final String absoluteResourcePath = getVersionKey(serviceName, resource, version); + try (final S3Object s3Object = s3.getObject(serviceBucket, absoluteResourcePath)) { + return IOUtils.toString(s3Object.getObjectContent()); + } catch (AmazonS3Exception e) { + if (isNotFoundException(e)) { + String error = + String.format("Object s3://%s/%s not found", serviceBucket, absoluteResourcePath); + throw new IllegalArgumentException(error, e); + } + throw e; + } + } + + private boolean isNotFoundException(AmazonS3Exception e) { + return e.getStatusCode() == 404; } } diff --git a/src/main/java/com/yelp/nrtsearch/server/remote/s3/S3ProgressListenerImpl.java b/src/main/java/com/yelp/nrtsearch/server/remote/s3/S3ProgressListenerImpl.java new file mode 100644 index 000000000..1c2f408f0 --- /dev/null +++ b/src/main/java/com/yelp/nrtsearch/server/remote/s3/S3ProgressListenerImpl.java @@ -0,0 +1,83 @@ +/* + * Copyright 2023 Yelp Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.yelp.nrtsearch.server.remote.s3; + +import com.amazonaws.event.ProgressEvent; +import com.amazonaws.services.s3.transfer.PersistableTransfer; +import com.amazonaws.services.s3.transfer.internal.S3ProgressListener; +import com.yelp.nrtsearch.server.backup.ContentDownloaderImpl; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.concurrent.Semaphore; +import java.util.concurrent.atomic.AtomicLong; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * {@link S3ProgressListener} that logs the status of a s3 transfer using the {@link + * com.amazonaws.services.s3.transfer.TransferManager}. + */ +public class S3ProgressListenerImpl implements S3ProgressListener { + private static final Logger logger = LoggerFactory.getLogger(ContentDownloaderImpl.class); + + private static final long LOG_THRESHOLD_BYTES = 1024 * 1024 * 500; // 500 MB + private static final long LOG_THRESHOLD_SECONDS = 30; + + private final String serviceName; + private final String resource; + private final String operation; + + private final Semaphore lock = new Semaphore(1); + private final AtomicLong totalBytesTransferred = new AtomicLong(); + private long bytesTransferredSinceLastLog = 0; + private LocalDateTime lastLoggedTime = LocalDateTime.now(); + + public S3ProgressListenerImpl(String serviceName, String resource, String operation) { + this.serviceName = serviceName; + this.resource = resource; + this.operation = operation; + } + + @Override + public void onPersistableTransfer(PersistableTransfer persistableTransfer) {} + + @Override + public void progressChanged(ProgressEvent progressEvent) { + long totalBytes = totalBytesTransferred.addAndGet(progressEvent.getBytesTransferred()); + + boolean acquired = lock.tryAcquire(); + + if (acquired) { + try { + bytesTransferredSinceLastLog += progressEvent.getBytesTransferred(); + long secondsSinceLastLog = + Duration.between(lastLoggedTime, LocalDateTime.now()).getSeconds(); + + if (bytesTransferredSinceLastLog > LOG_THRESHOLD_BYTES + || secondsSinceLastLog > LOG_THRESHOLD_SECONDS) { + logger.info( + String.format( + "service: %s, resource: %s, %s transferred bytes: %s", + serviceName, resource, operation, totalBytes)); + bytesTransferredSinceLastLog = 0; + lastLoggedTime = LocalDateTime.now(); + } + } finally { + lock.release(); + } + } + } +} diff --git a/src/main/java/com/yelp/nrtsearch/server/remote/s3/S3Util.java b/src/main/java/com/yelp/nrtsearch/server/remote/s3/S3Util.java new file mode 100644 index 000000000..aae1b701a --- /dev/null +++ b/src/main/java/com/yelp/nrtsearch/server/remote/s3/S3Util.java @@ -0,0 +1,136 @@ +/* + * Copyright 2023 Yelp Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.yelp.nrtsearch.server.remote.s3; + +import com.amazonaws.ClientConfiguration; +import com.amazonaws.auth.AWSCredentialsProvider; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.AnonymousAWSCredentials; +import com.amazonaws.auth.profile.ProfileCredentialsProvider; +import com.amazonaws.auth.profile.ProfilesConfigFile; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.client.builder.AwsClientBuilder.EndpointConfiguration; +import com.amazonaws.retry.PredefinedRetryPolicies; +import com.amazonaws.retry.RetryPolicy; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import com.amazonaws.services.s3.AmazonS3URI; +import com.google.common.base.Strings; +import com.yelp.nrtsearch.server.config.LuceneServerConfiguration; +import java.nio.file.Path; +import java.nio.file.Paths; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** Utility class for working with S3. */ +public class S3Util { + private static final Logger logger = LoggerFactory.getLogger(S3Util.class); + + private S3Util() {} + + /** + * Create a new s3 client from the given configuration. + * + * @param luceneServerConfiguration configuration + * @return s3 client + */ + public static AmazonS3 buildS3Client(LuceneServerConfiguration luceneServerConfiguration) { + if (luceneServerConfiguration + .getBotoCfgPath() + .equals(LuceneServerConfiguration.DEFAULT_BOTO_CFG_PATH.toString())) { + return AmazonS3ClientBuilder.standard() + .withCredentials(new AWSStaticCredentialsProvider(new AnonymousAWSCredentials())) + .withEndpointConfiguration( + new AwsClientBuilder.EndpointConfiguration("dummyService", "dummyRegion")) + .build(); + } else { + Path botoCfgPath = Paths.get(luceneServerConfiguration.getBotoCfgPath()); + final ProfilesConfigFile profilesConfigFile = new ProfilesConfigFile(botoCfgPath.toFile()); + final AWSCredentialsProvider awsCredentialsProvider = + new ProfileCredentialsProvider(profilesConfigFile, "default"); + AmazonS3 s3ClientInterim = + AmazonS3ClientBuilder.standard().withCredentials(awsCredentialsProvider).build(); + String region = s3ClientInterim.getBucketLocation(luceneServerConfiguration.getBucketName()); + // In useast-1, the region is returned as "US" which is an equivalent to "us-east-1" + // https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/model/Region.html#US_Standard + // However, this causes an UnknownHostException so we override it to the full region name + if (region.equals("US")) { + region = "us-east-1"; + } + String serviceEndpoint = String.format("s3.%s.amazonaws.com", region); + logger.info(String.format("S3 ServiceEndpoint: %s", serviceEndpoint)); + AmazonS3ClientBuilder clientBuilder = + AmazonS3ClientBuilder.standard() + .withCredentials(awsCredentialsProvider) + .withEndpointConfiguration(new EndpointConfiguration(serviceEndpoint, region)); + + int maxRetries = luceneServerConfiguration.getMaxS3ClientRetries(); + if (maxRetries > 0) { + RetryPolicy retryPolicy = + new RetryPolicy( + PredefinedRetryPolicies.DEFAULT_RETRY_CONDITION, + PredefinedRetryPolicies.DEFAULT_BACKOFF_STRATEGY, + maxRetries, + true); + ClientConfiguration clientConfiguration = + new ClientConfiguration().withRetryPolicy(retryPolicy); + clientBuilder.setClientConfiguration(clientConfiguration); + } + + if (luceneServerConfiguration.getEnableGlobalBucketAccess()) { + clientBuilder.enableForceGlobalBucketAccess(); + } + return clientBuilder.build(); + } + } + + /** + * Check if a string is a valid S3 file path. + * + * @param path String to check + * @return True if the string is a valid S3 file path, false otherwise + */ + public static boolean isValidS3FilePath(String path) { + try { + AmazonS3URI s3URI = new AmazonS3URI(path); + String key = s3URI.getKey(); + return isKeyValidForFile(key); + } catch (IllegalArgumentException e) { + return false; + } + } + + /** + * Get name of file in S3 from the S3 path, assuming that the name is the last part of a key with + * directories separated by "/". + * + * @param path S3 path + * @return Name of file + */ + public static String getS3FileName(String path) { + AmazonS3URI s3URI = new AmazonS3URI(path); + String key = s3URI.getKey(); + if (!isKeyValidForFile(key)) { + throw new IllegalArgumentException(String.format("S3 path %s is not valid for a file", path)); + } + String[] split = key.split("/"); + return split[split.length - 1]; + } + + private static boolean isKeyValidForFile(String key) { + return !Strings.isNullOrEmpty(key) && !key.endsWith("/"); + } +} diff --git a/src/main/java/com/yelp/nrtsearch/server/utils/S3Util.java b/src/main/java/com/yelp/nrtsearch/server/utils/S3Util.java deleted file mode 100644 index e2c61b042..000000000 --- a/src/main/java/com/yelp/nrtsearch/server/utils/S3Util.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2023 Yelp Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yelp.nrtsearch.server.utils; - -import com.amazonaws.services.s3.AmazonS3URI; -import com.google.common.base.Strings; - -/** Utility class for working with S3 paths. */ -public class S3Util { - - /** - * Check if a string is a valid S3 file path. - * - * @param path String to check - * @return True if the string is a valid S3 file path, false otherwise - */ - public static boolean isValidS3FilePath(String path) { - try { - AmazonS3URI s3URI = new AmazonS3URI(path); - String key = s3URI.getKey(); - return isKeyValidForFile(key); - } catch (IllegalArgumentException e) { - return false; - } - } - - /** - * Get name of file in S3 from the S3 path, assuming that the name is the last part of a key with - * directories separated by "/". - * - * @param path S3 path - * @return Name of file - */ - public static String getS3FileName(String path) { - AmazonS3URI s3URI = new AmazonS3URI(path); - String key = s3URI.getKey(); - if (!isKeyValidForFile(key)) { - throw new IllegalArgumentException(String.format("S3 path %s is not valid for a file", path)); - } - String[] split = key.split("/"); - return split[split.length - 1]; - } - - private static boolean isKeyValidForFile(String key) { - return !Strings.isNullOrEmpty(key) && !key.endsWith("/"); - } -} diff --git a/src/main/java/com/yelp/nrtsearch/tools/nrt_utils/incremental/IncrementalCommandUtils.java b/src/main/java/com/yelp/nrtsearch/tools/nrt_utils/incremental/IncrementalCommandUtils.java index 984520aa3..8ca78ddf5 100644 --- a/src/main/java/com/yelp/nrtsearch/tools/nrt_utils/incremental/IncrementalCommandUtils.java +++ b/src/main/java/com/yelp/nrtsearch/tools/nrt_utils/incremental/IncrementalCommandUtils.java @@ -17,7 +17,7 @@ import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.model.S3Object; -import com.yelp.nrtsearch.server.luceneserver.warming.Warmer; +import com.yelp.nrtsearch.server.remote.s3.S3Backend; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -52,7 +52,7 @@ public static String getIndexDataResource(String indexResource) { * @return index warming queries resource */ public static String getWarmingQueriesResource(String indexResource) { - return indexResource + Warmer.WARMING_QUERIES_RESOURCE; + return indexResource + S3Backend.WARMING_QUERIES_RESOURCE_SUFFIX; } /** diff --git a/src/test/java/com/yelp/nrtsearch/server/backup/ArchiverTest.java b/src/test/java/com/yelp/nrtsearch/server/backup/ArchiverTest.java deleted file mode 100644 index 43467d19e..000000000 --- a/src/test/java/com/yelp/nrtsearch/server/backup/ArchiverTest.java +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright 2020 Yelp Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yelp.nrtsearch.server.backup; - -import static com.yelp.nrtsearch.server.grpc.GrpcServer.rmDir; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.model.S3Object; -import com.amazonaws.services.s3.model.S3ObjectInputStream; -import com.amazonaws.util.IOUtils; -import com.yelp.nrtsearch.test_utils.AmazonS3Provider; -import java.io.ByteArrayInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; -import net.jpountz.lz4.LZ4FrameInputStream; -import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -public class ArchiverTest { - private final String BUCKET_NAME = "archiver-unittest"; - private Archiver archiver; - private AmazonS3 s3; - private Path archiverDirectory; - - @Rule public final TemporaryFolder folder = new TemporaryFolder(); - @Rule public final AmazonS3Provider s3Provider = new AmazonS3Provider(BUCKET_NAME); - - @Before - public void setup() throws IOException { - archiverDirectory = folder.newFolder("archiver").toPath(); - - s3 = s3Provider.getAmazonS3(); - s3.putObject(BUCKET_NAME, "testservice/_version/testresource/_latest_version", "1"); - s3.putObject(BUCKET_NAME, "testservice/_version/testresource/1", "abcdef"); - - archiver = - new ArchiverImpl( - s3, BUCKET_NAME, archiverDirectory, new TarImpl(TarImpl.CompressionMode.LZ4)); - } - - @Test - public void testDownload() throws IOException { - final TarEntry tarEntry = new TarEntry("foo", "testcontent"); - TarEntry.uploadToS3( - s3, BUCKET_NAME, Arrays.asList(tarEntry), "testservice/testresource/abcdef"); - - final Path location = archiver.download("testservice", "testresource"); - final List allLines = Files.readAllLines(location.resolve("foo")); - - assertEquals(1, allLines.size()); - assertEquals("testcontent", allLines.get(0)); - } - - @Test - public void testUpload() throws IOException { - upload(false); - } - - @Test - public void testUploadStream() throws IOException { - upload(true); - } - - private void upload(boolean stream) throws IOException { - String service = "testservice"; - String resource = "testresource"; - Path sourceDir = createDirWithFiles(service, resource); - String subDirPath = sourceDir.resolve("subDir").toString(); - - testUploadWithParameters(service, resource, sourceDir, List.of(), List.of(), List.of(), stream); - testUploadWithParameters( - service, - resource, - sourceDir, - List.of("test1"), - List.of(), - List.of("test2", "subDir"), - stream); - testUploadWithParameters( - service, resource, sourceDir, List.of(), List.of(subDirPath), List.of("test1"), stream); - testUploadWithParameters( - service, resource, sourceDir, List.of("test1"), List.of(subDirPath), List.of(), stream); - } - - private void testUploadWithParameters( - String service, - String resource, - Path sourceDir, - List includeFiles, - List includeDirs, - List ignoreVerifying, - boolean stream) - throws IOException { - String versionHash = - archiver.upload(service, resource, sourceDir, includeFiles, includeDirs, stream); - - Path actualDownloadDir = Files.createDirectory(archiverDirectory.resolve("actualDownload")); - try (S3Object s3Object = - s3.getObject(BUCKET_NAME, String.format("%s/%s/%s", service, resource, versionHash)); - S3ObjectInputStream s3ObjectInputStream = s3Object.getObjectContent(); - LZ4FrameInputStream lz4CompressorInputStream = - new LZ4FrameInputStream(s3ObjectInputStream); - TarArchiveInputStream tarArchiveInputStream = - new TarArchiveInputStream(lz4CompressorInputStream)) { - new TarImpl(TarImpl.CompressionMode.LZ4).extractTar(tarArchiveInputStream, actualDownloadDir); - } - assertTrue( - TarImplTest.dirsMatch( - actualDownloadDir.resolve(resource).toFile(), sourceDir.toFile(), ignoreVerifying)); - - rmDir(actualDownloadDir); - } - - @Test - public void testUploadDownload() throws IOException { - uploadDownload(false); - } - - @Test - public void testUploadDownloadStream() throws IOException { - uploadDownload(true); - } - - private void uploadDownload(boolean stream) throws IOException { - String service = "testservice"; - String resource = "testresource"; - Path sourceDir = createDirWithFiles(service, resource); - String versionHash = - archiver.upload(service, resource, sourceDir, List.of(), List.of(), stream); - archiver.blessVersion(service, resource, versionHash); - Path downloadPath = archiver.download(service, resource); - Path parentPath = downloadPath.getParent(); - Path path = parentPath.resolve(versionHash); - assertTrue(path.toFile().exists()); - } - - private Path createDirWithFiles(String service, String resource) throws IOException { - Path serviceDir = Files.createDirectory(archiverDirectory.resolve(service)); - Path resourceDir = Files.createDirectory(serviceDir.resolve(resource)); - Path subDir = Files.createDirectory(resourceDir.resolve("subDir")); - try (ByteArrayInputStream test1content = new ByteArrayInputStream("test1content".getBytes()); - ByteArrayInputStream test2content = new ByteArrayInputStream("test2content".getBytes()); - FileOutputStream fileOutputStream1 = - new FileOutputStream(resourceDir.resolve("test1").toFile()); - FileOutputStream fileOutputStream2 = - new FileOutputStream(subDir.resolve("test2").toFile()); ) { - IOUtils.copy(test1content, fileOutputStream1); - IOUtils.copy(test2content, fileOutputStream2); - } - return resourceDir; - } - - @Test - public void testCleanup() throws IOException { - final Path dontDeleteThisDirectory = - Files.createDirectory(archiverDirectory.resolve("somerandomsubdirectory")); - - final TarEntry tarEntry = new TarEntry("testresource/foo", "testcontent"); - TarEntry.uploadToS3( - s3, BUCKET_NAME, Arrays.asList(tarEntry), "testservice/testresource/abcdef"); - TarEntry.uploadToS3(s3, BUCKET_NAME, Arrays.asList(tarEntry), "testservice/testresource/cafe"); - - final Path firstLocation = archiver.download("testservice", "testresource").toRealPath(); - Assert.assertTrue(Files.exists(firstLocation.resolve("testresource/foo"))); - - s3.putObject(BUCKET_NAME, "testservice/_version/testresource/1", "cafe"); - - final Path secondLocation = archiver.download("testservice", "testresource").toRealPath(); - - assertFalse(Files.exists(firstLocation.resolve("testresource/foo"))); - Assert.assertTrue(Files.exists(secondLocation.resolve("testresource/foo"))); - Assert.assertTrue(Files.exists(dontDeleteThisDirectory)); - } - - @Test - public void testGetResources() throws IOException { - getResources(false); - } - - @Test - public void testGetResourcesStream() throws IOException { - getResources(true); - } - - private void getResources(boolean stream) throws IOException { - String service = "testservice"; - String[] resources = new String[] {"testresource"}; - Path sourceDir = createDirWithFiles(service, resources[0]); - String versionHash = - archiver.upload(service, resources[0], sourceDir, List.of(), List.of(), stream); - archiver.blessVersion(service, resources[0], versionHash); - List actualResources = archiver.getResources(service); - String[] actual = actualResources.toArray(new String[0]); - Assert.assertArrayEquals(resources, actual); - } - - @Test - public void testGetVersionedResource() throws IOException { - getVersionedResource(false); - } - - @Test - public void testGetVersionedResourceStream() throws IOException { - getVersionedResource(true); - } - - private void getVersionedResource(boolean stream) throws IOException { - String service = "testservice"; - String resource = "testresource"; - Path sourceDir = createDirWithFiles(service, resource); - String versionHash1 = - archiver.upload(service, resource, sourceDir, List.of(), List.of(), stream); - String versionHash2 = - archiver.upload(service, resource, sourceDir, List.of(), List.of(), stream); - List actualResources = archiver.getVersionedResource(service, resource); - - List versionHashes = - actualResources.stream() - .map(VersionedResource::getVersionHash) - .collect(Collectors.toList()); - - Assert.assertTrue(versionHashes.contains(versionHash1)); - Assert.assertTrue(versionHashes.contains(versionHash2)); - Assert.assertEquals(2, versionHashes.size()); - } - - @Test - public void testDeleteVersion() throws IOException { - deleteVersion(false); - } - - @Test - public void testDeleteVersionStream() throws IOException { - deleteVersion(true); - } - - private void deleteVersion(boolean stream) throws IOException { - String service = "testservice"; - String resource = "testresource"; - Path sourceDir = createDirWithFiles(service, resource); - String versionHash1 = - archiver.upload(service, resource, sourceDir, List.of(), List.of(), stream); - String versionHash2 = - archiver.upload(service, resource, sourceDir, List.of(), List.of(), stream); - - archiver.deleteVersion(service, resource, versionHash1); - - List actualResources = archiver.getVersionedResource(service, resource); - - List versionHashes = - actualResources.stream() - .map(VersionedResource::getVersionHash) - .collect(Collectors.toList()); - - assertFalse(versionHashes.contains(versionHash1)); - Assert.assertTrue(versionHashes.contains(versionHash2)); - Assert.assertEquals(1, versionHashes.size()); - } - - @Test - public void testDeleteLocalFiles() throws IOException { - createLocalFiles("resource1", 3, true); - createLocalFiles("resource2", 1, true); - createLocalFiles("resource3", 5, true); - - assertTrue(archiver.deleteLocalFiles("resource2")); - assertTrue(archiverDirectory.resolve("resource1").toFile().exists()); - assertFalse(archiverDirectory.resolve("resource2").toFile().exists()); - assertTrue(archiverDirectory.resolve("resource3").toFile().exists()); - - assertTrue(archiver.deleteLocalFiles("resource3")); - assertTrue(archiverDirectory.resolve("resource1").toFile().exists()); - assertFalse(archiverDirectory.resolve("resource2").toFile().exists()); - assertFalse(archiverDirectory.resolve("resource3").toFile().exists()); - - assertTrue(archiver.deleteLocalFiles("resource1")); - assertFalse(archiverDirectory.resolve("resource1").toFile().exists()); - assertFalse(archiverDirectory.resolve("resource2").toFile().exists()); - assertFalse(archiverDirectory.resolve("resource3").toFile().exists()); - } - - @Test - public void testDeleteLocalFiles_noCurrent() throws IOException { - createLocalFiles("resource1", 3, false); - createLocalFiles("resource2", 1, false); - createLocalFiles("resource3", 5, false); - - assertTrue(archiver.deleteLocalFiles("resource2")); - assertTrue(archiverDirectory.resolve("resource1").toFile().exists()); - assertFalse(archiverDirectory.resolve("resource2").toFile().exists()); - assertTrue(archiverDirectory.resolve("resource3").toFile().exists()); - - assertTrue(archiver.deleteLocalFiles("resource3")); - assertTrue(archiverDirectory.resolve("resource1").toFile().exists()); - assertFalse(archiverDirectory.resolve("resource2").toFile().exists()); - assertFalse(archiverDirectory.resolve("resource3").toFile().exists()); - - assertTrue(archiver.deleteLocalFiles("resource1")); - assertFalse(archiverDirectory.resolve("resource1").toFile().exists()); - assertFalse(archiverDirectory.resolve("resource2").toFile().exists()); - assertFalse(archiverDirectory.resolve("resource3").toFile().exists()); - } - - @Test - public void testDeleteLocalFiles_notExist() throws IOException { - createLocalFiles("resource1", 3, true); - assertTrue(archiver.deleteLocalFiles("resource2")); - assertTrue(archiverDirectory.resolve("resource1").toFile().exists()); - } - - @Test - public void testDeleteLocalFiles_notDirectory() throws IOException { - try (ByteArrayInputStream test1content = new ByteArrayInputStream("test1content".getBytes()); - ByteArrayInputStream test2content = new ByteArrayInputStream("test2content".getBytes()); - FileOutputStream fileOutputStream1 = - new FileOutputStream(archiverDirectory.resolve("resource1").toFile()); - FileOutputStream fileOutputStream2 = - new FileOutputStream(archiverDirectory.resolve("resource2").toFile()); ) { - IOUtils.copy(test1content, fileOutputStream1); - IOUtils.copy(test2content, fileOutputStream2); - } - assertFalse(archiver.deleteLocalFiles("resource1")); - assertTrue(Files.exists(archiverDirectory.resolve("resource1"))); - assertTrue(Files.exists(archiverDirectory.resolve("resource2"))); - assertFalse(archiver.deleteLocalFiles("resource2")); - assertTrue(Files.exists(archiverDirectory.resolve("resource1"))); - assertTrue(Files.exists(archiverDirectory.resolve("resource2"))); - } - - private void createLocalFiles(String resourceName, int numVersions, boolean withCurrent) - throws IOException { - assertTrue(numVersions > 0); - Path resourceRoot = archiverDirectory.resolve(resourceName); - Files.createDirectory(resourceRoot); - String hash = null; - for (int i = 0; i < numVersions; ++i) { - hash = UUID.randomUUID().toString(); - Path versionRoot = resourceRoot.resolve(hash); - Files.createDirectory(versionRoot); - try (ByteArrayInputStream test1content = new ByteArrayInputStream("test1content".getBytes()); - ByteArrayInputStream test2content = new ByteArrayInputStream("test2content".getBytes()); - FileOutputStream fileOutputStream1 = - new FileOutputStream(versionRoot.resolve("test1").toFile()); - FileOutputStream fileOutputStream2 = - new FileOutputStream(versionRoot.resolve("test2").toFile()); ) { - IOUtils.copy(test1content, fileOutputStream1); - IOUtils.copy(test2content, fileOutputStream2); - } - } - if (withCurrent) { - Files.createSymbolicLink(resourceRoot.resolve("current"), resourceRoot.resolve(hash)); - } - } -} diff --git a/src/test/java/com/yelp/nrtsearch/server/grpc/AckedCopyTest.java b/src/test/java/com/yelp/nrtsearch/server/grpc/AckedCopyTest.java index ec94df5ba..8541a48d5 100644 --- a/src/test/java/com/yelp/nrtsearch/server/grpc/AckedCopyTest.java +++ b/src/test/java/com/yelp/nrtsearch/server/grpc/AckedCopyTest.java @@ -20,11 +20,9 @@ import com.amazonaws.services.s3.AmazonS3; import com.yelp.nrtsearch.server.LuceneServerTestConfigurationFactory; -import com.yelp.nrtsearch.server.backup.Archiver; -import com.yelp.nrtsearch.server.backup.ArchiverImpl; -import com.yelp.nrtsearch.server.backup.Tar; -import com.yelp.nrtsearch.server.backup.TarImpl; import com.yelp.nrtsearch.server.config.LuceneServerConfiguration; +import com.yelp.nrtsearch.server.remote.RemoteBackend; +import com.yelp.nrtsearch.server.remote.s3.S3Backend; import com.yelp.nrtsearch.test_utils.AmazonS3Provider; import io.grpc.testing.GrpcCleanupRule; import java.io.IOException; @@ -56,7 +54,7 @@ public class AckedCopyTest { private GrpcServer replicationServerSecondary; private static final String BUCKET_NAME = "archiver-unittest"; - private Archiver archiver; + private RemoteBackend remoteBackend; private AmazonS3 s3; private Path archiverDirectory; @@ -71,8 +69,6 @@ public void tearDown() throws IOException { public void setUp(int chunkSize, int ackEvery, int maxInFlight) throws IOException { archiverDirectory = folder.newFolder("archiver").toPath(); s3 = s3Provider.getAmazonS3(); - archiver = - new ArchiverImpl(s3, BUCKET_NAME, archiverDirectory, new TarImpl(Tar.CompressionMode.LZ4)); String extraConfig = String.join( @@ -87,6 +83,7 @@ public void setUp(int chunkSize, int ackEvery, int maxInFlight) throws IOExcepti String testIndex = "test_index"; LuceneServerConfiguration luceneServerPrimaryConfiguration = LuceneServerTestConfigurationFactory.getConfig(Mode.PRIMARY, folder.getRoot(), extraConfig); + remoteBackend = new S3Backend(luceneServerPrimaryConfiguration, s3); luceneServerPrimary = new GrpcServer( grpcCleanup, @@ -96,7 +93,7 @@ public void setUp(int chunkSize, int ackEvery, int maxInFlight) throws IOExcepti luceneServerPrimaryConfiguration.getIndexDir(), testIndex, luceneServerPrimaryConfiguration.getPort(), - archiver); + remoteBackend); replicationServerPrimary = new GrpcServer( grpcCleanup, @@ -106,7 +103,7 @@ public void setUp(int chunkSize, int ackEvery, int maxInFlight) throws IOExcepti luceneServerPrimaryConfiguration.getIndexDir(), testIndex, luceneServerPrimaryConfiguration.getReplicationPort(), - archiver); + remoteBackend); luceneServerPrimary .getGlobalState() .replicationStarted(luceneServerPrimaryConfiguration.getReplicationPort()); @@ -123,7 +120,7 @@ public void setUp(int chunkSize, int ackEvery, int maxInFlight) throws IOExcepti luceneServerSecondaryConfiguration.getIndexDir(), testIndex, luceneServerSecondaryConfiguration.getPort(), - archiver); + remoteBackend); replicationServerSecondary = new GrpcServer( grpcCleanup, @@ -133,7 +130,7 @@ public void setUp(int chunkSize, int ackEvery, int maxInFlight) throws IOExcepti luceneServerSecondaryConfiguration.getIndexDir(), testIndex, luceneServerSecondaryConfiguration.getReplicationPort(), - archiver); + remoteBackend); luceneServerSecondary .getGlobalState() .replicationStarted(luceneServerSecondaryConfiguration.getReplicationPort()); diff --git a/src/test/java/com/yelp/nrtsearch/server/grpc/BackupRestoreIndexRequestHandlerTest.java b/src/test/java/com/yelp/nrtsearch/server/grpc/BackupRestoreIndexRequestHandlerTest.java deleted file mode 100644 index 265f927fc..000000000 --- a/src/test/java/com/yelp/nrtsearch/server/grpc/BackupRestoreIndexRequestHandlerTest.java +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Copyright 2020 Yelp Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yelp.nrtsearch.server.grpc; - -import static com.yelp.nrtsearch.server.grpc.GrpcServer.rmDir; -import static com.yelp.nrtsearch.server.grpc.LuceneServerTest.RETRIEVED_VALUES; -import static com.yelp.nrtsearch.server.grpc.LuceneServerTest.checkHits; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import com.amazonaws.services.s3.AmazonS3; -import com.google.common.collect.ImmutableList; -import com.yelp.nrtsearch.server.LuceneServerTestConfigurationFactory; -import com.yelp.nrtsearch.server.backup.Archiver; -import com.yelp.nrtsearch.server.backup.ArchiverImpl; -import com.yelp.nrtsearch.server.backup.Tar; -import com.yelp.nrtsearch.server.backup.TarImpl; -import com.yelp.nrtsearch.server.config.LuceneServerConfiguration; -import com.yelp.nrtsearch.test_utils.AmazonS3Provider; -import io.grpc.StatusRuntimeException; -import io.grpc.testing.GrpcCleanupRule; -import java.io.File; -import java.io.IOException; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; -import org.iq80.leveldb.util.FileUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -public class BackupRestoreIndexRequestHandlerTest { - private final String BUCKET_NAME = "archiver-unittest"; - private Archiver archiver; - private AmazonS3 s3; - private Path archiverDirectory; - - @Rule public final TemporaryFolder folder = new TemporaryFolder(); - - /** - * This rule manages automatic graceful shutdown for the registered servers and channels at the - * end of test. - */ - @Rule public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); - - @Rule public final AmazonS3Provider s3Provider = new AmazonS3Provider(BUCKET_NAME); - - private GrpcServer grpcServer; - - @Before - public void setup() throws IOException { - archiverDirectory = folder.newFolder("archiver").toPath(); - s3 = s3Provider.getAmazonS3(); - archiver = - new ArchiverImpl(s3, BUCKET_NAME, archiverDirectory, new TarImpl(Tar.CompressionMode.LZ4)); - grpcServer = setUpGrpcServer(); - } - - private GrpcServer setUpGrpcServer() throws IOException { - LuceneServerConfiguration luceneServerConfiguration = - LuceneServerTestConfigurationFactory.getConfig(Mode.STANDALONE, folder.getRoot()); - return new GrpcServer( - grpcCleanup, - luceneServerConfiguration, - folder, - null, - luceneServerConfiguration.getIndexDir(), - "test_index", - luceneServerConfiguration.getPort(), - archiver); - } - - @After - public void teardown() throws IOException { - tearDownGrpcServer(); - } - - private void tearDownGrpcServer() throws IOException { - grpcServer.getGlobalState().close(); - grpcServer.shutdown(); - rmDir(Paths.get(grpcServer.getIndexDir()).getParent()); - } - - @Test - public void testBackupRequestHandlerUpload_completeDirectoryBackup() - throws IOException, InterruptedException { - GrpcServer.TestServer testAddDocs = - new GrpcServer.TestServer(grpcServer, true, Mode.STANDALONE); - testAddDocs.addDocuments(); - - backupIndex(true); - Path downloadPath = archiver.download("testservice", "testresource_data"); - List actual = getFiles(downloadPath); - List expected = getFiles(Paths.get(grpcServer.getIndexDir())); - assertEquals(expected, actual); - } - - @Test - public void testBackupRequestHandlerUpload() throws IOException, InterruptedException { - GrpcServer.TestServer testAddDocs = - new GrpcServer.TestServer(grpcServer, true, Mode.STANDALONE); - testAddDocs.addDocuments(); - - backupIndex(false); - Path downloadPath = archiver.download("testservice", "testresource_data"); - List actual = getFiles(downloadPath); - List expected = getFiles(Paths.get(grpcServer.getIndexDir())); - // There are two write.lock files, one under ../test_index/shard0/taxonomy and another one under - // ../test_index/shard0/index - expected.remove("write.lock"); - expected.remove("write.lock"); - // The empty index is committed on first start, resulting in segments file that is not in the - // latest index version - expected.remove("segments_1"); - - assertEquals(expected, actual); - } - - @Test - public void testRestoreHandler_completeDirectoryBackup() - throws IOException, InterruptedException { - GrpcServer.TestServer testAddDocs = - new GrpcServer.TestServer(grpcServer, true, Mode.STANDALONE); - testAddDocs.addDocuments(); - - backupIndex(true); - testAddDocs.addDocuments(); - - restartIndexWithRestoreAndVerify(true, false); - } - - @Test - public void testRestoreHandler_deleteExistingDataAndRestoreIndexWithoutDeleteExistingDataOption() - throws IOException, InterruptedException { - GrpcServer.TestServer testAddDocs = - new GrpcServer.TestServer(grpcServer, true, Mode.STANDALONE); - testAddDocs.addDocuments(); - - backupIndex(false); - testAddDocs.addDocuments(); - - restartIndexWithRestoreAndVerify(true, false); - } - - @Test(expected = StatusRuntimeException.class) - public void testRestoreHandler_retainExistingDataAndRestoreIndex() - throws IOException, InterruptedException { - GrpcServer.TestServer testAddDocs = - new GrpcServer.TestServer(grpcServer, true, Mode.STANDALONE); - testAddDocs.addDocuments(); - - backupIndex(false); - testAddDocs.addDocuments(); - - try { - restartIndexWithRestoreAndVerify(false, false); - } catch (StatusRuntimeException e) { - assertTrue(e.getMessage().contains("Cannot restore, directory has index data file:")); - throw e; - } - } - - @Test - public void testRestoreHandler_retainExistingDataAndRestoreIndexWithDeleteExistingDataOption() - throws IOException, InterruptedException { - GrpcServer.TestServer testAddDocs = - new GrpcServer.TestServer(grpcServer, true, Mode.STANDALONE); - testAddDocs.addDocuments(); - - backupIndex(false); - testAddDocs.addDocuments(); - - restartIndexWithRestoreAndVerify(false, true); - } - - @Test - public void testRestoreHandler_deleteExistingDataAndRestoreIndexWithDeleteExistingDataOption() - throws IOException, InterruptedException { - GrpcServer.TestServer testAddDocs = - new GrpcServer.TestServer(grpcServer, true, Mode.STANDALONE); - testAddDocs.addDocuments(); - - backupIndex(false); - testAddDocs.addDocuments(); - - restartIndexWithRestoreAndVerify(true, true); - } - - /** - * When a backup is downloaded we just point the index directory the downloaded files. This test - * verifies that if deleteExistingData is set during restore it deletes the directories from the - * backup as well. - */ - @Test - public void - testRestoreHandler_indexInitiallyStartedFromBackup_deleteExistingDataAndRestoreIndexWithDeleteExistingDataOption() - throws IOException, InterruptedException { - GrpcServer.TestServer testAddDocs = - new GrpcServer.TestServer(grpcServer, true, Mode.STANDALONE); - testAddDocs.addDocuments(); - - backupIndex(false); - testAddDocs.addDocuments(); - - restartIndexWithRestoreAndVerify(true, true); - - restartIndexWithRestoreAndVerify(true, true); - } - - @Test(expected = StatusRuntimeException.class) - public void testRestoreHandler_throwErrorIfIndexStarted() - throws IOException, InterruptedException { - GrpcServer.TestServer testAddDocs = - new GrpcServer.TestServer(grpcServer, true, Mode.STANDALONE); - testAddDocs.addDocuments(); - - backupIndex(false); - testAddDocs.addDocuments(); - - try { - grpcServer - .getBlockingStub() - .startIndex( - StartIndexRequest.newBuilder() - .setIndexName("test_index") - .setMode(Mode.STANDALONE) - .setRestore( - RestoreIndex.newBuilder() - .setServiceName("testservice") - .setResourceName("testresource") - .setDeleteExistingData(true) - .build()) - .build()); - } catch (StatusRuntimeException e) { - assertEquals( - "INVALID_ARGUMENT: error while trying to start index: test_index\nIndex test_index is already started", - e.getMessage()); - throw e; - } - } - - private void restartIndexWithRestoreAndVerify( - boolean deleteIndexDataBeforeRestore, boolean setDeleteExistingDataInRestoreRequest) - throws IOException { - grpcServer - .getBlockingStub() - .stopIndex(StopIndexRequest.newBuilder().setIndexName("test_index").build()); - - if (deleteIndexDataBeforeRestore) { - deleteIndexAndMetadata(); - } - - grpcServer - .getBlockingStub() - .startIndex( - StartIndexRequest.newBuilder() - .setIndexName("test_index") - .setMode(Mode.STANDALONE) - .setRestore( - RestoreIndex.newBuilder() - .setServiceName("testservice") - .setResourceName("testresource") - .setDeleteExistingData(setDeleteExistingDataInRestoreRequest) - .build()) - .build()); - - grpcServer - .getBlockingStub() - .refresh(RefreshRequest.newBuilder().setIndexName(grpcServer.getTestIndex()).build()); - - SearchResponse searchResponse = - grpcServer - .getBlockingStub() - .search( - SearchRequest.newBuilder() - .setIndexName(grpcServer.getTestIndex()) - .setStartHit(0) - .setTopHits(10) - .addAllRetrieveFields(RETRIEVED_VALUES) - .build()); - - assertEquals(2, searchResponse.getTotalHits().getValue()); - assertEquals(2, searchResponse.getHitsList().size()); - SearchResponse.Hit firstHit = searchResponse.getHits(0); - checkHits(firstHit); - SearchResponse.Hit secondHit = searchResponse.getHits(1); - checkHits(secondHit); - } - - /** - * As compared to testRestoreHandler, this test does not add more documents after a backup and - * restarts index in a different way. - */ - @Test - public void testSnapshotRestore() throws IOException, InterruptedException { - GrpcServer.TestServer testAddDocs = - new GrpcServer.TestServer(grpcServer, true, Mode.STANDALONE); - // 2 docs addDocuments - testAddDocs.addDocuments(); - // Backup Index - backupIndex(false); - // stop server and remove data and state files. - tearDownGrpcServer(); - // restart server and Index - grpcServer = setUpGrpcServer(); - new GrpcServer.TestServer(grpcServer, true, Mode.STANDALONE, 0, true); - // search - SearchResponse searchResponse = - grpcServer - .getBlockingStub() - .search( - SearchRequest.newBuilder() - .setIndexName(grpcServer.getTestIndex()) - .setStartHit(0) - .setTopHits(10) - .addAllRetrieveFields(RETRIEVED_VALUES) - .build()); - assertEquals(2, searchResponse.getTotalHits().getValue()); - assertEquals(2, searchResponse.getHitsList().size()); - SearchResponse.Hit firstHit = searchResponse.getHits(0); - checkHits(firstHit); - SearchResponse.Hit secondHit = searchResponse.getHits(1); - checkHits(secondHit); - } - - private void deleteIndexAndMetadata() throws IOException { - try (DirectoryStream stream = - Files.newDirectoryStream(Path.of(grpcServer.getIndexDir()))) { - for (Path path : stream) { - try (DirectoryStream indexStream = Files.newDirectoryStream(path)) { - for (Path indexPath : indexStream) { - if (Files.isDirectory(indexPath)) { - rmDir(indexPath); - } else { - Files.delete(indexPath); - } - } - } - } - } - } - - public List getFiles(Path basePath) { - List result = new ArrayList<>(); - ImmutableList childFiles = FileUtils.listFiles(basePath.toFile()); - for (File childFile : childFiles) { - if (Files.isDirectory(childFile.toPath())) { - result.addAll(getFiles(childFile.toPath())); - } else if (Files.isRegularFile(childFile.toPath())) { - result.add(childFile.getName()); - } - } - return result.stream() - // the versions are bumped post a ReleaseSnapshot hence wont be same as snapshotted backed - // up version - // which will be on version less - .filter(x -> !x.startsWith("snapshots") && !x.startsWith("stateRefCounts")) - .collect(Collectors.toList()); - } - - private void backupIndex(boolean completeDirectory) { - grpcServer - .getBlockingStub() - .backupIndex( - BackupIndexRequest.newBuilder() - .setIndexName("test_index") - .setServiceName("testservice") - .setResourceName("testresource") - .setCompleteDirectory(completeDirectory) - .build()); - } -} diff --git a/src/test/java/com/yelp/nrtsearch/server/grpc/FailedBackupCleanupTest.java b/src/test/java/com/yelp/nrtsearch/server/grpc/FailedBackupCleanupTest.java deleted file mode 100644 index 5a6c9d154..000000000 --- a/src/test/java/com/yelp/nrtsearch/server/grpc/FailedBackupCleanupTest.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright 2020 Yelp Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yelp.nrtsearch.server.grpc; - -import static com.yelp.nrtsearch.server.grpc.GrpcServer.rmDir; -import static com.yelp.nrtsearch.server.grpc.LuceneServerTest.RETRIEVED_VALUES; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3Client; -import com.amazonaws.services.s3.model.PutObjectRequest; -import com.amazonaws.services.s3.model.PutObjectResult; -import com.google.gson.Gson; -import com.yelp.nrtsearch.server.LuceneServerTestConfigurationFactory; -import com.yelp.nrtsearch.server.backup.Archiver; -import com.yelp.nrtsearch.server.backup.ArchiverImpl; -import com.yelp.nrtsearch.server.backup.Tar; -import com.yelp.nrtsearch.server.backup.TarImpl; -import com.yelp.nrtsearch.server.config.LuceneServerConfiguration; -import io.grpc.StatusRuntimeException; -import io.grpc.stub.StreamObserver; -import io.grpc.testing.GrpcCleanupRule; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -public class FailedBackupCleanupTest { - private final String BUCKET_NAME = "archiver-unittest"; - private Archiver archiver; - private AmazonS3 s3; - private Path archiverDirectory; - private CountDownLatch s3TransferStartedLatch; - private LuceneServerConfiguration luceneServerConfiguration; - - @Rule public final TemporaryFolder folder = new TemporaryFolder(); - - /** - * This rule manages automatic graceful shutdown for the registered servers and channels at the - * end of test. - */ - @Rule public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); - - private GrpcServer grpcServer; - - @Before - public void setup() throws IOException { - archiverDirectory = Paths.get(folder.getRoot().toString(), "archiver"); - s3TransferStartedLatch = new CountDownLatch(1); - s3 = new DoNothingAndWaitAmazonS3(s3TransferStartedLatch); - archiver = - new ArchiverImpl(s3, BUCKET_NAME, archiverDirectory, new TarImpl(Tar.CompressionMode.LZ4)); - luceneServerConfiguration = - LuceneServerTestConfigurationFactory.getConfig( - Mode.PRIMARY, folder.getRoot(), archiverDirectory); - grpcServer = setUpGrpcServer(); - } - - private GrpcServer setUpGrpcServer() throws IOException { - return new GrpcServer( - grpcCleanup, - luceneServerConfiguration, - folder, - null, - luceneServerConfiguration.getIndexDir(), - "test_index", - luceneServerConfiguration.getPort(), - archiver); - } - - @After - public void teardown() throws IOException { - grpcServer.getGlobalState().close(); - grpcServer.forceShutdown(); - rmDir(Paths.get(grpcServer.getIndexDir()).getParent()); - } - - @Test(expected = StatusRuntimeException.class) - public void testBackupWhileAnotherBackupRunning() throws IOException, InterruptedException { - // Create index and add 2 documents - GrpcServer.TestServer testAddDocs = new GrpcServer.TestServer(grpcServer, true, Mode.PRIMARY); - testAddDocs.addDocuments(); - - attemptBackupAsync(); - - // This will wait until the server tries to upload the backup to S3, so that - // a snapshot and the backup indicator file have been created - s3TransferStartedLatch.await(10, TimeUnit.SECONDS); - - BackupIndexRequest request = - BackupIndexRequest.newBuilder() - .setIndexName(grpcServer.getTestIndex()) - .setServiceName("testservice") - .setResourceName("testresource") - .build(); - - try { - grpcServer.getBlockingStub().backupIndex(request); - } catch (StatusRuntimeException e) { - assertEquals( - "UNKNOWN: error while trying to backupIndex for index test_index for service: testservice, resource: testresource\n" - + "A backup is ongoing for index test_index, please try again after the current backup is finished", - e.getMessage()); - throw e; - } - } - - @Test - public void testFailedBackupCleanup() throws IOException, InterruptedException { - // Create index and add 2 documents - GrpcServer.TestServer testAddDocs = new GrpcServer.TestServer(grpcServer, true, Mode.PRIMARY); - testAddDocs.addDocuments(); - - // Verify that 2 documents were added - SearchResponse searchResponse = search(); - assertEquals(2, searchResponse.getHitsCount()); - - // Verify that no snapshots or tmp files are present - List allSnapshotIndexGen = getSnapshotIndexGensList(); - assertTrue(allSnapshotIndexGen.isEmpty()); - - attemptBackupAsync(); - - // This will wait until the server tries to upload the backup to S3, so that - // a snapshot and the backup indicator file have been created - s3TransferStartedLatch.await(10, TimeUnit.SECONDS); - - // Verify that snapshot was created during backup - allSnapshotIndexGen = getSnapshotIndexGensList(); - assertEquals(List.of(2L), allSnapshotIndexGen); - - forceShutdownServer(); - - Path backupIndicatorFilePath = Paths.get(archiverDirectory.toString(), "backup.txt"); - - // Verify that the backup indicator file was created - assertTrue(Files.exists(backupIndicatorFilePath)); - - String backupIndicatorFileContents = Files.readString(backupIndicatorFilePath); - - // Hacky way to assert exact file contents instead of asserting parsed json - TestBackupIndicatorDetails expectedBackupDetails = - new TestBackupIndicatorDetails(grpcServer.getTestIndex(), 2, -1, 0); - TestBackupIndicatorDetails actualBackupDetails = - new Gson().fromJson(backupIndicatorFileContents, TestBackupIndicatorDetails.class); - assertEquals(expectedBackupDetails, actualBackupDetails); - - // Verify that the backup created a temporary file which wasn't cleaned up - List tmpFilesInArchiverDirectory = getTmpFilesInArchiverDirectory(); - assertEquals(1, tmpFilesInArchiverDirectory.size()); - - grpcServer = setUpGrpcServer(); - grpcServer - .getBlockingStub() - .startIndex( - StartIndexRequest.newBuilder() - .setIndexName(grpcServer.getTestIndex()) - .setMode(Mode.PRIMARY) - .build()); - - // Confirm that the previous index with the data was started - searchResponse = search(); - assertEquals(2, searchResponse.getHitsCount()); - - // Verify that backup indicator file was deleted - assertFalse(Files.exists(backupIndicatorFilePath)); - - // Verify that the snapshot taken during backup was released - allSnapshotIndexGen = getSnapshotIndexGensList(); - assertTrue(allSnapshotIndexGen.isEmpty()); - - // Verify that temporary file created during backup was cleaned up - tmpFilesInArchiverDirectory = getTmpFilesInArchiverDirectory(); - assertEquals(0, tmpFilesInArchiverDirectory.size()); - } - - private List getSnapshotIndexGensList() { - return grpcServer - .getBlockingStub() - .getAllSnapshotIndexGen( - GetAllSnapshotGenRequest.newBuilder().setIndexName(grpcServer.getTestIndex()).build()) - .getIndexGensList(); - } - - private void forceShutdownServer() throws IOException { - grpcServer.getGlobalState().close(); - grpcServer.forceShutdown(); - } - - private SearchResponse search() { - return grpcServer - .getBlockingStub() - .search( - SearchRequest.newBuilder() - .setIndexName(grpcServer.getTestIndex()) - .setStartHit(0) - .setTopHits(10) - .addAllRetrieveFields(RETRIEVED_VALUES) - .build()); - } - - private void attemptBackupAsync() { - BackupIndexRequest request = - BackupIndexRequest.newBuilder() - .setIndexName(grpcServer.getTestIndex()) - .setServiceName("testservice") - .setResourceName("testresource") - .build(); - - StreamObserver responseObserver = - new StreamObserver<>() { - @Override - public void onNext(BackupIndexResponse value) {} - - @Override - public void onError(Throwable t) {} - - @Override - public void onCompleted() {} - }; - grpcServer.getStub().backupIndex(request, responseObserver); - } - - private List getTmpFilesInArchiverDirectory() throws IOException { - return Files.walk(archiverDirectory) - .filter(path -> path.toString().endsWith(".tmp")) - .collect(Collectors.toList()); - } - - /** - * An S3 client implementation that will do nothing and simply wait when calling putObject. This - * lets us easily interrupt the backup process after the backup indicator file is created, - * snapshot is taken and also the temporary file for backup has been created. - */ - private static class DoNothingAndWaitAmazonS3 extends AmazonS3Client { - - private final CountDownLatch countDownLatch; - - public DoNothingAndWaitAmazonS3(CountDownLatch countDownLatch) { - this.countDownLatch = countDownLatch; - } - - @Override - public PutObjectResult putObject(PutObjectRequest putObjectRequest) { - countDownLatch.countDown(); - sleepForALongTime(); - return null; - } - - private void sleepForALongTime() { - try { - Thread.sleep(100000); - } catch (InterruptedException ignored) { - } - } - } - - private static class TestBackupIndicatorDetails { - String indexName; - long indexGen; - long stateGen; - long taxonomyGen; - - public TestBackupIndicatorDetails( - String indexName, long indexGen, long stateGen, long taxonomyGen) { - this.indexName = indexName; - this.indexGen = indexGen; - this.stateGen = stateGen; - this.taxonomyGen = taxonomyGen; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - TestBackupIndicatorDetails that = (TestBackupIndicatorDetails) o; - return indexGen == that.indexGen - && stateGen == that.stateGen - && taxonomyGen == that.taxonomyGen - && Objects.equals(indexName, that.indexName); - } - - @Override - public int hashCode() { - return Objects.hash(indexName, indexGen, stateGen, taxonomyGen); - } - } -} diff --git a/src/test/java/com/yelp/nrtsearch/server/grpc/GrpcServer.java b/src/test/java/com/yelp/nrtsearch/server/grpc/GrpcServer.java index 3f00f7e24..7a408c539 100644 --- a/src/test/java/com/yelp/nrtsearch/server/grpc/GrpcServer.java +++ b/src/test/java/com/yelp/nrtsearch/server/grpc/GrpcServer.java @@ -17,13 +17,13 @@ import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.util.JsonFormat; -import com.yelp.nrtsearch.server.backup.Archiver; import com.yelp.nrtsearch.server.config.LuceneServerConfiguration; import com.yelp.nrtsearch.server.grpc.LuceneServer.LuceneServerImpl; import com.yelp.nrtsearch.server.luceneserver.GlobalState; import com.yelp.nrtsearch.server.monitoring.Configuration; import com.yelp.nrtsearch.server.monitoring.LuceneServerMonitoringServerInterceptor; import com.yelp.nrtsearch.server.plugins.Plugin; +import com.yelp.nrtsearch.server.remote.RemoteBackend; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; import io.grpc.Server; @@ -50,12 +50,12 @@ public class GrpcServer { // TODO: use this everywhere instead of importing test index name from - // ReplicationTestFailureScenarios + // ReplicationFailureScenariosTest public static final String TEST_INDEX = "test_index"; private final GrpcCleanupRule grpcCleanup; private final TemporaryFolder temporaryFolder; - private final Archiver archiver; + private final RemoteBackend remoteBackend; private String indexDir; private String testIndex; private LuceneServerGrpc.LuceneServerBlockingStub blockingStub; @@ -79,7 +79,7 @@ public GrpcServer( String indexDir, String index, int port, - Archiver archiver, + RemoteBackend remoteBackend, List plugins) throws IOException { this.grpcCleanup = grpcCleanup; @@ -88,8 +88,8 @@ public GrpcServer( this.globalState = replicationGlobalState; this.indexDir = indexDir; this.testIndex = index; - this.archiver = archiver; - invoke(collectorRegistry, replicationGlobalState != null, port, archiver, plugins); + this.remoteBackend = remoteBackend; + invoke(collectorRegistry, replicationGlobalState != null, port, remoteBackend, plugins); } public GrpcServer( @@ -100,7 +100,7 @@ public GrpcServer( String indexDir, String index, int port, - Archiver archiver) + RemoteBackend remoteBackend) throws IOException { this( null, @@ -111,7 +111,7 @@ public GrpcServer( indexDir, index, port, - archiver, + remoteBackend, Collections.emptyList()); } @@ -163,8 +163,8 @@ public GlobalState getGlobalState() { return globalState; } - private Archiver getArchiver() { - return archiver; + private RemoteBackend getRemoteBackend() { + return remoteBackend; } public void shutdown() { @@ -205,7 +205,7 @@ private void invoke( CollectorRegistry collectorRegistry, boolean isReplication, int port, - Archiver archiver, + RemoteBackend remoteBackend, List plugins) throws IOException { // Generate a unique in-process server name. @@ -215,7 +215,7 @@ private void invoke( if (collectorRegistry == null) { LuceneServerImpl serverImpl = new LuceneServer.LuceneServerImpl( - configuration, archiver, null, collectorRegistry, plugins); + configuration, null, remoteBackend, collectorRegistry, plugins); globalState = serverImpl.getGlobalState(); // Create a server, add service, start, and register for automatic graceful shutdown. server = @@ -235,7 +235,7 @@ private void invoke( nodeName); LuceneServerImpl serverImpl = new LuceneServer.LuceneServerImpl( - configuration, archiver, null, collectorRegistry, plugins); + configuration, null, remoteBackend, collectorRegistry, plugins); globalState = serverImpl.getGlobalState(); // Create a server, add service, start, and register for automatic graceful shutdown. server = diff --git a/src/test/java/com/yelp/nrtsearch/server/grpc/LuceneServerTest.java b/src/test/java/com/yelp/nrtsearch/server/grpc/LuceneServerTest.java index ace4229bb..5de89a3b1 100644 --- a/src/test/java/com/yelp/nrtsearch/server/grpc/LuceneServerTest.java +++ b/src/test/java/com/yelp/nrtsearch/server/grpc/LuceneServerTest.java @@ -28,13 +28,13 @@ import com.google.api.HttpBody; import com.google.protobuf.Empty; import com.yelp.nrtsearch.server.LuceneServerTestConfigurationFactory; -import com.yelp.nrtsearch.server.backup.Archiver; -import com.yelp.nrtsearch.server.backup.ArchiverImpl; -import com.yelp.nrtsearch.server.backup.TarImpl; import com.yelp.nrtsearch.server.config.LuceneServerConfiguration; import com.yelp.nrtsearch.server.grpc.LuceneServer.LuceneServerImpl; import com.yelp.nrtsearch.server.grpc.SearchResponse.Hit.CompositeFieldValue; import com.yelp.nrtsearch.server.luceneserver.search.cache.NrtQueryCache; +import com.yelp.nrtsearch.server.remote.RemoteBackend; +import com.yelp.nrtsearch.server.remote.RemoteBackend.IndexResourceType; +import com.yelp.nrtsearch.server.remote.s3.S3Backend; import com.yelp.nrtsearch.test_utils.AmazonS3Provider; import io.grpc.StatusRuntimeException; import io.grpc.testing.GrpcCleanupRule; @@ -116,7 +116,7 @@ public class LuceneServerTest { private GrpcServer grpcServer; private GrpcServer replicaGrpcServer; private CollectorRegistry collectorRegistry; - private Archiver archiver; + private RemoteBackend remoteBackend; private AmazonS3 s3; private final String TEST_SERVICE_NAME = "TEST_SERVICE_NAME"; @@ -140,26 +140,27 @@ private void tearDownReplicaGrpcServer() throws IOException { @Before public void setUp() throws IOException { + LuceneServerConfiguration luceneServerConfiguration = + LuceneServerTestConfigurationFactory.getConfig( + Mode.STANDALONE, folder.getRoot(), "bucketName: " + bucketName); + collectorRegistry = new CollectorRegistry(); - archiver = setUpArchiver(); - grpcServer = setUpGrpcServer(collectorRegistry); + remoteBackend = setUpRemoteBackend(luceneServerConfiguration); + grpcServer = setUpGrpcServer(luceneServerConfiguration, collectorRegistry); replicaGrpcServer = setUpReplicaGrpcServer(collectorRegistry); setUpWarmer(); } - private Archiver setUpArchiver() throws IOException { - Path archiverDirectory = folder.newFolder("archiver").toPath(); - + private RemoteBackend setUpRemoteBackend(LuceneServerConfiguration configuration) + throws IOException { s3 = s3Provider.getAmazonS3(); - - return new ArchiverImpl( - s3, bucketName, archiverDirectory, new TarImpl(TarImpl.CompressionMode.LZ4)); + return new S3Backend(configuration, s3); } private void setUpWarmer() throws IOException { Path warmingQueriesDir = folder.newFolder("warming_queries").toPath(); - try (BufferedWriter writer = - Files.newBufferedWriter(warmingQueriesDir.resolve("warming_queries.txt"))) { + Path warmingQueriesPath = warmingQueriesDir.resolve("warming_queries.txt"); + try (BufferedWriter writer = Files.newBufferedWriter(warmingQueriesPath)) { List testSearchRequestsJson = getTestSearchRequestsAsJsonStrings(); for (String line : testSearchRequestsJson) { writer.write(line); @@ -167,11 +168,8 @@ private void setUpWarmer() throws IOException { } writer.flush(); } - String resourceName = "test_index_warming_queries"; - String versionHash = - archiver.upload( - TEST_SERVICE_NAME, resourceName, warmingQueriesDir, List.of(), List.of(), false); - archiver.blessVersion(TEST_SERVICE_NAME, resourceName, versionHash); + remoteBackend.uploadFile( + TEST_SERVICE_NAME, "test_index", IndexResourceType.WARMING_QUERIES, warmingQueriesPath); } private List getTestSearchRequestsAsJsonStrings() { @@ -180,10 +178,11 @@ private List getTestSearchRequestsAsJsonStrings() { "{\"indexName\":\"test_index\",\"query\":{\"termQuery\":{\"field\":\"field1\"}}}"); } - private GrpcServer setUpGrpcServer(CollectorRegistry collectorRegistry) throws IOException { + private GrpcServer setUpGrpcServer( + LuceneServerConfiguration luceneServerConfiguration, CollectorRegistry collectorRegistry) + throws IOException { String testIndex = "test_index"; - LuceneServerConfiguration luceneServerConfiguration = - LuceneServerTestConfigurationFactory.getConfig(Mode.STANDALONE, folder.getRoot()); + return new GrpcServer( collectorRegistry, grpcCleanup, @@ -193,7 +192,7 @@ private GrpcServer setUpGrpcServer(CollectorRegistry collectorRegistry) throws I luceneServerConfiguration.getIndexDir(), testIndex, luceneServerConfiguration.getPort(), - archiver, + remoteBackend, Collections.emptyList()); } @@ -212,7 +211,7 @@ private GrpcServer setUpReplicaGrpcServer(CollectorRegistry collectorRegistry) luceneServerReplicaConfiguration.getIndexDir(), testIndex, luceneServerReplicaConfiguration.getPort(), - archiver); + remoteBackend); } private String getExtraConfig() { @@ -948,7 +947,7 @@ public void testBackupWarmingQueries() throws IOException, InterruptedException replicaGrpcServer .getGlobalState() .getIndex(replicaGrpcServer.getTestIndex()) - .initWarmer(archiver); + .initWarmer(remoteBackend); assertNotNull( replicaGrpcServer.getGlobalState().getIndex(replicaGrpcServer.getTestIndex()).getWarmer()); // Average case should pass diff --git a/src/test/java/com/yelp/nrtsearch/server/grpc/ReplicationFailureScenariosTest.java b/src/test/java/com/yelp/nrtsearch/server/grpc/ReplicationFailureScenariosTest.java new file mode 100644 index 000000000..c7e32c611 --- /dev/null +++ b/src/test/java/com/yelp/nrtsearch/server/grpc/ReplicationFailureScenariosTest.java @@ -0,0 +1,290 @@ +/* + * Copyright 2020 Yelp Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.yelp.nrtsearch.server.grpc; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import com.yelp.nrtsearch.server.config.IndexStartConfig.IndexDataLocationType; +import io.grpc.testing.GrpcCleanupRule; +import java.io.IOException; +import java.util.stream.Stream; +import org.junit.After; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ReplicationFailureScenariosTest { + public static final String TEST_INDEX = "test_index"; + + /** + * This rule manages automatic graceful shutdown for the registered servers and channels at the + * end of test. + */ + @Rule public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); + + /** + * This rule ensure the temporary folder which maintains stateDir are cleaned up after each test + */ + @Rule public final TemporaryFolder folder = new TemporaryFolder(); + + @After + public void cleanup() { + TestServer.cleanupAll(); + } + + @Test + public void replicaDownedWhenPrimaryIndexing() throws IOException { + // startIndex Primary + TestServer primaryServer = + TestServer.builder(folder) + .withAutoStartConfig(true, Mode.PRIMARY, 0, IndexDataLocationType.REMOTE) + .build(); + primaryServer.createSimpleIndex(TEST_INDEX); + primaryServer.startPrimaryIndex(TEST_INDEX, -1, null); + + // startIndex replica + TestServer replicaServer = + TestServer.builder(folder) + .withAutoStartConfig( + true, + Mode.REPLICA, + primaryServer.getReplicationPort(), + IndexDataLocationType.REMOTE) + .build(); + + // add 2 docs to primary + primaryServer.addSimpleDocs(TEST_INDEX, 1, 2); + // backup index + primaryServer.commit(TEST_INDEX); + // refresh (also sends NRTPoint to replicas) + primaryServer.refresh(TEST_INDEX); + + primaryServer.verifySimpleDocs(TEST_INDEX, 2); + replicaServer.waitForReplication(TEST_INDEX); + replicaServer.verifySimpleDocs(TEST_INDEX, 2); + + // stop replica instance + replicaServer.stop(); + + // add 2 docs to primary + primaryServer.addSimpleDocs(TEST_INDEX, 3, 4); + + // re-start replica instance from a fresh index state i.e. empty index dir + replicaServer.restart(true); + + // add 2 more docs (6 total now), annoying, sendNRTPoint gets called from primary only upon a + // flush i.e. an index operation + primaryServer.addSimpleDocs(TEST_INDEX, 5, 6); + primaryServer.refresh(TEST_INDEX); + + primaryServer.verifySimpleDocs(TEST_INDEX, 6); + replicaServer.waitForReplication(TEST_INDEX); + replicaServer.verifySimpleDocs(TEST_INDEX, 6); + } + + @Test + public void primaryStoppedAndRestartedWithPreviousLocalIndex() throws IOException { + // startIndex primary + TestServer primaryServer = + TestServer.builder(folder) + .withAutoStartConfig(true, Mode.PRIMARY, 0, IndexDataLocationType.LOCAL) + .withWriteDiscoveryFile(true) + .build(); + primaryServer.createSimpleIndex(TEST_INDEX); + primaryServer.startPrimaryIndex(TEST_INDEX, -1, null); + + // startIndex replica + TestServer replicaServer = + TestServer.builder(folder) + .withAutoStartConfig(true, Mode.REPLICA, -1, IndexDataLocationType.LOCAL) + .withAdditionalConfig("discoveryFileUpdateIntervalMs: 1000") + .build(); + + // add 2 docs to primary + primaryServer.addSimpleDocs(TEST_INDEX, 1, 2); + primaryServer.refresh(TEST_INDEX); + + // both primary and replica should have 2 docs + primaryServer.verifySimpleDocs(TEST_INDEX, 2); + replicaServer.waitForReplication(TEST_INDEX); + replicaServer.verifySimpleDocs(TEST_INDEX, 2); + + // commit primary + primaryServer.commit(TEST_INDEX); + + // gracefully stop and restart primary + primaryServer.restart(); + // restart secondary to connect to "new" primary + replicaServer.restart(); + + // add 2 docs to primary + primaryServer.addSimpleDocs(TEST_INDEX, 3, 4); + primaryServer.refresh(TEST_INDEX); + + primaryServer.verifySimpleDocs(TEST_INDEX, 4); + replicaServer.waitForReplication(TEST_INDEX); + replicaServer.verifySimpleDocs(TEST_INDEX, 4); + } + + @Test + public void primaryDurabilityBasic() throws IOException { + // startIndex primary + TestServer primaryServer = + TestServer.builder(folder) + .withAutoStartConfig(true, Mode.PRIMARY, 0, IndexDataLocationType.REMOTE) + .build(); + primaryServer.createSimpleIndex(TEST_INDEX); + primaryServer.startPrimaryIndex(TEST_INDEX, -1, null); + + // add 2 docs to primary + primaryServer.addSimpleDocs(TEST_INDEX, 1, 2); + primaryServer.refresh(TEST_INDEX); + // backup index + primaryServer.commit(TEST_INDEX); + + primaryServer.verifySimpleDocs(TEST_INDEX, 2); + + // non-graceful primary restart (i.e. blow away index and state directory) + primaryServer.restart(true); + + // add 2 docs to primary + primaryServer.addSimpleDocs(TEST_INDEX, 3, 4); + primaryServer.refresh(TEST_INDEX); + + // primary should show numDocs hits now + primaryServer.verifySimpleDocs(TEST_INDEX, 4); + } + + @Test + public void primaryDurabilitySyncWithReplica() throws IOException { + // startIndex primary + TestServer primaryServer = + TestServer.builder(folder) + .withAutoStartConfig(true, Mode.PRIMARY, 0, IndexDataLocationType.REMOTE) + .withWriteDiscoveryFile(true) + .build(); + primaryServer.createSimpleIndex(TEST_INDEX); + primaryServer.startPrimaryIndex(TEST_INDEX, -1, null); + + // startIndex replica + TestServer replicaServer = + TestServer.builder(folder) + .withAutoStartConfig(true, Mode.REPLICA, -1, IndexDataLocationType.REMOTE) + .withAdditionalConfig("discoveryFileUpdateIntervalMs: 1000") + .build(); + + // add 2 docs to primary + primaryServer.addSimpleDocs(TEST_INDEX, 1, 2); + primaryServer.refresh(TEST_INDEX); + + // both primary and replica should have 2 docs + primaryServer.verifySimpleDocs(TEST_INDEX, 2); + replicaServer.waitForReplication(TEST_INDEX); + replicaServer.verifySimpleDocs(TEST_INDEX, 2); + + // backupIndex (with 2 docs) + primaryServer.commit(TEST_INDEX); + + // add 6 more docs to primary but do not commit, NRT is at 8 docs but commit point at 2 docs + primaryServer.addSimpleDocs(TEST_INDEX, 3, 4); + primaryServer.addSimpleDocs(TEST_INDEX, 5, 6); + primaryServer.addSimpleDocs(TEST_INDEX, 7, 8); + primaryServer.refresh(TEST_INDEX); + + primaryServer.verifySimpleDocs(TEST_INDEX, 8); + replicaServer.waitForReplication(TEST_INDEX); + replicaServer.verifySimpleDocs(TEST_INDEX, 8); + + // non-graceful primary restart (i.e. blow away index directory and stateDir) + primaryServer.restart(true); + // restart secondary to connect to "new" primary + replicaServer.restart(); + replicaServer.registerWithPrimary(TEST_INDEX); + + // add 2 more docs to primary + primaryServer.addSimpleDocs(TEST_INDEX, 9, 10); + primaryServer.refresh(TEST_INDEX); + + primaryServer.verifySimpleDocs(TEST_INDEX, 4); + replicaServer.waitForReplication(TEST_INDEX); + replicaServer.verifySimpleDocs(TEST_INDEX, 4); + } + + @Test + public void primaryDurabilityWithMultipleCommits() throws IOException { + // startIndex primary + TestServer primaryServer = + TestServer.builder(folder) + .withAutoStartConfig(true, Mode.PRIMARY, 0, IndexDataLocationType.REMOTE) + .build(); + primaryServer.createSimpleIndex(TEST_INDEX); + primaryServer.startPrimaryIndex(TEST_INDEX, -1, null); + + // add 4 docs to primary + primaryServer.addSimpleDocs(TEST_INDEX, 1, 2); + primaryServer.addSimpleDocs(TEST_INDEX, 3, 4); + primaryServer.commit(TEST_INDEX); + // add 4 docs to primary + primaryServer.addSimpleDocs(TEST_INDEX, 5, 6); + primaryServer.addSimpleDocs(TEST_INDEX, 7, 8); + primaryServer.commit(TEST_INDEX); + + // non-graceful primary restart (i.e. blow away index directory and stateDir) + primaryServer.restart(true); + + // add 2 docs to primary + primaryServer.addSimpleDocs(TEST_INDEX, 9, 10); + primaryServer.refresh(TEST_INDEX); + + // primary should show numDocs hits now + primaryServer.verifySimpleDocs(TEST_INDEX, 10); + } + + @Test + public void testPrimaryEphemeralIdChanges() throws IOException { + // startIndex primary + TestServer primaryServer = + TestServer.builder(folder) + .withAutoStartConfig(true, Mode.PRIMARY, 0, IndexDataLocationType.REMOTE) + .build(); + primaryServer.createSimpleIndex(TEST_INDEX); + primaryServer.startPrimaryIndex(TEST_INDEX, -1, null); + + // add docs to primary and check ephemeral id + AddDocumentResponse response = + primaryServer.addDocs(Stream.of(primaryServer.getSimpleDocRequest(TEST_INDEX, 1))); + String firstId = response.getPrimaryId(); + response = primaryServer.addDocs(Stream.of(primaryServer.getSimpleDocRequest(TEST_INDEX, 2))); + assertEquals(firstId, response.getPrimaryId()); + + // backup index + primaryServer.commit(TEST_INDEX); + + // non-graceful primary restart (i.e. blow away index and state directory) + primaryServer.restart(true); + + // add docs to primary and check ephemeral id + response = primaryServer.addDocs(Stream.of(primaryServer.getSimpleDocRequest(TEST_INDEX, 3))); + String secondId = response.getPrimaryId(); + assertNotEquals(firstId, secondId); + response = primaryServer.addDocs(Stream.of(primaryServer.getSimpleDocRequest(TEST_INDEX, 4))); + assertEquals(secondId, response.getPrimaryId()); + } +} diff --git a/src/test/java/com/yelp/nrtsearch/server/grpc/ReplicationServerTest.java b/src/test/java/com/yelp/nrtsearch/server/grpc/ReplicationServerTest.java index c8c0415f4..eccf6e567 100644 --- a/src/test/java/com/yelp/nrtsearch/server/grpc/ReplicationServerTest.java +++ b/src/test/java/com/yelp/nrtsearch/server/grpc/ReplicationServerTest.java @@ -22,15 +22,12 @@ import com.amazonaws.services.s3.AmazonS3; import com.yelp.nrtsearch.server.LuceneServerTestConfigurationFactory; -import com.yelp.nrtsearch.server.backup.Archiver; -import com.yelp.nrtsearch.server.backup.ArchiverImpl; -import com.yelp.nrtsearch.server.backup.Tar; -import com.yelp.nrtsearch.server.backup.TarImpl; import com.yelp.nrtsearch.server.config.LuceneServerConfiguration; +import com.yelp.nrtsearch.server.remote.RemoteBackend; +import com.yelp.nrtsearch.server.remote.s3.S3Backend; import com.yelp.nrtsearch.test_utils.AmazonS3Provider; import io.grpc.testing.GrpcCleanupRule; import java.io.IOException; -import java.nio.file.Path; import java.nio.file.Paths; import java.util.Iterator; import org.junit.After; @@ -516,16 +513,13 @@ private void initServerSyncInitialNrtPointFalse() throws IOException { private void initLuceneServers(String extraConfig) throws IOException { // setup S3 for backup/restore - Path s3Directory = folder.newFolder("s3").toPath(); - Path archiverDirectory = folder.newFolder("archiver").toPath(); AmazonS3 s3 = s3Provider.getAmazonS3(); - Archiver archiver = - new ArchiverImpl(s3, BUCKET_NAME, archiverDirectory, new TarImpl(Tar.CompressionMode.LZ4)); // set up primary servers String testIndex = "test_index"; LuceneServerConfiguration luceneServerPrimaryConfiguration = LuceneServerTestConfigurationFactory.getConfig(Mode.PRIMARY, folder.getRoot(), extraConfig); + RemoteBackend remoteBackend = new S3Backend(luceneServerPrimaryConfiguration, s3); luceneServerPrimary = new GrpcServer( grpcCleanup, @@ -535,7 +529,7 @@ private void initLuceneServers(String extraConfig) throws IOException { luceneServerPrimaryConfiguration.getIndexDir(), testIndex, luceneServerPrimaryConfiguration.getPort(), - archiver); + remoteBackend); replicationServerPrimary = new GrpcServer( grpcCleanup, @@ -545,7 +539,7 @@ private void initLuceneServers(String extraConfig) throws IOException { luceneServerPrimaryConfiguration.getIndexDir(), testIndex, luceneServerPrimaryConfiguration.getReplicationPort(), - archiver); + remoteBackend); luceneServerPrimary .getGlobalState() .replicationStarted(luceneServerPrimaryConfiguration.getReplicationPort()); @@ -562,7 +556,7 @@ private void initLuceneServers(String extraConfig) throws IOException { luceneServerSecondaryConfiguration.getIndexDir(), testIndex, luceneServerSecondaryConfiguration.getPort(), - archiver); + remoteBackend); replicationServerSecondary = new GrpcServer( grpcCleanup, @@ -572,7 +566,7 @@ private void initLuceneServers(String extraConfig) throws IOException { luceneServerSecondaryConfiguration.getIndexDir(), testIndex, luceneServerSecondaryConfiguration.getReplicationPort(), - archiver); + remoteBackend); luceneServerSecondary .getGlobalState() .replicationStarted(luceneServerSecondaryConfiguration.getReplicationPort()); diff --git a/src/test/java/com/yelp/nrtsearch/server/grpc/ReplicationTestFailureScenarios.java b/src/test/java/com/yelp/nrtsearch/server/grpc/ReplicationTestFailureScenarios.java deleted file mode 100644 index 48403333c..000000000 --- a/src/test/java/com/yelp/nrtsearch/server/grpc/ReplicationTestFailureScenarios.java +++ /dev/null @@ -1,506 +0,0 @@ -/* - * Copyright 2020 Yelp Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yelp.nrtsearch.server.grpc; - -import static com.yelp.nrtsearch.server.grpc.GrpcServer.rmDir; -import static com.yelp.nrtsearch.server.grpc.LuceneServerTest.RETRIEVED_VALUES; -import static com.yelp.nrtsearch.server.grpc.LuceneServerTest.checkHits; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; - -import com.amazonaws.services.s3.AmazonS3; -import com.yelp.nrtsearch.server.LuceneServerTestConfigurationFactory; -import com.yelp.nrtsearch.server.backup.Archiver; -import com.yelp.nrtsearch.server.backup.ArchiverImpl; -import com.yelp.nrtsearch.server.backup.Tar; -import com.yelp.nrtsearch.server.backup.TarImpl; -import com.yelp.nrtsearch.server.config.LuceneServerConfiguration; -import com.yelp.nrtsearch.test_utils.AmazonS3Provider; -import io.grpc.testing.GrpcCleanupRule; -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -@RunWith(JUnit4.class) -public class ReplicationTestFailureScenarios { - public static final String TEST_INDEX = "test_index"; - - /** - * This rule manages automatic graceful shutdown for the registered servers and channels at the - * end of test. - */ - @Rule public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); - - /** - * This rule ensure the temporary folder which maintains stateDir are cleaned up after each test - */ - @Rule public final TemporaryFolder folder = new TemporaryFolder(); - - @Rule public final AmazonS3Provider s3Provider = new AmazonS3Provider(BUCKET_NAME); - - private GrpcServer luceneServerPrimary; - private GrpcServer replicationServerPrimary; - - private GrpcServer luceneServerSecondary; - private GrpcServer replicationServerSecondary; - - private static final String BUCKET_NAME = "archiver-unittest"; - private Archiver archiver; - private AmazonS3 s3; - private Path archiverDirectory; - - @After - public void tearDown() throws IOException { - luceneServerPrimary.getGlobalState().close(); - luceneServerSecondary.getGlobalState().close(); - rmDir(Paths.get(luceneServerPrimary.getIndexDir()).getParent()); - rmDir(Paths.get(luceneServerSecondary.getIndexDir()).getParent()); - } - - @Before - public void setUp() throws IOException { - // setup S3 for backup/restore - archiverDirectory = folder.newFolder("archiver").toPath(); - s3 = s3Provider.getAmazonS3(); - archiver = - new ArchiverImpl(s3, BUCKET_NAME, archiverDirectory, new TarImpl(Tar.CompressionMode.LZ4)); - - startPrimaryServer(); - startSecondaryServer(); - } - - public void startPrimaryServer() throws IOException { - LuceneServerConfiguration luceneServerPrimaryConfiguration = - LuceneServerTestConfigurationFactory.getConfig(Mode.PRIMARY, folder.getRoot()); - luceneServerPrimary = - new GrpcServer( - grpcCleanup, - luceneServerPrimaryConfiguration, - folder, - null, - luceneServerPrimaryConfiguration.getIndexDir(), - TEST_INDEX, - luceneServerPrimaryConfiguration.getPort(), - archiver); - replicationServerPrimary = - new GrpcServer( - grpcCleanup, - luceneServerPrimaryConfiguration, - folder, - luceneServerPrimary.getGlobalState(), - luceneServerPrimaryConfiguration.getIndexDir(), - TEST_INDEX, - 9001, - archiver); - luceneServerPrimary.getGlobalState().replicationStarted(9001); - } - - public void startSecondaryServer() throws IOException { - LuceneServerConfiguration luceneSecondaryConfiguration = - LuceneServerTestConfigurationFactory.getConfig(Mode.REPLICA, folder.getRoot()); - - luceneServerSecondary = - new GrpcServer( - grpcCleanup, - luceneSecondaryConfiguration, - folder, - null, - luceneSecondaryConfiguration.getIndexDir(), - TEST_INDEX, - luceneSecondaryConfiguration.getPort(), - archiver); - replicationServerSecondary = - new GrpcServer( - grpcCleanup, - luceneSecondaryConfiguration, - folder, - luceneServerSecondary.getGlobalState(), - luceneSecondaryConfiguration.getIndexDir(), - TEST_INDEX, - luceneSecondaryConfiguration.getReplicationPort(), - archiver); - luceneServerSecondary - .getGlobalState() - .replicationStarted(luceneSecondaryConfiguration.getReplicationPort()); - } - - public void shutdownPrimaryServer() throws IOException { - luceneServerPrimary.getGlobalState().close(); - rmDir(Paths.get(luceneServerPrimary.getIndexDir()).getParent()); - luceneServerPrimary.shutdown(); - replicationServerPrimary.shutdown(); - } - - public void shutdownSecondaryServer() throws IOException { - luceneServerSecondary.getGlobalState().close(); - rmDir(Paths.get(luceneServerSecondary.getIndexDir()).getParent()); - luceneServerSecondary.shutdown(); - replicationServerSecondary.shutdown(); - } - - @Test - public void replicaDownedWhenPrimaryIndexing() throws IOException, InterruptedException { - // startIndex Primary - GrpcServer.TestServer testServerPrimary = - new GrpcServer.TestServer(luceneServerPrimary, true, Mode.PRIMARY); - // startIndex replica - GrpcServer.TestServer testServerReplica = - new GrpcServer.TestServer(luceneServerSecondary, true, Mode.REPLICA); - - // add 2 docs to primary - testServerPrimary.addDocuments(); - - // backup index - backupIndex(); - - // refresh (also sends NRTPoint to replicas) - luceneServerPrimary - .getBlockingStub() - .refresh(RefreshRequest.newBuilder().setIndexName(TEST_INDEX).build()); - - // stop replica instance - shutdownSecondaryServer(); - - // add 2 docs to primary - testServerPrimary.addDocuments(); - - // re-start replica instance from a fresh index state i.e. empty index dir - startSecondaryServer(); - // startIndex replica - testServerReplica = - new GrpcServer.TestServer(luceneServerSecondary, true, Mode.REPLICA, 0, true); - - // add 2 more docs (6 total now), annoying, sendNRTPoint gets called from primary only upon a - // flush i.e. an index operation - testServerPrimary.addDocuments(); - - // publish new NRT point (retrieve the current searcher version on primary) - publishNRTAndValidateSearchResults(6); - } - - @Test - public void primaryStoppedAndRestartedWithNoPreviousIndex() - throws IOException, InterruptedException { - // startIndex Primary - GrpcServer.TestServer testServerPrimary = - new GrpcServer.TestServer(luceneServerPrimary, true, Mode.PRIMARY); - // startIndex replica - GrpcServer.TestServer testServerReplica = - new GrpcServer.TestServer(luceneServerSecondary, true, Mode.REPLICA); - // add 2 docs to primary - testServerPrimary.addDocuments(); - // add 2 docs to primary - testServerPrimary.addDocuments(); - // both primary and replica should have 4 docs - publishNRTAndValidateSearchResults(4); - // backup primary - backupIndex(); - // commit secondary state - luceneServerSecondary - .getBlockingStub() - .commit(CommitRequest.newBuilder().setIndexName(TEST_INDEX).build()); - - // non-graceful primary shutdown (i.e. blow away index directory) - shutdownPrimaryServer(); - // start primary again with new empty index directory - startPrimaryServer(); - // startIndex Primary with primaryGen = 1 - testServerPrimary = new GrpcServer.TestServer(luceneServerPrimary, true, Mode.PRIMARY, 1); - // stop and restart secondary to connect to "new" primary - gracefullRestartSecondary(); - // add 2 docs to primary - testServerPrimary.addDocuments(); - // both primary and secondary have only 2 docs now (replica has fewer docs than before as - // expected) - publishNRTAndValidateSearchResults(2); - } - - @Test - public void primaryStoppedAndRestartedWithPreviousLocalIndex() - throws IOException, InterruptedException { - // startIndex primary - GrpcServer.TestServer testServerPrimary = - new GrpcServer.TestServer(luceneServerPrimary, true, Mode.PRIMARY); - // startIndex replica - GrpcServer.TestServer testServerReplica = - new GrpcServer.TestServer(luceneServerSecondary, true, Mode.REPLICA); - // add 2 docs to primary - testServerPrimary.addDocuments(); - // both primary and replica should have 2 docs - publishNRTAndValidateSearchResults(2); - // commit primary - luceneServerPrimary - .getBlockingStub() - .commit(CommitRequest.newBuilder().setIndexName(TEST_INDEX).build()); - // commit metadata state for secondary - luceneServerSecondary - .getBlockingStub() - .commit(CommitRequest.newBuilder().setIndexName(TEST_INDEX).build()); - - // gracefully stop and restart primary - gracefullRestartPrimary(1); - // stop and restart secondary to connect to "new" primary - gracefullRestartSecondary(); - // add 2 docs to primary - testServerPrimary.addDocuments(); - publishNRTAndValidateSearchResults(4); - } - - @Test - public void primaryDurabilityBasic() throws IOException, InterruptedException { - // startIndex primary - GrpcServer.TestServer testServerPrimary = - new GrpcServer.TestServer(luceneServerPrimary, true, Mode.PRIMARY); - // add 2 docs to primary - testServerPrimary.addDocuments(); - // backup index - backupIndex(); - // non-graceful primary shutdown (i.e. blow away index and state directory) - shutdownPrimaryServer(); - // start primary again with latest commit point - startPrimaryServer(); - // startIndex Primary with primaryGen = 1 - testServerPrimary = new GrpcServer.TestServer(luceneServerPrimary, true, Mode.PRIMARY, 1, true); - // add 2 docs to primary - testServerPrimary.addDocuments(); - - // publish new NRT point (retrieve the current searcher version on primary) - SearcherVersion searcherVersionPrimary = - replicationServerPrimary - .getReplicationServerBlockingStub() - .writeNRTPoint(IndexName.newBuilder().setIndexName(TEST_INDEX).build()); - - // primary should show numDocs hits now - SearchResponse searchResponsePrimary = - luceneServerPrimary - .getBlockingStub() - .search( - SearchRequest.newBuilder() - .setIndexName(luceneServerPrimary.getTestIndex()) - .setStartHit(0) - .setTopHits(10) - .setVersion(searcherVersionPrimary.getVersion()) - .addAllRetrieveFields(RETRIEVED_VALUES) - .build()); - - validateSearchResults(4, searchResponsePrimary); - } - - @Test - public void primaryDurabilitySyncWithReplica() throws IOException, InterruptedException { - // startIndex primary - GrpcServer.TestServer testServerPrimary = - new GrpcServer.TestServer(luceneServerPrimary, true, Mode.PRIMARY); - // startIndex replica - GrpcServer.TestServer testServerReplica = - new GrpcServer.TestServer(luceneServerSecondary, true, Mode.REPLICA); - // add 2 docs to primary - testServerPrimary.addDocuments(); - // both primary and replica should have 2 docs - publishNRTAndValidateSearchResults(2); - - // backupIndex (with 2 docs) - backupIndex(); - // commit metadata state for secondary, since we wil reuse this upon startIndex - luceneServerSecondary - .getBlockingStub() - .commit(CommitRequest.newBuilder().setIndexName(TEST_INDEX).build()); - - // add 6 more docs to primary but dont commit, NRT is at 8 docs but commit point at 2 docs - testServerPrimary.addDocuments(); - testServerPrimary.addDocuments(); - testServerPrimary.addDocuments(); - publishNRTAndValidateSearchResults(8); - - // non-graceful primary shutdown (i.e. blow away index directory and stateDir) - shutdownPrimaryServer(); - - // start primary again, download data from latest commit point - startPrimaryServer(); - // startIndex Primary with primaryGen = 1 - testServerPrimary = new GrpcServer.TestServer(luceneServerPrimary, true, Mode.PRIMARY, 1, true); - // stop and restart secondary to connect to "new" primary, - gracefullRestartSecondary(); - // add 2 more docs to primary - testServerPrimary.addDocuments(); - publishNRTAndValidateSearchResults(4); - } - - @Test - public void primaryDurabilityWithMultipleCommits() throws IOException, InterruptedException { - // startIndex primary - GrpcServer.TestServer testServerPrimary = - new GrpcServer.TestServer(luceneServerPrimary, true, Mode.PRIMARY); - for (int i = 0; i < 2; i++) { - // add 4 docs to primary - testServerPrimary.addDocuments(); - testServerPrimary.addDocuments(); - backupIndex(); - } - - // non-graceful primary shutdown (i.e. blow away index directory and stateDir) - shutdownPrimaryServer(); - - // start primary again, download data from latest commit point - startPrimaryServer(); - // startIndex Primary with primaryGen = 1 - testServerPrimary = new GrpcServer.TestServer(luceneServerPrimary, true, Mode.PRIMARY, 1, true); - - // add 2 docs to primary - testServerPrimary.addDocuments(); - - // publish new NRT point (retrieve the current searcher version on primary) - SearcherVersion searcherVersionPrimary = - replicationServerPrimary - .getReplicationServerBlockingStub() - .writeNRTPoint(IndexName.newBuilder().setIndexName(TEST_INDEX).build()); - - // primary should show numDocs hits now - SearchResponse searchResponsePrimary = - luceneServerPrimary - .getBlockingStub() - .search( - SearchRequest.newBuilder() - .setIndexName(luceneServerPrimary.getTestIndex()) - .setStartHit(0) - .setTopHits(10) - .setVersion(searcherVersionPrimary.getVersion()) - .addAllRetrieveFields(RETRIEVED_VALUES) - .build()); - - validateSearchResults(10, searchResponsePrimary); - } - - private void gracefullRestartSecondary() { - luceneServerSecondary - .getBlockingStub() - .stopIndex(StopIndexRequest.newBuilder().setIndexName(TEST_INDEX).build()); - luceneServerSecondary - .getBlockingStub() - .startIndex( - StartIndexRequest.newBuilder() - .setIndexName(TEST_INDEX) - .setMode(Mode.REPLICA) - .setPrimaryAddress("localhost") - .setPort(9001) // primary port for replication server - .build()); - } - - @Test - public void testPrimaryEphemeralIdChanges() throws IOException, InterruptedException { - // startIndex primary - GrpcServer.TestServer testServerPrimary = - new GrpcServer.TestServer(luceneServerPrimary, true, Mode.PRIMARY); - - // add docs to primary and check ephemeral id - AddDocumentResponse response = testServerPrimary.addDocuments(); - String firstId = response.getPrimaryId(); - response = testServerPrimary.addDocuments(); - assertEquals(firstId, response.getPrimaryId()); - - // backup index - backupIndex(); - // non-graceful primary shutdown (i.e. blow away index and state directory) - shutdownPrimaryServer(); - // start primary again with latest commit point - startPrimaryServer(); - // startIndex Primary with primaryGen = 1 - testServerPrimary = new GrpcServer.TestServer(luceneServerPrimary, true, Mode.PRIMARY, 1, true); - - // add docs to primary and check ephemeral id - response = testServerPrimary.addDocuments(); - String secondId = response.getPrimaryId(); - assertNotEquals(firstId, secondId); - response = testServerPrimary.addDocuments(); - assertEquals(secondId, response.getPrimaryId()); - } - - private void gracefullRestartPrimary(int primaryGen) { - luceneServerPrimary - .getBlockingStub() - .stopIndex(StopIndexRequest.newBuilder().setIndexName(TEST_INDEX).build()); - luceneServerPrimary - .getBlockingStub() - .startIndex( - StartIndexRequest.newBuilder() - .setIndexName(TEST_INDEX) - .setMode(Mode.PRIMARY) - .setPrimaryGen(primaryGen) - .build()); - } - - private void publishNRTAndValidateSearchResults(int numDocs) { - // publish new NRT point (retrieve the current searcher version on primary) - SearcherVersion searcherVersionPrimary = - replicationServerPrimary - .getReplicationServerBlockingStub() - .writeNRTPoint(IndexName.newBuilder().setIndexName(TEST_INDEX).build()); - // primary should show numDocs hits now - SearchResponse searchResponsePrimary = - luceneServerPrimary - .getBlockingStub() - .search( - SearchRequest.newBuilder() - .setIndexName(luceneServerPrimary.getTestIndex()) - .setStartHit(0) - .setTopHits(10) - .setVersion(searcherVersionPrimary.getVersion()) - .addAllRetrieveFields(RETRIEVED_VALUES) - .build()); - // replica should also have numDocs hits - SearchResponse searchResponseSecondary = - luceneServerSecondary - .getBlockingStub() - .search( - SearchRequest.newBuilder() - .setIndexName(luceneServerSecondary.getTestIndex()) - .setStartHit(0) - .setTopHits(10) - .setVersion(searcherVersionPrimary.getVersion()) - .addAllRetrieveFields(RETRIEVED_VALUES) - .build()); - - validateSearchResults(numDocs, searchResponsePrimary); - validateSearchResults(numDocs, searchResponseSecondary); - } - - public static void validateSearchResults(int numHitsExpected, SearchResponse searchResponse) { - assertEquals(numHitsExpected, searchResponse.getTotalHits().getValue()); - assertEquals(numHitsExpected, searchResponse.getHitsList().size()); - SearchResponse.Hit firstHit = searchResponse.getHits(0); - checkHits(firstHit); - SearchResponse.Hit secondHit = searchResponse.getHits(1); - checkHits(secondHit); - } - - private void backupIndex() { - luceneServerPrimary - .getBlockingStub() - .backupIndex( - BackupIndexRequest.newBuilder() - .setIndexName("test_index") - .setServiceName("testservice") - .setResourceName("testresource") - .build()); - } -} diff --git a/src/test/java/com/yelp/nrtsearch/server/grpc/StateBackendServerTest.java b/src/test/java/com/yelp/nrtsearch/server/grpc/StateBackendServerTest.java index fa49a7f83..229d7b8ac 100644 --- a/src/test/java/com/yelp/nrtsearch/server/grpc/StateBackendServerTest.java +++ b/src/test/java/com/yelp/nrtsearch/server/grpc/StateBackendServerTest.java @@ -216,8 +216,6 @@ private LuceneServerConfiguration getPrimaryArchiverConfig() { "stateDir: " + getStateDir(), "indexDir: " + getPrimaryIndexDir(), "archiveDirectory: " + getPrimaryArchiveDir(), - "backupWithIncArchiver: true", - "restoreFromIncArchiver: true", "stateConfig:", " backendType: REMOTE", " remote:", @@ -251,7 +249,6 @@ private LuceneServerConfiguration getReplicaArchiverConfig() { "archiveDirectory: " + getReplicaArchiveDir(), // don't sync on start to make restore testing easier "syncInitialNrtPoint: false", - "restoreFromIncArchiver: true", "stateConfig:", " backendType: REMOTE"); return new LuceneServerConfiguration(new ByteArrayInputStream(configStr.getBytes())); @@ -277,8 +274,8 @@ private void restartPrimaryWithArchiver() throws IOException { LuceneServerImpl serverImpl = new LuceneServerImpl( getPrimaryArchiverConfig(), - null, archiverPrimary, + null, new CollectorRegistry(), Collections.emptyList()); @@ -311,8 +308,8 @@ private void restartReplicaWithArchiver() throws IOException { LuceneServerImpl serverImpl = new LuceneServerImpl( getReplicaArchiverConfig(), - null, archiverReplica, + null, new CollectorRegistry(), Collections.emptyList()); diff --git a/src/test/java/com/yelp/nrtsearch/server/grpc/TestServer.java b/src/test/java/com/yelp/nrtsearch/server/grpc/TestServer.java index df6a83559..5580a9eea 100644 --- a/src/test/java/com/yelp/nrtsearch/server/grpc/TestServer.java +++ b/src/test/java/com/yelp/nrtsearch/server/grpc/TestServer.java @@ -30,14 +30,12 @@ import com.google.gson.JsonObject; import com.yelp.nrtsearch.clientlib.Node; import com.yelp.nrtsearch.server.backup.Archiver; -import com.yelp.nrtsearch.server.backup.ArchiverImpl; import com.yelp.nrtsearch.server.backup.BackupDiffManager; import com.yelp.nrtsearch.server.backup.ContentDownloader; import com.yelp.nrtsearch.server.backup.ContentDownloaderImpl; import com.yelp.nrtsearch.server.backup.FileCompressAndUploader; import com.yelp.nrtsearch.server.backup.IndexArchiver; import com.yelp.nrtsearch.server.backup.NoTarImpl; -import com.yelp.nrtsearch.server.backup.Tar; import com.yelp.nrtsearch.server.backup.TarImpl; import com.yelp.nrtsearch.server.backup.VersionManager; import com.yelp.nrtsearch.server.config.IndexStartConfig.IndexDataLocationType; @@ -50,6 +48,8 @@ import com.yelp.nrtsearch.server.luceneserver.GlobalState; import com.yelp.nrtsearch.server.luceneserver.IndexState; import com.yelp.nrtsearch.server.luceneserver.ShardState; +import com.yelp.nrtsearch.server.remote.RemoteBackend; +import com.yelp.nrtsearch.server.remote.s3.S3Backend; import com.yelp.nrtsearch.server.utils.FileUtil; import io.findify.s3mock.S3Mock; import io.grpc.Server; @@ -116,8 +116,8 @@ public class TestServer { private Server replicationServer; private LuceneServerClient client; private LuceneServerImpl serverImpl; - private Archiver legacyArchiver; private Archiver indexArchiver; + private RemoteBackend remoteBackend; public static void initS3(TemporaryFolder folder) throws IOException { if (api == null) { @@ -128,7 +128,7 @@ public static void initS3(TemporaryFolder folder) throws IOException { } public static void cleanupAll() { - createdServers.forEach(TestServer::cleanup); + createdServers.forEach(TestServer::stop); createdServers.clear(); if (api != null) { api.shutdown(); @@ -178,14 +178,11 @@ private IndexArchiver createIndexArchiver(Path archiverDir) throws IOException { archiverDir); } - private Archiver createLegacyArchiver(Path archiverDir) throws IOException { - Files.createDirectories(archiverDir); - + private RemoteBackend createRemoteBackend() { AmazonS3 s3 = new AmazonS3Client(new AnonymousAWSCredentials()); s3.setEndpoint(S3_ENDPOINT); s3.createBucket(TEST_BUCKET); - return new ArchiverImpl( - s3, TEST_BUCKET, archiverDir, new TarImpl(Tar.CompressionMode.LZ4), true); + return new S3Backend(configuration, s3); } public void restart() throws IOException { @@ -193,14 +190,14 @@ public void restart() throws IOException { } public void restart(boolean clearData) throws IOException { - cleanup(clearData); - legacyArchiver = createLegacyArchiver(Paths.get(configuration.getArchiveDirectory())); + stop(clearData); indexArchiver = createIndexArchiver(Paths.get(configuration.getArchiveDirectory())); + remoteBackend = createRemoteBackend(); serverImpl = new LuceneServerImpl( configuration, - legacyArchiver, indexArchiver, + remoteBackend, new CollectorRegistry(), Collections.emptyList()); @@ -255,19 +252,19 @@ public LuceneServerClient getClient() { return client; } - public Archiver getLegacyArchiver() { - return legacyArchiver; - } - public Archiver getIndexArchiver() { return indexArchiver; } - public void cleanup() { - cleanup(false); + public RemoteBackend getRemoteBackend() { + return remoteBackend; } - public void cleanup(boolean clearData) { + public void stop() { + stop(false); + } + + public void stop(boolean clearData) { if (serverImpl != null) { GlobalState globalState = serverImpl.getGlobalState(); for (String indexName : globalState.getIndexNames()) { @@ -476,19 +473,20 @@ public void onCompleted() { public void addSimpleDocs(String indexName, int... ids) { List requests = new ArrayList<>(); for (int id : ids) { - requests.add( - AddDocumentRequest.newBuilder() - .setIndexName(indexName) - .putFields("id", MultiValuedField.newBuilder().addValue(String.valueOf(id)).build()) - .putFields( - "field1", MultiValuedField.newBuilder().addValue(String.valueOf(id * 3)).build()) - .putFields( - "field2", MultiValuedField.newBuilder().addValue(String.valueOf(id * 5)).build()) - .build()); + requests.add(getSimpleDocRequest(indexName, id)); } addDocs(requests.stream()); } + public AddDocumentRequest getSimpleDocRequest(String indexName, int id) { + return AddDocumentRequest.newBuilder() + .setIndexName(indexName) + .putFields("id", MultiValuedField.newBuilder().addValue(String.valueOf(id)).build()) + .putFields("field1", MultiValuedField.newBuilder().addValue(String.valueOf(id * 3)).build()) + .putFields("field2", MultiValuedField.newBuilder().addValue(String.valueOf(id * 5)).build()) + .build(); + } + public void verifyFieldName(String indexName, String fieldName) { StateResponse rawResponse = client.getBlockingStub().state(StateRequest.newBuilder().setIndexName(indexName).build()); @@ -648,8 +646,6 @@ public static class Builder { private StateBackendType stateBackendType = StateBackendType.LOCAL; private boolean backendReadOnly = true; - private boolean incArchiver = true; - private boolean syncInitialNrtPoint = true; private int maxWarmingQueries = 0; @@ -695,11 +691,6 @@ public Builder withRemoteStateBackend(boolean readOnly) { return this; } - public Builder withIncArchiver(boolean enabled) { - this.incArchiver = enabled; - return this; - } - public Builder withDecInitialCommit(boolean enabled) { this.decInitialCommit = enabled; return this; @@ -731,7 +722,6 @@ public TestServer build() throws IOException { baseConfig(), backendConfig(), autoStartConfig(), - archiverConfig(), warmingConfig(), "syncInitialNrtPoint: " + syncInitialNrtPoint, additionalConfig); @@ -741,11 +731,6 @@ public TestServer build() throws IOException { Paths.get(folder.getRoot().toString(), DISCOVERY_FILE)); } - private String archiverConfig() { - return String.join( - "\n", "backupWithIncArchiver: " + incArchiver, "restoreFromIncArchiver: " + incArchiver); - } - private String backendConfig() { if (StateBackendType.LOCAL.equals(stateBackendType)) { return String.join("\n", "stateConfig:", " backendType: LOCAL"); @@ -790,6 +775,7 @@ private String baseConfig() { "\n", "nodeName: test_node-" + uuid, "serviceName: " + serviceName, + "bucketName: " + TEST_BUCKET, "stateDir: " + Paths.get(folder.getRoot().toString(), "state_dir"), "indexDir: " + Paths.get(folder.getRoot().toString(), "index_dir-" + uuid), "archiveDirectory: " + Paths.get(folder.getRoot().toString(), "archive_dir-" + uuid), diff --git a/src/test/java/com/yelp/nrtsearch/server/grpc/WarmingQueriesTest.java b/src/test/java/com/yelp/nrtsearch/server/grpc/WarmingQueriesTest.java index 01ef0e39d..b6d49e9f7 100644 --- a/src/test/java/com/yelp/nrtsearch/server/grpc/WarmingQueriesTest.java +++ b/src/test/java/com/yelp/nrtsearch/server/grpc/WarmingQueriesTest.java @@ -20,10 +20,12 @@ import com.google.protobuf.util.JsonFormat; import com.yelp.nrtsearch.server.config.IndexStartConfig.IndexDataLocationType; -import com.yelp.nrtsearch.server.luceneserver.warming.Warmer; +import com.yelp.nrtsearch.server.remote.RemoteBackend.IndexResourceType; +import java.io.BufferedReader; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.junit.After; @@ -80,17 +82,20 @@ public void testCreateWarmingQueries() throws IOException { .setNumQueriesThreshold(0) .build()); - Path downloadPath = + InputStream queriesStream = replica - .getLegacyArchiver() - .download( + .getRemoteBackend() + .downloadStream( SERVICE_NAME, - server.getGlobalState().getDataResourceForIndex("test_index") - + Warmer.WARMING_QUERIES_RESOURCE); - - Path warmingQueriesDir = downloadPath.resolve("warming_queries"); - Path warmingQueriesFile = warmingQueriesDir.resolve("warming_queries.txt"); - List lines = Files.readAllLines(warmingQueriesFile); + server.getGlobalState().getDataResourceForIndex("test_index"), + IndexResourceType.WARMING_QUERIES); + List lines = new ArrayList<>(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(queriesStream))) { + String line; + while ((line = reader.readLine()) != null) { + lines.add(line); + } + } assertEquals(1, lines.size()); assertEquals( JsonFormat.printer().omittingInsignificantWhitespace().print(searchRequest), lines.get(0)); diff --git a/src/test/java/com/yelp/nrtsearch/server/luceneserver/DeleteIndexBackupHandlerTest.java b/src/test/java/com/yelp/nrtsearch/server/luceneserver/DeleteIndexBackupHandlerTest.java deleted file mode 100644 index d9e1e79b6..000000000 --- a/src/test/java/com/yelp/nrtsearch/server/luceneserver/DeleteIndexBackupHandlerTest.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2020 Yelp Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yelp.nrtsearch.server.luceneserver; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.yelp.nrtsearch.server.backup.Archiver; -import com.yelp.nrtsearch.server.backup.VersionedResource; -import com.yelp.nrtsearch.server.grpc.DeleteIndexBackupRequest; -import com.yelp.nrtsearch.server.grpc.DeleteIndexBackupResponse; -import com.yelp.nrtsearch.server.luceneserver.Handler.HandlerException; -import java.io.IOException; -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.Arrays; -import org.junit.Assert; -import org.junit.Test; - -public class DeleteIndexBackupHandlerTest { - - @Test - public void testDeleteIndexBackupHandlerHandle() throws HandlerException, IOException { - String indexName = "testindex"; - String serviceName = "testservice"; - String resourceName = "testresource"; - int nDays = 30; - - Archiver archiver = mock(Archiver.class); - DeleteIndexBackupHandler handler = new DeleteIndexBackupHandler(archiver); - DeleteIndexBackupRequest request = - DeleteIndexBackupRequest.newBuilder() - .setIndexName(indexName) - .setServiceName(serviceName) - .setResourceName(resourceName) - .setNDays(nDays) - .build(); - - IndexState testIndex = mock(IndexState.class); - - Instant now = Instant.now(); - - Instant date1 = now.minus(20, ChronoUnit.DAYS); - Instant date2 = now.minus(40, ChronoUnit.DAYS); - - String versionHash1 = "hash_1"; - String versionHash2 = "hash_2"; - - String resourceData = IndexBackupUtils.getResourceData(resourceName); - String resourceMetadata = IndexBackupUtils.getResourceMetadata(resourceName); - String resourceVersionData = IndexBackupUtils.getResourceVersionData(resourceName); - String resourceVersionMetadata = IndexBackupUtils.getResourceVersionMetadata(resourceName); - - VersionedResource resourceData1 = - buildVersionedResource(serviceName, resourceData, date1, versionHash1); - VersionedResource resourceMetadata1 = - buildVersionedResource(serviceName, resourceMetadata, date1, versionHash1); - VersionedResource resourceVersionData1 = - buildVersionedResource(serviceName, resourceVersionData, date1, versionHash1); - VersionedResource resourceVersionMetadata1 = - buildVersionedResource(serviceName, resourceVersionMetadata, date1, versionHash1); - - VersionedResource resourceData2 = - buildVersionedResource(serviceName, resourceData, date2, versionHash2); - VersionedResource resourceMetadata2 = - buildVersionedResource(serviceName, resourceMetadata, date2, versionHash2); - VersionedResource resourceVersionData2 = - buildVersionedResource(serviceName, resourceVersionData, date2, versionHash2); - VersionedResource resourceVersionMetadata2 = - buildVersionedResource(serviceName, resourceVersionMetadata, date2, versionHash2); - - // data from {resource}_data folder - when(archiver.getVersionedResource(serviceName, resourceData)) - .thenReturn(Arrays.asList(resourceData1, resourceData2)); - - // data from {resource}_metadata folder - when(archiver.getVersionedResource(serviceName, resourceMetadata)) - .thenReturn(Arrays.asList(resourceMetadata1, resourceMetadata2)); - - // data from _version/{resource}_data folder - when(archiver.getVersionedResource(serviceName, resourceVersionData)) - .thenReturn(Arrays.asList(resourceVersionData1, resourceVersionData2)); - - // data from _version/{resource}_metadata folder - when(archiver.getVersionedResource(serviceName, resourceVersionMetadata)) - .thenReturn(Arrays.asList(resourceVersionMetadata1, resourceVersionMetadata2)); - - DeleteIndexBackupResponse response = handler.handle(testIndex, request); - - // verify that a 20 days old backup doesn't get deleted - verify(archiver, never()).deleteVersion(serviceName, resourceData, versionHash1); - verify(archiver, never()).deleteVersion(serviceName, resourceMetadata, versionHash1); - verify(archiver, never()).deleteVersion(serviceName, resourceVersionData, versionHash1); - verify(archiver, never()).deleteVersion(serviceName, resourceVersionMetadata, versionHash1); - - // verify that a 40 days old backup gets deleted completely - verify(archiver).deleteVersion(serviceName, resourceData, versionHash2); - verify(archiver).deleteVersion(serviceName, resourceMetadata, versionHash2); - verify(archiver).deleteVersion(serviceName, resourceVersionData, versionHash2); - verify(archiver).deleteVersion(serviceName, resourceVersionMetadata, versionHash2); - - // verify the response format: data from all four locations should be deleted. The locations: - // {resource}_data - Assert.assertEquals(response.getDeletedResourceDataHashesList(), Arrays.asList(versionHash2)); - // {resource}_metadata - Assert.assertEquals( - response.getDeletedResourceMetadataHashesList(), Arrays.asList(versionHash2)); - // _version/{resource}_data - Assert.assertEquals(response.getDeletedDataVersionsList(), Arrays.asList(versionHash2)); - // _version/{resource}_metadata - Assert.assertEquals(response.getDeletedMetadataVersionsList(), Arrays.asList(versionHash2)); - } - - @Test - public void testIsOlderThanNDays() { - - Instant now = Instant.now(); - Instant date1 = now.minus(20, ChronoUnit.DAYS); - Instant date2 = now.minus(35, ChronoUnit.DAYS); - - int nDays = 30; - - VersionedResource testObj1 = - VersionedResource.builder().setCreationTimestamp(date1).createVersionedResource(); - - Assert.assertEquals(false, DeleteIndexBackupHandler.isOlderThanNDays(testObj1, now, nDays)); - - VersionedResource testObj2 = - VersionedResource.builder().setCreationTimestamp(date2).createVersionedResource(); - - Assert.assertEquals(true, DeleteIndexBackupHandler.isOlderThanNDays(testObj2, now, nDays)); - } - - private VersionedResource buildVersionedResource( - String serviceName, String resourceName, Instant timestamp, String versionHash) { - VersionedResource versionedResource = - VersionedResource.builder() - .setServiceName(serviceName) - .setResourceName(resourceName) - .setCreationTimestamp(timestamp) - .setVersionHash(versionHash) - .createVersionedResource(); - - return versionedResource; - } -} diff --git a/src/test/java/com/yelp/nrtsearch/server/luceneserver/GlobalStateTest.java b/src/test/java/com/yelp/nrtsearch/server/luceneserver/GlobalStateTest.java index 08be88fb7..d2ca9007e 100644 --- a/src/test/java/com/yelp/nrtsearch/server/luceneserver/GlobalStateTest.java +++ b/src/test/java/com/yelp/nrtsearch/server/luceneserver/GlobalStateTest.java @@ -43,7 +43,7 @@ public void testCreateBackendGlobalState() throws IOException { " backendType: LOCAL", "stateDir: " + folder.getRoot().getAbsolutePath()); LuceneServerConfiguration configuration = getConfig(configFile); - GlobalState globalState = GlobalState.createState(configuration); + GlobalState globalState = GlobalState.createState(configuration, null, null); assertTrue(globalState instanceof BackendGlobalState); } @@ -51,7 +51,7 @@ public void testCreateBackendGlobalState() throws IOException { public void testGetGeneration() throws IOException { String configFile = String.join("\n", "stateConfig:", " backendType: LOCAL"); LuceneServerConfiguration configuration = getConfig(configFile); - GlobalState globalState = GlobalState.createState(configuration); + GlobalState globalState = GlobalState.createState(configuration, null, null); long gen = globalState.getGeneration(); assertTrue(gen > 0); assertEquals(gen, globalState.getGeneration()); @@ -60,7 +60,7 @@ public void testGetGeneration() throws IOException { Thread.sleep(50); } catch (InterruptedException ignore) { } - GlobalState globalState2 = GlobalState.createState(configuration); + GlobalState globalState2 = GlobalState.createState(configuration, null, null); assertTrue(globalState2.getGeneration() > gen); } } diff --git a/src/test/java/com/yelp/nrtsearch/server/luceneserver/index/BackendStateManagerTest.java b/src/test/java/com/yelp/nrtsearch/server/luceneserver/index/BackendStateManagerTest.java index 4b1eefc57..9f5a2b2a7 100644 --- a/src/test/java/com/yelp/nrtsearch/server/luceneserver/index/BackendStateManagerTest.java +++ b/src/test/java/com/yelp/nrtsearch/server/luceneserver/index/BackendStateManagerTest.java @@ -1086,11 +1086,6 @@ public void testStartIndexReplicaSkipCommit() throws IOException { when(mockBackend.loadIndexState(BackendGlobalState.getUniqueIndexName("test_index", "test_id"))) .thenReturn(initialState); - String configFile = String.join("\n", "backupWithIncArchiver: true"); - LuceneServerConfiguration configuration = - new LuceneServerConfiguration(new ByteArrayInputStream(configFile.getBytes())); - when(mockGlobalState.getConfiguration()).thenReturn(configuration); - ImmutableIndexState mockState = mock(ImmutableIndexState.class); when(mockState.isStarted()).thenReturn(false); MockStateManager.nextState = mockState; @@ -1122,11 +1117,6 @@ public void testStartIndexInitialCommit() throws IOException { when(mockBackend.loadIndexState(BackendGlobalState.getUniqueIndexName("test_index", "test_id"))) .thenReturn(initialState); - String configFile = String.join("\n", "backupWithIncArchiver: true"); - LuceneServerConfiguration configuration = - new LuceneServerConfiguration(new ByteArrayInputStream(configFile.getBytes())); - when(mockGlobalState.getConfiguration()).thenReturn(configuration); - ImmutableIndexState mockState = mock(ImmutableIndexState.class); when(mockState.getFieldAndFacetState()).thenReturn(new FieldAndFacetState()); when(mockState.getCurrentStateInfo()).thenReturn(initialState); @@ -1151,11 +1141,10 @@ public void testStartIndexInitialCommit() throws IOException { verify(mockBackend, times(1)) .commitIndexState( BackendGlobalState.getUniqueIndexName("test_index", "test_id"), updatedState); - verify(mockGlobalState, times(1)).getConfiguration(); verify(mockState, times(3)).getCurrentStateInfo(); verify(mockState, times(1)).isStarted(); verify(mockState, times(1)).start(Mode.PRIMARY, Path.of("/tmp"), 1, mockReplicationClient); - verify(mockState, times(1)).commit(true); + verify(mockState, times(1)).commit(); verify(mockState, times(1)).getFieldAndFacetState(); verifyNoMoreInteractions(mockBackend, mockGlobalState, mockState, mockState2); diff --git a/src/test/java/com/yelp/nrtsearch/server/luceneserver/index/ImmutableIndexStateTest.java b/src/test/java/com/yelp/nrtsearch/server/luceneserver/index/ImmutableIndexStateTest.java index bedc07077..0929a9a8e 100644 --- a/src/test/java/com/yelp/nrtsearch/server/luceneserver/index/ImmutableIndexStateTest.java +++ b/src/test/java/com/yelp/nrtsearch/server/luceneserver/index/ImmutableIndexStateTest.java @@ -1077,7 +1077,7 @@ public void testCommit() throws IOException { shardStateMap.put(0, mockShard); ImmutableIndexState indexState = getIndexState(getEmptyState(), new FieldAndFacetState(), shardStateMap); - indexState.commit(false); + indexState.commit(); verify(mockShard, times(1)).commit(); } diff --git a/src/test/java/com/yelp/nrtsearch/server/luceneserver/state/BackendGlobalStateTest.java b/src/test/java/com/yelp/nrtsearch/server/luceneserver/state/BackendGlobalStateTest.java index e67a90e9e..c9c20f929 100644 --- a/src/test/java/com/yelp/nrtsearch/server/luceneserver/state/BackendGlobalStateTest.java +++ b/src/test/java/com/yelp/nrtsearch/server/luceneserver/state/BackendGlobalStateTest.java @@ -98,7 +98,7 @@ static class MockBackendGlobalState extends BackendGlobalState { public MockBackendGlobalState( LuceneServerConfiguration luceneServerConfiguration, Archiver incArchiver) throws IOException { - super(luceneServerConfiguration, incArchiver); + super(luceneServerConfiguration, incArchiver, null); } @Override @@ -624,7 +624,7 @@ public void testUseLocalBackend() throws IOException { "indexDir: " + folder.newFolder("index").getAbsolutePath()); LuceneServerConfiguration config = new LuceneServerConfiguration(new ByteArrayInputStream(configFile.getBytes())); - BackendGlobalState backendGlobalState = new BackendGlobalState(config, null); + BackendGlobalState backendGlobalState = new BackendGlobalState(config, null, null); assertTrue(backendGlobalState.getStateBackend() instanceof LocalStateBackend); } @@ -648,7 +648,7 @@ public void testUseRemoteBackend() throws IOException { Archiver archiver = mock(Archiver.class); when(archiver.download(any(), any())).thenReturn(Paths.get(folder.getRoot().getAbsolutePath())); - BackendGlobalState backendGlobalState = new BackendGlobalState(config, archiver); + BackendGlobalState backendGlobalState = new BackendGlobalState(config, archiver, null); assertTrue(backendGlobalState.getStateBackend() instanceof RemoteStateBackend); } diff --git a/src/test/java/com/yelp/nrtsearch/server/luceneserver/warming/WarmerTest.java b/src/test/java/com/yelp/nrtsearch/server/luceneserver/warming/WarmerTest.java index a5c124f9a..18cf07714 100644 --- a/src/test/java/com/yelp/nrtsearch/server/luceneserver/warming/WarmerTest.java +++ b/src/test/java/com/yelp/nrtsearch/server/luceneserver/warming/WarmerTest.java @@ -21,17 +21,22 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import com.amazonaws.services.s3.AmazonS3; -import com.yelp.nrtsearch.server.backup.Archiver; -import com.yelp.nrtsearch.server.backup.ArchiverImpl; -import com.yelp.nrtsearch.server.backup.TarImpl; +import com.yelp.nrtsearch.server.config.LuceneServerConfiguration; import com.yelp.nrtsearch.server.grpc.Query; import com.yelp.nrtsearch.server.grpc.SearchRequest; import com.yelp.nrtsearch.server.grpc.TermQuery; import com.yelp.nrtsearch.server.luceneserver.IndexState; import com.yelp.nrtsearch.server.luceneserver.SearchHandler; +import com.yelp.nrtsearch.server.remote.RemoteBackend; +import com.yelp.nrtsearch.server.remote.RemoteBackend.IndexResourceType; +import com.yelp.nrtsearch.server.remote.s3.S3Backend; import com.yelp.nrtsearch.test_utils.AmazonS3Provider; +import java.io.BufferedReader; import java.io.BufferedWriter; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -46,9 +51,8 @@ public class WarmerTest { private final String service = "test_service"; private final String index = "test_index"; - private final String resource = "test_index_warming_queries"; private final String bucketName = "warmer-unittest"; - private Archiver archiver; + private RemoteBackend remoteBackend; private AmazonS3 s3; private Warmer warmer; @@ -57,13 +61,12 @@ public class WarmerTest { @Before public void setup() throws IOException { - Path archiverDirectory = folder.newFolder("archiver").toPath(); - + String configStr = "bucketName: " + bucketName; + LuceneServerConfiguration config = + new LuceneServerConfiguration(new ByteArrayInputStream(configStr.getBytes())); s3 = s3Provider.getAmazonS3(); - archiver = - new ArchiverImpl( - s3, bucketName, archiverDirectory, new TarImpl(TarImpl.CompressionMode.LZ4)); - warmer = new Warmer(archiver, service, index, 2); + remoteBackend = new S3Backend(config, s3); + warmer = new Warmer(remoteBackend, service, index, 2); } @Test @@ -74,11 +77,16 @@ public void testAddSearchRequest_backupWarmingQueriesToS3() throws IOException { warmer.backupWarmingQueriesToS3(service); - Path downloadPath = archiver.download(service, resource); + InputStream queriesStream = + remoteBackend.downloadStream(service, index, IndexResourceType.WARMING_QUERIES); + List lines = new ArrayList<>(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(queriesStream))) { + String line; + while ((line = reader.readLine()) != null) { + lines.add(line); + } + } - Path warmingQueriesDir = downloadPath.resolve("warming_queries"); - Path warmingQueriesFile = warmingQueriesDir.resolve("warming_queries.txt"); - List lines = Files.readAllLines(warmingQueriesFile); Assertions.assertThat(lines).containsAll(getTestSearchRequestsAsJsonStrings()); } @@ -86,8 +94,8 @@ public void testAddSearchRequest_backupWarmingQueriesToS3() throws IOException { public void testWarmFromS3() throws IOException, SearchHandler.SearchHandlerException, InterruptedException { Path warmingQueriesDir = folder.newFolder("warming_queries").toPath(); - try (BufferedWriter writer = - Files.newBufferedWriter(warmingQueriesDir.resolve("warming_queries.txt"))) { + Path warmingQueriesPath = warmingQueriesDir.resolve("warming_queries.txt"); + try (BufferedWriter writer = Files.newBufferedWriter(warmingQueriesPath)) { List testSearchRequestsJson = getTestSearchRequestsAsJsonStrings(); for (String line : testSearchRequestsJson) { writer.write(line); @@ -95,9 +103,8 @@ public void testWarmFromS3() } writer.flush(); } - String versionHash = - archiver.upload(service, resource, warmingQueriesDir, List.of(), List.of(), false); - archiver.blessVersion(service, resource, versionHash); + remoteBackend.uploadFile( + service, "test_index", IndexResourceType.WARMING_QUERIES, warmingQueriesPath); IndexState mockIndexState = mock(IndexState.class); SearchHandler mockSearchHandler = mock(SearchHandler.class); @@ -114,8 +121,8 @@ public void testWarmFromS3() public void testWarmFromS3_multiple() throws IOException, SearchHandler.SearchHandlerException, InterruptedException { Path warmingQueriesDir = folder.newFolder("warming_queries").toPath(); - try (BufferedWriter writer = - Files.newBufferedWriter(warmingQueriesDir.resolve("warming_queries.txt"))) { + Path warmingQueriesPath = warmingQueriesDir.resolve("warming_queries.txt"); + try (BufferedWriter writer = Files.newBufferedWriter(warmingQueriesPath)) { List testSearchRequestsJson = getTestSearchRequestsAsJsonStrings(); for (String line : testSearchRequestsJson) { writer.write(line); @@ -123,9 +130,8 @@ public void testWarmFromS3_multiple() } writer.flush(); } - String versionHash = - archiver.upload(service, resource, warmingQueriesDir, List.of(), List.of(), false); - archiver.blessVersion(service, resource, versionHash); + remoteBackend.uploadFile( + service, "test_index", IndexResourceType.WARMING_QUERIES, warmingQueriesPath); IndexState mockIndexState = mock(IndexState.class); SearchHandler mockSearchHandler = mock(SearchHandler.class); @@ -143,9 +149,9 @@ public void testWarmFromS3_multiple() public void testWarmFromS3_parallel() throws IOException, SearchHandler.SearchHandlerException, InterruptedException { Path warmingQueriesDir = folder.newFolder("warming_queries").toPath(); + Path warmingQueriesPath = warmingQueriesDir.resolve("warming_queries.txt"); int warmingCountPerQuery = 10; - try (BufferedWriter writer = - Files.newBufferedWriter(warmingQueriesDir.resolve("warming_queries.txt"))) { + try (BufferedWriter writer = Files.newBufferedWriter(warmingQueriesPath)) { List testSearchRequestsJson = getTestSearchRequestsAsJsonStrings(); List moreTestSearchRequestsJson = new ArrayList<>(); for (int i = 0; i < warmingCountPerQuery; i++) { @@ -157,9 +163,8 @@ public void testWarmFromS3_parallel() } writer.flush(); } - String versionHash = - archiver.upload(service, resource, warmingQueriesDir, List.of(), List.of(), false); - archiver.blessVersion(service, resource, versionHash); + remoteBackend.uploadFile( + service, "test_index", IndexResourceType.WARMING_QUERIES, warmingQueriesPath); IndexState mockIndexState = mock(IndexState.class); SearchHandler mockSearchHandler = mock(SearchHandler.class); diff --git a/src/test/java/com/yelp/nrtsearch/server/remote/s3/S3BackendTest.java b/src/test/java/com/yelp/nrtsearch/server/remote/s3/S3BackendTest.java new file mode 100644 index 000000000..80c90d09d --- /dev/null +++ b/src/test/java/com/yelp/nrtsearch/server/remote/s3/S3BackendTest.java @@ -0,0 +1,390 @@ +/* + * Copyright 2023 Yelp Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.yelp.nrtsearch.server.remote.s3; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.model.CompleteMultipartUploadRequest; +import com.amazonaws.services.s3.model.InitiateMultipartUploadRequest; +import com.amazonaws.services.s3.model.InitiateMultipartUploadResult; +import com.amazonaws.services.s3.model.PartETag; +import com.amazonaws.services.s3.model.UploadPartRequest; +import com.amazonaws.services.s3.model.UploadPartResult; +import com.yelp.nrtsearch.server.config.LuceneServerConfiguration; +import com.yelp.nrtsearch.server.remote.RemoteBackend.IndexResourceType; +import com.yelp.nrtsearch.test_utils.AmazonS3Provider; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import org.apache.commons.io.IOUtils; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; + +public class S3BackendTest { + private static final String BUCKET_NAME = "s3-backend-test"; + private static final String KEY = "test_key"; + private static final String CONTENT = "test_content"; + + @ClassRule public static final AmazonS3Provider S3_PROVIDER = new AmazonS3Provider(BUCKET_NAME); + + private static AmazonS3 s3; + private static S3Backend s3Backend; + + @BeforeClass + public static void setup() throws IOException { + String configStr = "bucketName: " + BUCKET_NAME; + LuceneServerConfiguration config = + new LuceneServerConfiguration(new ByteArrayInputStream(configStr.getBytes())); + s3 = S3_PROVIDER.getAmazonS3(); + s3Backend = new S3Backend(config, s3); + s3.putObject(BUCKET_NAME, KEY, CONTENT); + } + + @AfterClass + public static void cleanUp() { + s3Backend.close(); + } + + @Test + public void testDownloadFromS3Path() throws IOException { + InputStream inputStream = s3Backend.downloadFromS3Path(BUCKET_NAME, KEY); + String contentFromS3 = convertToString(inputStream); + assertEquals(CONTENT, contentFromS3); + + inputStream = s3Backend.downloadFromS3Path(String.format("s3://%s/%s", BUCKET_NAME, KEY)); + contentFromS3 = convertToString(inputStream); + assertEquals(CONTENT, contentFromS3); + } + + @Test + public void testDownloadFromS3Path_fileDoesNotExist() { + String s3Path = String.format("s3://%s/%s", BUCKET_NAME, "does_not_exist"); + try { + s3Backend.downloadFromS3Path(s3Path); + fail(); + } catch (IllegalArgumentException e) { + assertEquals(String.format("Object %s not found", s3Path), e.getMessage()); + } + + try { + s3Backend.downloadFromS3Path("bucket_not_exist", KEY); + fail(); + } catch (IllegalArgumentException e) { + assertEquals( + String.format("Object s3://%s/%s not found", "bucket_not_exist", KEY), e.getMessage()); + } + } + + @Test + public void testExists() throws IOException { + String resource = S3Backend.getResourceName("exist_index", IndexResourceType.WARMING_QUERIES); + String key = S3Backend.getVersionKey("exist_service", resource, S3Backend.LATEST_VERSION); + s3.putObject(BUCKET_NAME, key, "1"); + + assertTrue(s3Backend.exists("exist_service", "exist_index", IndexResourceType.WARMING_QUERIES)); + assertFalse( + s3Backend.exists("exist_service_2", "exist_index", IndexResourceType.WARMING_QUERIES)); + assertFalse( + s3Backend.exists("exist_service", "exist_index_2", IndexResourceType.WARMING_QUERIES)); + } + + @Test + public void testDownloadStream_singlePart() throws IOException { + String resource = + S3Backend.getResourceName("download_index", IndexResourceType.WARMING_QUERIES); + String latestKey = + S3Backend.getVersionKey("download_service", resource, S3Backend.LATEST_VERSION); + s3.putObject(BUCKET_NAME, latestKey, "1"); + + String versionKey = S3Backend.getVersionKey("download_service", resource, "1"); + String resourceHash = UUID.randomUUID().toString(); + s3.putObject(BUCKET_NAME, versionKey, resourceHash); + + String resourceKey = S3Backend.getResourceKey("download_service", resource, resourceHash); + s3.putObject(BUCKET_NAME, resourceKey, "resource_data"); + + InputStream downloadStream = + s3Backend.downloadStream( + "download_service", "download_index", IndexResourceType.WARMING_QUERIES); + assertEquals("resource_data", convertToString(downloadStream)); + } + + @Test + public void testDownloadStream_multiPart() throws IOException { + String resource = + S3Backend.getResourceName("download_index_2", IndexResourceType.WARMING_QUERIES); + String latestKey = + S3Backend.getVersionKey("download_service_2", resource, S3Backend.LATEST_VERSION); + s3.putObject(BUCKET_NAME, latestKey, "1"); + + String versionKey = S3Backend.getVersionKey("download_service_2", resource, "1"); + String resourceHash = UUID.randomUUID().toString(); + s3.putObject(BUCKET_NAME, versionKey, resourceHash); + + String resourceKey = S3Backend.getResourceKey("download_service_2", resource, resourceHash); + putMultiPart(resourceKey, List.of("aaaa", "bbbb", "cccc", "dddd")); + + InputStream downloadStream = + s3Backend.downloadStream( + "download_service_2", "download_index_2", IndexResourceType.WARMING_QUERIES); + assertEquals("aaaabbbbccccdddd", convertToString(downloadStream)); + } + + @Test + public void testDownloadStream_notFound() throws IOException { + try { + s3Backend.downloadStream( + "download_service_3", "download_index_3", IndexResourceType.WARMING_QUERIES); + fail(); + } catch (IllegalArgumentException e) { + assertEquals( + "Object s3://s3-backend-test/download_service_3/_version/download_index_3_warming_queries/_latest_version not found", + e.getMessage()); + } + + String resource = + S3Backend.getResourceName("download_index_3", IndexResourceType.WARMING_QUERIES); + String latestKey = + S3Backend.getVersionKey("download_service_3", resource, S3Backend.LATEST_VERSION); + s3.putObject(BUCKET_NAME, latestKey, "1"); + + try { + s3Backend.downloadStream( + "download_service_3", "download_index_3", IndexResourceType.WARMING_QUERIES); + fail(); + } catch (IllegalArgumentException e) { + assertEquals( + "Object s3://s3-backend-test/download_service_3/_version/download_index_3_warming_queries/1 not found", + e.getMessage()); + } + + String versionKey = S3Backend.getVersionKey("download_service_3", resource, "1"); + String resourceHash = UUID.randomUUID().toString(); + s3.putObject(BUCKET_NAME, versionKey, resourceHash); + + try { + s3Backend.downloadStream( + "download_service_3", "download_index_3", IndexResourceType.WARMING_QUERIES); + fail(); + } catch (IllegalArgumentException e) { + assertEquals( + "Object s3://s3-backend-test/download_service_3/download_index_3_warming_queries/" + + resourceHash + + " not found", + e.getMessage()); + } + } + + @Test + public void testDownloadStream_updateData() throws IOException { + String resource = + S3Backend.getResourceName("download_index_4", IndexResourceType.WARMING_QUERIES); + String latestKey = + S3Backend.getVersionKey("download_service_4", resource, S3Backend.LATEST_VERSION); + s3.putObject(BUCKET_NAME, latestKey, "1"); + + String versionKey = S3Backend.getVersionKey("download_service_4", resource, "1"); + String resourceHash = UUID.randomUUID().toString(); + s3.putObject(BUCKET_NAME, versionKey, resourceHash); + + String resourceKey = S3Backend.getResourceKey("download_service_4", resource, resourceHash); + s3.putObject(BUCKET_NAME, resourceKey, "resource_data_1"); + + InputStream downloadStream = + s3Backend.downloadStream( + "download_service_4", "download_index_4", IndexResourceType.WARMING_QUERIES); + assertEquals("resource_data_1", convertToString(downloadStream)); + + // update resource data + String resourceHash2 = UUID.randomUUID().toString(); + String resourceKey2 = S3Backend.getResourceKey("download_service_4", resource, resourceHash2); + s3.putObject(BUCKET_NAME, resourceKey2, "resource_data_2"); + + String versionKey2 = S3Backend.getVersionKey("download_service_4", resource, "2"); + s3.putObject(BUCKET_NAME, versionKey2, resourceHash2); + s3.putObject(BUCKET_NAME, latestKey, "2"); + + downloadStream = + s3Backend.downloadStream( + "download_service_4", "download_index_4", IndexResourceType.WARMING_QUERIES); + assertEquals("resource_data_2", convertToString(downloadStream)); + } + + @Test + public void testUploadFile() throws IOException { + File uploadFile = S3_PROVIDER.getTemporaryFolder().newFile("upload_file"); + Files.write(uploadFile.toPath(), "file_data".getBytes()); + + s3Backend.uploadFile( + "upload_service", "upload_index", IndexResourceType.WARMING_QUERIES, uploadFile.toPath()); + + String resource = S3Backend.getResourceName("upload_index", IndexResourceType.WARMING_QUERIES); + String latestKey = + S3Backend.getVersionKey("upload_service", resource, S3Backend.LATEST_VERSION); + String contents = convertToString(s3.getObject(BUCKET_NAME, latestKey).getObjectContent()); + assertEquals("0", contents); + + String versionKey = S3Backend.getVersionKey("upload_service", resource, "0"); + contents = convertToString(s3.getObject(BUCKET_NAME, versionKey).getObjectContent()); + // check parsable + UUID.fromString(contents); + + String resourceKey = S3Backend.getResourceKey("upload_service", resource, contents); + contents = convertToString(s3.getObject(BUCKET_NAME, resourceKey).getObjectContent()); + assertEquals("file_data", contents); + } + + @Test + public void testUploadFile_updateResource() throws IOException { + File uploadFile = S3_PROVIDER.getTemporaryFolder().newFile("upload_file_1"); + Files.write(uploadFile.toPath(), "file_data_1".getBytes()); + + s3Backend.uploadFile( + "upload_service_1", + "upload_index_1", + IndexResourceType.WARMING_QUERIES, + uploadFile.toPath()); + + String resource = + S3Backend.getResourceName("upload_index_1", IndexResourceType.WARMING_QUERIES); + String latestKey = + S3Backend.getVersionKey("upload_service_1", resource, S3Backend.LATEST_VERSION); + String contents = convertToString(s3.getObject(BUCKET_NAME, latestKey).getObjectContent()); + assertEquals("0", contents); + + String versionKey = S3Backend.getVersionKey("upload_service_1", resource, "0"); + contents = convertToString(s3.getObject(BUCKET_NAME, versionKey).getObjectContent()); + // check parsable + UUID.fromString(contents); + + String resourceKey = S3Backend.getResourceKey("upload_service_1", resource, contents); + contents = convertToString(s3.getObject(BUCKET_NAME, resourceKey).getObjectContent()); + assertEquals("file_data_1", contents); + + // update data + uploadFile = S3_PROVIDER.getTemporaryFolder().newFile("upload_file_2"); + Files.write(uploadFile.toPath(), "file_data_2".getBytes()); + + s3Backend.uploadFile( + "upload_service_1", + "upload_index_1", + IndexResourceType.WARMING_QUERIES, + uploadFile.toPath()); + + contents = convertToString(s3.getObject(BUCKET_NAME, latestKey).getObjectContent()); + assertEquals("1", contents); + + versionKey = S3Backend.getVersionKey("upload_service_1", resource, "1"); + contents = convertToString(s3.getObject(BUCKET_NAME, versionKey).getObjectContent()); + // check parsable + UUID.fromString(contents); + + resourceKey = S3Backend.getResourceKey("upload_service_1", resource, contents); + contents = convertToString(s3.getObject(BUCKET_NAME, resourceKey).getObjectContent()); + assertEquals("file_data_2", contents); + } + + @Test + public void testUploadFile_notExist() throws IOException { + Path path = Path.of(S3_PROVIDER.getTemporaryFolder().getRoot().toString(), "not_exist"); + try { + s3Backend.uploadFile( + "upload_service_2", "upload_index_2", IndexResourceType.WARMING_QUERIES, path); + fail(); + } catch (IllegalArgumentException e) { + assertTrue(e.getMessage().startsWith("File does not exist:")); + assertTrue(e.getMessage().contains("not_exist")); + } + } + + @Test + public void testUploadFile_notRegularFile() throws IOException { + Path path = S3_PROVIDER.getTemporaryFolder().newFolder("upload_folder").toPath(); + try { + s3Backend.uploadFile( + "upload_service_3", "upload_index_3", IndexResourceType.WARMING_QUERIES, path); + fail(); + } catch (IllegalArgumentException e) { + assertTrue(e.getMessage().startsWith("Is not regular file:")); + assertTrue(e.getMessage().contains("upload_folder")); + } + } + + @Test + public void testGetResourceName() { + assertEquals( + "index_1_warming_queries", + S3Backend.getResourceName("index_1", IndexResourceType.WARMING_QUERIES)); + } + + @Test + public void testGetResourceKey() { + assertEquals( + "test_service/test_resource/test_version_hash", + S3Backend.getResourceKey("test_service", "test_resource", "test_version_hash")); + } + + @Test + public void testGetVersionKey() { + assertEquals( + "test_service/_version/test_resource/version", + S3Backend.getVersionKey("test_service", "test_resource", "version")); + } + + private void putMultiPart(String key, List partsData) { + InitiateMultipartUploadRequest initRequest = + new InitiateMultipartUploadRequest(BUCKET_NAME, key); + InitiateMultipartUploadResult initResponse = s3.initiateMultipartUpload(initRequest); + + List partETags = new ArrayList<>(); + for (int i = 0; i < partsData.size(); ++i) { + UploadPartRequest uploadRequest = + new UploadPartRequest() + .withBucketName(BUCKET_NAME) + .withKey(key) + .withUploadId(initResponse.getUploadId()) + .withPartNumber(i + 1) + .withInputStream(new ByteArrayInputStream(partsData.get(i).getBytes())) + .withPartSize(partsData.get(i).length()); + + UploadPartResult uploadResult = s3.uploadPart(uploadRequest); + partETags.add(uploadResult.getPartETag()); + } + + CompleteMultipartUploadRequest compRequest = + new CompleteMultipartUploadRequest(BUCKET_NAME, key, initResponse.getUploadId(), partETags); + s3.completeMultipartUpload(compRequest); + } + + private String convertToString(InputStream inputStream) throws IOException { + StringWriter writer = new StringWriter(); + IOUtils.copy(inputStream, writer); + return writer.toString(); + } +} diff --git a/src/test/java/com/yelp/nrtsearch/server/utils/S3UtilTest.java b/src/test/java/com/yelp/nrtsearch/server/remote/s3/S3UtilTest.java similarity index 91% rename from src/test/java/com/yelp/nrtsearch/server/utils/S3UtilTest.java rename to src/test/java/com/yelp/nrtsearch/server/remote/s3/S3UtilTest.java index 494ff0653..906af305f 100644 --- a/src/test/java/com/yelp/nrtsearch/server/utils/S3UtilTest.java +++ b/src/test/java/com/yelp/nrtsearch/server/remote/s3/S3UtilTest.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.yelp.nrtsearch.server.utils; +package com.yelp.nrtsearch.server.remote.s3; -import static com.yelp.nrtsearch.server.utils.S3Util.getS3FileName; -import static com.yelp.nrtsearch.server.utils.S3Util.isValidS3FilePath; +import static com.yelp.nrtsearch.server.remote.s3.S3Util.getS3FileName; +import static com.yelp.nrtsearch.server.remote.s3.S3Util.isValidS3FilePath; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThrows; diff --git a/src/test/java/com/yelp/nrtsearch/server/utils/S3DownloaderTest.java b/src/test/java/com/yelp/nrtsearch/server/utils/S3DownloaderTest.java deleted file mode 100644 index 3d45e8201..000000000 --- a/src/test/java/com/yelp/nrtsearch/server/utils/S3DownloaderTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2023 Yelp Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yelp.nrtsearch.server.utils; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import com.amazonaws.services.s3.AmazonS3; -import com.yelp.nrtsearch.test_utils.AmazonS3Provider; -import java.io.IOException; -import java.io.InputStream; -import java.io.StringWriter; -import org.apache.commons.io.IOUtils; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; - -public class S3DownloaderTest { - private static final String BUCKET_NAME = "s3-downloader-test"; - private static final String KEY = "test_key"; - private static final String CONTENT = "test_content"; - - @ClassRule public static final AmazonS3Provider S3_PROVIDER = new AmazonS3Provider(BUCKET_NAME); - - private static S3Downloader s3Downloader; - - @BeforeClass - public static void setup() throws IOException { - AmazonS3 s3 = S3_PROVIDER.getAmazonS3(); - s3Downloader = new S3Downloader(s3); - s3.putObject(BUCKET_NAME, KEY, CONTENT); - } - - @AfterClass - public static void cleanUp() { - s3Downloader.close(); - } - - @Test - public void testDownloadFromS3Path() throws IOException { - InputStream inputStream = s3Downloader.downloadFromS3Path(BUCKET_NAME, KEY); - String contentFromS3 = convertToString(inputStream); - assertEquals(CONTENT, contentFromS3); - - inputStream = s3Downloader.downloadFromS3Path(String.format("s3://%s/%s", BUCKET_NAME, KEY)); - contentFromS3 = convertToString(inputStream); - assertEquals(CONTENT, contentFromS3); - } - - @Test - public void testDownloadFromS3Path_fileDoesNotExist() { - String s3Path = String.format("s3://%s/%s", BUCKET_NAME, "does_not_exist"); - try { - s3Downloader.downloadFromS3Path(s3Path); - fail(); - } catch (IllegalArgumentException e) { - assertEquals(String.format("Object %s not found", s3Path), e.getMessage()); - } - - try { - s3Downloader.downloadFromS3Path("bucket_not_exist", KEY); - fail(); - } catch (IllegalArgumentException e) { - assertEquals( - String.format("Object s3://%s/%s not found", "bucket_not_exist", KEY), e.getMessage()); - } - } - - private String convertToString(InputStream inputStream) throws IOException { - StringWriter writer = new StringWriter(); - IOUtils.copy(inputStream, writer); - return writer.toString(); - } -} diff --git a/src/test/java/com/yelp/nrtsearch/test_utils/AmazonS3Provider.java b/src/test/java/com/yelp/nrtsearch/test_utils/AmazonS3Provider.java index 43a7e5083..92240fca8 100644 --- a/src/test/java/com/yelp/nrtsearch/test_utils/AmazonS3Provider.java +++ b/src/test/java/com/yelp/nrtsearch/test_utils/AmazonS3Provider.java @@ -94,4 +94,8 @@ public String getS3DirectoryPath() { } return s3Path; } + + public TemporaryFolder getTemporaryFolder() { + return temporaryFolder; + } }