public static SolutionResult Solve( ISolver solver, IDictionary <NodeId, Node> nodes, InternodeMessagesMap map, List <InternodeMessage> messages, List <FixedConstraint> fixedConstraints, HashSet <string> allowInstancesMergingForRoles) { using (var solverModel = solver.CreateModel()) { var msgDecisions = messages .SelectMany(interNodeMsg => new [] { interNodeMsg.IncomingMessage, interNodeMsg.OutgoingMessage }) .ToDictionary(m => m, m => new MessageDecision(solverModel, m)); var nodeDecisions = nodes .ToDictionary(n => n.Key, n => new NodeDecision(solverModel, n.Value)); AddMessagingConstraints(messages, solverModel, msgDecisions, nodeDecisions); SolverUtils.AddFixedConstraints(fixedConstraints, nodeDecisions, solverModel); SolverUtils.AddUnboundNodesConstraints(map, nodeDecisions, solverModel); SolverUtils.AddIsolatedRoleInstancesConstraints(map, nodeDecisions, allowInstancesMergingForRoles, solverModel); AddGoals(solverModel, msgDecisions); var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(20)); var solution = solverModel.Solve(cancellation.Token); /*Func<Message, bool> mok = m => messages.Any(im => im.IncomingMessage == m || im.OutgoingMessage == m); * var nodeToMsg = nodes.Values.Select(n => new * { * Node = n.NodeId.ToString(), * Msgs = * string.Join("\n", n.Messages.Where(mok).Select(m => m.Key.ToString()).ToArray()) * }).ToArray();*/ if (solution.IsInfeasible) { return(new SolutionResult(cancellation.IsCancellationRequested ? SolutionStatus.Timeout : SolutionStatus.Infeasible, null)); } return(new SolutionResult( SolutionStatus.Solved, nodeDecisions.ToDictionary( d => d.Key, d => (INodeSolution) new NodeSolution( d.Value.TimeDelta, GetNonmonotonicTimeDeltasForNode(msgDecisions, d.Value), d.Value.NrOnConstraints ) ) )); } }
private void PrintInternodeMessagesMap(InternodeMessagesMap map, StringBuilder log) { log.AppendLine(); log.AppendLine("Inter-node messages map:"); log.Append(" from"); for (int i = 0; i < map.NodeIndexes.Count; ++i) { log.AppendFormat("\t#{0}", i); } log.AppendLine(); log.AppendLine("to"); for (int i = 0; i < map.NodeIndexes.Count; ++i) { log.AppendFormat("#{0}", i); for (int j = 0; j < map.NodeIndexes.Count; ++j) { if (i != j) { log.AppendFormat("\t{0}", map.Map[j, i]); } else { log.Append("\t-"); } } log.AppendLine(); } if (map.Domains.Count > 0) { log.AppendLine(); log.AppendLine("Isolated domains:"); foreach (var domain in map.Domains) { log.AppendFormat(" {0}", string.Join(",", domain.Select(i => i.ToString()))); log.AppendLine(); } } log.AppendLine(); foreach (var i in map.NodeIndexes) { log.AppendFormat("#{0}\t{1}{2}", i.Value, i.Key.NodeId, Environment.NewLine); } }
private void PrintFixedConstraints(List <FixedConstraint> fixedConstraints, Dictionary <NodeId, Node> nodes, InternodeMessagesMap map, StringBuilder log) { if (fixedConstraints.Count == 0) { return; } log.AppendLine(); log.AppendLine("Known constraints:"); foreach (var c in fixedConstraints) { log.AppendFormat(" diff between #{0} and #{1} is {2}{3}", map.NodeIndexes[nodes[c.Node1]], map.NodeIndexes[nodes[c.Node2]], c.Value, Environment.NewLine); } }
public static ISolutionResult Solve( ISolver solver, IDictionary <NodeId, Node> nodes, InternodeMessagesMap map, List <InternodeMessage> messages, List <FixedConstraint> fixedConstraints, HashSet <string> allowInstancesMergingForRoles) { using (var solverModel = solver.CreateModel()) { var decisions = nodes.ToDictionary(n => n.Key, n => new NodeDecision(solverModel, n.Value)); AddMessagingConstraints(messages, decisions, solverModel); SolverUtils.AddFixedConstraints(fixedConstraints, decisions, solverModel); SolverUtils.AddUnboundNodesConstraints(map, decisions, solverModel); SolverUtils.AddIsolatedRoleInstancesConstraints(map, decisions, allowInstancesMergingForRoles, solverModel); AddGoals(decisions, solverModel); var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(10)); var solution = solverModel.Solve(cancellation.Token); if (solution.IsInfeasible) { return(new SolutionResult(cancellation.IsCancellationRequested ? SolutionStatus.Timeout : SolutionStatus.Infeasible)); } return(new SolutionResult( SolutionStatus.Solved, decisions.ToDictionary( d => d.Key, d => (INodeSolution) new NodeSolution( d.Value.TimeDelta, new List <TimeDeltaEntry>(), d.Value.NrOnConstraints ) ) )); } }
public Task <ISolutionResult> Correlate( Dictionary <NodeId, IEnumerable <Messaging.Event> > input, List <FixedConstraint> fixedConstraints, HashSet <string> allowInstancesMergingForRoles ) { var log = new StringBuilder(); var nodes = input.ToDictionary(i => i.Key, i => new Node(i.Key)); var unpairedMessages = new List <A.Message>(); var internodeMessagesDetectorInput = input.ToDictionary(i => nodes[i.Key], i => i.Value); var internodeMessages = internodeMessagesDetector.DiscoverInternodeMessages(internodeMessagesDetectorInput, internodeMessagesLimit, unpairedMessages); internodeMessagesDetector.InitializeMessagesLinkedList(nodes.Values); var internodeMessagesMap = new InternodeMessagesMap(nodes, internodeMessages); ISolutionResult solution; if (nodes.Count == 1) { log.AppendLine("Correlation is not required: only one node is found in the log(s)"); solution = new SolutionResult(SolutionStatus.Solved, nodes.ToDictionary(n => n.Key, n => (INodeSolution) new NodeSolution(TimeSpan.Zero, new List <TimeDeltaEntry>(), 0))); } else if (internodeMessages.Count == 0 && fixedConstraints.Count == 0) { log.AppendFormat("Correlation is not possible: no inter-node messages found"); solution = new SolutionResult(SolutionStatus.NoInternodeMessages, new Dictionary <NodeId, INodeSolution>()); } else { log.AppendFormat("Correlating logs using {0} inter-node messages...{1}", internodeMessages.Count, Environment.NewLine); solution = MonotonicTimeSolution.Solve(solver, nodes, internodeMessagesMap, internodeMessages, fixedConstraints, allowInstancesMergingForRoles); if (solution.Status != SolutionStatus.Solved) { if (solution.Status == SolutionStatus.Timeout) { log.AppendLine("Solver timed out."); } log.AppendLine("Can not correlate logs with the assumption of monotonous time. Trying finding the solution for nonmonotonic time..."); for (int currentInternodeMessagesLimit = internodeMessagesLimit; ;) { try { solution = NonmonotonicTimeSolution.Solve(solver, nodes, internodeMessagesMap, internodeMessages, fixedConstraints, allowInstancesMergingForRoles); } catch (UnsolvableModelException ume) { if (ume is ModelTooComplexException) { log.AppendLine("Can not correlate logs because of too many constraints. Msg count = " + currentInternodeMessagesLimit.ToString()); currentInternodeMessagesLimit = currentInternodeMessagesLimit * 3 / 4; if (currentInternodeMessagesLimit < nodes.Count) { throw; } internodeMessages = internodeMessagesDetector.DiscoverInternodeMessages(internodeMessagesDetectorInput, currentInternodeMessagesLimit, new List <A.Message>()); continue; } throw; } break; } if (solution.Status != SolutionStatus.Solved && debugMode) { var problematicNodes = SolutionTroubleshooting.FindProblematicNodesCombinations(solver, nodes, internodeMessages, fixedConstraints, allowInstancesMergingForRoles); if (problematicNodes.Count > 0) { log.AppendLine(SolutionTroubleshooting.LogProblematicNodes(problematicNodes)); } } } if (solution.Status != SolutionStatus.Solved) { if (solution.Status == SolutionStatus.Timeout) { log.AppendLine("Solver timed out."); } log.AppendLine("Can not correlate logs :("); } else { log.AppendLine(solution.ToString()); } } log.AppendLine(); log.AppendLine("Details:"); log.Append(internodeMessagesDetector.Log); ReportUnpairedMessages(unpairedMessages, log); PrintInternodeMessagesMap(internodeMessagesMap, log); PrintFixedConstraints(fixedConstraints, nodes, internodeMessagesMap, log); ((SolutionResult)solution).SetLog(log.ToString()); return(Task.FromResult(solution)); }
public static void AddUnboundNodesConstraints( InternodeMessagesMap map, IDictionary <NodeId, NodeDecision> nodeDecisions, Solver.IModel solverModel) { for (int i = 0; i < map.NodeIndexes.Count; ++i) { for (int j = 0; j < map.NodeIndexes.Count; ++j) { if (i > j && (map.Map[i, j] != 0) != (map.Map[j, i] != 0)) // if all internode messages between nodes i and j flow in one direction { var n1 = map.Nodes[i]; var n2 = map.Nodes[j]; // find the least "steep" internode message var message = n1.Messages .Where(m => m.InternodeMessage != null && m.InternodeMessage.GetOppositeMessage(m).Node == n2) .Where(m => !(m.InternodeMessage.OutgoingMessage.Event is ResponselessNetworkMessageEvent)) .Select(m => m.InternodeMessage) .Aggregate(new { D = TimeSpan.MaxValue, M = (InternodeMessage)null }, (rslt, m) => { var d = m.FromTimestamp - m.ToTimestamp; return(d < rslt.D ? new { D = d, M = m } : rslt); }, rslt => rslt.M); if (message == null) { continue; } // add the constraint that emulates instantaneous response to the found message. // this allows finding solution for the two nodes that would be impossible otherwise. var toNodeDecision = nodeDecisions[message.To.NodeId]; var fromNodeDecision = nodeDecisions[message.From.NodeId]; solverModel.AddConstraints( SolverUtils.MakeValidSolverIdentifierFromString(message.Id) + "_reverse", new OperatorExpr() { Op = OperatorExpr.OpType.Get, Left = new OperatorExpr() { Op = OperatorExpr.OpType.Sub, Left = new TermExpr() { Variable = fromNodeDecision.Decision }, Right = new TermExpr() { Variable = toNodeDecision.Decision } }, Right = new ConstantExpr() { Value = (message.ToTimestamp - message.FromTimestamp).Ticks - 1 } } ); } } } }
public static void AddIsolatedRoleInstancesConstraints( InternodeMessagesMap map, IDictionary <NodeId, NodeDecision> nodeDecisions, HashSet <string> allowedRoles, Solver.IModel solverModel) { var handledBadDomains = new HashSet <ISet <int> >(); foreach (var roleGroup in map.NodeIndexes .Where(x => allowedRoles.Contains(x.Key.NodeId.Role)) .GroupBy(x => x.Key.NodeId.Role)) { // domain -> [{node, node index}] where all nodes are instances of to one role var domainGroups = roleGroup .GroupBy(inst => map.NodeDomains[inst.Value]) .ToDictionary(domainGroup => domainGroup.Key, domainGroup => domainGroup.ToList()); // skip the role if all instances of it belong to one domain if (domainGroups.Count < 2) { continue; } // good is the domain that consists of more than one node var goodDomain = domainGroups.FirstOrDefault(d => d.Key.Count > 1); if (goodDomain.Key == null) { continue; } foreach (var badDomain in domainGroups .Where(d => d.Key.Count == 1) .Where(d => !handledBadDomains.Contains(d.Key))) { var goodDomainDecision = nodeDecisions[goodDomain.Value[0].Key.NodeId]; var badDomainDecision = nodeDecisions[badDomain.Value[0].Key.NodeId]; solverModel.AddConstraints( "isolated_domain_link_" + SolverUtils.MakeValidSolverIdentifierFromString(string.Join("_", badDomain.Key)), new OperatorExpr() { Op = OperatorExpr.OpType.Eq, Left = new OperatorExpr() { Op = OperatorExpr.OpType.Sub, Left = new TermExpr() { Variable = goodDomainDecision.Decision }, Right = new TermExpr() { Variable = badDomainDecision.Decision } }, Right = new ConstantExpr() { Value = 0 } } ); handledBadDomains.Add(badDomain.Key); } } ; }