예제 #1
0
        // Note about special case: members with CascadeDelete attribute.
        // Demo case setup. 3 entities, IBook, IAuthor, and IBookAuthor as link table; IBookAuthor references IBook with CascadeDelete,
        // and references IAuthor without cascade.
        // Because of CascadeDelete, when we delete IBook and IBookAuthor in one operation, the order of IBook vs IBookAuthor does not matter:
        // even if IBook comes before IBookAuthor, delete will succeed because of cascade delete of IBookAuthor.
        // The problem case is when we are deleting IBook and IAuthor, without explicitly deleting IBookAuthor.
        // In this case IAuthor should be deleted after IBook - otherwise still existing IBookAuthor record
        // would prevent it from deleting. As there's no explicit IBookAuthor in delete set, and there's
        // no FK links between IAuthor and IBook - then they may come to delete in any order, and trans might fail.
        // The solution is to introduce an extra direct link between IBook and IAuthor in abstract SCC node tree.
        // This extra link will ensure proper topological ordering of IBook and IAuthor.
        // Note that we still need to add link between IBookAuthor and IBook - for proper ordering of inserts.
        private void ComputeTopologicalIndexes()
        {
            // Run SCC algorithm
            var g = new SccGraph();

            //Perform SCC analysis.
            foreach (var ent in Model.Entities)
            {
                ent.SccVertex = g.Add(ent);
            }
            //setup links
            foreach (var ent in Model.Entities)
            {
                var cascadeMembers    = new List <EntityMemberInfo>();
                var nonCascadeMembers = new List <EntityMemberInfo>();
                foreach (var member in ent.RefMembers)
                {
                    var targetEnt = member.ReferenceInfo.ToKey.Entity;
                    ent.SccVertex.AddLink(targetEnt.SccVertex);
                    if (member.Flags.IsSet(EntityMemberFlags.CascadeDelete))
                    {
                        cascadeMembers.Add(member);
                    }
                    else
                    {
                        nonCascadeMembers.Add(member);
                    }
                }//foreach member
                //For all cascade member (IBookAuthor.Author) targets add direct links to all non-cascade member targets
                // (from IBook to IAuthor)
                foreach (var cascMember in cascadeMembers)
                {
                    var cascTarget = cascMember.ReferenceInfo.ToKey.Entity;
                    foreach (var nonCascMember in nonCascadeMembers)
                    {
                        var nonCascTarget = nonCascMember.ReferenceInfo.ToKey.Entity;
                        cascTarget.SccVertex.AddLink(nonCascTarget.SccVertex);
                    }
                } //foreach cascMember
            }     //foreach ent

            //Build SCC
            var sccCount = g.BuildScc();

            //read scc index and clear vertex fields
            foreach (var ent in Model.Entities)
            {
                var v = ent.SccVertex;
                ent.TopologicalIndex = v.SccIndex;
                if (v.NonTrivialGroup)
                {
                    ent.Flags |= EntityFlags.TopologicalGroupNonTrivial;
                }
                ent.SccVertex = null;
            }
        }
예제 #2
0
파일: HelpersTests.cs 프로젝트: radtek/vita
        public void TestHelpers_GraphSccAlgorithm()
        {
            //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 SccGraph();

            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.");
        }
예제 #3
0
파일: HelpersTests.cs 프로젝트: radtek/vita
        // Builds a sample graph from http://en.wikipedia.org/wiki/Strongly_connected_components
        private static void SetupSampleGraph(SccGraph 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);
        }
예제 #4
0
        public void Solve(ConsoleReader cr, ConsoleWriter cw)
        {
            int n = cr;
            int m = cr;

            var g = new SccGraph(n);

            for (int i = 0; i < m; i++)
            {
                int u = cr;
                int v = cr;
                g.AddEdge(u, v);
            }

            var scc = g.SCC();

            cw.WriteLine(scc.Length);
            foreach (var v in scc)
            {
                cw.StreamWriter.Write(v.Length);
                cw.StreamWriter.Write(' ');
                cw.WriteLineJoin(v);
            }
        }
예제 #5
0
파일: DbUpdateSet.cs 프로젝트: radtek/vita
        //Sequence set of records in a looped non-trivial entity group. Assigns record.SortSubIndex value as a result of sequencing
        private static void AssignSubIndexes(IList <EntityRecord> records)
        {
            var graph = new SccGraph();

            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;
                    }
                    // Both records 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 SortSubIndex
            bool hasNonTrivialGroups = false;

            foreach (var v in graph.Vertexes)
            {
                var rec = (EntityRecord)v.Tag;
                rec.SortSubIndex     = rec.Status == EntityStatus.New ? v.SccIndex : -v.SccIndex; // -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     = Util.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;
            }
        }