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

"ran out of memory" checking spec with a large tuple #413

Closed
ajdavis opened this issue Jan 5, 2020 · 28 comments
Closed

"ran out of memory" checking spec with a large tuple #413

ajdavis opened this issue Jan 5, 2020 · 28 comments
Labels
bug error, glitch, fault, flaw, ... Tools The command line tools - TLC, SANY, ...

Comments

@ajdavis
Copy link
Contributor

ajdavis commented Jan 5, 2020

Hello, I'm continuing development of my trace-checker. (We began discussion in #367, I'm following Ron Pressler's method from "Verifying Software Traces Against a Formal Specification
with TLA+ and TLC
".)

Currently, I have a Python script that parses a MongoDB log file and generates a TLA+ spec with a tuple of 6532 states. Each state is a tuple of variable values. Some of these values are large, including tuples up to 1014 elements long. The whole spec is 130MB of TLA+.

Here is the spec and config file.

TLC can parse this file, although it takes some time. The problem is this: TLC runs out of memory during model-checking. This surprises me, because there are only 6532 states. I increased the heap size to nearly the size of my physical RAM with -Xmx60g. That didn't prevent the crash, it only delayed it.

TLC2 Version 2.14 of 10 July 2019 (rev: 0cae24f)
Running breadth-first search Model-Checking with fp 115 and seed 4672165855747705837 with 1 worker on 16 cores with 54613MB heap and 64MB
 offheap memory (Linux 4.15.0-55-generic amd64, Private Build 1.8.0_232 x86_64, MSBDiskFPSet, DiskStateQueue).
Parsing file /mirror/co/repl-trace-checker/Trace.tla
Parsing file /tmp/Integers.tla
Parsing file /tmp/Sequences.tla
Parsing file /tmp/Naturals.tla
Parsing file /mirror/co/repl-trace-checker/RaftMongo.tla
Parsing file /tmp/FiniteSets.tla
Parsing file /tmp/TLC.tla
Semantic processing of module Naturals
Semantic processing of module Integers
Semantic processing of module Sequences
Semantic processing of module FiniteSets
Semantic processing of module TLC
Semantic processing of module RaftMongo
Semantic processing of module Trace
Error: Java ran out of memory.  Running Java with a larger memory allocation
pool (heap) may fix this.  But it won't help if some state has an enormous
number of successor states, or if TLC must compute the value of a huge set.
Finished in 03h 52min at (2020-01-05 14:13:12)

Is there a way to diagnose why TLC needs so much memory, so I can determine a solution to the problem? Do you think I should use a different data structure rather than a tuple of tuples?

@lemmy

This comment has been minimized.

@lemmy lemmy added bug error, glitch, fault, flaw, ... Tools The command line tools - TLC, SANY, ... labels Jan 5, 2020
@ajdavis

This comment has been minimized.

@lemmy
Copy link
Member

lemmy commented Jan 5, 2020

TLC2 Version 2.15 of Day Month 20??
Running breadth-first search Model-Checking with fp 32 and seed -6369847100450992759 with 1 worker on 4 cores with 5301MB heap and 64MB offheap memory [pid: 18120] (Linux 4.18.0-16-generic amd64, Private Build 11.0.5 x86_64, MSBDiskFPSet, DiskStateQueue).
Parsing file /home/markus/src/TLA/_specs/models/tlcbugs/Github413/Trace.tla
Error: Java ran out of memory.  Running Java with a larger memory allocation
pool (heap) may fix this.  But it won't help if some state has an enormous
number of successor states, or if TLC must compute the value of a huge set.
Finished in 47min 47s at (2020-01-05 16:34:55)

How long does it take TLC to parse the file (I killed it after ~5 minutes)? How many workers do you run the spec with? It is a long shot, but if more than one, please check with a single worker.

Generally, the problems indicates that we want a special operator - such as ReadTuple(n, pathToFile) - that reads tuples one by one instead of all at once. The technical challenge is to work around the deficiencies of the existing parser. Can you list the TLA+ "data types" (sequences, records, ...) and their nesting that you can foresee to need?

@lemmy
Copy link
Member

lemmy commented Jan 6, 2020

@ajdavis How do you create Trace.tla? From the looks of it, you seem to have created a Python program that takes an execution log and converts it into proper TLA+.

To skip parsing - which will be difficult to optimize - the Python program could be rewritten to convert the execution log directly into TLC's IValue instances that can then be efficiently serialized and later read back into TLC during model checking.

@ajdavis
Copy link
Contributor Author

ajdavis commented Jan 6, 2020

Thanks @lemmy. I'm not explicitly passing -workers to TLC, and I think the default number of workers is one.

The Trace.tla that you see now uses the follow data structure:

tuple (sequence of states) containing
   tuple (values for one state) containing
      int (Raft term)
      string (action name)
      tuple (Raft logs for all servers) containing
         tuple (Raft log for one server) containing
            record (one Raft log entry)
      ... a few other similar members

I think these are all the data types I'm going to need. I don't think I'll need to nest any more deeply than this.

You're correct, Trace.tla is generated with a Python script. TLC seems to take 3 minutes to parse it on my workstation. We could consider ways to optimize parsing; however, parsing does finish eventually. My top priority right now is to allow the next step (model checking?) to finish. Do you have any suggestions for how to achieve that?

One idea is: break Trace.tla into chunks. Perhaps Trace1.tla has states 1-100 inclusive, Trace2.tla has states 100-200 inclusive, and so on. I can run TLC on each TraceN.tla file and check that all the state transitions in that file are allowed by RaftMongo.tla. Since each file's last state is equal to the next file's first state, I'll be confident that the entire sequence of all files is a valid trace according to RaftMongo.tla.

@lemmy
Copy link
Member

lemmy commented Jan 6, 2020

@quaeler The bottleneck WRT parsing is:

ParseAlgorithm.FindToken("PlusCal", deTabbedSpecification, searchLoc, "");

Ideas how to make this faster (especially for specs with no PlusCal)?

@lemmy
Copy link
Member

lemmy commented Jan 6, 2020

The second bottleneck - affecting @ajdavis - is semantic processing of the parse tree:

markus@avocado:~/src/TLA/models/tlcbugs/Github413$ jstack -l 24290
2020-01-05 22:40:29
Full thread dump OpenJDK 64-Bit Server VM (11.0.5+10-post-Ubuntu-0ubuntu1.118.04 mixed mode, sharing):

Threads class SMR info:
_java_thread_list=0x00007ffa900ad260, length=13, elements={
0x00007ffafc015000, 0x00007ffafc054800, 0x00007ffafc056800, 0x00007ffafc05d800,
0x00007ffafc05f800, 0x00007ffafc061800, 0x00007ffafc063800, 0x00007ffafc0ab000,
0x00007ffafc169800, 0x00007ffafc1ad000, 0x00007ffaa0001800, 0x00007ffafc1b8000,
0x00007ffabc001000
}

"main" #1 prio=5 os_prio=0 cpu=19863,08ms elapsed=406,89s tid=0x00007ffafc015000 nid=0x5ee7 runnable  [0x00007ffb0335b000]
   java.lang.Thread.State: RUNNABLE
	at java.util.HashSet.<init>(java.base@11.0.5/HashSet.java:106)
	at tla2sany.semantic.LevelNode.<init>(LevelNode.java:70)
	at tla2sany.semantic.ExprOrOpArgNode.<init>(ExprOrOpArgNode.java:22)
	at tla2sany.semantic.ExprNode.<init>(ExprNode.java:77)
	at tla2sany.semantic.OpApplNode.<init>(OpApplNode.java:171)
	at tla2sany.semantic.Generator.processRcdForms(Generator.java:3837)
	at tla2sany.semantic.Generator.generateExpressionOrLAP(Generator.java:3194)
	at tla2sany.semantic.Generator.generateExpression(Generator.java:2816)
	at tla2sany.semantic.Generator.generateExpressionOrLAP(Generator.java:3035)
	at tla2sany.semantic.Generator.generateExpression(Generator.java:2816)
	at tla2sany.semantic.Generator.generateExpressionOrLAP(Generator.java:3035)
	at tla2sany.semantic.Generator.generateExpression(Generator.java:2816)
	at tla2sany.semantic.Generator.generateExpressionOrLAP(Generator.java:3035)
	at tla2sany.semantic.Generator.generateExpression(Generator.java:2816)
	at tla2sany.semantic.Generator.generateExpressionOrLAP(Generator.java:3035)
	at tla2sany.semantic.Generator.generateExpression(Generator.java:2816)
	at tla2sany.semantic.Generator.processOperator(Generator.java:2436)
	at tla2sany.semantic.Generator.generateModule(Generator.java:2032)
	at tla2sany.semantic.Generator.generate(Generator.java:1973)
	at tla2sany.drivers.SANY.frontEndSemanticAnalysis(SANY.java:301)
	at tla2sany.drivers.SANY.frontEndMain(SANY.java:130)
	at tlc2.tool.impl.SpecProcessor.processSpec(SpecProcessor.java:318)
	at tlc2.tool.impl.SpecProcessor.<init>(SpecProcessor.java:157)
	at tlc2.tool.impl.Spec.<init>(Spec.java:121)
	at tlc2.tool.impl.Tool.<init>(Tool.java:126)
	at tlc2.tool.impl.Tool.<init>(Tool.java:121)
	at tlc2.tool.impl.Tool.<init>(Tool.java:116)
	at tlc2.TLC.process(TLC.java:930)
	at tlc2.TLC.main(TLC.java:247)

   Locked ownable synchronizers:
	- None

...
markus@avocado:~/src/TLA/models/tlcbugs/Github413$ jstack -l 24290
2020-01-05 22:41:45
Full thread dump OpenJDK 64-Bit Server VM (11.0.5+10-post-Ubuntu-0ubuntu1.118.04 mixed mode, sharing):

Threads class SMR info:
_java_thread_list=0x00007ffa900ad260, length=13, elements={
0x00007ffafc015000, 0x00007ffafc054800, 0x00007ffafc056800, 0x00007ffafc05d800,
0x00007ffafc05f800, 0x00007ffafc061800, 0x00007ffafc063800, 0x00007ffafc0ab000,
0x00007ffafc169800, 0x00007ffafc1ad000, 0x00007ffaa0001800, 0x00007ffafc1b8000,
0x00007ffabc001000
}

