JamieDixon / GraphViz-C-Sharp-Wrapper

GraphViz C# Wrapper
93 stars 55 forks source link

Program hang in ReadFully #1

Closed the21st closed 10 years ago

the21st commented 10 years ago

Hi! I experienced a hang while using your library. It happened when I passed a somewhat longer and more complicated DOT string into it.

After googling a bit, I found out it might be caused by a deadlock caused by redirecting both the standard output and standard error streams of the dot.exe process. When I tried NOT redirecting standard error, everything started working as expected.

The DOT string that was causing problems:

digraph G {
  Sequence_START_1 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr><tr><td></td><td align="left">a</td></tr></table>>]

  START -> Sequence_START_1 [label=""]

  Sequence_START_1 -> Decision_1 [label=""]  Sequence_1_1 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr></table>>]

  Decision_1 -> Sequence_1_1 [label=""]

  Sequence_1_1 -> Decision_1_1 [label=""]  Sequence_1_2 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr></table>>]

  Decision_1 -> Sequence_1_2 [label=""]

  Sequence_1_2 -> Decision_1_2 [label=""]  Sequence_1_3 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr></table>>]

  Decision_1 -> Sequence_1_3 [label=""]

  Sequence_1_3 -> Decision_1_3 [label=""]  Sequence_1_4 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr></table>>]

  Decision_1 -> Sequence_1_4 [label=""]

  Sequence_1_4 -> Decision_1_4 [label=""]  Sequence_1_5 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr></table>>]

  Decision_1 -> Sequence_1_5 [label=""]

  Sequence_1_5 -> Decision_1_5 [label=""]  Sequence_1_6 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr></table>>]

  Decision_1 -> Sequence_1_6 [label=""]

  Sequence_1_6 -> Decision_1_6 [label=""]  Sequence_1_1_1 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr><tr><td>VILLAGER 1</td><td align="left">a</td></tr></table>>]

  Decision_1_1 -> Sequence_1_1_1 [label=""]

  Sequence_1_1_1 -> Tend [label=""]  Sequence_1_1_2 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr><tr><td>VILLAGER 1</td><td align="left">a</td></tr></table>>]

  Decision_1_1 -> Sequence_1_1_2 [label=""]

  Sequence_1_1_2 -> Tend [label=""]  Sequence_1_1_3 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr><tr><td>VILLAGER 1</td><td align="left">a</td></tr></table>>]

  Decision_1_1 -> Sequence_1_1_3 [label=""]

  Sequence_1_1_3 -> Tend [label=""]  Sequence_1_2_1 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr><tr><td>VILLAGER 2</td><td align="left">a</td></tr></table>>]

  Decision_1_2 -> Sequence_1_2_1 [label=""]

  Sequence_1_2_1 -> Tend [label=""]  Sequence_1_2_2 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr><tr><td>VILLAGER 2</td><td align="left">a</td></tr></table>>]

  Decision_1_2 -> Sequence_1_2_2 [label=""]

  Sequence_1_2_2 -> Tend [label=""]  Sequence_1_3_1 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr><tr><td>VILLAGE WOMAN</td><td align="left">a</td></tr></table>>]

  Decision_1_3 -> Sequence_1_3_1 [label=""]

  Sequence_1_3_1 -> Tend [label=""]  Sequence_1_3_2 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr><tr><td>VILLAGE WOMAN</td><td align="left">a</td></tr></table>>]

  Decision_1_3 -> Sequence_1_3_2 [label=""]

  Sequence_1_3_2 -> Tend [label=""]  Sequence_1_4_1 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr><tr><td>CITIZEN 1</td><td align="left">a</td></tr></table>>]

  Decision_1_4 -> Sequence_1_4_1 [label=""]

  Sequence_1_4_1 -> Tend [label=""]  Sequence_1_4_2 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr><tr><td>CITIZEN 1</td><td align="left">a</td></tr></table>>]

  Decision_1_4 -> Sequence_1_4_2 [label=""]

  Sequence_1_4_2 -> Tend [label=""]  Sequence_1_4_3 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr><tr><td>CITIZEN 1</td><td align="left">a</td></tr></table>>]

  Decision_1_4 -> Sequence_1_4_3 [label=""]

  Sequence_1_4_3 -> Tend [label=""]  Sequence_1_5_1 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr><tr><td>CITIZEN 2</td><td align="left">a</td></tr></table>>]

  Decision_1_5 -> Sequence_1_5_1 [label=""]

  Sequence_1_5_1 -> Tend [label=""]  Sequence_1_5_2 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr><tr><td>CITIZEN 2</td><td align="left">a</td></tr></table>>]

  Decision_1_5 -> Sequence_1_5_2 [label=""]

  Sequence_1_5_2 -> Tend [label=""]  Sequence_1_5_3 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr><tr><td>CITIZEN 2</td><td align="left">a</td></tr></table>>]

  Decision_1_5 -> Sequence_1_5_3 [label=""]

  Sequence_1_5_3 -> Tend [label=""]  Sequence_1_6_1 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr><tr><td>FEMALE CITIZEN</td><td align="left">a</td></tr></table>>]

  Decision_1_6 -> Sequence_1_6_1 [label=""]

  Sequence_1_6_1 -> Tend [label=""]  Sequence_1_6_2 [shape=none, label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="lightblue">Char</td><td bgcolor="lightblue">Text</td></tr><tr><td>FEMALE CITIZEN</td><td align="left">a</td></tr></table>>]

  Decision_1_6 -> Sequence_1_6_2 [label=""]

  Sequence_1_6_2 -> Tend [label=""]
}
JamieDixon commented 10 years ago

