Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Installplan installed state #3863

Merged
merged 7 commits into from
Sep 20, 2016
Merged

Installplan installed state #3863

merged 7 commits into from
Sep 20, 2016

Conversation

dcoutts
Copy link
Contributor

@dcoutts dcoutts commented Sep 18, 2016

So why add an Installed state? Didn't we just remove the Installed, Processing and Failed states? Those states were used when we followed the approach of updating the InstallPlan as a build progressed (whereas we now do traversals without altering the InstallPlan).

The idea of adding an Installed state now is that we can more usefully represent the state of the plan when we "improve" the plan with packages from the store or when we update the plan having checked if inplace packages are up to date. Currently in these two places we replace Configured source packages with PreExisting packages. There's a couple problems with this. Firstly the PreExisting state only contains an InstalledPackageInfo which means we loose information compared to all the detail in the Configured source package. This is relevant for things like plan.json output or other features that want to know the status of a project. Secondly we have to fake things for executables since they are not properly represented by InstalledPackageInfo. So this avoids the need for thos hacks.

Also simplify the way we do the improvement now that we no longer need the InstalledPackageInfo. Now rather than reading the ghc-pkg db we can just get the dir listing for the store and use that as a set of UnitIds.

This already helps the plan.json output and will also be needed for maintaining the .ghc.environment file sanely.

@dcoutts dcoutts mentioned this pull request Sep 19, 2016
@hvr
Copy link
Member

hvr commented Sep 19, 2016

This already helps the plan.json output

Do you have an example plan.json files (e.g. gist or paste) showing before/after? :-)

@dcoutts
Copy link
Contributor Author

dcoutts commented Sep 19, 2016

No idea why we're getting ghc-pkg dump failed in the appveyor tests. That's coming from the Cabal lib (Setup.hs) bit, which this patch does not touch.

@dcoutts
Copy link
Contributor Author

dcoutts commented Sep 19, 2016

Do you have an example plan.json files (e.g. gist or paste) showing before/after? :-)

So actually it needs one more change before we plan output changes:

-    phaseMaintainPlanOutputs _improvedPlan elaboratedPlan elaboratedShared = do
+    phaseMaintainPlanOutputs improvedPlan _elaboratedPlan elaboratedShared = do
         liftIO $ debug verbosity "Updating plan.json"
         liftIO $ writePlanExternalRepresentation
                    distDirLayout
-                   elaboratedPlan
+                   improvedPlan
                    elaboratedShared

With that, then the change is that the "type" field of many components/packages changes from "configured" to "installed". That's the only change.

Now if we want to do it like this then actually it makes sense to update the plan after building so that it reflects the new installed status post-build. Of course it'd still be updated on configure or build --dry-run. I've got some further refactoring in the WIP branch ghc-environments that will help with maintaining status post-build, so I might include this change in that lot, if we agree we want the plan.json status to reflect the installed states.

This patch just adds the state without yet using it. That'll follow in
subsequent patches.

So why add an Installed state? Didn't we just remove the Installed,
Processing and Failed states? Those states were used when we followed
the approach of updating the InstallPlan as a build progressed (whereas
we now do traversals without altering the InstallPlan).

The idea of adding an Installed state now is that we can more usefully
represent the state of the plan when we "improve" the plan with packages
from the store or when we update the plan having checked if inplace
packages are up to date. Currently in these two places we replace
Configured source packages with PreExisting packages. There's a couple
problems with this. Firstly the PreExisting state only contains an
InstalledPackageInfo which means we loose information compared to all
the detail in the Configured source package. This is relevant for things
like plan.json output or other features that want to know the status of
a project. Secondly we have to fake things for executables since they
are not properly represented by InstalledPackageInfo.
The change in how we use the PreExisting vs Installed states means that
we'll now have full details for all packages, rather than installed
ones having only the subset of info available from the
InstalledPackageInfo. So the 'type' field now can take the values
"pre-existing", "configured" or "installed".

Also do a little bit of tidying up.
Change improvement and --dry-run phases to use Installed state rather
than the PreExisting state. This means that PreExisting is now only used
for installed packages from the global db, and never for installed
packages from the store.
We only ever switch Configured to Installed. The PreExisting state only
comes from the original solver plan, which only uses installed packages
from the global db.
Not a big deal, but should be useful later for more precise status
reporting. For now just means the rebuild reasons can be more precise.
@dcoutts
Copy link
Contributor Author

