rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97.65k stars 12.63k forks source link

concurrent rustdoc usage can lead to bad times #30220

Open letheed opened 8 years ago

letheed commented 8 years ago

I noticed that the documentation generated by cargo doc was not exactly the same depending on if I ran cargo test or cargo build first.

Running:

$ cargo clean
$ cargo doc
$ mv target/doc tdoc
$ cargo clean
$ cargo test # or cargo build
$ cargo doc
$ diff -r tdoc target/doc
diff -r tdoc/search-index.js target/doc/search-index.js
2d1
< searchIndex['takuzu'] = {"items":[[0,"","takuzu","A Takuzu (a.k.a. Binairo) solving library.",null,null],[3,"Grid","","A container for takuzu grid manipulation.",null,null],[4,"GridError","","An error returned when checking if the grid is well-sized and legal.",null,null],[13,"BadSize","","The grid does not have the right size.",0,null],[13,"Illegal","","The grid is illegal, that is it infringes at least one of the rules.",0,null],[4,"GridParseError","","An error returned when parsing a string to create a grid failed.",null,null],[13,"CreationError","","A `Grid` cannot be created from this `Array`.",1,null],[13,"UnexpectedCharacter","","At least one character other than `0`, `1`, `.` or '\\n'\nwas found in the string.",1,null],[4,"GridSizeError","","An error returned when the grid is not properly sized.",null,null],[13,"Empty","","The grid is empty.",2,null],[13,"NotASquare","","The grid is not a square.\nThe field contains the line number that triggered the error.",2,null],[13,"OddRowNumber","","The grid has an odd number of rows.",2,null],[4,"SourceError","","An error returned by the `source` method when either reading or parsing failed.",null,null],[13,"IO","","Reading from the source failed.",3,null],[13,"Parsing","","Parsing failed.",3,null],[11,"eq","","",0,{"inputs":[{"name":"griderror"},{"name":"griderror"}],"output":{"name":"bool"}}],[11,"ne","","",0,{"inputs":[{"name":"griderror"},{"name":"griderror"}],"output":{"name":"bool"}}],[11,"hash","","",0,null],[11,"fmt","","",0,{"inputs":[{"name":"griderror"},{"name":"formatter"}],"output":{"name":"result"}}],[11,"clone","","",0,{"inputs":[{"name":"griderror"}],"output":{"name":"griderror"}}],[11,"fmt","","",0,{"inputs":[{"name":"griderror"},{"name":"formatter"}],"output":{"name":"result"}}],[11,"description","","",0,{"inputs":[{"name":"griderror"}],"output":{"name":"str"}}],[11,"cause","","",0,{"inputs":[{"name":"griderror"}],"output":{"name":"option"}}],[11,"from","","",0,{"inputs":[{"name":"griderror"},{"name":"gridsizeerror"}],"output":{"name":"self"}}],[11,"eq","","",1,{"inputs":[{"name":"gridparseerror"},{"name":"gridparseerror"}],"output":{"name":"bool"}}],[11,"ne","","",1,{"inputs":[{"name":"gridparseerror"},{"name":"gridparseerror"}],"output":{"name":"bool"}}],[11,"hash","","",1,null],[11,"fmt","","",1,{"inputs":[{"name":"gridparseerror"},{"name":"formatter"}],"output":{"name":"result"}}],[11,"clone","","",1,{"inputs":[{"name":"gridparseerror"}],"output":{"name":"gridparseerror"}}],[11,"fmt","","",1,{"inputs":[{"name":"gridparseerror"},{"name":"formatter"}],"output":{"name":"result"}}],[11,"description","","",1,{"inputs":[{"name":"gridparseerror"}],"output":{"name":"str"}}],[11,"cause","","",1,{"inputs":[{"name":"gridparseerror"}],"output":{"name":"option"}}],[11,"eq","","",2,{"inputs":[{"name":"gridsizeerror"},{"name":"gridsizeerror"}],"output":{"name":"bool"}}],[11,"ne","","",2,{"inputs":[{"name":"gridsizeerror"},{"name":"gridsizeerror"}],"output":{"name":"bool"}}],[11,"hash","","",2,null],[11,"fmt","","",2,{"inputs":[{"name":"gridsizeerror"},{"name":"formatter"}],"output":{"name":"result"}}],[11,"clone","","",2,{"inputs":[{"name":"gridsizeerror"}],"output":{"name":"gridsizeerror"}}],[11,"fmt","","",2,{"inputs":[{"name":"gridsizeerror"},{"name":"formatter"}],"output":{"name":"result"}}],[11,"description","","",2,{"inputs":[{"name":"gridsizeerror"}],"output":{"name":"str"}}],[11,"eq","","",4,{"inputs":[{"name":"grid"},{"name":"grid"}],"output":{"name":"bool"}}],[11,"ne","","",4,{"inputs":[{"name":"grid"},{"name":"grid"}],"output":{"name":"bool"}}],[11,"hash","","",4,null],[11,"fmt","","",4,{"inputs":[{"name":"grid"},{"name":"formatter"}],"output":{"name":"result"}}],[11,"clone","","",4,{"inputs":[{"name":"grid"}],"output":{"name":"grid"}}],[11,"fmt","","",4,{"inputs":[{"name":"grid"},{"name":"formatter"}],"output":{"name":"result"}}],[11,"from_str","","",4,{"inputs":[{"name":"grid"},{"name":"str"}],"output":{"name":"result"}}],[11,"index","","",4,null],[11,"index_mut","","",4,null],[11,"new","","Creates a `Grid` from a preexisting array.",4,{"inputs":[{"name":"grid"},{"name":"array"}],"output":{"name":"result"}}],[11,"size","","Returns the size of the grid.",4,{"inputs":[{"name":"grid"}],"output":{"name":"usize"}}],[11,"into_inner","","Consumes a `Grid` and returns the underlying array.",4,{"inputs":[{"name":"grid"}],"output":{"name":"array"}}],[11,"is_filled","","Returns `true` if the grid contains no empty cell.",4,{"inputs":[{"name":"grid"}],"output":{"name":"bool"}}],[11,"is_legal","","Verifies that the grid does not currently violate any of the rules.\nReturns `true` if the grid is legal.",4,{"inputs":[{"name":"grid"}],"output":{"name":"bool"}}],[11,"is_cell_legal","","Verifies that a certain cell does not violate any of the rules.\nReturns `true` if the value is legal.",4,{"inputs":[{"name":"grid"},{"name":"usize"},{"name":"usize"}],"output":{"name":"bool"}}],[11,"next_empty","","Returns the index of the first empty cell or None if the grid is filled.",4,{"inputs":[{"name":"grid"}],"output":{"name":"option"}}],[11,"apply_rules","","Skims through the grid once for each rule and fills in the blanks\nwhere the value is unambiguous.\nReturns `true` if the grid was modified.",4,{"inputs":[{"name":"grid"}],"output":{"name":"bool"}}],[11,"solve","","Solves the grid using both rules logic and a backtracking algorithm,\nand returns an array containing the solution(s).\nIf no solution exists, an empty array is returned.",4,{"inputs":[{"name":"grid"}],"output":{"name":"vec"}}],[11,"to_string_diff","","Suitable for terminals.",4,{"inputs":[{"name":"grid"},{"name":"grid"}],"output":{"name":"string"}}],[11,"fmt","","",3,{"inputs":[{"name":"sourceerror"},{"name":"formatter"}],"output":{"name":"result"}}],[11,"fmt","","",3,{"inputs":[{"name":"sourceerror"},{"name":"formatter"}],"output":{"name":"result"}}],[11,"description","","",3,{"inputs":[{"name":"sourceerror"}],"output":{"name":"str"}}],[11,"cause","","",3,{"inputs":[{"name":"sourceerror"}],"output":{"name":"option"}}],[11,"from","","",3,{"inputs":[{"name":"sourceerror"},{"name":"ioerror"}],"output":{"name":"self"}}],[11,"from","","",3,{"inputs":[{"name":"sourceerror"},{"name":"gridparseerror"}],"output":{"name":"self"}}],[6,"Array","","A raw takuzu grid representation.",null,null],[8,"Source","","The `Source` trait allows to use any implementor of the `Read` trait\nas an input source for the grid string format with no additional effort.",null,null],[11,"source","","Creates a `Grid` from a readable source.\nReads from the source until EOF, parses the data as a string,\nthen checks the array for size and legality and converts it to a `Grid`",5,{"inputs":[{"name":"source"}],"output":{"name":"result"}}],[11,"source","","Creates a `Grid` from a readable source.\nReads from the source until EOF, parses the data as a string,\nthen checks the array for size and legality and converts it to a `Grid`",5,{"inputs":[{"name":"source"}],"output":{"name":"result"}}]],"paths":[[4,"GridError"],[4,"GridParseError"],[4,"GridSizeError"],[4,"SourceError"],[3,"Grid"],[8,"Source"]]};
3a3
> searchIndex['takuzu'] = {"items":[[0,"","takuzu","A Takuzu (a.k.a. Binairo) solving library.",null,null],[3,"Grid","","A container for takuzu grid manipulation.",null,null],[4,"GridError","","An error returned when checking if the grid is well-sized and legal.",null,null],[13,"BadSize","","The grid does not have the right size.",0,null],[13,"Illegal","","The grid is illegal, that is it infringes at least one of the rules.",0,null],[4,"GridParseError","","An error returned when parsing a string to create a grid failed.",null,null],[13,"CreationError","","A `Grid` cannot be created from this `Array`.",1,null],[13,"UnexpectedCharacter","","At least one character other than `0`, `1`, `.` or '\\n'\nwas found in the string.",1,null],[4,"GridSizeError","","An error returned when the grid is not properly sized.",null,null],[13,"Empty","","The grid is empty.",2,null],[13,"NotASquare","","The grid is not a square.\nThe field contains the line number that triggered the error.",2,null],[13,"OddRowNumber","","The grid has an odd number of rows.",2,null],[4,"SourceError","","An error returned by the `source` method when either reading or parsing failed.",null,null],[13,"IO","","Reading from the source failed.",3,null],[13,"Parsing","","Parsing failed.",3,null],[11,"eq","","",0,{"inputs":[{"name":"griderror"},{"name":"griderror"}],"output":{"name":"bool"}}],[11,"ne","","",0,{"inputs":[{"name":"griderror"},{"name":"griderror"}],"output":{"name":"bool"}}],[11,"hash","","",0,null],[11,"fmt","","",0,{"inputs":[{"name":"griderror"},{"name":"formatter"}],"output":{"name":"result"}}],[11,"clone","","",0,{"inputs":[{"name":"griderror"}],"output":{"name":"griderror"}}],[11,"fmt","","",0,{"inputs":[{"name":"griderror"},{"name":"formatter"}],"output":{"name":"result"}}],[11,"description","","",0,{"inputs":[{"name":"griderror"}],"output":{"name":"str"}}],[11,"cause","","",0,{"inputs":[{"name":"griderror"}],"output":{"name":"option"}}],[11,"from","","",0,{"inputs":[{"name":"griderror"},{"name":"gridsizeerror"}],"output":{"name":"self"}}],[11,"eq","","",1,{"inputs":[{"name":"gridparseerror"},{"name":"gridparseerror"}],"output":{"name":"bool"}}],[11,"ne","","",1,{"inputs":[{"name":"gridparseerror"},{"name":"gridparseerror"}],"output":{"name":"bool"}}],[11,"hash","","",1,null],[11,"fmt","","",1,{"inputs":[{"name":"gridparseerror"},{"name":"formatter"}],"output":{"name":"result"}}],[11,"clone","","",1,{"inputs":[{"name":"gridparseerror"}],"output":{"name":"gridparseerror"}}],[11,"fmt","","",1,{"inputs":[{"name":"gridparseerror"},{"name":"formatter"}],"output":{"name":"result"}}],[11,"description","","",1,{"inputs":[{"name":"gridparseerror"}],"output":{"name":"str"}}],[11,"cause","","",1,{"inputs":[{"name":"gridparseerror"}],"output":{"name":"option"}}],[11,"eq","","",2,{"inputs":[{"name":"gridsizeerror"},{"name":"gridsizeerror"}],"output":{"name":"bool"}}],[11,"ne","","",2,{"inputs":[{"name":"gridsizeerror"},{"name":"gridsizeerror"}],"output":{"name":"bool"}}],[11,"hash","","",2,null],[11,"fmt","","",2,{"inputs":[{"name":"gridsizeerror"},{"name":"formatter"}],"output":{"name":"result"}}],[11,"clone","","",2,{"inputs":[{"name":"gridsizeerror"}],"output":{"name":"gridsizeerror"}}],[11,"fmt","","",2,{"inputs":[{"name":"gridsizeerror"},{"name":"formatter"}],"output":{"name":"result"}}],[11,"description","","",2,{"inputs":[{"name":"gridsizeerror"}],"output":{"name":"str"}}],[11,"eq","","",4,{"inputs":[{"name":"grid"},{"name":"grid"}],"output":{"name":"bool"}}],[11,"ne","","",4,{"inputs":[{"name":"grid"},{"name":"grid"}],"output":{"name":"bool"}}],[11,"hash","","",4,null],[11,"fmt","","",4,{"inputs":[{"name":"grid"},{"name":"formatter"}],"output":{"name":"result"}}],[11,"clone","","",4,{"inputs":[{"name":"grid"}],"output":{"name":"grid"}}],[11,"fmt","","",4,{"inputs":[{"name":"grid"},{"name":"formatter"}],"output":{"name":"result"}}],[11,"from_str","","",4,{"inputs":[{"name":"grid"},{"name":"str"}],"output":{"name":"result"}}],[11,"index","","",4,null],[11,"index_mut","","",4,null],[11,"new","","Creates a `Grid` from a preexisting array.",4,{"inputs":[{"name":"grid"},{"name":"array"}],"output":{"name":"result"}}],[11,"size","","Returns the size of the grid.",4,{"inputs":[{"name":"grid"}],"output":{"name":"usize"}}],[11,"into_inner","","Consumes a `Grid` and returns the underlying array.",4,{"inputs":[{"name":"grid"}],"output":{"name":"array"}}],[11,"is_filled","","Returns `true` if the grid contains no empty cell.",4,{"inputs":[{"name":"grid"}],"output":{"name":"bool"}}],[11,"is_legal","","Verifies that the grid does not currently violate any of the rules.\nReturns `true` if the grid is legal.",4,{"inputs":[{"name":"grid"}],"output":{"name":"bool"}}],[11,"is_cell_legal","","Verifies that a certain cell does not violate any of the rules.\nReturns `true` if the value is legal.",4,{"inputs":[{"name":"grid"},{"name":"usize"},{"name":"usize"}],"output":{"name":"bool"}}],[11,"next_empty","","Returns the index of the first empty cell or None if the grid is filled.",4,{"inputs":[{"name":"grid"}],"output":{"name":"option"}}],[11,"apply_rules","","Skims through the grid once for each rule and fills in the blanks\nwhere the value is unambiguous.\nReturns `true` if the grid was modified.",4,{"inputs":[{"name":"grid"}],"output":{"name":"bool"}}],[11,"solve","","Solves the grid using both rules logic and a backtracking algorithm,\nand returns an array containing the solution(s).\nIf no solution exists, an empty array is returned.",4,{"inputs":[{"name":"grid"}],"output":{"name":"vec"}}],[11,"to_string_diff","","Suitable for terminals.",4,{"inputs":[{"name":"grid"},{"name":"grid"}],"output":{"name":"string"}}],[11,"fmt","","",3,{"inputs":[{"name":"sourceerror"},{"name":"formatter"}],"output":{"name":"result"}}],[11,"fmt","","",3,{"inputs":[{"name":"sourceerror"},{"name":"formatter"}],"output":{"name":"result"}}],[11,"description","","",3,{"inputs":[{"name":"sourceerror"}],"output":{"name":"str"}}],[11,"cause","","",3,{"inputs":[{"name":"sourceerror"}],"output":{"name":"option"}}],[11,"from","","",3,{"inputs":[{"name":"sourceerror"},{"name":"ioerror"}],"output":{"name":"self"}}],[11,"from","","",3,{"inputs":[{"name":"sourceerror"},{"name":"gridparseerror"}],"output":{"name":"self"}}],[6,"Array","","A raw takuzu grid representation.",null,null],[8,"Source","","The `Source` trait allows to use any implementor of the `Read` trait\nas an input source for the grid string format with no additional effort.",null,null],[11,"source","","Creates a `Grid` from a readable source.\nReads from the source until EOF, parses the data as a string,\nthen checks the array for size and legality and converts it to a `Grid`",5,{"inputs":[{"name":"source"}],"output":{"name":"result"}}],[11,"source","","Creates a `Grid` from a readable source.\nReads from the source until EOF, parses the data as a string,\nthen checks the array for size and legality and converts it to a `Grid`",5,{"inputs":[{"name":"source"}],"output":{"name":"result"}}]],"paths":[[4,"GridError"],[4,"GridParseError"],[4,"GridSizeError"],[4,"SourceError"],[3,"Grid"],[8,"Source"]]};
diff -r tdoc/tackle/fn.solve_from.html target/doc/tackle/fn.solve_from.html
49c49
< <pre class='rust fn'>pub fn solve_from&lt;T: Source + ?<a class='trait' href='https://doc.rust-lang.org/nightly/core/marker/trait.Sized.html' title='core::marker::Sized'>Sized</a>&gt;(source: &amp;mut T)</pre><div class='docblock'><p>Reads a grid from a source, triggers the solving algorithm

