Beispiel #1
0
 public void TestGraphSccAlgorithm()
 {
     //This test uses a simple graph from the wikipedia page about SCC: http://en.wikipedia.org/wiki/Strongly_connected_components
       // The copy of this image is in SccTestGraph.jpg file in this test project.
       var expected = "a, Scc=1; b, Scc=1; e, Scc=1; c, Scc=2; d, Scc=2; h, Scc=2; f, Scc=3; g, Scc=3"; //expected SCC indexes
       var gr = new Graph();
       SetupSampleGraph(gr);
       gr.BuildScc();
       // additionally sort by tags, so that result string matches
       var sortedVertexes = gr.Vertexes.OrderBy(v => v.SccIndex).ThenBy(v => (string)v.Tag).ToList();
       var strOut = string.Join("; ", sortedVertexes);
       Assert.AreEqual(expected, strOut, "SCC computation did not return expected result.");
 }
Beispiel #2
0
 // Builds a sample graph from http://en.wikipedia.org/wiki/Strongly_connected_components
 private static void SetupSampleGraph(Graph gr)
 {
     var a = gr.Add("a");
       var b = gr.Add("b");
       var c = gr.Add("c");
       var d = gr.Add("d");
       var e = gr.Add("e");
       var f = gr.Add("f");
       var g = gr.Add("g");
       var h = gr.Add("h");
       //links
       a.AddLink(b);
       b.AddLink(e, f, c);
       c.AddLink(d, g);
       d.AddLink(c, h);
       e.AddLink(a, f);
       f.AddLink(g);
       g.AddLink(f);
       h.AddLink(g, d);
 }
Beispiel #3
0
 //Sequences set of records in a looped non-trivial entity group. Assigns record.SortSubIndex value after sequencing
 private void SequenceSubGroup(IEnumerable<EntityRecord> records)
 {
     var graph = new Graph();
       foreach (var rec in records) {
     var ent = rec.EntityInfo;
     foreach (var refMember in ent.RefMembers) {
       var targetEnt = rec.GetValue(refMember);
       //If reference is not modified or not set, then nothing to do
       if (targetEnt == null)
     continue;
       var targetRec = EntityHelper.GetRecord(targetEnt);
       // we are interested only in case when both records are inserted, or both are deleted.
       if (targetRec.Status != rec.Status)
     continue;
       // finally, the target record's table must be in the same SCC group - i.e. have the same SccIndex
       if (targetRec.EntityInfo.TopologicalIndex != rec.EntityInfo.TopologicalIndex)
     continue;
       // We have potential conflict; add vertexes and link for the conflict
       var thisV = graph.FindOrAdd(rec);
       var targetV = graph.FindOrAdd(targetRec);
       thisV.AddLink(targetV);
     }
       }//foreach cmd
       //Check if any conflicts found
       if (graph.Vertexes.Count == 0) return;
       //Build SCC graph
       graph.BuildScc();
       // Once SCC is built, we have SCC indexes in Vertexes; use them to assign Record's TopologicalIndex
       bool hasNonTrivialGroups = false;
       foreach (var v in graph.Vertexes) {
     var rec = (EntityRecord)v.Tag;
     rec.SortSubIndex = rec.Status == EntityStatus.New ? -v.SccIndex : v.SccIndex;
     hasNonTrivialGroups |= v.NonTrivialGroup;
       }
       //if there are non-trivial groups, it means we have circular references in the set.
       if (hasNonTrivialGroups) {
     var entList = string.Join(",", records.Select(r=> r.PrimaryKey.ToString()));
     var msg = StringHelper.SafeFormat("Detected circular references between entities in an update set. Cannot commit group update. Entities: [{0}].", entList);
     var fault = new ClientFault() {Code = ClientFaultCodes.CircularEntityReference, Message = msg};
     var faultEx = new ClientFaultException(new[] { fault });
     faultEx.LogAsError = true;
     throw faultEx;
       }
 }