Skip to content

Make hackageIndexLayout faster#343

Open
Bodigrim wants to merge 2 commits into
masterfrom
faster-hackageIndexLayout
Open

Make hackageIndexLayout faster#343
Bodigrim wants to merge 2 commits into
masterfrom
faster-hackageIndexLayout

Conversation

@Bodigrim

Copy link
Copy Markdown
Contributor

Before these patches hackageIndexLayout takes up to 50% of cabal update time. With the patches applied this reduces to ~10% of cabal update, making it almost 2x faster.

I originally developed this code for hackage-revdeps, so the approach has been exercised for some time. Besides, hackageIndexLayout is covered by tests for hackage-security.

Bodigrim added 2 commits July 10, 2026 20:09
`hackageIndexLayout` runs `fromPath` in a hot loop, for every file
in the Hackage 01-index.tar. However, `fromPath` is rather wasteful
when parsing `PackageIdentifier`: it concatenates together package name and
version and asks `Cabal-syntax` to parse. This is very backwards, because
`PackageIdentifier` is exactly a record with two fields: package name
and its version. We already have the name at hand, there is no need
to parse it again, and the version can be parsed more efficiently
without resorting to `parsec`.

This performance optimization was earlier attested in the `hackage-revdeps`
package.
`hackageIndexLayout` runs `fromPath` in a hot loop, for every file
in the Hackage 01-index.tar. However, `fromPath` is rather wasteful:
it uses `splitFragments` (and underlying `System.FilePath.splitDirectories`)
to explode `base/4.22.0.0/base.cabal` into `["base", "4.22.0.0", "base.cabal"]`.

One could have expected that `splitDirectories` simply splits filepath
by '/', but this is not the case. It's a general function, which does a lot
of transformations such as checking for absolute paths, splitting drive letter,
first retaining '/', then stripping them, etc.

The patch replaces `splitDirectories` with a rather specialized operations,
aiming to avoid traversing the same characters twice. It was previously
attested in the `hackage-revdeps` package that this microptimization
brings measurable performance benefits.
@Bodigrim Bodigrim requested review from Mikolaj and andreasabel July 10, 2026 19:24
@mergify

mergify Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@Mikolaj Mikolaj left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

If the speedup is confirmed in practice, this is a great improvement!

@ulysses4ever

Copy link
Copy Markdown
Contributor

Do we want to a) release this asap and b) make sure cabal 3.18.1 0 will allow the latest release?

@Bodigrim

Copy link
Copy Markdown
Contributor Author

This is not a breaking change, so presumably it can be released as hackage-security-0.6.4.0, in which case no action is required on Cabal side, because cabal-install is happy to pick up any hackage-security >=0.6 && <0.7.

Comment on lines +110 to +117
case reverse basename of
-- ".cabal" reversed
'l' : 'a' : 'b' : 'a' : 'c' : '.' : _ ->
return $ Some $ IndexPkgCabal pkgId
-- ".json" reversed
'n' : 'o' : 's' : 'j' : '.' : _ ->
return $ Some $ IndexPkgMetadata pkgId
_ -> Nothing

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this faster than isSuffixOf?

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.

4 participants