#! /usr/bin/perl -w

my $labels;
my $tids = {};
my $committed = {};
my $edges = [];
my $duration = {};

sub create_labels(@) {
    my (@files) = @_;
    my $labels = {};
    my $a;
    my $z;

    a: for ($a = 0; ; $a++) {
	if (length($files[0]) <= $a) {
	    last a;
	}
	for (my $n = 1; $n < @files; $n++) {
	    if (length($files[$n]) <= $a ||
		substr($files[0], $a, 1) ne substr($files[$n], $a, 1)) {
		last a;
	    }
	}
    }
    z: for ($z = 0; ; $z++) {
	if (length($files[0]) <= $z) {
	    last z;
	}
	for (my $n = 1; $n < @files; $n++) {
	    if (length($files[$n]) <= $z ||
		substr($files[0], -($z + 1), 1) ne substr($files[$n], -($z + 1), 1)) {
		last z;
	    }
	}
    }
    for (my $n = 0; $n < @files; $n++) {
	my $label = substr($files[$n], $a);
	$label = substr($label, 0, -$z)
	    if $z;
	$labels->{$files[$n]} = $label;
    }
    return $labels;
}

$labels = create_labels(@ARGV);

foreach my $ARGV (@ARGV) {
    open STDIN, $ARGV
	or die "$ARGV: $!\n";

    my $tid;
    my $ended;

    while (<STDIN>) {
	if (/Preparing cluster-wide state change (\d+)/) {
	    print STDERR "$ARGV: $& during transaction $tid in line $.?\n"
		if $tid && !$ended;
	    $tids->{$1} = ($labels->{$ARGV} // $ARGV);
	    $tid = $1;
	    $ended = undef;
	}
	if (/(Committing|Aborting) cluster-wide state change (\d+) \((\d+)ms\)/) {
	    print STDERR "$ARGV: Ending transaction $2 instead of $tid in line $.?\n"
		if $tid ne $2;
	    $ended = 1;
	    $committed->{$2} = 1
		if $1 eq "Committing";
	    $duration->{$2} = $3;
	}

	if (/Preparing remote state change (\d+)/) {
	    print STDERR "$ARGV: $& during transaction $tid in line $.?\n"
		if $tid && !$ended;
	    $tid = $1;
	    $ended = undef;
	}
	if (/(?:Committing|Aborting) remote state change (\d+)/) {
	    print STDERR "$ARGV: Ending transaction $1 instead of $tid in line $.?\n"
		if $tid ne $1;
	    $ended = 1;
	}

	if (/Rejecting concurrent remote state change (\d+)/) {
	    if ($tid) {
		push @$edges, [$tid, $1];
	    } else {
		print STDERR "$ARGV: $1: Rejected for an unknown reason\n";
	    }
	}
    }
}

open STDOUT, "| dot -Tsvg";
print "digraph transactions {\n";
print "\trankdir=LR;\n";
foreach my $tid (keys %$tids) {
    my $attrs = [];
    push @$attrs, "label=\"$tid\\n$tids->{$tid}: $duration->{$tid}ms\""
	if exists $duration->{$tid};
    push @$attrs, "style=bold"
	if exists $committed->{$tid};
    push @$attrs, "style=dotted"
	if !exists $committed->{$tid};
    print "\t$tid" . ( @$attrs ? " [" . join(",", @$attrs) . "]" : "" ) . ";\n"
}
foreach my $edge (@$edges) {
    print "\t$edge->[0] -> $edge->[1];\n";
}
print "}\n";
close STDOUT;