"main" #1 prio=5 os_prio=0 cpu=19863,92ms elapsed=483,49s tid=0x00007ffafc015000 nid=0x5ee7 runnable  [0x00007ffb0335b000]
   java.lang.Thread.State: RUNNABLE
	at tla2sany.semantic.LevelNode.<init>(LevelNode.java:85)
	at tla2sany.semantic.ExprOrOpArgNode.<init>(ExprOrOpArgNode.java:22)
	at tla2sany.semantic.ExprNode.<init>(ExprNode.java:77)
	at tla2sany.semantic.NumeralNode.<init>(NumeralNode.java:43)
	at tla2sany.semantic.Generator.generateExpressionOrLAP(Generator.java:2838)
	at tla2sany.semantic.Generator.generateExpression(Generator.java:2816)
	at tla2sany.semantic.Generator.processRcdForms(Generator.java:3830)
	at tla2sany.semantic.Generator.generateExpressionOrLAP(Generator.java:3194)
	at tla2sany.semantic.Generator.generateExpression(Generator.java:2816)
	at tla2sany.semantic.Generator.generateExpressionOrLAP(Generator.java:3035)
	at tla2sany.semantic.Generator.generateExpression(Generator.java:2816)
	at tla2sany.semantic.Generator.generateExpressionOrLAP(Generator.java:3035)
	at tla2sany.semantic.Generator.generateExpression(Generator.java:2816)
	at tla2sany.semantic.Generator.generateExpressionOrLAP(Generator.java:3035)
	at tla2sany.semantic.Generator.generateExpression(Generator.java:2816)
	at tla2sany.semantic.Generator.generateExpressionOrLAP(Generator.java:3035)
	at tla2sany.semantic.Generator.generateExpression(Generator.java:2816)
	at tla2sany.semantic.Generator.processOperator(Generator.java:2436)
	at tla2sany.semantic.Generator.generateModule(Generator.java:2032)
	at tla2sany.semantic.Generator.generate(Generator.java:1973)
	at tla2sany.drivers.SANY.frontEndSemanticAnalysis(SANY.java:301)
	at tla2sany.drivers.SANY.frontEndMain(SANY.java:130)
	at tlc2.tool.impl.SpecProcessor.processSpec(SpecProcessor.java:318)
	at tlc2.tool.impl.SpecProcessor.<init>(SpecProcessor.java:157)
	at tlc2.tool.impl.Spec.<init>(Spec.java:121)
	at tlc2.tool.impl.Tool.<init>(Tool.java:126)
	at tlc2.tool.impl.Tool.<init>(Tool.java:121)
	at tlc2.tool.impl.Tool.<init>(Tool.java:116)
	at tlc2.TLC.process(TLC.java:930)
	at tlc2.TLC.main(TLC.java:247)

   Locked ownable synchronizers:
	- None

I haven't checked if this particular code can be made faster, but I'm generally skeptical: SANY has not been designed with large specs in mind. The Generator is definitely not written to bulk-load large amounts of "data". We will have to come up with a more efficient mechanism to load it that skips the existing syntactic and semantic processing steps.

@lemmy
Copy link
Member

lemmy commented Jan 6, 2020

@ajdavis Can you share the original execution log?

@ajdavis
Copy link
Contributor Author

ajdavis commented Jan 6, 2020

Sure, I've added three log files to the Dropbox folder. They were written by three MongoDB server processes acting as a replica set (also known as a "Raft group"):

https://www.dropbox.com/sh/nq1guc0nqv940ns/AAC1031rhi5sxCziig4rUSOFa?dl=0

My Python script merges these three server process's logs (sorting by timestamp), reads JSON representations of the states, and writes Trace.tla.

Earlier I made a mistake and duplicated one of the logs; now that I've removed the duplicate, Trace.tla is only 97MB, not 130MB. I've updated the Trace.tla in the Dropbox folder. Model-checking now completes in a couple minutes! I haven't investigated why, I'm surprised that fixing my mistake and reducing the size of Trace.tla by a moderate amount has had such a large effect.

@lemmy
Copy link
Member

lemmy commented Jan 6, 2020

I hacked a TLC module override for your trace file that parse the trace into memory relying on the schema outlined above:

/*******************************************************************************
 * Copyright (c) 2020 Microsoft Research. All rights reserved. 
 *
 * The MIT License (MIT)
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy 
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software. 
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * Contributors:
 *   Markus Alexander Kuppe - initial API and implementation
 ******************************************************************************/
package tlc2.overrides;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import tlc2.value.IValue;
import tlc2.value.impl.IntValue;
import tlc2.value.impl.RecordValue;
import tlc2.value.impl.StringValue;
import tlc2.value.impl.TupleValue;
import tlc2.value.impl.Value;
import util.UniqueString;

public class IOUtils {

