Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(server): add debug information about running transactions #820

Merged
merged 1 commit into from
Feb 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions src/server/debugcmd.cc
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ void DebugCmd::Run(CmdArgList args) {
return Inspect(key);
}

if (subcmd == "TRANSACTION") {
return TxAnalysis();
}

string reply = UnknownSubCmd(subcmd, "DEBUG");
return (*cntx_)->SendError(reply, kSyntaxErrType);
}
Expand Down Expand Up @@ -430,4 +434,61 @@ void DebugCmd::Watched() {
(*cntx_)->SendStringArr(watched_keys);
}

void DebugCmd::TxAnalysis() {
atomic_uint32_t queue_len{0}, free_cnt{0}, armed_cnt{0};

using SvLockTable = absl::flat_hash_map<string_view, IntentLock>;
vector<SvLockTable> lock_table_arr(shard_set->size());

auto cb = [&](EngineShard* shard) {
ShardId sid = shard->shard_id();

TxQueue* queue = shard->txq();

if (queue->Empty())
return;

auto cur = queue->Head();
do {
auto value = queue->At(cur);
Transaction* trx = std::get<Transaction*>(value);
queue_len.fetch_add(1, std::memory_order_relaxed);

if (trx->IsArmedInShard(sid)) {
armed_cnt.fetch_add(1, std::memory_order_relaxed);

IntentLock::Mode mode = trx->Mode();

// We consider keys from the currently assigned command inside the transaction.
// Meaning that for multi-tx it does not take into account all the keys.
KeyLockArgs lock_args = trx->GetLockArgs(sid);
auto& lock_table = lock_table_arr[sid];

// We count locks ourselves and do not rely on the lock table inside dbslice.
// The reason for this - to account for ordering information.
// For example, consider T1, T2 both residing in the queue and both lock 'x' exclusively.
// DbSlice::CheckLock returns false for both transactions, but T1 in practice owns the lock.
bool can_take = true;
for (size_t i = 0; i < lock_args.args.size(); i += lock_args.key_step) {
string_view s = lock_args.args[i];
bool was_ack = lock_table[s].Acquire(mode);
if (!was_ack) {
can_take = false;
}
}

if (can_take) {
free_cnt.fetch_add(1, std::memory_order_relaxed);
}
}
cur = queue->Next(cur);
} while (cur != queue->Head());
};

shard_set->RunBriefInParallel(cb);

(*cntx_)->SendSimpleString(absl::StrCat("queue_len:", queue_len.load(),
"armed: ", armed_cnt.load(), " free:", free_cnt.load()));
}

} // namespace dfly
1 change: 1 addition & 0 deletions src/server/debugcmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class DebugCmd {
void Load(std::string_view filename);
void Inspect(std::string_view key);
void Watched();
void TxAnalysis();

ServerFamily& sf_;
ConnectionContext* cntx_;
Expand Down