dcoutts commented Sep 19, 2016

Rebased on latest master with ezyang's improved ghc-pkg dump error message so hopefully we can diagnose the appveyor build failures.

@dcoutts
Copy link
Contributor Author

dcoutts commented Sep 19, 2016

Ah, ok, that's better:

  cabal.exe: ghc-pkg dump failed: user error
  ('C:\ProgramData\chocolatey\lib\ghc\tools\ghc-8.0.1\bin\ghc-pkg.exe' exited
  with an error:
  ghc-pkg.exe:
  C:\Users\appveyor\AppData\Roaming\cabal\store\ghc-8.0.1\package.db:
  getDirectoryContents: does not exist (The system cannot find the path
  specified.)
  )

@dcoutts
Copy link
Contributor Author

dcoutts commented Sep 19, 2016

Ok, now I really don't get these appveyor build failures:

ghc-pkg.exe: C:\Users\appveyor\AppData\Roaming\ghc\x86_64-mingw32-8.0.1\package.conf.d\package.cache:
you don't have permission to modify this file

This happens when building the dependencies of cabal. And this is after having installed and registered dozens of other packages, so how did the file permissions change?

@ezyang
Copy link
Contributor

ezyang commented Sep 19, 2016

Usually that indicates an intermittent failure. I kick a rebuild in such cases. We should eventually figure out why this is happening though.

@ezyang
Copy link
Contributor

ezyang commented Sep 19, 2016

LGTM, assuming tests pass.

@ezyang ezyang added this to the 2.0 milestone Sep 19, 2016
Install plan improvement is the process of replacing configured source
packages with installed instances from the store. Originally we did this
by reading the ghc-pkg db to get the InstalledPackageInfo for all the
packages in the store. We had to do that because when we replaced
configured source packages by installed instances we used the
PreExisting constructor which requires an InstalledPackageInfo, which we
get from the installed package db. But now that we no longer use
PreExisting for packages from the store we also no longer need the
InstalledPackageInfo. All we need is a set of UnitIds. Also, once
support for depending on executables was added then we needed a way to
do plan improvement for executable packages/components. We did this by
the simple approach of grabbing the dir listing for the store and using
that as a set of UnitIds.

So this patch extends the approach we use for executables and uses it
for all packages. This means we no longer load the package db for the
store. Note that we still have to create the package db in the store.

This also relates to the locking protocol in the store. The goal for the
store is to be able to access and update it concurrently. The locking
protocol will include checking membership by checking if the directory
entry for the package is present. So this patch gets us to the right
point for the reading side, leaving the writing side to do.
All the use sites (currently only two but soon to be three) use
InstallPlan.installed to do a bulk change of states, differing only in
the filter condition. So it simplifies things and shares more code if
we make the main one be the bulk version. The InstallPlan.remove already
works similarly.
@ezyang ezyang merged commit 7b67f37 into master Sep 20, 2016
@23Skidoo 23Skidoo deleted the installplan-installed-state branch September 20, 2016 14:32
ezyang added a commit that referenced this pull request Sep 20, 2016
…tate"

This reverts commit 7b67f37, reversing
changes made to c12290f.
@ezyang
Copy link
Contributor

ezyang commented Sep 20, 2016

I reverted this because it seems to have broken improvement:

ezyang@sabre:~/Dev/cabal-shake$ cabal new-build cabal -O0
In order, the following will be built (use -v for more details):
 - base16-bytestring-0.1.1.6 (lib:base16-bytestring) (requires build)
 - base64-bytestring-1.0.0.1 (lib) (requires build)
 - cryptohash-sha256-0.11.100.1 (lib) (requires build)
 - ed25519-0.0.5.0 (lib) (requires build)
 - tar-0.5.0.3 (lib) (requires build)
 - hackage-security-0.5.2.2 (lib) (dependency rebuilt)
 - cabal-install-1.25.0.0 (exe:cabal) (dependency rebuilt)