	private static List<String> allLines;
	static {
		try {
			allLines = Files.readAllLines(Paths.get("Trace.txt"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	@TLAPlusOperator(identifier = "Trace", module = "Trace")
	public static final IValue readline(final IntValue idx) throws IOException {
		String line = allLines.get(idx.val - 1);
//		final String bak = new String(line.substring(0, line.length() - 1));

		final Value[] values = new Value[6];

		// Skip first tuple marker.
		line = line.substring(2);

		// field 0:
		values[0] = IntValue.gen(Integer.parseInt(line.substring(0, 1)));
		line = line.substring(3);

		// field 1:
		int indexOf = line.indexOf('"');
		values[1] = new StringValue(line.substring(0, indexOf));
		line = line.substring(indexOf + 2);

		// field 2: find end of first triple.
		indexOf = line.indexOf(">>>>");
		String triple = line.substring(2, indexOf + 2);
		line = line.substring(indexOf + 5);

		Matcher matcher = f2.matcher(triple);
		matcher.find();

		Value[] triplet = new Value[3];
		triplet[0] = tupleToRecordsWrap(matcher.group(1));
		triplet[1] = tupleToRecordsWrap(matcher.group(2));
		triplet[2] = tupleToRecordsWrap(matcher.group(3));
		values[2] = new TupleValue(triplet);

		// field 3: <<"Leader","Follower","Follower">>,
		indexOf = line.indexOf(">>");
		String substring = line.substring(2, indexOf);
		line = line.substring(indexOf + 3);
		String[] split2 = substring.split(",");
		Value[] stngs = new Value[3];
		for (int i = 0; i < split2.length; i++) {
			stngs[i] = new StringValue(split2[i].replace("\"", ""));
		}
		values[3] = new TupleValue(stngs);

		// field 4:
		indexOf = line.indexOf(">>");
		values[4] = tupleToRecords(line.substring(0, indexOf + 2));
		line = line.substring(indexOf + 3);

		// field 5:
		indexOf = line.lastIndexOf('"');
		values[5] = new StringValue(line.substring(1, indexOf));

		TupleValue tupleValue = new TupleValue(values);
//		String replaceAll = tupleValue.toString().replaceAll("\\s", "");
//		assert replaceAll.equals(bak.replaceAll("\\s", ""));
		return tupleValue;
	}

	private static final Pattern f2 = Pattern.compile("<<(.*?)>>,<<(.*?)>>,<<(.*?)>>");
	
	private static final Pattern pattern = Pattern.compile("(\\[.*?\\])");
	
	private static Value tupleToRecordsWrap(String tuple) {
		return tupleToRecords("<<"+tuple+">>");
	}

	private static Value tupleToRecords(String tuple) {
		if ("<<>>".equals(tuple))
			return TupleValue.EmptyTuple;

		String rcds = tuple.substring(2, tuple.length() - 2);
		List<Value> v = new ArrayList<>();

		Matcher matcher = pattern.matcher(rcds);
		while (matcher.find()) {
			String group = matcher.group();
			v.add(toRecord(group));
		}
		return new TupleValue(v.toArray(new Value[v.size()]));
	}

	private static Value toRecord(String rcd) {
		rcd = rcd.substring(1, rcd.length() - 1);
		String[] split = rcd.split(",");

		UniqueString[] keys = new UniqueString[split.length];
		Value[] vals = new Value[split.length];

		for (int i = 0; i < split.length; i++) {
			String[] kv = split[i].trim().split(" \\|-> ");
			keys[i] = UniqueString.uniqueStringOf(kv[0]);
			vals[i] = IntValue.gen(Integer.parseInt(kv[1]));
		}
		return new RecordValue(keys, vals, false);
	}
}

with Trace.tla simplified to:

--------------------------------- MODULE Trace ---------------------------------
EXTENDS Integers, Sequences

\* Generated by repl-trace-checker.py 2020-01-05 09:49:06.209179 local time.
\* This execution trace was generated from an actual replica set's log files.
\* Each tuple is <<globalCurrentTerm, action, log, state, commitPoint, serverLogLocation>>

TraceLen == 72
Trace(idx) == TRUE


\* Adapted from Pressler 2018, including Pressler's comments.

VARIABLES globalCurrentTerm, log, state, commitPoint
Model == INSTANCE RaftMongo WITH
  MaxClientWriteSize <- 11,
  Server <- {1, 2, 3}

vars == <<globalCurrentTerm, log, state, commitPoint>>

VARIABLE i \* the trace index

\* "Reading" a record is just vars = Trace(i), but unfortunately TLC isn’t happy
\* with that, so:
Read == LET Rec == Trace(i)
        IN
           /\ globalCurrentTerm = Rec[1]
           /\ log = Rec[3]
           /\ state = Rec[4]
           /\ commitPoint = Rec[5]

\* Unfortunately, TLC also isn’t happy with just Read' – which is equivalent to:
ReadNext == LET Rec == Trace(i')
            IN
               /\ globalCurrentTerm' = Rec[1]
               /\ log' = Rec[3]
               /\ state' = Rec[4]
               /\ commitPoint' = Rec[5]

Init == i = 1 /\ Read
Next == \/ i < TraceLen /\ i' = i + 1 /\ ReadNext
        \/ UNCHANGED <<i, vars>> \* So that we don’t get a deadlock error in TLC

TraceBehavior == Init /\ [][Next]_<<vars, i>>

\* Because we’re dealing with a finite trace, we only care about safety
\* properties, as liveness concerns only infinite behaviors.
THEOREM TraceBehavior => Model!SpecBehavior

\* To verify, we check the spec TraceBehavior in TLC , with Model!SpecBehavior
\* as a temporal property. As we’re always wary of success, we modify the above
\* trace to ensure that TLC finds an error.

\* Added by A. Jesse Jiryu Davis, for command-line model checking with TLC:
SpecBehavior == Model!SpecBehavior

===============================================================================

and Trace.txt:

<<0,"Init",<<<<>>,<<>>,<<>>>>,<<"Follower","Follower","Follower">>,<<[term |-> 0, index |-> 0],[term |-> 0, index |-> 0],[term |-> 0, index |-> 0]>>,"">>,
<<1,"BecomePrimaryByMagic",<<<<>>,<<>>,<<>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 0, index |-> 0],[term |-> 0, index |-> 0],[term |-> 0, index |-> 0]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:412">>,
<<1,"ClientWrite",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<>>,<<>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 0, index |-> 0],[term |-> 0, index |-> 0],[term |-> 0, index |-> 0]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:426">>,
<<1,"AdvanceCommitPoint",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<>>,<<>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 4],[term |-> 0, index |-> 0],[term |-> 0, index |-> 0]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:459">>,
<<1,"ClientWrite",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<>>,<<>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 4],[term |-> 0, index |-> 0],[term |-> 0, index |-> 0]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:461">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 4],[term |-> 1, index |-> 4],[term |-> 0, index |-> 0]>>,"/home/emptysquare/RollbackFuzzer/mongod.log:455">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 4],[term |-> 1, index |-> 4],[term |-> 1, index |-> 4]>>,"/home/emptysquare/RollbackFuzzer/mongod1.log:455">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 4],[term |-> 1, index |-> 4],[term |-> 1, index |-> 4]>>,"/home/emptysquare/RollbackFuzzer/mongod2.log:455">>,
<<1,"AppendOplog",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 4],[term |-> 1, index |-> 4],[term |-> 1, index |-> 4]>>,"/home/emptysquare/RollbackFuzzer/mongod.log:456">>,
<<1,"AppendOplog",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 4],[term |-> 1, index |-> 4],[term |-> 1, index |-> 4]>>,"/home/emptysquare/RollbackFuzzer/mongod1.log:456">>,
<<1,"AppendOplog",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 4],[term |-> 1, index |-> 4],[term |-> 1, index |-> 4]>>,"/home/emptysquare/RollbackFuzzer/mongod2.log:456">>,
<<1,"ClientWrite",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 4],[term |-> 1, index |-> 4],[term |-> 1, index |-> 4]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:473">>,
<<1,"AdvanceCommitPoint",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 5],[term |-> 1, index |-> 4],[term |-> 1, index |-> 4]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:475">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 5],[term |-> 1, index |-> 4],[term |-> 1, index |-> 5]>>,"/home/emptysquare/RollbackFuzzer/mongod1.log:457">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 5],[term |-> 1, index |-> 5],[term |-> 1, index |-> 5]>>,"/home/emptysquare/RollbackFuzzer/mongod.log:457">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 5],[term |-> 1, index |-> 5],[term |-> 1, index |-> 5]>>,"/home/emptysquare/RollbackFuzzer/mongod2.log:457">>,
<<1,"AppendOplog",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 5],[term |-> 1, index |-> 5],[term |-> 1, index |-> 5]>>,"/home/emptysquare/RollbackFuzzer/mongod.log:458">>,
<<1,"AppendOplog",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 5],[term |-> 1, index |-> 5],[term |-> 1, index |-> 5]>>,"/home/emptysquare/RollbackFuzzer/mongod1.log:458">>,
<<1,"AppendOplog",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 5],[term |-> 1, index |-> 5],[term |-> 1, index |-> 5]>>,"/home/emptysquare/RollbackFuzzer/mongod2.log:458">>,
<<1,"AdvanceCommitPoint",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 6],[term |-> 1, index |-> 5],[term |-> 1, index |-> 5]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:476">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 6],[term |-> 1, index |-> 5],[term |-> 1, index |-> 6]>>,"/home/emptysquare/RollbackFuzzer/mongod1.log:459">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 6],[term |-> 1, index |-> 6],[term |-> 1, index |-> 6]>>,"/home/emptysquare/RollbackFuzzer/mongod.log:459">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 6],[term |-> 1, index |-> 6],[term |-> 1, index |-> 6]>>,"/home/emptysquare/RollbackFuzzer/mongod2.log:459">>,
<<1,"ClientWrite",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 6],[term |-> 1, index |-> 6],[term |-> 1, index |-> 6]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:537">>,
<<1,"ClientWrite",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 6],[term |-> 1, index |-> 6],[term |-> 1, index |-> 6]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:538">>,
<<1,"AppendOplog",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 6],[term |-> 1, index |-> 6],[term |-> 1, index |-> 6]>>,"/home/emptysquare/RollbackFuzzer/mongod1.log:514">>,
<<1,"AppendOplog",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 6],[term |-> 1, index |-> 6],[term |-> 1, index |-> 6]>>,"/home/emptysquare/RollbackFuzzer/mongod.log:514">>,
<<1,"AppendOplog",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 6],[term |-> 1, index |-> 6],[term |-> 1, index |-> 6]>>,"/home/emptysquare/RollbackFuzzer/mongod2.log:514">>,
<<1,"AdvanceCommitPoint",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 7],[term |-> 1, index |-> 6],[term |-> 1, index |-> 6]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:539">>,
<<1,"AppendOplog",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 7],[term |-> 1, index |-> 6],[term |-> 1, index |-> 6]>>,"/home/emptysquare/RollbackFuzzer/mongod1.log:516">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 7],[term |-> 1, index |-> 7],[term |-> 1, index |-> 6]>>,"/home/emptysquare/RollbackFuzzer/mongod.log:516">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 7],[term |-> 1, index |-> 7],[term |-> 1, index |-> 6]>>,"/home/emptysquare/RollbackFuzzer/mongod2.log:516">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 7],[term |-> 1, index |-> 7],[term |-> 1, index |-> 7]>>,"/home/emptysquare/RollbackFuzzer/mongod1.log:517">>,
<<1,"AppendOplog",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 7],[term |-> 1, index |-> 7],[term |-> 1, index |-> 7]>>,"/home/emptysquare/RollbackFuzzer/mongod.log:517">>,
<<1,"AppendOplog",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 7],[term |-> 1, index |-> 7],[term |-> 1, index |-> 7]>>,"/home/emptysquare/RollbackFuzzer/mongod2.log:517">>,
<<1,"AdvanceCommitPoint",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 8],[term |-> 1, index |-> 7],[term |-> 1, index |-> 7]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:540">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 8],[term |-> 1, index |-> 8],[term |-> 1, index |-> 7]>>,"/home/emptysquare/RollbackFuzzer/mongod.log:518">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 8],[term |-> 1, index |-> 8],[term |-> 1, index |-> 8]>>,"/home/emptysquare/RollbackFuzzer/mongod1.log:518">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 8],[term |-> 1, index |-> 8],[term |-> 1, index |-> 8]>>,"/home/emptysquare/RollbackFuzzer/mongod2.log:518">>,
<<1,"ClientWrite",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 8],[term |-> 1, index |-> 8],[term |-> 1, index |-> 8]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:581">>,
<<1,"ClientWrite",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 8],[term |-> 1, index |-> 8],[term |-> 1, index |-> 8]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:582">>,
<<1,"AppendOplog",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 8],[term |-> 1, index |-> 8],[term |-> 1, index |-> 8]>>,"/home/emptysquare/RollbackFuzzer/mongod1.log:557">>,
<<1,"AdvanceCommitPoint",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 9],[term |-> 1, index |-> 8],[term |-> 1, index |-> 8]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:584">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 9],[term |-> 1, index |-> 8],[term |-> 1, index |-> 9]>>,"/home/emptysquare/RollbackFuzzer/mongod1.log:559">>,
<<1,"AppendOplog",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 9],[term |-> 1, index |-> 8],[term |-> 1, index |-> 9]>>,"/home/emptysquare/RollbackFuzzer/mongod1.log:560">>,
<<1,"ClientWrite",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 9],[term |-> 1, index |-> 8],[term |-> 1, index |-> 9]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:586">>,
<<1,"AdvanceCommitPoint",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 10],[term |-> 1, index |-> 8],[term |-> 1, index |-> 9]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:587">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 10],[term |-> 1, index |-> 8],[term |-> 1, index |-> 10]>>,"/home/emptysquare/RollbackFuzzer/mongod1.log:561">>,
<<1,"AppendOplog",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 10],[term |-> 1, index |-> 8],[term |-> 1, index |-> 10]>>,"/home/emptysquare/RollbackFuzzer/mongod1.log:564">>,
<<1,"AdvanceCommitPoint",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 11],[term |-> 1, index |-> 8],[term |-> 1, index |-> 10]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:592">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 11],[term |-> 1, index |-> 8],[term |-> 1, index |-> 11]>>,"/home/emptysquare/RollbackFuzzer/mongod1.log:565">>,
<<1,"ClientWrite",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 11],[term |-> 1, index |-> 8],[term |-> 1, index |-> 11]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:596">>,
<<1,"ClientWrite",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 11],[term |-> 1, index |-> 8],[term |-> 1, index |-> 11]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:602">>,
...

You can download a custom TLC build at https://tla.msr-inria.inria.fr/kuppe/tla2tools-gh413.jar.

TLC finds a violation for a state for which I don't have the time to check if it is due to a parsing bug:

markus@avocado:~/src/TLA/models/tlcbugs/Github413$ java -jar tla2tools-gh413.jar Trace
TLC2 Version 2.15 of Day Month 20?? (rev: d144879)
Warning: Please run the Java VM which executes TLC with a throughput optimized garbage collector by passing the "-XX:+UseParallelGC" property.
(Use the -nowarning option to disable this warning.)
Running breadth-first search Model-Checking with fp 105 and seed 68364854445761522 with 1 worker on 4 cores with 5964MB heap and 64MB offheap memory [pid: 17419] (Linux 4.18.0-16-generic amd64, Private Build 11.0.5 x86_64, MSBDiskFPSet, DiskStateQueue).
Parsing file /home/markus/src/TLA/_specs/models/tlcbugs/Github413/Trace.tla.plain
Parsing file /tmp/Integers.tla
Parsing file /tmp/Sequences.tla
Parsing file /tmp/Naturals.tla
Parsing file /home/markus/src/TLA/_specs/models/tlcbugs/Github413/RaftMongo.tla
Parsing file /tmp/FiniteSets.tla
Parsing file /tmp/TLC.tla
Semantic processing of module Naturals
Semantic processing of module Integers
Semantic processing of module Sequences
Semantic processing of module FiniteSets
Semantic processing of module TLC
Semantic processing of module RaftMongo
Semantic processing of module Trace
Starting... (2020-01-06 13:46:18)
Loading Trace operator override from tlc2.overrides.IOUtils with signature: <Java Method: public static final tlc2.value.IValue tlc2.overrides.IOUtils.readline(tlc2.value.impl.IntValue) throws java.io.IOException>.
Computing initial states...
Finished computing initial states: 1 distinct state generated at 2020-01-06 13:46:18.
Error: Action property line 268, col 25 to line 268, col 37 of module RaftMongo is violated.
Error: The behavior up to this point is:
State 1: <Initial predicate>
/\ globalCurrentTerm = 0
/\ log = <<<<>>, <<>>, <<>>>>
/\ i = 1
/\ state = <<"Follower", "Follower", "Follower">>
/\ commitPoint = << [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0] >>

