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

Avoid loading of package caches during build plan construction #2077

Merged
merged 1 commit into from
Apr 29, 2016

Conversation

sjakobi
Copy link
Member

@sjakobi sjakobi commented Apr 28, 2016

via IORef trickery

caches <- getPackageCaches
liftIO $ writeIORef icaches caches
readIORef icaches
inner getPackageCaches'
Copy link
Member Author

Choose a reason for hiding this comment

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

I've been looking how to do this properly with MonadBaseControl but failed. My impression was that you'd always have to evaluate getPackageCaches before you could pass it to inner.

@mgsloan
Copy link
Contributor

mgsloan commented Apr 28, 2016

I don't see what this buys us. getPackageCaches already does caching. It does feel a little ugly to have an IORef in the Config datatype, but it seems like all bets are already off there due to the configEnvOverride type.

Perhaps that caching isn't working in practice (could happen from initializing multiple Config, but I don't think that's happening)?

@sjakobi
Copy link
Member Author

sjakobi commented Apr 29, 2016

Does this make it any clearer?

-- | Access the package caches from 'IO'.
withPackageCaches
    :: (MonadIO m, MonadReader env m, HasConfig env, MonadLogger m, HasHttpManager env, MonadBaseControl IO m, MonadCatch m)
    => (IO (Map PackageIdentifier (PackageIndex, PackageCache)) -> m a)
    -> m a
withPackageCaches inner = do
    getCaches <- toIO getPackageCaches
    inner getCaches

toIO :: (MonadIO m, MonadBaseControl IO m) => m a -> m (IO a)
toIO m = do
    -- TODO: Use monad base control properly.
    runInBase <- liftBaseWith $ \run -> return (void . run)
    return $ do
        i <- newIORef (error "Impossible evaluation in toIO")
        runInBase $ do
            x <- m
            liftIO $ writeIORef i x
        readIORef i

It looks rather illegal to me.

Alas, we want to access (and update!) the package caches and index during build plan construction, but deserialize the caches only when necessary. The functions in Stack.Build.ConstructPlan are all basically in IO.

I can only speculate why this hasn't been solved differently:

  • Changing the types in Stack.Build.ConstructPlan was too much work
  • The functions that construct the build plan have to be fast, so we can't just layer all of getPackageCaches' monad transformers on top. (I really have no experience with performance with monad transformers, but that's what I've heard)

Some ideas how to improve the situation:

For the case where we want to make nice error messages (addPackageDeps) I think we could just pass the constraints back to constructPlan and load the package caches there.

Regarding loadPackage I don't really understand yet what installPackage and tellExecutablesUpstream actually do.
For a stack install of stack there are two calls to loadPackage: One for path-io and one for hpack.

Maybe we could make a simpler alternative to loadPackage, without the update logic. When that function doesn't find what we want, we just return an error to constructPlan, let constructPlan update the index and start afresh. At that point the time to construct another build plan doesn't matter anymore.

Or we just add the monad transformers.

@mgsloan
Copy link
Contributor

mgsloan commented Apr 29, 2016

Ah, I think what confused me is that withPackageCaches could be getPackageCachesIO :: ... => m (IO PackageCaches). There is no reason for it to bracket, and I thought this had something to do with scoping out caching.

The changes to ConstructPlan look reasonable, but I haven't thought too hard about it.

For a stack install of stack there are two calls to loadPackage: One for path-io and one for hpack.

It surprised me that we'd need the package index if the appropriate path-io and hpack versions are installed.

@sjakobi sjakobi force-pushed the withpackagecaches branch from 8ae1cd8 to 8751030 Compare April 29, 2016 02:39
@sjakobi
Copy link
Member Author

sjakobi commented Apr 29, 2016

There is no reason for it to bracket, and I thought this had something to do with scoping out caching.

Good point, I've updated the PR!

It surprised me that we'd need the package index if the appropriate path-io and hpack versions are installed.

Looks like we should take a closer look! 😄

@mgsloan
Copy link
Contributor

mgsloan commented Apr 29, 2016

LGTM, thanks! Yes, probably a close look at that case should be taken before closing out #1892

@mgsloan mgsloan merged commit a18c511 into commercialhaskell:master Apr 29, 2016
@sjakobi sjakobi deleted the withpackagecaches branch April 29, 2016 03:00
@sjakobi
Copy link
Member Author

sjakobi commented Apr 29, 2016

Thanks for reviewing!

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.

3 participants