Configuring base16-bytestring-0.1.1.6...
Preprocessing library base16-bytestring-0.1.1.6...
[1 of 2] Compiling Data.ByteString.Base16 ( Data/ByteString/Base16.hs, dist/build/Data/ByteString/Base16.o )
[2 of 2] Compiling Data.ByteString.Base16.Lazy ( Data/ByteString/Base16/Lazy.hs, dist/build/Data/ByteString/Base16/Lazy.o )
Installing library in
/home/ezyang/.cabal/store/ghc-7.10.3/base16-bytestring-0.1.1.6-1d0031adeec946836493faef6f6e89559987ac1263d4f3a841aedd1caca658cc/lib
Configuring component lib from base64-bytestring-1.0.0.1
Preprocessing library base64-bytestring-1.0.0.1...
[1 of 5] Compiling Data.ByteString.Base64.Internal ( Data/ByteString/Base64/Internal.hs, dist/build/Data/ByteString/Base64/Internal.o )
[2 of 5] Compiling Data.ByteString.Base64.URL ( Data/ByteString/Base64/URL.hs, dist/build/Data/ByteString/Base64/URL.o )
[3 of 5] Compiling Data.ByteString.Base64.URL.Lazy ( Data/ByteString/Base64/URL/Lazy.hs, dist/build/Data/ByteString/Base64/URL/Lazy.o )
[4 of 5] Compiling Data.ByteString.Base64 ( Data/ByteString/Base64.hs, dist/build/Data/ByteString/Base64.o )
[5 of 5] Compiling Data.ByteString.Base64.Lazy ( Data/ByteString/Base64/Lazy.hs, dist/build/Data/ByteString/Base64/Lazy.o )
Installing library in
/home/ezyang/.cabal/store/ghc-7.10.3/base64-bytestring-1.0.0.1-04b69d0b7a0aa1c476da284e4df855734f201d7635898e7a80d43fbb3275c7e3/lib
Configuring component lib from cryptohash-sha256-0.11.100.1
Preprocessing library cryptohash-sha256-0.11.100.1...
[1 of 1] Compiling Crypto.Hash.SHA256 ( src/Crypto/Hash/SHA256.hs, dist/build/Crypto/Hash/SHA256.o )

src/Crypto/Hash/SHA256.hs:124:11: Warning:
    Rule "digestSize" may never fire
      because ‘B.length’ might inline first
    Probable fix: add an INLINE[n] or NOINLINE[n] pragma on ‘B.length’
Installing library in
/home/ezyang/.cabal/store/ghc-7.10.3/cryptohash-sha256-0.11.100.1-e4cc04e9a14cdc76f135f864276b08c5b752707fe1271f651783891059f407d1/lib
Configuring component lib from ed25519-0.0.5.0
Preprocessing library ed25519-0.0.5.0...
[1 of 1] Compiling Crypto.Sign.Ed25519 ( src/Crypto/Sign/Ed25519.hs, dist/build/Crypto/Sign/Ed25519.o )
Installing library in
/home/ezyang/.cabal/store/ghc-7.10.3/ed25519-0.0.5.0-3f7ef59086021ba8575d17b646e419022e67f0e41690abaa0054d5508d27e746/lib
Configuring component lib from tar-0.5.0.3
Preprocessing library tar-0.5.0.3...
[ 1 of 11] Compiling Codec.Archive.Tar.Index.IntTrie ( Codec/Archive/Tar/Index/IntTrie.hs, dist/build/Codec/Archive/Tar/Index/IntTrie.o )
[ 2 of 11] Compiling Codec.Archive.Tar.Index.StringTable ( Codec/Archive/Tar/Index/StringTable.hs, dist/build/Codec/Archive/Tar/Index/StringTable.o )
[ 3 of 11] Compiling Codec.Archive.Tar.Types ( Codec/Archive/Tar/Types.hs, dist/build/Codec/Archive/Tar/Types.o )
[ 4 of 11] Compiling Codec.Archive.Tar.Read ( Codec/Archive/Tar/Read.hs, dist/build/Codec/Archive/Tar/Read.o )
[ 5 of 11] Compiling Codec.Archive.Tar.Write ( Codec/Archive/Tar/Write.hs, dist/build/Codec/Archive/Tar/Write.o )
[ 6 of 11] Compiling Codec.Archive.Tar.Pack ( Codec/Archive/Tar/Pack.hs, dist/build/Codec/Archive/Tar/Pack.o )
[ 7 of 11] Compiling Codec.Archive.Tar.Index ( Codec/Archive/Tar/Index.hs, dist/build/Codec/Archive/Tar/Index.o )
[ 8 of 11] Compiling Codec.Archive.Tar.Check ( Codec/Archive/Tar/Check.hs, dist/build/Codec/Archive/Tar/Check.o )
[ 9 of 11] Compiling Codec.Archive.Tar.Unpack ( Codec/Archive/Tar/Unpack.hs, dist/build/Codec/Archive/Tar/Unpack.o )
[10 of 11] Compiling Codec.Archive.Tar.Entry ( Codec/Archive/Tar/Entry.hs, dist/build/Codec/Archive/Tar/Entry.o )
[11 of 11] Compiling Codec.Archive.Tar ( Codec/Archive/Tar.hs, dist/build/Codec/Archive/Tar.o )
Installing library in
/home/ezyang/.cabal/store/ghc-7.10.3/tar-0.5.0.3-310447fffba92e9605afc215238d176d28f3215cc1a498e97df941b3e2dde83d/lib
Preprocessing library hackage-security-0.5.2.2...
Preprocessing executable 'cabal' for cabal-install-1.25.0.0...
[ 90 of 125] Compiling Distribution.Client.Dependency ( Distribution/Client/Dependency.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/Dependency.o )