State 2: <Next line 41, col 12 to line 41, col 49 of module Trace>
/\ globalCurrentTerm = 1
/\ log = <<<<>>, <<>>, <<>>>>
/\ i = 2
/\ state = <<"Leader", "Follower", "Follower">>
/\ commitPoint = << [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0] >>

State 3: <Next line 41, col 12 to line 41, col 49 of module Trace>
/\ globalCurrentTerm = 1
/\ log = <<<<[term |-> 1], [term |-> 1], [term |-> 1], [term |-> 1]>>, <<>>, <<>>>>
/\ i = 3
/\ state = <<"Leader", "Follower", "Follower">>
/\ commitPoint = << [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0] >>

State 4: <Next line 41, col 12 to line 41, col 49 of module Trace>
/\ globalCurrentTerm = 1
/\ log = <<<<[term |-> 1], [term |-> 1], [term |-> 1], [term |-> 1]>>, <<>>, <<>>>>
/\ i = 4
/\ state = <<"Leader", "Follower", "Follower">>
/\ commitPoint = << [index |-> 4, term |-> 1],
   [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0] >>

6 states generated, 4 distinct states found, 0 states left on queue.
The depth of the complete state graph search is 4.
The average outdegree of the complete state graph is 1 (minimum is 1, the maximum 1 and the 95th percentile is 1).
Finished in 00s at (2020-01-06 13:46:18)

Generally, this is upside-down. Instead of parsing the output of your Python script, a Java program should parse your exec log into Value instances directly.

@ajdavis
Copy link
Contributor Author

ajdavis commented Jan 6, 2020

That spec violation is expected - fixing that is my next hurdle. Therefore, seeing that spec violation shows that your code is working correctly, thank you!

@lemmy
Copy link
Member

lemmy commented Jan 6, 2020

For the complete log of 6351 lines, TLC takes ~20secs to read Trace.txt and model check it.

lemmy added a commit that referenced this issue Jan 6, 2020
@ajdavis
Copy link
Contributor Author

ajdavis commented Jan 7, 2020

This is excellent, I really appreciate it. If I wanted to continue development, what would be a less hacky way to proceed? Create a custom module like one of these?:

https://github.com/tlaplus/CommunityModules/tree/master/modules/tlc2/overrides

Could I use this technique with a standard tla2tools.jar?

@lemmy
Copy link
Member

lemmy commented Jan 7, 2020

@ajdavis

Trace.tla (Note IOUtils module and IODeserialize operator)

--------------------------------- MODULE Trace ---------------------------------
EXTENDS Integers, Sequences, IOUtils

\* Generated by repl-trace-checker.py 2020-01-05 09:49:06.209179 local time.
\* This execution trace was generated from an actual replica set's log files.
\* Each tuple is <<globalCurrentTerm, action, log, state, commitPoint, serverLogLocation>>

Trace == IODeserialize("Trace.bin", TRUE)

\* Adapted from Pressler 2018, including Pressler's comments.

VARIABLES globalCurrentTerm, log, state, commitPoint
Model == INSTANCE RaftMongo WITH
  MaxClientWriteSize <- 11,
  Server <- {1, 2, 3}

vars == <<globalCurrentTerm, log, state, commitPoint>>

VARIABLE i \* the trace index

\* "Reading" a record is just vars = Trace(i), but unfortunately TLC isn’t happy
\* with that, so:
Read == LET Rec == Trace[i]
        IN
           /\ globalCurrentTerm = Rec[1]
           /\ log = Rec[3]
           /\ state = Rec[4]
           /\ commitPoint = Rec[5]

\* Unfortunately, TLC also isn’t happy with just Read' – which is equivalent to:
ReadNext == LET Rec == Trace[i']
            IN
               /\ globalCurrentTerm' = Rec[1]
               /\ log' = Rec[3]
               /\ state' = Rec[4]
               /\ commitPoint' = Rec[5]

Init == i = 1 /\ Read
Next == \/ i < Len(Trace) /\ i' = i + 1 /\ ReadNext
        \/ UNCHANGED <<i, vars>> \* So that we don’t get a deadlock error in TLC

TraceBehavior == Init /\ [][Next]_<<vars, i>>

\* Because we’re dealing with a finite trace, we only care about safety
\* properties, as liveness concerns only infinite behaviors.
THEOREM TraceBehavior => Model!SpecBehavior

\* To verify, we check the spec TraceBehavior in TLC , with Model!SpecBehavior
\* as a temporal property. As we’re always wary of success, we modify the above
\* trace to ensure that TLC finds an error.

\* Added by A. Jesse Jiryu Davis, for command-line model checking with TLC:
SpecBehavior == Model!SpecBehavior

===============================================================================

Trace.txt

<<0,"Init",<<<<>>,<<>>,<<>>>>,<<"Follower","Follower","Follower">>,<<[term |-> 0, index |-> 0],[term |-> 0, index |-> 0],[term |-> 0, index |-> 0]>>,"">>,
<<1,"BecomePrimaryByMagic",<<<<>>,<<>>,<<>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 0, index |-> 0],[term |-> 0, index |-> 0],[term |-> 0, index |-> 0]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:412">>,
<<1,"ClientWrite",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<>>,<<>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 0, index |-> 0],[term |-> 0, index |-> 0],[term |-> 0, index |-> 0]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:426">>,
<<1,"AdvanceCommitPoint",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<>>,<<>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 4],[term |-> 0, index |-> 0],[term |-> 0, index |-> 0]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:459">>,
<<1,"ClientWrite",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<>>,<<>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 4],[term |-> 0, index |-> 0],[term |-> 0, index |-> 0]>>,"/home/emptysquare/RollbackFuzzer/mongod0.log:461">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 4],[term |-> 1, index |-> 4],[term |-> 0, index |-> 0]>>,"/home/emptysquare/RollbackFuzzer/mongod.log:455">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 4],[term |-> 1, index |-> 4],[term |-> 1, index |-> 4]>>,"/home/emptysquare/RollbackFuzzer/mongod1.log:455">>,
<<1,"LearnCommitPointFromSyncSourceNeverBeyondLastApplied",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 4],[term |-> 1, index |-> 4],[term |-> 1, index |-> 4]>>,"/home/emptysquare/RollbackFuzzer/mongod2.log:455">>,
<<1,"AppendOplog",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 4],[term |-> 1, index |-> 4],[term |-> 1, index |-> 4]>>,"/home/emptysquare/RollbackFuzzer/mongod.log:456">>,
<<1,"AppendOplog",<<<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>,<<[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1],[term |-> 1]>>>>,<<"Leader","Follower","Follower">>,<<[term |-> 1, index |-> 4],[term |-> 1, index |-> 4],[term |-> 1, index |-> 4]>>,"/home/emptysquare/RollbackFuzzer/mongod1.log:456">>,
...

Jars:

Parse Trace.txt into TLA+ values (Trace.bin)

markus@avocado:~/src/TLA/models/tlcbugs/Github413$ java -cp tla2tools.jar:mongo2tla.jar tlc2.contrib.MongoToTLA Trace.txt Trace.bin
Parsing 6351 lines in Trace.txt to Trace.bin.
Successfully parsed Trace.txt to Trace.bin.
markus@avocado:~/src/TLA/models/tlcbugs/Github413$ ls -lah Trace.bin
-rw-r--r-- 1 markus markus 1,1M Jan  6 20:47 Trace.bin

Check trace with TLC

markus@avocado:~/src/TLA/models/tlcbugs/Github413$ java -cp CommunityModules-202001070430.jar:tla2tools.jar tlc2.TLC Trace
TLC2 Version 2.15 of Day Month 20?? (rev: e6ec62b)
Warning: Please run the Java VM which executes TLC with a throughput optimized garbage collector by passing the "-XX:+UseParallelGC" property.
(Use the -nowarning option to disable this warning.)
Running breadth-first search Model-Checking with fp 64 and seed 7241795494624237021 with 1 worker on 4 cores with 5964MB heap and 64MB offheap memory [pid: 15787] (Linux 4.18.0-16-generic amd64, Private Build 11.0.5 x86_64, MSBDiskFPSet, DiskStateQueue).
Parsing file /home/markus/src/TLA/_specs/models/tlcbugs/Github413/Trace.tla.plain
Parsing file /tmp/Integers.tla
Parsing file /tmp/Sequences.tla
Parsing file /tmp/IOUtils.tla
Parsing file /tmp/Naturals.tla
Parsing file /home/markus/src/TLA/_specs/models/tlcbugs/Github413/RaftMongo.tla
Parsing file /tmp/FiniteSets.tla
Parsing file /tmp/TLC.tla
Semantic processing of module Naturals
Semantic processing of module Integers
Semantic processing of module Sequences
Semantic processing of module FiniteSets
Semantic processing of module TLC
Semantic processing of module IOUtils
Semantic processing of module RaftMongo
Semantic processing of module Trace
Starting... (2020-01-06 20:49:39)
Failed to match TLCExt!AssertError operator override from jar:file:/home/markus/src/TLA/_specs/models/tlcbugs/Github413/CommunityModules-202001070430.jar!/tlc2/overrides/TLCExt.class with signature: <Java Method: public static synchronized tlc2.value.impl.Value tlc2.overrides.TLCExt.assertError(tlc2.tool.impl.Tool,tla2sany.semantic.ExprOrOpArgNode[],tlc2.util.Context,tlc2.tool.TLCState,tlc2.tool.TLCState,int,tlc2.tool.coverage.CostModel)> (no such module).
Failed to match TLCExt!PickSuccessor operator override from jar:file:/home/markus/src/TLA/_specs/models/tlcbugs/Github413/CommunityModules-202001070430.jar!/tlc2/overrides/TLCExt.class with signature: <Java Method: public static synchronized tlc2.value.impl.Value tlc2.overrides.TLCExt.pickSuccessor(tlc2.tool.impl.Tool,tla2sany.semantic.ExprOrOpArgNode[],tlc2.util.Context,tlc2.tool.TLCState,tlc2.tool.TLCState,int,tlc2.tool.coverage.CostModel)> (no such module).
Loading IODeserialize operator override from tlc2.overrides.IOUtils with signature: <Java Method: public static final tlc2.value.IValue tlc2.overrides.IOUtils.deserialize(tlc2.value.impl.StringValue,tlc2.value.impl.BoolValue) throws java.io.IOException>.
Loading IOSerialize operator override from tlc2.overrides.IOUtils with signature: <Java Method: public static final tlc2.value.IValue tlc2.overrides.IOUtils.serialize(tlc2.value.IValue,tlc2.value.impl.StringValue,tlc2.value.impl.BoolValue) throws java.io.IOException>.
Computing initial states...
Finished computing initial states: 1 distinct state generated at 2020-01-06 20:49:42.
Error: Action property line 268, col 25 to line 268, col 37 of module RaftMongo is violated.
Error: The behavior up to this point is:
State 1: <Initial predicate>
/\ globalCurrentTerm = 0
/\ log = <<<<>>, <<>>, <<>>>>
/\ i = 1
/\ state = <<"Follower", "Follower", "Follower">>
/\ commitPoint = << [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0] >>

