Blag

He's not dead, he's resting

New Paludis Query Interface

Paludis trunk will be getting a new query interface shortly. This will replace the old interface (we’re not keeping API stability until 1.0), so you’ll need to change your code — fortunately, the compiler will tell you where.

Code that used to look like this:

    env.package_database()->query(
        query::Matches(blah) & query::SupportsAction<InstallAction>(),
        qo_order_by_version);

will now look like:

    env[selection::AllVersionsSorted(
        generator::Matches(blah) | filter::SupportsAction<InstallAction>())];

In particular:

  • Querying is now done by Environment, not PackageDatabase. This makes trickery with AdaptedEnvironment easier.
  • The QueryOrder enum is gone, replaced with Selection subclasses.
  • The Query class is gone, replaced by Generator and Filter subclasses.

The Selection subclasses substantially reduce the amount of work done to get a result in certain circumstances. Previously, a full set of results would be generated, and then that set would be sorted and reduced as specified. But in certain fairly common situations, this is overkill. Consider this old snippet:

    if (env.package_database()->query(query::Matches(spec), qo_whatever)->empty())
        /* ... */

This will return an entire set of PackageID instances, but all we really care about is whether at least one match was found. If spec is something simple, the overhead is minimal. But if spec contains slot dependencies, it means loading or generating metadata for every single matching ID, which is either slow (a metadata load is a filesystem access) or really really slow (a metadata generation is a bash invocation).

Now we do this instead:

    if (env[selection::SomeArbitraryVersion(generator::Matches(spec))]->empty())
        /* ... */

And selection::SomeArbitraryVersion is smart enough to stop trying the match as soon as it finds at least one match. (In future, we might even let IDs state the relative cost of doing such a metadata query, so we can try matching IDs whose metadata is already loaded first.)

The Query to Generator and Filter split enables a related optimisation. Given the following (which is slightly unrealistic, because there should really be an ‘installable’ check in there too):

    env.package_database()->query(
        query::Matches(blah) & query::NotMasked(),
        qo_order_by_version);

the query::NotMasked() would get called for all IDs whose name could potentially match the query::Matches(blah) spec. So if you asked for >=app-misc/foo-3, all versions of app-misc/foo would be checked for whether they’re masked — and a mask check requires metadata.

But with the new code:

    env[selection::AllVersionsSorted(
        generator::Matches(blah) | filter::NotMasked()];

only those IDs that really do match will be queried for maskedness. And if that’s combined with a smarter selection:

    env[selection::BestVersionOnly(
        generator::Matches(blah) | filter::NotMasked()];

then Paludis is now smart enough to start with the best version matching blah and work downwards until it finds a not masked version.

In Part II, we discuss available components and how they can be combined.

2 responses to “New Paludis Query Interface

  1. Pingback: New Paludis Query Interface (Part II) « Ciaran McCreesh’s Blag

  2. Pingback: New Paludis Query Interface (Part III) « Ciaran McCreesh’s Blag

Leave a comment