Distribution/Client/Dependency.hs:326:1: Warning:
    Defined but not used: ‘setSolveExecutables’
[ 91 of 125] Compiling Distribution.Client.ProjectConfig.Types ( Distribution/Client/ProjectConfig/Types.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/ProjectConfig/Types.o )
[ 92 of 125] Compiling Distribution.Client.Setup ( Distribution/Client/Setup.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/Setup.o )
[ 93 of 125] Compiling Distribution.Client.Config ( Distribution/Client/Config.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/Config.o )
[ 94 of 125] Compiling Distribution.Client.Sandbox.PackageEnvironment ( Distribution/Client/Sandbox/PackageEnvironment.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/Sandbox/PackageEnvironment.o ) [Distribution.Compat.Exception changed]
[ 95 of 125] Compiling Distribution.Client.Manpage ( Distribution/Client/Manpage.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/Manpage.o ) [Distribution.Simple.Command changed]
[ 96 of 125] Compiling Distribution.Client.IndexUtils ( Distribution/Client/IndexUtils.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/IndexUtils.o )
[ 97 of 125] Compiling Distribution.Client.SetupWrapper ( Distribution/Client/SetupWrapper.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/SetupWrapper.o ) [Distribution.Compat.Exception changed]
[ 98 of 125] Compiling Distribution.Client.SrcDist ( Distribution/Client/SrcDist.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/SrcDist.o )
[ 99 of 125] Compiling Distribution.Client.List ( Distribution/Client/List.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/List.o ) [Distribution.InstalledPackageInfo changed]
[100 of 125] Compiling Distribution.Client.Configure ( Distribution/Client/Configure.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/Configure.o )
[101 of 125] Compiling Distribution.Client.Update ( Distribution/Client/Update.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/Update.o ) [Hackage.Security.Client changed]
[102 of 125] Compiling Distribution.Client.Fetch ( Distribution/Client/Fetch.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/Fetch.o ) [Distribution.Package changed]
[103 of 125] Compiling Distribution.Client.Freeze ( Distribution/Client/Freeze.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/Freeze.o ) [Distribution.Package changed]
[104 of 125] Compiling Distribution.Client.Get ( Distribution/Client/Get.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/Get.o ) [Distribution.Compat.Exception changed]
[105 of 125] Compiling Distribution.Client.Init ( Distribution/Client/Init.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/Init.o ) [Distribution.InstalledPackageInfo changed]
[106 of 125] Compiling Distribution.Client.GenBounds ( Distribution/Client/GenBounds.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/GenBounds.o )
[107 of 125] Compiling Distribution.Client.Sandbox.Index ( Distribution/Client/Sandbox/Index.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/Sandbox/Index.o ) [Control.Monad.Writer.Lazy changed]
[108 of 125] Compiling Distribution.Client.Sandbox.Timestamp ( Distribution/Client/Sandbox/Timestamp.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/Sandbox/Timestamp.o ) [Distribution.Compat.Exception changed]
[109 of 125] Compiling Distribution.Client.InstallSymlink ( Distribution/Client/InstallSymlink.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/InstallSymlink.o ) [Distribution.Compat.Exception changed]
[110 of 125] Compiling Distribution.Client.Install ( Distribution/Client/Install.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/Install.o )
[111 of 125] Compiling Distribution.Client.Sandbox ( Distribution/Client/Sandbox.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/Sandbox.o )
[112 of 125] Compiling Distribution.Client.Exec ( Distribution/Client/Exec.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/Exec.o ) [Distribution.Compiler changed]
[113 of 125] Compiling Distribution.Client.Reconfigure ( Distribution/Client/Reconfigure.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/Reconfigure.o )
[114 of 125] Compiling Distribution.Client.BuildReports.Upload ( Distribution/Client/BuildReports/Upload.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/BuildReports/Upload.o ) [Network.URI changed]
[115 of 125] Compiling Distribution.Client.Upload ( Distribution/Client/Upload.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/Upload.o ) [Network.HTTP changed]
[116 of 125] Compiling Distribution.Client.ProjectConfig.Legacy ( Distribution/Client/ProjectConfig/Legacy.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/ProjectConfig/Legacy.o )
[117 of 125] Compiling Distribution.Client.ProjectConfig ( Distribution/Client/ProjectConfig.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/ProjectConfig.o )
[118 of 125] Compiling Distribution.Client.ProjectPlanning ( Distribution/Client/ProjectPlanning.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/ProjectPlanning.o )
[119 of 125] Compiling Distribution.Client.CmdFreeze ( Distribution/Client/CmdFreeze.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/CmdFreeze.o ) [Distribution.Package changed]
[120 of 125] Compiling Distribution.Client.ProjectBuilding ( Distribution/Client/ProjectBuilding.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/ProjectBuilding.o )
[121 of 125] Compiling Distribution.Client.ProjectOrchestration ( Distribution/Client/ProjectOrchestration.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/ProjectOrchestration.o )
[122 of 125] Compiling Distribution.Client.CmdConfigure ( Distribution/Client/CmdConfigure.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/CmdConfigure.o )
[123 of 125] Compiling Distribution.Client.CmdBuild ( Distribution/Client/CmdBuild.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/CmdBuild.o )
[124 of 125] Compiling Distribution.Client.CmdRepl ( Distribution/Client/CmdRepl.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Distribution/Client/CmdRepl.o )
[125 of 125] Compiling Main             ( Main.hs, /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal-tmp/Main.o )
Linking /srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal ...
Generating manual page
/srv/code/cabal-shake/dist-newstyle/build/x86_64-linux/ghc-7.10.3/cabal-install-1.25.0.0/noopt/build/cabal/cabal.1
...
ezyang@sabre:~/Dev/cabal-shake$ cabal new-build cabal -O0
In order, the following will be built (use -v for more details):
 - base16-bytestring-0.1.1.6 (lib:base16-bytestring) (requires build)
 - base64-bytestring-1.0.0.1 (lib) (requires build)
 - cryptohash-sha256-0.11.100.1 (lib) (requires build)
 - ed25519-0.0.5.0 (lib) (requires build)
 - tar-0.5.0.3 (lib) (requires build)
 - hackage-security-0.5.2.2 (lib) (dependency rebuilt)
 - cabal-install-1.25.0.0 (exe:cabal) (dependency rebuilt)

