Blag
He's not dead, he's resting
New Paludis Query Interface
May 31, 2008
Posted by on 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
, notPackageDatabase
. This makes trickery withAdaptedEnvironment
easier. - The
QueryOrder
enum is gone, replaced withSelection
subclasses. - The
Query
class is gone, replaced byGenerator
andFilter
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.
Pingback: New Paludis Query Interface (Part II) « Ciaran McCreesh’s Blag
Pingback: New Paludis Query Interface (Part III) « Ciaran McCreesh’s Blag