State 2: <Next line 39, col 12 to line 39, col 51 of module Trace>
/\ globalCurrentTerm = 1
/\ log = <<<<>>, <<>>, <<>>>>
/\ i = 2
/\ state = <<"Leader", "Follower", "Follower">>
/\ commitPoint = << [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0] >>

State 3: <Next line 39, col 12 to line 39, col 51 of module Trace>
/\ globalCurrentTerm = 1
/\ log = <<<<[term |-> 1], [term |-> 1], [term |-> 1], [term |-> 1]>>, <<>>, <<>>>>
/\ i = 3
/\ state = <<"Leader", "Follower", "Follower">>
/\ commitPoint = << [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0] >>

State 4: <Next line 39, col 12 to line 39, col 51 of module Trace>
/\ globalCurrentTerm = 1
/\ log = <<<<[term |-> 1], [term |-> 1], [term |-> 1], [term |-> 1]>>, <<>>, <<>>>>
/\ i = 4
/\ state = <<"Leader", "Follower", "Follower">>
/\ commitPoint = << [index |-> 4, term |-> 1],
   [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0] >>

6 states generated, 4 distinct states found, 0 states left on queue.
The depth of the complete state graph search is 4.
The average outdegree of the complete state graph is 1 (minimum is 1, the maximum 1 and the 95th percentile is 1).
Finished in 03s at (2020-01-06 20:49:42)

Note that the Mongo2TLA hack should eventually be simplified into/merged with your Python script, i.e. a JSon2TLA script.

@lemmy
Copy link
Member

lemmy commented Jan 8, 2020

@ajdavis When you merge the log files based on the timestamps, do you just assume perfectly synchronized clocks? Why don't you use logical clocks? Also, has logging been built into your app just to validate traces or was it already available?

What I'm getting at is, how to design a TLA+ specific logging API that is linked to the actual implementation and that creates the Trace.out file. Another variant of this logging API could even validate impl traces on-line by (asynchronously) sending each new log statement to a running TLC. Provided its overhead is negligible, this could then run as a monitor in production. The tricky part is to make this logging API convenient to use.

@ajdavis
Copy link
Contributor Author

ajdavis commented Jan 9, 2020

We run our test servers as processes on a single machine so that they have access to a synchronized clock. To ensure that causally-related events have properly ordered timestamps, our test servers pause 1ms before logging each event. Obviously, our approach wouldn't be appropriate for trace checking in production. We considered logical clocks, but the solution we chose is much simpler. MongoDB has a typical logging framework for a database server; we added some custom code for TLA+ trace logging.

It's an interesting idea to directly write the Trace.out file from MongoDB's C++ code instead of post-processing MongoDB logs with Python to produce the trace. There would still need to be a step at some point in the pipeline for merging event streams from multiple processes.

@lemmy
Copy link
Member

lemmy commented Jan 9, 2020

Cannot one of your MongoDBs be the sink for the event stream that merges the log data, followed by writing Trace.out? At any rate, an offline API seems better suited for trace validation of single process apps. In the on-line case on the other hand, TLC could directly act as the sink for all MongoDBs.

@ajdavis
Copy link
Contributor Author

ajdavis commented Jan 20, 2020

Thanks for your advice, and thanks especially for providing us with TLC optimizations and a module for speeding up trace checking! We've concluded our research for now. Unfortunately, we've concluded that model-based trace-checking is more effort than it's worth for our particular scenario. TLC has the features we need, thanks to you. But getting our TLA+ specification to match the output of MongoDB's trace logging is too much trouble. We'll be analyzing our results and publishing later this year, stay tuned.

@ajdavis ajdavis closed this as completed Jan 20, 2020
@ajdavis
Copy link
Contributor Author

ajdavis commented Jan 22, 2020

I have another question, however, if you're willing to answer it.

I want to measure how much RaftMongo.tla coverage this trace achieved. When I follow your instructions and include -coverage 1 in the TLC command, I get this:

... same output as your Jan 6 comment ...
Error: Action property line 271, col 25 to line 271, col 37 of module RaftMongo is violated.
Error: The behavior up to this point is:
... same output as your Jan 6 comment ...
The coverage statistics at 2020-01-22 12:43:05
<Init line 34, col 1 to line 34, col 4 of module Trace>: 2:2
  line 34, col 9 to line 34, col 21 of module Trace: 2
<Next line 35, col 1 to line 35, col 4 of module Trace (35 12 35 51)>: 3:6
  line 35, col 12 to line 35, col 25 of module Trace: 5
  |line 35, col 12 to line 35, col 12 of module Trace: 6
  |line 35, col 16 to line 35, col 25 of module Trace: 6
  line 35, col 30 to line 35, col 39 of module Trace: 5
  |line 35, col 35 to line 35, col 39 of module Trace: 6
  line 29, col 19 to line 29, col 45 of module Trace: 5
  |line 29, col 40 to line 29, col 45 of module Trace: 6
  line 30, col 19 to line 30, col 31 of module Trace: 5
  |line 30, col 26 to line 30, col 31 of module Trace: 6
  line 31, col 19 to line 31, col 33 of module Trace: 5
  |line 31, col 28 to line 31, col 33 of module Trace: 6
  line 32, col 19 to line 32, col 39 of module Trace: 5
  |line 32, col 34 to line 32, col 39 of module Trace: 6
<Next line 35, col 1 to line 35, col 4 of module Trace (36 12 36 32)>: 0:2
  line 36, col 12 to line 36, col 32 of module Trace: 2
End of statistics.
6 states generated, 4 distinct states found, 0 states left on queue.
... same output as your Jan 6 comment ...

I do not see any lines in RaftMongo.tla covered, only the Trace module, which imports RaftMongo. Is there a way to measure the coverage within RaftMongo.tla?

Thanks!

@lemmy
Copy link
Member

lemmy commented Jan 22, 2020

Try this build: https://tla.msr-inria.inria.fr/kuppe/tla2tools-413.jar