Copy link
Contributor

@ezyang ezyang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is the bug.

@@ -731,6 +733,11 @@ getPkgConfigDb verbosity progdb = do
liftIO $ readPkgConfigDb verbosity progdb


getDirectoryContentsMonitored :: FilePath -> Rebuild [FilePath]
getDirectoryContentsMonitored dir = do
monitorFiles [monitorDirectory dir]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is wrong, you need to monitor the directory contents, not the directory itself.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this is just an example of how the API is error prone; better to do something Shake-like where you have no access to the manual monitorFiles call ;)

Copy link
Contributor Author

@dcoutts dcoutts Sep 20, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure? A directory should change mtime when any entry within it is created/deleted.

I could be wrong of course, but I did actually think about this very issue when writing that code. Re error prone, yes more wrappers like this one in the Rebuild monad will help. Of course we have to get those ones correct :-)

Copy link
Contributor Author

@dcoutts dcoutts Sep 20, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the stat(2) man page (and I think this is true on Windows too):

Moreover, st_mtime of a directory is changed by the creation or deletion of files in that directory.

(which is also what I observe experimentally)

So this should be just enough for getDirectoryContentsMonitored, since it's the creation of dirs in the store that should trigger re-reading the entries of that dir.

And getDirectoryContentsMonitored should be just enough for reading the store, since entries in the store are (supposed to be) immutable so it's just the adding/removing of them that matters.

So where is this breaking down?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This behaviour is the same on NTFS, though apparently not on FAT.

https://support.microsoft.com/en-us/kb/299648

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, you are right. I guess there is a different bug...

@ezyang
Copy link
Contributor

