syntax = "proto3";
package deadlock;

import "gogoproto/gogo.proto";

message WaitForEntriesRequest {
}

message WaitForEntriesResponse {
	repeated WaitForEntry entries = 1 [(gogoproto.nullable) = false];
}

message WaitForEntry {
	// The transaction id that is waiting.
	uint64 txn = 1;
	// The transaction id that is being waited for.
	uint64 wait_for_txn = 2;
	// The hash value of the key is being waited for.
	uint64 key_hash = 3;
	// The key the current txn is trying to lock.
	bytes key = 4;
	// The tag came from the lock request's context.
	bytes resource_group_tag = 5;
	// Milliseconds it has been waits.
	uint64 wait_time = 6;
}

enum DeadlockRequestType {
	Detect = 0;
	// CleanUpWaitFor cleans a single entry the transaction is waiting.
	CleanUpWaitFor = 1;
	// CleanUp cleans all entries the transaction is waiting.
	CleanUp = 2;
}

message DeadlockRequest {
	DeadlockRequestType tp = 1;
	WaitForEntry entry = 2 [(gogoproto.nullable) = false];
}

message DeadlockResponse {
	// The same entry sent by DeadlockRequest, identifies the sender.
	WaitForEntry entry = 1 [(gogoproto.nullable) = false];
	// The key hash of the lock that is hold by the waiting transaction.
	uint64 deadlock_key_hash = 2;
	// The other entries of the dead lock circle. The current entry is in `entry` field and  not
	// included in this field.
	repeated WaitForEntry wait_chain = 3;
}

service Deadlock {
	// Get local wait for entries, should be handle by every node.
	// The owner should sent this request to all members to build the complete wait for graph.
	rpc GetWaitForEntries(WaitForEntriesRequest) returns (WaitForEntriesResponse) {}

	// Detect should only sent to the owner. only be handled by the owner.
	// The DeadlockResponse is sent back only if there is deadlock detected.
	// CleanUpWaitFor and CleanUp doesn't return responses.
	rpc Detect(stream DeadlockRequest) returns (stream DeadlockResponse) {}
}
