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

fix exception handling of downloads in new-build #3630

Merged
merged 5 commits into from
Jul 28, 2016

Conversation

dcoutts
Copy link
Contributor

@dcoutts dcoutts commented Jul 26, 2016

Partly this is a continuation of the InstallPlan refactoring #3622, but also a related change to fix #3387, by handling exceptions during download properly.

These things are also a step towards finishing #3394 properly, since it means we now have all the BuildResults using proper exception types and so will be able to use that to report at the end what if anything when wrong.

As a result of the previous InstallPlan refactoring, we can now use the
non-serialisable BuildFailure type from D.C.Types which uses
SomeException, where previously we had to use a copy of that type that
used String for the errors.

So now there's no longer any need to have a separate set of types for
BuildResult, BuildResults, BuildSuccess or BuildFailure. There was a
minor difference in the structure of the BuildSuccess, where in the new
build code we need to be able to produce the InstalledPackageInfo at a
different point from the rest of the info in the BuildSuccess. This can
be kept local to the ProjecBuilding module, but accounts for the
somewhat larger number of changes in that module.
Just hnd -> do
debug verbosity $ "Waiting for download of " ++ show srcloc
either throwIO return =<< takeMVar hnd
Nothing -> fail "waitAsyncFetchPackage: package not being download"
Copy link
Contributor

Choose a reason for hiding this comment

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

downloaded

dcoutts added 2 commits July 26, 2016 19:05
Split things up a little so the generic async fetch can live with the
other fetch utils. This also makes it easier to test.

Change the exception handling so that any exception in fetching is
propagated when collecting the fetch result.
Download errors are now put into the residual install plan, like other
build errors.

Fixes issue haskell#3387
@dcoutts dcoutts force-pushed the new-build-exception-handling branch from 0fedb42 to 49b31ed Compare July 26, 2016 18:05
-- location) to a completion var for that package. So the body action should
-- lookup the location and use 'asyncFetchPackage' to get the result.
--
asyncFetchPackages :: Verbosity
Copy link
Contributor

Choose a reason for hiding this comment

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

If you're using the async package, why not just actually use the combinators on Async to implement this? Using withAsync and then ignoring the passed in Async just seems extremely strange.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What I used to do was fork them all off using async and put the async handles in the map. The problem with that is we don't actually wan to do them all concurrently, and also we want to do them in a particular order, to get the ones we need back soonest. I don't see any way to implement this while still fitting the async API.

@ezyang
Copy link
Contributor

ezyang commented Jul 26, 2016

I don't really understand the patch, but if it fixes the exceptions problem 👍

@dcoutts
Copy link
Contributor Author

dcoutts commented Jul 26, 2016

I don't really understand the patch, but if it fixes the exceptions problem 👍

Which one, the first one or the downloads one?

Patch 2 does two things: it moves code around and tidies things up, and also it makes sure to catch exceptions from fetchPackage and stuff those into the MVar and re-throw them when the caller picks up the download result later with waitAsyncFetchPackage. It's the latter thing that makes things behave sensibly wrt exceptions, and then possible to catch and stash into the BuildResults in patch 3.

fetchPackages =
forM_ asyncDownloadVars $ \(pkgloc, var) -> do
result <- try $ fetchPackage verbosity repoCtxt pkgloc
putMVar var result
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 is the crucial bit really, for fixing exception handling. Previously the exception was propagated locally in the async action and so the callers picking up the async fetch package results would wait forever (or rather get an MVar deadlock exception).

@ezyang
Copy link
Contributor

ezyang commented Jul 26, 2016

My lack of understanding is mostly cdacc51; there's some shuffling around of types, but I don't really know how things were structured previously, or how they are structured now. But... code got removed, so I'm happy to take your word for it ;)

@dcoutts
Copy link
Contributor Author

dcoutts commented Jul 26, 2016

So the new-build code previously used:

data GenericBuildResult ipkg iresult ifailure
                  = BuildFailure ifailure
                  | BuildSuccess [ipkg] iresult
type BuildResult  = GenericBuildResult InstalledPackageInfo
                                       BuildSuccess BuildFailure
data BuildSuccess = BuildOk DocsResult TestsResult
data BuildFailure = ...

whereas the common D.C.Types used by the D.C.Install etc code uses:

type BuildResult  = Either BuildFailure BuildSuccess
 data BuildSuccess = BuildOk DocsResult TestsResult [InstalledPackageInfo]
data BuildFailure = ...

So the main difference (apart from using Either vs a custom 2-constructor type) is that the previous new-build code put the [InstalledPackageInfo] into the BuildResult constructor separately from the BuildSuccess type. So that's where the main shuffling is happening. Otherwise it's just a matter of using the types defined in D.C.Types.

@dcoutts
Copy link
Contributor Author

dcoutts commented Jul 26, 2016

I don't understand the travis failure on 7.4.2. It looks like it's cabal sdist that is failing, but the code in this PR is completely unrelated to sdist.

@ezyang
Copy link
Contributor

ezyang commented Jul 26, 2016

I think it's OK if we disable sdist test in the main test; I've found that it doesn't work very reliably if there is configuration (as there is here) for a differing version of Cabal; if you clean it works. We do have a test for sdist in bootstrap.

@dcoutts
Copy link
Contributor Author

dcoutts commented Jul 26, 2016

Ok to merge then?

@ezyang
Copy link
Contributor

ezyang commented Jul 26, 2016

Yep, but you or I will have to immediately push a commit to remove the sdist from travis-script.sh

23Skidoo added a commit to 23Skidoo/cabal that referenced this pull request Jul 27, 2016
23Skidoo added a commit to 23Skidoo/cabal that referenced this pull request Jul 27, 2016
@dcoutts dcoutts merged commit d5717e5 into haskell:master Jul 28, 2016
@23Skidoo
Copy link
Member

LGTM as well.

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.

confusing error-message "thread blocked indefinitely in an MVar operation" when downloading tarball fails
3 participants