Thanks Simon. I'll take a look at this as soon as a I can. Hope you've found this little library helpful!

the21st commented 10 years ago

I have found it very useful, thanks Jamie.

JamieDixon commented 10 years ago

Hi Simon,

Can you give me any additional details about the error that you got. At the moment I've been unable to reproduce the problem.

Here's my test:

[Test]
        public void Passing_Large_Diagraph_Input_With_StdInput_StdError_Redirected()
        {
            byte[] output = wrapper.GenerateGraph("digraph G {Sequence_START_1 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr><tr><td></td><td align='left'>a</td></tr></table>>]START -> Sequence_START_1 [label='']Sequence_START_1 -> Decision_1 [label='']  Sequence_1_1 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr></table>>]Decision_1 -> Sequence_1_1 [label='']Sequence_1_1 -> Decision_1_1 [label='']  Sequence_1_2 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr></table>>]Decision_1 -> Sequence_1_2 [label='']Sequence_1_2 -> Decision_1_2 [label='']  Sequence_1_3 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr></table>>]Decision_1 -> Sequence_1_3 [label='']Sequence_1_3 -> Decision_1_3 [label='']  Sequence_1_4 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr></table>>]Decision_1 -> Sequence_1_4 [label='']Sequence_1_4 -> Decision_1_4 [label='']  Sequence_1_5 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr></table>>]Decision_1 -> Sequence_1_5 [label='']Sequence_1_5 -> Decision_1_5 [label='']  Sequence_1_6 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr></table>>]Decision_1 -> Sequence_1_6 [label='']Sequence_1_6 -> Decision_1_6 [label='']  Sequence_1_1_1 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr><tr><td>VILLAGER 1</td><td align='left'>a</td></tr></table>>]Decision_1_1 -> Sequence_1_1_1 [label='']Sequence_1_1_1 -> Tend [label='']  Sequence_1_1_2 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr><tr><td>VILLAGER 1</td><td align='left'>a</td></tr></table>>]Decision_1_1 -> Sequence_1_1_2 [label='']Sequence_1_1_2 -> Tend [label='']  Sequence_1_1_3 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr><tr><td>VILLAGER 1</td><td align='left'>a</td></tr></table>>]Decision_1_1 -> Sequence_1_1_3 [label='']Sequence_1_1_3 -> Tend [label='']  Sequence_1_2_1 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr><tr><td>VILLAGER 2</td><td align='left'>a</td></tr></table>>]Decision_1_2 -> Sequence_1_2_1 [label='']Sequence_1_2_1 -> Tend [label='']  Sequence_1_2_2 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr><tr><td>VILLAGER 2</td><td align='left'>a</td></tr></table>>]Decision_1_2 -> Sequence_1_2_2 [label='']Sequence_1_2_2 -> Tend [label='']  Sequence_1_3_1 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr><tr><td>VILLAGE WOMAN</td><td align='left'>a</td></tr></table>>]Decision_1_3 -> Sequence_1_3_1 [label='']Sequence_1_3_1 -> Tend [label='']  Sequence_1_3_2 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr><tr><td>VILLAGE WOMAN</td><td align='left'>a</td></tr></table>>]Decision_1_3 -> Sequence_1_3_2 [label='']Sequence_1_3_2 -> Tend [label='']  Sequence_1_4_1 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr><tr><td>CITIZEN 1</td><td align='left'>a</td></tr></table>>]Decision_1_4 -> Sequence_1_4_1 [label='']Sequence_1_4_1 -> Tend [label='']  Sequence_1_4_2 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr><tr><td>CITIZEN 1</td><td align='left'>a</td></tr></table>>]Decision_1_4 -> Sequence_1_4_2 [label='']Sequence_1_4_2 -> Tend [label='']  Sequence_1_4_3 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr><tr><td>CITIZEN 1</td><td align='left'>a</td></tr></table>>]Decision_1_4 -> Sequence_1_4_3 [label='']Sequence_1_4_3 -> Tend [label='']  Sequence_1_5_1 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr><tr><td>CITIZEN 2</td><td align='left'>a</td></tr></table>>]Decision_1_5 -> Sequence_1_5_1 [label='']Sequence_1_5_1 -> Tend [label='']  Sequence_1_5_2 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr><tr><td>CITIZEN 2</td><td align='left'>a</td></tr></table>>]Decision_1_5 -> Sequence_1_5_2 [label='']Sequence_1_5_2 -> Tend [label='']  Sequence_1_5_3 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr><tr><td>CITIZEN 2</td><td align='left'>a</td></tr></table>>]Decision_1_5 -> Sequence_1_5_3 [label='']Sequence_1_5_3 -> Tend [label='']  Sequence_1_6_1 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr><tr><td>FEMALE CITIZEN</td><td align='left'>a</td></tr></table>>]Decision_1_6 -> Sequence_1_6_1 [label='']Sequence_1_6_1 -> Tend [label='']  Sequence_1_6_2 [shape=none, label=<<table border='0' cellborder='1' cellspacing='0'><tr><td bgcolor='lightblue'>Char</td><td bgcolor='lightblue'>Text</td></tr><tr><td>FEMALE CITIZEN</td><td align='left'>a</td></tr></table>>]Decision_1_6 -> Sequence_1_6_2 [label='']Sequence_1_6_2 -> Tend [label='']}", Enums.GraphReturnType.Png);

            Assert.That(output.Length, Is.GreaterThanOrEqualTo(0));
        }