ezyang commented Sep 21, 2016

Ok you are right. I think I have diagnosed the real problem: it is a bug in the file monitor API.

But first, here are steps to reproduce:

  1. Run cabal new-build in such a way that some store packages need to be built (e.g. Use a fresh store)
  2. After one of the packages is built and installed, c-c the process
  3. Rerun the build. You will see that we will attempt to rebuild the library we just installed.

So the problem, discovered by tracing the monitor calls, is that the store directory gets monitored twice: first tracking mtime, and then with just existence. What seems to happen is that the mtime monitor is overwritten, so that we now only test directory existence. I guess monitors should be a monoid and accumulate?

I have a failing unit test for this (just call monitor on the same dir twice), but my bad internet connection won't let me upload it.

On September 21, 2016 2:16:24 AM GMT+09:00, Duncan Coutts notifications@github.com wrote:

dcoutts commented on this pull request.

@@ -731,6 +733,11 @@ getPkgConfigDb verbosity progdb = do
liftIO $ readPkgConfigDb verbosity progdb

+getDirectoryContentsMonitored :: FilePath -> Rebuild [FilePath]
+getDirectoryContentsMonitored dir = do

  • monitorFiles [monitorDirectory dir]

This behaviour is the same on NTFS, though apparently not on FAT.

https://support.microsoft.com/en-us/kb/299648

You are receiving this because you modified the open/close state.
Reply to this email directly or view it on GitHub:
#3863

Sent from my Android device with K-9 Mail. Please excuse my brevity.

@dcoutts
Copy link
Contributor Author

dcoutts commented Sep 21, 2016

What seems to happen is that the mtime monitor is overwritten, so that we now only test directory existence. I guess monitors should be a monoid and accumulate?

Ahh! Yes. You're quite right. Great catch!

Now that you've pointed it out I can clearly see this behaviour from the code. We simply probe the state of each file/dir requested and insert the result into a Map (hence overwriting if we probed that file before). I'll alter it to build a Map first, merging the monitor kinds, then probe them all.

@ezyang
Copy link
Contributor

ezyang commented Sep 21, 2016

Here is a unit test for the problem, for your patch ;)

diff --git a/cabal-install/tests/UnitTests/Distribution/Client/FileMonitor.hs b/cabal-install/tests/UnitTests/Distribution/Client/FileMonitor.hs
index 3b8b8c6..b77c29e 100644
--- a/cabal-install/tests/UnitTests/Distribution/Client/FileMonitor.hs
+++ b/cabal-install/tests/UnitTests/Distribution/Client/FileMonitor.hs
@@ -34,6 +34,7 @@ tests mtimeChange =
   , testCase "remove file"           testRemoveFile
   , testCase "non-existent file"     testNonExistentFile
   , testCase "changed file type"     $ testChangedFileType mtimeChange
+  , testCase "monitor twice"         testMonitorTwice

   , testGroup "glob matches"
     [ testCase "no change"           testGlobNoChange
@@ -88,6 +89,18 @@ testNoMonitorCache =
     reason <- expectMonitorChanged root (monitor :: FileMonitor () ()) ()
     reason @?= MonitorFirstRun

+-- if we monitor a directory, and then subsequently monitor its
+-- existence, we should still be monitoring its mtime
+testMonitorTwice :: Assertion
+testMonitorTwice =
+  withFileMonitor $ \root monitor -> do
+    createDir root "a"
+    updateMonitor root monitor [monitorDirectory "a"] () ()
+    updateMonitor root monitor [monitorDirectoryExistence "a"] () ()
+    touchFile root ("a" </> "b")
+    reason <- expectMonitorChanged root monitor ()
+    reason @?= MonitoredFileChanged "a"
+
 -- write garbage into the binary cache file
 testCorruptMonitorCache :: Assertion
 testCorruptMonitorCache =

@dcoutts dcoutts mentioned this pull request Sep 23, 2016
@dcoutts
Copy link
Contributor Author

dcoutts commented Sep 23, 2016

@ezyang oh, sorry didn't see your unit test, but I added one fairly similar. FYI, now that I see it, I don't think that test will work. Note that it's not in the rebuild monad so that updateMonitor is the passed the full set of monitor specifications, so the second call is always expected to obliterate the first. The test in #3887 does indeed fail before the fix and passes afterwards.

So I'll rebase this PR and resubmit. Thanks again for the speedy reversion and diagnosis.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants