syntax = "proto3";

package tipb;

option java_multiple_files = true;
option java_package = "com.pingcap.tidb.tipb";

import "gogoproto/gogo.proto";
import "rustproto.proto";

option (gogoproto.marshaler_all) = true;
option (gogoproto.sizer_all) = true;
option (gogoproto.unmarshaler_all) = true;
option (gogoproto.goproto_unkeyed_all) = false;
option (gogoproto.goproto_unrecognized_all) = false;
option (gogoproto.goproto_sizecache_all) = false;
option (rustproto.lite_runtime_all) = true;

// TopSQLAgent is the persistent agent service for TopSQL records
service TopSQLAgent {
    // ReportTopSQLRecords is called periodically (e.g. per minute) to save the in-memory TopSQL records
    rpc ReportTopSQLRecords(stream TopSQLRecord) returns (EmptyResponse) {}
    // ReportSQLMeta reports SQL meta to the agent.
    // The agent should ensure that the SQL meta exists before sending the SQL CPU time records to the remote database.
    rpc ReportSQLMeta(stream SQLMeta) returns (EmptyResponse) {}
    // ReportPlanMeta reports plan meta to the agent.
    // The agent should deal with plan meta similarly to SQL meta.
    rpc ReportPlanMeta(stream PlanMeta) returns (EmptyResponse) {}
}

message TopSQLRecord {
    bytes sql_digest = 1;
    bytes plan_digest = 2;
    repeated TopSQLRecordItem items = 3;
    bytes keyspace_name = 4;
}

message TopSQLRecordItem {
    uint64 timestamp_sec = 1; // timestamp in second
    uint32 cpu_time_ms = 2; // this value can be greater than 1000 when counting concurrent running SQL queries
    uint64 stmt_exec_count = 3;
    map<string, uint64> stmt_kv_exec_count = 4; // target => count
    uint64 stmt_duration_sum_ns = 5;
    uint64 stmt_duration_count = 6;
}

message SQLMeta {
    bytes sql_digest = 1;

    // SQL text with sensitive fields trimmed.
    //
    // Producers should limit the size to less than 4KiB. Truncation can be chosen to reduce size.
    string normalized_sql = 2;

    // If true, this sql and plan is internally generated by tidb itself, not user.
    bool is_internal_sql = 3;
    bytes keyspace_name = 4;
}

message PlanMeta {
    bytes plan_digest = 1;

    // Plan text with sensitive fields trimmed.
    //
    // Producers should limit the size to less than 4KiB. Consider use `encoded_normalized_plan` if the size exceeds.
    string normalized_plan = 2;

    // If `normalized_plan` is unacceptably large, set `encoded_normalized_plan` instead.
    //
    // The textual normalized plan is expected to get by following steps:
    // 1. decode from base64
    // 2. decode from snappy
    // 3. decode from github.com/pingcap/tidb/util/plancodec.DecodeNormalizedPlan
    string encoded_normalized_plan = 3;
    bytes keyspace_name = 4;
}

message EmptyResponse {}

// TiDB implements TopSQLPubSub service for clients to subscribe to TopSQL data.
service TopSQLPubSub {
    // Clients subscribe to TopSQL data through this RPC, and TiDB periodically (e.g. per minute)
    // publishes TopSQL data to clients via gRPC stream.
    rpc Subscribe(TopSQLSubRequest) returns (stream TopSQLSubResponse) {}
}

message TopSQLSubRequest {}

message TopSQLSubResponse {
    oneof resp_oneof {
        TopSQLRecord record = 1;
        SQLMeta sql_meta = 2;
        PlanMeta plan_meta = 3;
    }
}