MindMusic commented 10 years ago

I have run into this same issue... the execution hangs at GraphGeneration.cs->ReadFully->input.CopyTo(ms); ... It works fine on smaller graphs, but larger ones hang on this line... strangely, running against dot manually generates the graph just fine... Here's my graph text...

digraph G {subgraph cluster_T1 { label = "WORK ORDER"; S1 [label = "ACCEPTED"]; S2 [label = "DENIED"]; S5 [label = "SCHEDULED"]; S44 [label = "COMPLETE"]; S47 [label = "DELIVERED"]; S48 [label = "CANCELLED"]; } subgraph cluster_T2 { label = "MILL/DIG CHECK OUT"; S3 [label = "PROGRAMMING"]; S4 [label = "CUTTER PATH"]; } subgraph cluster_T24 { label = "OFFLOAD INTERNAL"; S83 [label = "IN PROCESS"]; S84 [label = "FINISHED"]; } subgraph cluster_T23 { label = "OFFLOAD EXTERNAL"; S45 [label = "IN PROCESS"]; S46 [label = "FINISHED"]; S82 [label = "QUOTE PENDING"]; } subgraph cluster_T1 { label = "WORK ORDER"; S49 [label = "WAITING 5-AXIS"]; S50 [label = "WAITING DATA CHANGE"]; } subgraph cluster_T8 { label = "MILL 1"; S15 [label = "IN PROCESS"]; S16 [label = "FINISHED"]; } subgraph cluster_T9 { label = "MILL 2"; S17 [label = "IN PROCESS"]; S18 [label = "FINISHED"]; } subgraph cluster_T10 { label = "MILL 3"; S20 [label = "IN PROCESS"]; S21 [label = "FINISHED"]; } subgraph cluster_T11 { label = "MILL 4"; S22 [label = "IN PROCESS"]; S23 [label = "FINISHED"]; } subgraph cluster_T12 { label = "MILL 5"; S24 [label = "IN PROCESS"]; S25 [label = "FINISHED"]; } subgraph cluster_T13 { label = "MILL 6"; S26 [label = "IN PROCESS"]; S27 [label = "FINISHED"]; } subgraph cluster_T14 { label = "MILL 7"; S28 [label = "IN PROCESS"]; S29 [label = "FINISHED"]; } subgraph cluster_T15 { label = "MILL 8"; S30 [label = "IN PROCESS"]; S31 [label = "FINISHED"]; } subgraph cluster_T16 { label = "HAAS"; S32 [label = "IN PROCESS"]; S33 [label = "FINISHED"]; } subgraph cluster_T17 { label = "FADAL 1"; S34 [label = "IN PROCESS"]; S35 [label = "FINISHED"]; } subgraph cluster_T18 { label = "FADAL 2"; S36 [label = "IN PROCESS"]; S37 [label = "FINISHED"]; } subgraph cluster_T19 { label = "DUPLICATOR"; S38 [label = "IN PROCESS"]; S39 [label = "FINISHED"]; } subgraph cluster_T20 { label = "TWIN RED"; S40 [label = "IN PROCESS"]; S41 [label = "FINISHED"]; } subgraph cluster_T21 { label = "TWIN BLUE"; S42 [label = "IN PROCESS"]; S43 [label = "FINISHED"]; } S1->S3;S47->S44;S3->S4;S4->S5;S83->S84;S84->S47;S45->S46;S46->S47;S82->S45;S15->S16;S16->S47;S17->S18;S18->S47;S20->S21;S21->S47;S22->S23;S23->S47;S24->S25;S25->S47;S26->S27;S27->S47;S28->S29;S29->S47;S30->S31;S31->S47;S32->S33;S33->S47;S34->S35;S35->S47;S36->S37;S37->S47;S38->S39;S39->S47;S40->S41;S41->S47;S42->S43;S43->S47;}

Any ideas?

JamieDixon commented 10 years ago

Thanks for bringing this issue to my attention guys. Now that I've understood what's happening I've committed a fix that opens up the standard error stream asynchronously which avoids the deadlock we were seeing with large inputs.