diff --git a/tlatools/src/tlc2/tool/coverage/CostModelCreator.java b/tlatools/src/tlc2/tool/coverage/CostModelCreator.java
index accb150e1..bef33617c 100644
--- a/tlatools/src/tlc2/tool/coverage/CostModelCreator.java
+++ b/tlatools/src/tlc2/tool/coverage/CostModelCreator.java
@@ -391,6 +391,13 @@ public class CostModelCreator extends ExplorerVisitor {
                for (Action invariant : tool.getInvariants()) {
                        invariant.cm = collector.getCM(invariant, Relation.PROP);
                }
+               
+               for (Action impliedInits : tool.getImpliedInits()) {
+                       impliedInits.cm = collector.getCM(impliedInits, Relation.PROP);
+               }
+               for (Action impliedActions : tool.getImpliedActions()) {
+                       impliedActions.cm = collector.getCM(impliedActions, Relation.PROP);
+               }
        }
        
        public static void report(final ITool tool, final long startTime) {
@@ -427,8 +434,15 @@ public class CostModelCreator extends ExplorerVisitor {
         for (Action invariant : tool.getInvariants()) {
                //TODO May need to be ordered similar to next-state actions above.
                invariant.cm.report();
-               }
+               }       
         
+               for (Action impliedInits : tool.getImpliedInits()) {
+                       impliedInits.cm.report();
+               }
+               for (Action impliedActions : tool.getImpliedActions()) {
+                       impliedActions.cm.report();
+               }
+       
                // Notify users about the performance overhead related to coverage collection
                // after N minutes of model checking. The assumption is that a user has little
                // interest in coverage for a large (long-running) model anyway.  In the future

@ajdavis
Copy link
Contributor Author

ajdavis commented Jan 23, 2020

Terrific! Now I see coverage lines logged on the imported module, RaftMongo.tla.

Since this requires a newer tla2tools.jar than what we have bundled in the TLA+ Toolbox, must I rebuild the Toolbox in order to see this coverage visualized in the Toolbox? Or is there a way to import coverage into the Toolbox? (I see we can't yet use a custom tla2tools.jar with the Toolbox #406).

lemmy added a commit that referenced this issue Jan 23, 2020
implied actions (INSTANCE).

Activate with "-Dtlc2.tool.coverage.CostModelCreator.implied=true" JVM
property when running TLC.  In the Toolbox, go to the TLC Options page
of the Model and paste the property into the JVM arguments box.

Seehttps://github.com//issues/413#issuecomment-577304602
for background.

[Feature][TLC]
@lemmy
Copy link
Member

lemmy commented Jan 23, 2020

https://nightly.tlapl.us/products/ will soon (~1h) have a build with change.

Peek 2020-01-22 17-21

@ajdavis
Copy link
Contributor Author

ajdavis commented Jan 23, 2020

Thanks for the video, this is super-helpful. I've just downloaded the latest TLA+ Toolbox and I seem to have a different bundled version of the tools than you, commit hash 6232c31 rather than your f30148c. My coverage output still doesn't include RaftMongo.tla.

Here's my TLC console output:

TLC2 Version 2.15 of Day Month 20?? (rev: 6232c31)
Running breadth-first search Model-Checking with fp 84 and seed -6360122614966313401 with 1 worker on 12 cores with 3884MB heap and 8737MB offheap memory [pid: 21033] (Mac OS X 10.14.6 x86_64, AdoptOpenJDK 13.0.1 x86_64, OffHeapDiskFPSet, DiskStateQueue).
Starting SANY...
Parsing file /Users/emptysquare/Dropbox/tlaplus-github-issue-413/TraceWithIO.toolbox/Model_1/MC.tla
Parsing file /Users/emptysquare/Dropbox/tlaplus-github-issue-413/TraceWithIO.toolbox/Model_1/TraceWithIO.tla
Parsing file /private/var/folders/j6/9cfy8vr16td833rpy1rs_w5w0000gn/T/AppTranslocation/A5079AC6-D68D-42E0-B206-9B32B1405009/d/TLA+ Toolbox.app/Contents/Eclipse/plugins/org.lamport.tlatools_1.0.0.202001230323/tla2sany/StandardModules/TLC.tla
Parsing file /private/var/folders/j6/9cfy8vr16td833rpy1rs_w5w0000gn/T/AppTranslocation/A5079AC6-D68D-42E0-B206-9B32B1405009/d/TLA+ Toolbox.app/Contents/Eclipse/plugins/org.lamport.tlatools_1.0.0.202001230323/tla2sany/StandardModules/Integers.tla
Parsing file /private/var/folders/j6/9cfy8vr16td833rpy1rs_w5w0000gn/T/AppTranslocation/A5079AC6-D68D-42E0-B206-9B32B1405009/d/TLA+ Toolbox.app/Contents/Eclipse/plugins/org.lamport.tlatools_1.0.0.202001230323/tla2sany/StandardModules/Sequences.tla
Parsing file /private/var/folders/j6/9cfy8vr16td833rpy1rs_w5w0000gn/T/IOUtils.tla
Parsing file /private/var/folders/j6/9cfy8vr16td833rpy1rs_w5w0000gn/T/AppTranslocation/A5079AC6-D68D-42E0-B206-9B32B1405009/d/TLA+ Toolbox.app/Contents/Eclipse/plugins/org.lamport.tlatools_1.0.0.202001230323/tla2sany/StandardModules/Naturals.tla
Parsing file /Users/emptysquare/Dropbox/tlaplus-github-issue-413/TraceWithIO.toolbox/Model_1/RaftMongo.tla
Parsing file /private/var/folders/j6/9cfy8vr16td833rpy1rs_w5w0000gn/T/AppTranslocation/A5079AC6-D68D-42E0-B206-9B32B1405009/d/TLA+ Toolbox.app/Contents/Eclipse/plugins/org.lamport.tlatools_1.0.0.202001230323/tla2sany/StandardModules/FiniteSets.tla
...
Starting... (2020-01-23 12:00:31)
Failed to match TLCExt!AssertError operator override from jar:file:/Users/emptysquare/Dropbox/tlaplus-github-issue-413/CommunityModules-202001070430.jar!/tlc2/overrides/TLCExt.class with signature: <Java Method: public static synchronized tlc2.value.impl.Value tlc2.overrides.TLCExt.assertError(tlc2.tool.impl.Tool,tla2sany.semantic.ExprOrOpArgNode[],tlc2.util.Context,tlc2.tool.TLCState,tlc2.tool.TLCState,int,tlc2.tool.coverage.CostModel)> (no such module).
Failed to match TLCExt!PickSuccessor operator override from jar:file:/Users/emptysquare/Dropbox/tlaplus-github-issue-413/CommunityModules-202001070430.jar!/tlc2/overrides/TLCExt.class with signature: <Java Method: public static synchronized tlc2.value.impl.Value tlc2.overrides.TLCExt.pickSuccessor(tlc2.tool.impl.Tool,tla2sany.semantic.ExprOrOpArgNode[],tlc2.util.Context,tlc2.tool.TLCState,tlc2.tool.TLCState,int,tlc2.tool.coverage.CostModel)> (no such module).
Loading IODeserialize operator override from tlc2.overrides.IOUtils with signature: <Java Method: public static final tlc2.value.IValue tlc2.overrides.IOUtils.deserialize(tlc2.value.impl.StringValue,tlc2.value.impl.BoolValue) throws java.io.IOException>.
Loading IOSerialize operator override from tlc2.overrides.IOUtils with signature: <Java Method: public static final tlc2.value.IValue tlc2.overrides.IOUtils.serialize(tlc2.value.IValue,tlc2.value.impl.StringValue,tlc2.value.impl.BoolValue) throws java.io.IOException>.
Computing initial states...
Finished computing initial states: 1 distinct state generated at 2020-01-23 12:00:38.
Action property line 271, col 25 to line 271, col 37 of module RaftMongo is violated.
...
The coverage statistics at 2020-01-23 12:00:38
<Init line 34, col 1 to line 34, col 4 of module TraceWithIO>: 2:2
  line 34, col 9 to line 34, col 21 of module TraceWithIO: 2
<Next line 35, col 1 to line 35, col 4 of module TraceWithIO (35 12 35 51)>: 3:6
  line 35, col 12 to line 35, col 25 of module TraceWithIO: 5
  |line 35, col 12 to line 35, col 12 of module TraceWithIO: 6
  |line 35, col 16 to line 35, col 25 of module TraceWithIO: 6
  line 35, col 30 to line 35, col 39 of module TraceWithIO: 5
  |line 35, col 35 to line 35, col 39 of module TraceWithIO: 6
  line 29, col 19 to line 29, col 45 of module TraceWithIO: 5
  |line 29, col 40 to line 29, col 45 of module TraceWithIO: 6
  line 30, col 19 to line 30, col 31 of module TraceWithIO: 5
  |line 30, col 26 to line 30, col 31 of module TraceWithIO: 6
  line 31, col 19 to line 31, col 33 of module TraceWithIO: 5
  |line 31, col 28 to line 31, col 33 of module TraceWithIO: 6
  line 32, col 19 to line 32, col 39 of module TraceWithIO: 5
  |line 32, col 34 to line 32, col 39 of module TraceWithIO: 6
<Next line 35, col 1 to line 35, col 4 of module TraceWithIO (36 12 36 32)>: 0:2
  line 36, col 12 to line 36, col 32 of module TraceWithIO: 2
End of statistics.
Progress(4) at 2020-01-23 12:00:38: 6 states generated (47 s/min), 4 distinct states found (31 ds/min), 0 states left on queue.
6 states generated, 4 distinct states found, 0 states left on queue.
The depth of the complete state graph search is 4.
The average outdegree of the complete state graph is 1 (minimum is 1, the maximum 1 and the 95th percentile is 1).
Finished in 7660ms at (2020-01-23 12:00:38)

Screen Shot 2020-01-23 at 11 59 24 AM

@lemmy
Copy link
Member

lemmy commented Jan 23, 2020

Works here (see below). Might it be possible that you missed to set -Dtlc2.tool.coverage.CostModelCreator.implied=true under JVM arguments on the TLC Options page?

TLC2 Version 2.15 of Day Month 20?? (rev: 6232c31)
Running breadth-first search Model-Checking with fp 15 and seed 4115925180713148936 with 1 worker on 4 cores with 2192MB heap and 4928MB offheap memory [pid: 2604] (Linux 4.18.0-16-generic amd64, AdoptOpenJDK 13.0.1 x86_64, OffHeapDiskFPSet, DiskStateQueue).
Starting SANY...
Parsing file /home/markus/src/TLA/_specs/models/tlcbugs/Github413/TraceValidationRaftMongo.toolbox/Model_1/MC.tla
Parsing file /home/markus/src/TLA/_specs/models/tlcbugs/Github413/TraceValidationRaftMongo.toolbox/Model_1/Trace.tla
Parsing file /opt/TLA+Toolbox/plugins/org.lamport.tlatools_1.0.0.202001230323/tla2sany/StandardModules/TLC.tla
Parsing file /opt/TLA+Toolbox/plugins/org.lamport.tlatools_1.0.0.202001230323/tla2sany/StandardModules/Integers.tla
Parsing file /opt/TLA+Toolbox/plugins/org.lamport.tlatools_1.0.0.202001230323/tla2sany/StandardModules/Sequences.tla
Parsing file /tmp/IOUtils.tla
Parsing file /opt/TLA+Toolbox/plugins/org.lamport.tlatools_1.0.0.202001230323/tla2sany/StandardModules/Naturals.tla
Parsing file /home/markus/src/TLA/_specs/models/tlcbugs/Github413/TraceValidationRaftMongo.toolbox/Model_1/RaftMongo.tla
Parsing file /opt/TLA+Toolbox/plugins/org.lamport.tlatools_1.0.0.202001230323/tla2sany/StandardModules/FiniteSets.tla
Semantic processing of module Naturals
Semantic processing of module Integers
Semantic processing of module Sequences
Semantic processing of module FiniteSets
Semantic processing of module TLC
Semantic processing of module IOUtils
Semantic processing of module RaftMongo
Semantic processing of module Trace
Semantic processing of module MC
SANY finished.
Starting... (2020-01-23 09:10:50)
Failed to match TLCExt!AssertError operator override from jar:file:/home/markus/src/TLA/_specs/models/tlcbugs/Github413/CommunityModules-202001070430.jar!/tlc2/overrides/TLCExt.class with signature: <Java Method: public static synchronized tlc2.value.impl.Value tlc2.overrides.TLCExt.assertError(tlc2.tool.impl.Tool,tla2sany.semantic.ExprOrOpArgNode[],tlc2.util.Context,tlc2.tool.TLCState,tlc2.tool.TLCState,int,tlc2.tool.coverage.CostModel)> (no such module).
Failed to match TLCExt!PickSuccessor operator override from jar:file:/home/markus/src/TLA/_specs/models/tlcbugs/Github413/CommunityModules-202001070430.jar!/tlc2/overrides/TLCExt.class with signature: <Java Method: public static synchronized tlc2.value.impl.Value tlc2.overrides.TLCExt.pickSuccessor(tlc2.tool.impl.Tool,tla2sany.semantic.ExprOrOpArgNode[],tlc2.util.Context,tlc2.tool.TLCState,tlc2.tool.TLCState,int,tlc2.tool.coverage.CostModel)> (no such module).
Loading IODeserialize operator override from tlc2.overrides.IOUtils with signature: <Java Method: public static final tlc2.value.IValue tlc2.overrides.IOUtils.deserialize(tlc2.value.impl.StringValue,tlc2.value.impl.BoolValue) throws java.io.IOException>.
Loading IOSerialize operator override from tlc2.overrides.IOUtils with signature: <Java Method: public static final tlc2.value.IValue tlc2.overrides.IOUtils.serialize(tlc2.value.IValue,tlc2.value.impl.StringValue,tlc2.value.impl.BoolValue) throws java.io.IOException>.
Computing initial states...
Finished computing initial states: 1 distinct state generated at 2020-01-23 09:10:59.
Action property line 268, col 25 to line 268, col 37 of module RaftMongo is violated.
The behavior up to this point is:
1: <Initial predicate>
/\ globalCurrentTerm = 0
/\ log = <<<<>>, <<>>, <<>>>>
/\ i = 1
/\ state = <<"Follower", "Follower", "Follower">>
/\ commitPoint = << [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0] >>
2: <Next line 39, col 12 to line 39, col 51 of module Trace>
/\ globalCurrentTerm = 1
/\ log = <<<<>>, <<>>, <<>>>>
/\ i = 2
/\ state = <<"Leader", "Follower", "Follower">>
/\ commitPoint = << [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0] >>
3: <Next line 39, col 12 to line 39, col 51 of module Trace>
/\ globalCurrentTerm = 1
/\ log = <<<<[term |-> 1], [term |-> 1], [term |-> 1], [term |-> 1]>>, <<>>, <<>>>>
/\ i = 3
/\ state = <<"Leader", "Follower", "Follower">>
/\ commitPoint = << [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0] >>
4: <Next line 39, col 12 to line 39, col 51 of module Trace>
/\ globalCurrentTerm = 1
/\ log = <<<<[term |-> 1], [term |-> 1], [term |-> 1], [term |-> 1]>>, <<>>, <<>>>>
/\ i = 4
/\ state = <<"Leader", "Follower", "Follower">>
/\ commitPoint = << [index |-> 4, term |-> 1],
   [index |-> 0, term |-> 0],
   [index |-> 0, term |-> 0] >>
The coverage statistics at 2020-01-23 09:10:59
<Init line 38, col 1 to line 38, col 4 of module Trace>: 2:2
  line 38, col 9 to line 38, col 21 of module Trace: 2
<Next line 39, col 1 to line 39, col 4 of module Trace (39 12 39 51)>: 3:6
  line 39, col 12 to line 39, col 25 of module Trace: 5
  |line 39, col 12 to line 39, col 12 of module Trace: 6
  |line 39, col 16 to line 39, col 25 of module Trace: 6
  line 39, col 30 to line 39, col 39 of module Trace: 5
  |line 39, col 35 to line 39, col 39 of module Trace: 6
  line 33, col 19 to line 33, col 45 of module Trace: 5
  |line 33, col 40 to line 33, col 45 of module Trace: 6
  line 34, col 19 to line 34, col 31 of module Trace: 5
  |line 34, col 26 to line 34, col 31 of module Trace: 6
  line 35, col 19 to line 35, col 33 of module Trace: 5
  |line 35, col 28 to line 35, col 33 of module Trace: 6
  line 36, col 19 to line 36, col 39 of module Trace: 5
  |line 36, col 34 to line 36, col 39 of module Trace: 6
<Next line 39, col 1 to line 39, col 4 of module Trace (40 12 40 32)>: 0:2
  line 40, col 12 to line 40, col 32 of module Trace: 2
<Action line 13, col 1 to line 15, col 21 of module Trace>
  line 116, col 22 to line 116, col 42 of module RaftMongo: 1
<Action line 13, col 1 to line 15, col 21 of module Trace>
  line 117, col 22 to line 117, col 70 of module RaftMongo: 1
<Action line 13, col 1 to line 15, col 21 of module Trace>
  line 118, col 22 to line 118, col 85 of module RaftMongo: 1
<Action line 13, col 1 to line 15, col 21 of module Trace>
  line 119, col 22 to line 119, col 65 of module RaftMongo: 1
<Action line 13, col 1 to line 15, col 21 of module Trace>
  line 13, col 1 to line 15, col 21 of module Trace: 11
  line 13, col 1 to line 15, col 21 of module Trace: 53
  line 13, col 1 to line 15, col 21 of module Trace: 44
  line 13, col 1 to line 15, col 21 of module Trace: 26
  line 15, col 13 to line 15, col 21 of module Trace: 8:516
  line 268, col 27 to line 268, col 37 of module RaftMongo: 5
  |line 268, col 28 to line 268, col 31 of module RaftMongo: 5
  ||line 258, col 5 to line 266, col 65 of module RaftMongo: 5
  |||line 258, col 8 to line 258, col 24 of module RaftMongo: 5
  ||||line 207, col 5 to line 207, col 41 of module RaftMongo: 5
  |||||line 207, col 25 to line 207, col 41 of module RaftMongo: 45
  ||||||line 129, col 5 to line 133, col 31 of module RaftMongo: 45
  |||||||line 129, col 8 to line 129, col 24 of module RaftMongo: 45
  ||||||||line 75, col 5 to line 76, col 49 of module RaftMongo: 45
  |||||||||line 75, col 8 to line 75, col 32 of module RaftMongo: 45
  |||||||||line 76, col 8 to line 76, col 49 of module RaftMongo: 2
  ||||||||line 129, col 20 to line 129, col 20 of module RaftMongo: 45
  ||||||||line 129, col 23 to line 129, col 23 of module RaftMongo: 45
  |||||||line 130, col 8 to line 132, col 64 of module RaftMongo: 2
  ||||||||line 131, col 32 to line 131, col 76 of module RaftMongo: 8
  ||||||||line 132, col 13 to line 132, col 64 of module RaftMongo: 8
  ||||||||line 130, col 28 to line 130, col 57 of module RaftMongo: 2
  |||||||line 133, col 8 to line 133, col 31 of module RaftMongo: 0
  ||||||line 207, col 37 to line 207, col 37 of module RaftMongo: 45
  ||||||line 207, col 40 to line 207, col 40 of module RaftMongo: 45
  |||||line 207, col 16 to line 207, col 21 of module RaftMongo: 5
  |||line 259, col 8 to line 259, col 26 of module RaftMongo: 5
  ||||line 210, col 5 to line 210, col 43 of module RaftMongo: 5
  |||||line 210, col 25 to line 210, col 43 of module RaftMongo: 45
  ||||||line 142, col 5 to line 146, col 31 of module RaftMongo: 45
  |||||||line 142, col 8 to line 142, col 29 of module RaftMongo: 45
  ||||||||line 102, col 5 to line 106, col
 42 of module RaftMongo: 45
  |||||||||line 102, col 8 to line 102, col 22 of module RaftMongo: 45
  |||||||||line 103, col 8 to line 103, col 22 of module RaftMongo: 3
  |||||||||line 106, col 8 to line 106, col 42 of module RaftMongo: 1
  ||||||||line 142, col 25 to line 142, col 25 of module RaftMongo: 45
  ||||||||line 142, col 28 to line 142, col 28 of module RaftMongo: 3
  |||||||line 146, col 8 to line 146, col 31 of module RaftMongo: 0
  ||||||line 210, col 39 to line 210, col 39 of module RaftMongo: 45
  ||||||line 210, col 42 to line 210, col 42 of module RaftMongo: 3
  |||||line 210, col 16 to line 210, col 21 of module RaftMongo: 5
  |||line 260, col 8 to line 260, col 33 of module RaftMongo: 5
  ||||line 213, col 5 to line 213, col 90 of module RaftMongo: 5
  |||||line 213, col 23 to line 213, col 90 of module RaftMongo: 13
  ||||||line 213, col 57 to line 213, col 90 of module RaftMongo: 101
  |||||||line 152, col 5 to line 158, col 41 of module RaftMongo: 101
  ||||||||line 152, col 8 to line 152, col 43 of module RaftMongo: 101
  |||||||||line 152, col 29 to line 152, col 43 of module RaftMongo: 141
  ||||||||||line 79, col 21 to line 81, col 53 of module RaftMongo: 141
  |||||||||||line 79, col 24 to line 79, col 59 of module RaftMongo: 141
  ||||||||||||line 79, col 24 to line 79, col 40 of module RaftMongo: 141
  |||||||||||||line 68, col 19 to line 68, col 42 of module RaftMongo: 141
  ||||||||||||||line 66, col 25 to line 66, col 65 of module RaftMongo: 141
  |||||||||||||||line 66, col 28 to line 66, col 36 of module RaftMongo: 141
  |||||||||||||||line 66, col 50 to line 66, col 65 of module RaftMongo: 12
  ||||||||||||||line 68, col 27 to line 68, col 30 of module RaftMongo: 12
  ||||||||||||||line 68, col 33 to line 68, col 41 of module RaftMongo: 141
  |||||||||||||line 79, col 33 to line 79, col 39 of module RaftMongo: 141
  ||||||||||||line 79, col 44 to line 79, col 59 of module RaftMongo: 141
  |||||||||||||line 68, col 19 to line 68, col 42 of module RaftMongo: 141
  ||||||||||||||line 66, col 25 to line 66, col 65 of module RaftMongo: 141
  |||||||||||||||line 66, col 28 to line 66, col 36 of module RaftMongo: 141
  |||||||||||||||line 66, col 50 to line 66, col 65 of module RaftMongo: 12
  ||||||||||||||line 68, col 27 to line 68, col 30 of module RaftMongo: 12
  ||||||||||||||line 68, col 33 to line 68, col 41 of module RaftMongo: 141
  |||||||||||||line 79, col 53 to line 79, col 58 of module RaftMongo: 141
  |||||||||||line 80, col 24 to line 81, col 53 of module RaftMongo: 133
  ||||||||||||line 80, col 27 to line 80, col 62 of module RaftMongo: 133
  |||||||||||||line 80, col 27 to line 80, col 43 of module RaftMongo: 133
  ||||||||||||||line 68, col 19 to line 68, col 42 of module RaftMongo: 133
  |||||||||||||||line 66, col 25 to line 66, col 65 of module RaftMongo: 133
  ||||||||||||||||line 66, col 28 to line 66, col 36 of module RaftMongo: 133
  ||||||||||||||||line 66, col 50 to line 66, col 65 of module RaftMongo: 4
  |||||||||||||||line 68, col 27 to line 68, col 30 of module RaftMongo: 4
  |||||||||||||||line 68, col 33 to line 68, col 41 of module RaftMongo: 133
  ||||||||||||||line 80, col 36 to line 80, col 42 of module RaftMongo: 133
  |||||||||||||line 80, col 47 to line 80, col 62 of module RaftMongo: 133
  ||||||||||||||line 68, col 19 to line 68, col 42 of module RaftMongo: 133
  |||||||||||||||line 66, col 25 to line 66, col 65 of module RaftMongo: 133
  ||||||||||||||||line 66, col 28 to line 66, col 36 of module RaftMongo: 133
  ||||||||||||||||line 66, col 50 to line 66, col 65 of module RaftMongo: 12
  |||||||||||||||line 68, col 27 to line 68, col 30 of module RaftMongo: 12
  |||||||||||||||line 68, col 33 to line 68, col 41 of module RaftMongo: 133
  ||||||||||||||line 80, col 56 to line 80, col 61 of module RaftMongo: 133
  ||||||||||||line 81, col 27 to line 81, col 53 of module RaftMongo: 125
  ||||||||||line 152, col 39 to line 152, col 39 of module RaftMongo: 141
  ||||||||||line 152, col 42 to line 152, col 42 of module RaftMongo: 141
  |||||||||line 152, col 17 to line 152, col 25 of module RaftMongo: 101
  ||||||||line 153, col 8 to line 153, col 28 of module RaftMongo: 93
  ||||||||line 154, col 8 to line 156, col 86 of module RaftMongo: 43
  ||||||||line 157, col 8 to line 157, col 49 of module RaftMongo: 16
  ||||||||line 158, col 8 to line 158, col 41 of module RaftMongo: 2
  |||||||line 213, col 78 to line 213, col 78 of module RaftMongo: 88
  |||||||line 213, col 81 to line 213, col 89 of module RaftMongo: 101
  ||||||line 213, col 40 to line 213, col 53 of module RaftMongo: 13:242
  |||||line 213, col 14 to line 213, col 19 of module RaftMongo: 5
  |||line 261, col 8 to line 261, col 24 of module RaftMongo: 4
  ||||line 216, col 5 to line 216, col 36 of module RaftMongo: 4
  |
||||line 216, col 23 to line 216, col 36 of module RaftMongo: 10
  ||||||line 163, col 5 to line 169, col 31 of module RaftMongo: 10
  |||||||line 163, col 8 to line 163, col 26 of module RaftMongo: 10
  |||||||line 164, col 8 to line 168, col 45 of module RaftMongo: 3
  ||||||||line 166, col 27 to line 166, col 59 of module RaftMongo: 26:284
  ||||||||line 165, col 22 to line 165, col 49 of module RaftMongo: 26
  ||||||||line 167, col 23 to line 167, col 42 of module RaftMongo: 26
  ||||||||line 168, col 13 to line 168, col 45 of module RaftMongo: 26
  ||||||||line 164, col 26 to line 164, col 46 of module RaftMongo: 3
  |||||||line 169, col 8 to line 169, col 31 of module RaftMongo: 2
  ||||||line 216, col 35 to line 216, col 35 of module RaftMongo: 10
  |||||line 216, col 14 to line 216, col 19 of module RaftMongo: 4
  |||line 264, col 8 to line 264, col 25 of module RaftMongo: 3
  ||||line 173, col 5 to line 183, col 50 of module RaftMongo: 3
  |||||line 174, col 9 to line 183, col 50 of module RaftMongo: 9
  ||||||line 174, col 12 to line 174, col 35 of module RaftMongo: 9
  ||||||line 176, col 12 to line 183, col 50 of module RaftMongo: 2
  |||||||line 177, col 13 to line 183, col 50 of module RaftMongo: 4
  ||||||||line 177, col 16 to line 177, col 50 of module RaftMongo: 4
  |||||||||line 96, col 5 to line 97, col 48 of module RaftMongo: 4
  ||||||||||line 96, col 8 to line 96, col 38 of module RaftMongo: 4
  |||||||||||line 65, col 24 to line 65, col 69 of module RaftMongo: 4
  |||||||||||line 96, col 19 to line 96, col 37 of module RaftMongo: 4
  ||||||||||||line 85, col 5 to line 87, col 60 of module RaftMongo: 4
  |||||||||||||line 86, col 9 to line 87, col 58 of module RaftMongo: 12
  ||||||||||||||line 86, col 12 to line 86, col 37 of module RaftMongo: 12
  ||||||||||||||line 87, col 12 to line 87, col 58 of module RaftMongo: 4
  |||||||||||||line 85, col 16 to line 85, col 21 of module RaftMongo: 4
  ||||||||||||line 96, col 25 to line 96, col 26 of module RaftMongo: 4
  ||||||||||||line 96, col 29 to line 96, col 36 of module RaftMongo: 4
  |||||||||line 177, col 28 to line 177, col 33 of module RaftMongo: 4
  |||||||||line 177, col 36 to line 177, col 49 of module RaftMongo: 4
  ||||||||line 183, col 16 to line 183, col 50 of module RaftMongo: 0
  |||||||line 176, col 34 to line 176, col 82 of module RaftMongo: 2
  |||||line 173, col 19 to line 173, col 24 of module RaftMongo: 3
  |||line 265, col 8 to line 265, col 42 of module RaftMongo: 3
  ||||line 219, col 5 to line 219, col 60 of module RaftMongo: 3
  |||||line 219, col 26 to line 219, col 60 of module RaftMongo: 27
  ||||||line 188, col 5 to line 189, col 29 of module RaftMongo: 27
  |||||||line 188, col 8 to line 188, col 45 of module RaftMongo: 27
  ||||||||line 188, col 8 to line 188, col 23 of module RaftMongo: 27
  |||||||||line 68, col 19 to line 68, col 42 of module RaftMongo: 27
  ||||||||||line 66, col 25 to line 66, col 65 of module RaftMongo: 27
  |||||||||||line 66, col 28 to line 66, col 36 of module RaftMongo: 27
  |||||||||||line 66, col 50 to line 66, col 65 of module RaftMongo: 3
  ||||||||||line 68, col 27 to line 68, col 30 of module RaftMongo: 3
  ||||||||||line 68, col 33 to line 68, col 41 of module RaftMongo: 27
  |||||||||line 188, col 17 to line 188, col 22 of module RaftMongo: 27
  ||||||||line 188, col 27 to line 188, col 45 of module RaftMongo: 27
  |||||||line 189, col 8 to line 189, col 29 of module RaftMongo: 24
  ||||||||line 137, col 5 to line 139, col 42 of module RaftMongo: 24
  |||||||||line 137, col 8 to line 137, col 32 of module RaftMongo: 24
  |||||||||line 139, col 8 to line 139, col 42 of module RaftMongo: 0
  ||||||||line 189, col 25 to line 189, col 25 of module RaftMongo: 24
  ||||||||line 189, col 28 to line 189, col 28 of module RaftMongo: 24
  ||||||line 219, col 56 to line 219, col 56 of module RaftMongo: 27
  ||||||line 219, col 59 to line 219, col 59 of module RaftMongo: 27
  |||||line 219, col 17 to line 219, col 22 of module RaftMongo: 3
  |||line 266, col 8 to line 266, col 65 of module RaftMongo: 3
  ||||line 222, col 5 to line 222, col 83 of module RaftMongo: 3
  |||||line 222, col 26 to line 222, col 83 of module RaftMongo: 27
  ||||||line 194, col 5 to line 203, col 42 of module RaftMongo: 27
  |||||||line 194, col 8 to line 194, col 24 of module RaftMongo: 27
  ||||||||line 75, col 5 to line 76, col 49 of module RaftMongo: 27
  |||||||||line 75, col 8 to line 75, col 32 of module RaftMongo: 27
  |||||||||line 76, col 8 to line 76, col 49 of module RaftMongo: 2
  ||||||||line 194, col 20 to line 194, col 20 of module RaftMongo: 27
  ||||||||line 194, col 23 to line 194, col 23 of module RaftMongo: 27
  |||||||line 195, col 8 to line 195, col 32 of module RaftMongo: 2
ENDMSG 2221 @!@!@
  |||||||line 203, col 8 to line 203, col 42 of module RaftMongo: 0
  ||||||line 222, col 79 to line 222, col 79 of module RaftMongo: 27
  ||||||line 222, col 82 to line 222, col 82 of module RaftMongo: 27
  |||||line 222, col 17 to line 222, col 22 of module RaftMongo: 3
  |line 268, col 34 to line 268, col 37 of module RaftMongo: 6
End of statistics.
Progress(4) at 2020-01-23 09:10:59: 6 states generated (34 s/min), 4 distinct states found (22 ds/min), 0 states left on queue.
6 states generated, 4 distinct states found, 0 states left on queue.
The depth of the complete state graph search is 4.
The average outdegree of the complete state graph is 1 (minimum is 1, the maximum 1 and the 95th percentile is 1).
Finished in 10548ms at (2020-01-23 09:10:59)

@ajdavis
Copy link
Contributor Author

ajdavis commented Jan 23, 2020

I misspelled it -Dtlc2.tool.coverage.CostModelCreate.implied=true. Thanks! I have coverage info now.

@lemmy
Copy link
Member

lemmy commented Jan 26, 2020

FWIW: Trace validation applied to a concurrent (Java) app: https://github.com/lemmy/BlockingQueue#v16-traces-print-partial-implementation-executions

@ajdavis
Copy link
Contributor Author

ajdavis commented Jan 27, 2020

That's a spectacularly useful tutorial, especially with the addition of trace-checking!

quaeler added a commit that referenced this issue Jan 29, 2020
. Minor improvements on the Validator performance for the usecase of specs with verbosity prefixing the module
. Performance unit test
. Comments on where further efforts could be made.

[Feature][Tools]
@ahelwer
Copy link
Contributor

ahelwer commented Feb 3, 2022

Hey @ajdavis it looks like the dropbox links are dead, is it possible for you to repost the specs somehow? Would like to see how the tree-sitter grammar fares on them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug error, glitch, fault, flaw, ... Tools The command line tools - TLC, SANY, ...
Development

No branches or pull requests

3 participants