// Copyright (C) 2024 Quickwit, Inc.
//
// Quickwit is offered under the AGPL v3.0 and as commercial software.
// For commercial licensing, contact us at hello@quickwit.io.
//
// AGPL:
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

syntax = "proto3";

package quickwit.control_plane;

import "quickwit/common.proto";
import "quickwit/indexing.proto";
import "quickwit/ingest.proto";
import "quickwit/metastore.proto";

service ControlPlaneService {
  // The control plane acts as a proxy for the metastore for a subset of the API so it can track the state of the
  // metastore accurately and react to events in real-time.

  // The following RPCs are forwarded and handled by the metastore:
  // - `create_index`
  // - `update_index`
  // - `delete_index`
  // - `add_source`
  // - `toggle_source`
  // - `delete_source`

  // Index API

  // Creates a new index.
  rpc CreateIndex(quickwit.metastore.CreateIndexRequest) returns (quickwit.metastore.CreateIndexResponse);

  // Updates an index.
  rpc UpdateIndex(quickwit.metastore.UpdateIndexRequest) returns (quickwit.metastore.IndexMetadataResponse);

  // Deletes an index.
  rpc DeleteIndex(quickwit.metastore.DeleteIndexRequest) returns (quickwit.metastore.EmptyResponse);

  // Source API

  // Adds a source to an index.
  rpc AddSource(quickwit.metastore.AddSourceRequest) returns (quickwit.metastore.EmptyResponse);

  // Enables or disables a source.
  rpc ToggleSource(quickwit.metastore.ToggleSourceRequest) returns (quickwit.metastore.EmptyResponse);

  // Removes a source from an index.
  rpc DeleteSource(quickwit.metastore.DeleteSourceRequest) returns (quickwit.metastore.EmptyResponse);

  // Shard API

  // Returns the list of open shards for one or several sources. If the control plane is not able to find any
  // for a source, it will pick a pair of leader-follower ingesters and will open a new shard.
  rpc GetOrCreateOpenShards(GetOrCreateOpenShardsRequest) returns (GetOrCreateOpenShardsResponse);

  // Asks the control plane whether the shards listed in the request should be deleted or truncated.
  rpc AdviseResetShards(AdviseResetShardsRequest) returns (AdviseResetShardsResponse);

  // Performs a debounced shard pruning request to the metastore.
  rpc PruneShards(quickwit.metastore.PruneShardsRequest) returns (quickwit.metastore.EmptyResponse);
}

// Shard API

message GetOrCreateOpenShardsRequest {
  repeated GetOrCreateOpenShardsSubrequest subrequests = 1;
  repeated quickwit.ingest.ShardIds closed_shards = 2;
  // The control plane should return shards that are not present on the supplied leaders.
  //
  // The control plane does not change the status of those leaders just from this signal.
  // It will check the status of its own ingester pool.
  repeated string unavailable_leaders = 3;
}

message GetOrCreateOpenShardsSubrequest {
  uint32 subrequest_id = 1;
  string index_id = 2;
  string source_id = 3;
}

message GetOrCreateOpenShardsResponse {
  repeated GetOrCreateOpenShardsSuccess successes = 1;
  repeated GetOrCreateOpenShardsFailure failures = 2;
}

message GetOrCreateOpenShardsSuccess {
  uint32 subrequest_id = 1;
  quickwit.common.IndexUid index_uid = 2;
  string source_id = 3;
  repeated quickwit.ingest.Shard open_shards = 4;
}

enum GetOrCreateOpenShardsFailureReason {
  GET_OR_CREATE_OPEN_SHARDS_FAILURE_REASON_UNSPECIFIED = 0;
  GET_OR_CREATE_OPEN_SHARDS_FAILURE_REASON_INDEX_NOT_FOUND = 1;
  GET_OR_CREATE_OPEN_SHARDS_FAILURE_REASON_SOURCE_NOT_FOUND = 2;
  GET_OR_CREATE_OPEN_SHARDS_FAILURE_REASON_NO_INGESTERS_AVAILABLE = 3;
}

message GetOrCreateOpenShardsFailure {
  uint32 subrequest_id = 1;
  string index_id = 2;
  string source_id = 3;
  GetOrCreateOpenShardsFailureReason reason = 4;
}

message AdviseResetShardsRequest {
  repeated quickwit.ingest.ShardIds shard_ids = 1;
}

message AdviseResetShardsResponse {
  repeated quickwit.ingest.ShardIds shards_to_delete = 1;
  repeated quickwit.ingest.ShardIdPositions shards_to_truncate = 2;
}
