Distribute ResolveAssemblyReference cache (#3989)
Distribute ResolveAssemblyReference cache (#3989)

Previously, each instance of the SystemState cache copied all FileState objects accessed and serialized them onto disk for each project. This resulted in large amounts of identical data written to disk and deserialized into memory.

This adds some bookkeeping to each SystemState instance to ensure that FileState objects aren't duplicated from the process-wide cache if another instance is already responsible for serializing that object. This results in some additional IO on multi-proc builds since RAR execution order may change around and result in some cache misses, but it seems to be outweighed by the huge savings in memory and RAR times.

In two traces taken from building WebLarge and OrchardCore, this results in a nearly 30% reduction in time spent on RAR.
mono/msbuild,mono/msbuild,AndyGerlicher/msbuild,mono/msbuild,rainersigwald/msbuild,rainersigwald/msbuild,AndyGerlicher/msbuild,chipitsine/msbuild,cdmihai/msbuild,sean-gilliam/msbuild,jeffkl/msbuild,jeffkl/msbuild,cdmihai/msbuild,Microsoft/msbuild,rainersigwald/msbuild,rainersigwald/msbuild,Microsoft/msbuild,AndyGerlicher/msbuild,cdmihai/msbuild,mono/msbuild,AndyGerlicher/msbuild,chipitsine/msbuild,sean-gilliam/msbuild,cdmihai/msbuild,Microsoft/msbuild,jeffkl/msbuild,sean-gilliam/msbuild,sean-gilliam/msbuild,Microsoft/msbuild,chipitsine/msbuild,chipitsine/msbuild,jeffkl/msbuild