---
> <pre class='rust fn'>pub fn solve_from&lt;T: <a class='trait' href='../takuzu/source/trait.Source.html' title='takuzu::source::Source'>Source</a> + ?<a class='trait' href='https://doc.rust-lang.org/nightly/core/marker/trait.Sized.html' title='core::marker::Sized'>Sized</a>&gt;(source: &amp;mut T)</pre><div class='docblock'><p>Reads a grid from a source, triggers the solving algorithm

The first point is not that big of a problem but the second one is clearly a bug.

As suggested by @alexcrichton, using the --jobs 1 flag on both cargo doc and cargo build/test solves the problem by making the process deterministic, at the expense of compile/docgen time obviously.

lucab commented 8 years ago

We have just observed the same (non-deterministic JSON ordering) during reproducible rebuilds in Debian. In general, it would be a good idea to make the serialization deterministic.

sfackler commented 8 years ago

This should be filed in the rust-lang/cargo repo.

letheed commented 8 years ago

@sfackler actually I did that in the first place but I was told to open a new one here. The original bug report can be found here

alexcrichton commented 8 years ago

Yes I think this is likely related to the nondeterminism of running multiple processes at once and I think that rustdoc can probably add more safeguards/sorting rather than Cargo handling this (unless I'm misunderstanding)

steveklabnik commented 4 years ago

Triage: is anyone still seeing this issue? Any way of reproducing it more easily?