commit:     13be8e6fab9c9dd40f2b346f82a54f7235b1efb0
Author:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
AuthorDate: Mon Jan  5 20:30:39 2026 +0000
Commit:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
CommitDate: Mon Jan  5 20:30:39 2026 +0000
URL:        https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=13be8e6f

libq/tree: add explicit caching mode for foreach_pkg

Next to transparent cache building when required for sorting. allow
explicit request for caching a tree in memory.  Adapt the logic such
that it becomes fully transparent of sort or cache being in use.

Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>

 libq/tree.c | 74 +++++++++++++++++++++++++++++++++++--------------------------
 libq/tree.h | 20 +++++++++++++----
 2 files changed, 59 insertions(+), 35 deletions(-)

diff --git a/libq/tree.c b/libq/tree.c
index 3d707ba..e485af2 100644
--- a/libq/tree.c
+++ b/libq/tree.c
@@ -606,15 +606,18 @@ tree_pkg_compar(const void *l, const void *r)
 static tree_pkg_ctx *
 tree_next_pkg_int(tree_cat_ctx *cat_ctx)
 {
-       tree_pkg_ctx *pkg_ctx = NULL;
+       tree_pkg_ctx        *pkg_ctx = NULL;
        const struct dirent *de;
-       const depend_atom *qa = cat_ctx->ctx->query_atom;
+       const depend_atom   *qa      = cat_ctx->ctx->query_atom;
+       bool                 filter  = qa != NULL && qa->PN != NULL;
 
        if (cat_ctx->ctx->do_sort) {
                if (cat_ctx->pkg_ctxs == NULL) {
                        size_t pkg_size = 0;
+
                        cat_ctx->pkg_cnt = 0;
                        cat_ctx->pkg_cur = 0;
+
                        while ((de = readdir(cat_ctx->dir)) != NULL) {
                                char *name;
 
@@ -627,12 +630,12 @@ tree_next_pkg_int(tree_cat_ctx *cat_ctx)
                                 * note that we might over-match, but that's 
easier than
                                 * trying to deal with end of string or '-' 
here (which
                                 * still wouldn't be 100% because name rules 
are complex) */
-                               if (qa != NULL && qa->PN != NULL &&
-                                               strncmp(qa->PN, de->d_name, 
strlen(qa->PN)) != 0)
+                               if (filter &&
+                                       strncmp(qa->PN, de->d_name, 
strlen(qa->PN)) != 0)
                                        continue;
 
                                if (cat_ctx->pkg_cnt == pkg_size) {
-                                       pkg_size += 256;
+                                       pkg_size += 64;
                                        cat_ctx->pkg_ctxs = 
xrealloc(cat_ctx->pkg_ctxs,
                                                                
sizeof(*cat_ctx->pkg_ctxs) * pkg_size);
                                }
@@ -653,8 +656,14 @@ tree_next_pkg_int(tree_cat_ctx *cat_ctx)
                }
 
                pkg_ctx = NULL;
-               if (cat_ctx->pkg_cur < cat_ctx->pkg_cnt)
+               while (cat_ctx->pkg_cur < cat_ctx->pkg_cnt) {
                        pkg_ctx = cat_ctx->pkg_ctxs[cat_ctx->pkg_cur++];
+                       if (!filter ||
+                               atom_compare(tree_get_atom(pkg_ctx, qa->SLOT != 
NULL),
+                                                        qa) == EQUAL)
+                               break;
+                       pkg_ctx = NULL;
+               }
        } else {
                do {
                        de = readdir(cat_ctx->dir);
@@ -665,8 +674,8 @@ tree_next_pkg_int(tree_cat_ctx *cat_ctx)
                                continue;
 
                        /* perform package name check as for the sorted variant 
*/
-                       if (qa != NULL && qa->PN != NULL &&
-                                       strncmp(qa->PN, de->d_name, 
strlen(qa->PN)) != 0)
+                       if (filter &&
+                               strncmp(qa->PN, de->d_name, strlen(qa->PN)) != 
0)
                                continue;
 
                        pkg_ctx = tree_open_pkg(cat_ctx, de->d_name);
@@ -1422,10 +1431,8 @@ tree_pkg_read(tree_pkg_ctx *pkg_ctx)
                ret = (tree_pkg_meta *)pkg_ctx->cat_ctx->ctx->pkgs;
        }
 
-       pkg_ctx->meta = ret;
+       pkg_ctx->meta = ret;  /* may be NULL when e.g. VDB */
 
-       if (ret == NULL)
-               warn("Unknown/unsupported metadata cache type!");
        return ret;
 }
 
@@ -1698,7 +1705,7 @@ tree_foreach_cache_populate_cb
 
        cat_ctx = get_set(atom->CATEGORY, cache);
        if (cat_ctx == NULL) {
-               cat_ctx = tree_open_cat(tctx, ".");
+               cat_ctx = tree_open_cat(tctx, atom->CATEGORY);
                if (cache != NULL)  /* for static code analysers */
                        add_set_value(atom->CATEGORY, cat_ctx, NULL, cache);
                /* get a pointer from the set */
@@ -1739,6 +1746,7 @@ tree_foreach_cache_populate_cb
                }
                pkg->binpkg_isgpkg = ctx->binpkg_isgpkg;
        } else {
+               pkg->fd   = -1;
                pkg->meta = NULL;
        }
 
@@ -2181,12 +2189,12 @@ tree_foreach_gtree(tree_ctx *ctx, tree_pkg_cb callback, 
void *priv)
 #endif
 
 int
-tree_foreach_pkg
+tree_foreach_pkg_int
 (
        tree_ctx          *ctx,
        tree_pkg_cb        callback,
        void              *priv,
-       bool               sort,
+       tree_foreach_type  mode,
        const depend_atom *query
 )
 {
@@ -2204,7 +2212,7 @@ tree_foreach_pkg
        if (ctx->cache.all_categories) {
                /* always exploit the cache if it exists (next_cat doesn't
                 * consider it if sorting isn't requested) */
-               sort = true;
+               mode = TREE_FOREACH_SORT;
        } else {
                /* perform sorting post retrieval by caching first:
                 * - binpkgs can be a combination of files and directories,
@@ -2214,11 +2222,14 @@ tree_foreach_pkg
                 * - gtree should be fine, but since we can't assume it is
                 *   (others may start producing them), it's like packages
                 *   above, something we read serially not necessarily in the
-                *   correct order */
-               if (sort &&
-                       (ctx->treetype == TREE_BINPKGS ||
-                        ctx->treetype == TREE_PACKAGES ||
-                        ctx->treetype == TREE_METADATA_GTREE))
+                *   correct order
+                * of course we should also build the cache when it was
+                * explicitly requested */
+               if (mode == TREE_FOREACH_CACHE ||
+                       (mode == TREE_FOREACH_SORT &&
+                        (ctx->treetype == TREE_BINPKGS ||
+                         ctx->treetype == TREE_PACKAGES ||
+                         ctx->treetype == TREE_METADATA_GTREE)))
                {
                        callback = tree_foreach_cache_populate_cb;
                        priv     = (void *)create_set();
@@ -2250,15 +2261,18 @@ tree_foreach_pkg
        ret = 0;
        if (traverse)
        {
-               ctx->do_sort    = postsort ? false : sort;
-               ctx->query_atom = query;
+               if (postsort) {
+                       ctx->do_sort    = false;
+                       ctx->query_atom = NULL;
+               } else {
+                       ctx->do_sort    = mode == TREE_FOREACH_SORT;
+                       ctx->query_atom = query;
+               }
 
                while ((cat_ctx = tree_next_cat(ctx))) {
-                       if (callback != NULL) {
-                               while ((pkg_ctx = tree_next_pkg(cat_ctx))) {
-                                       ret |= callback(pkg_ctx, priv);
-                                       tree_close_pkg(pkg_ctx);
-                               }
+                       while ((pkg_ctx = tree_next_pkg(cat_ctx))) {
+                               ret |= callback(pkg_ctx, priv);
+                               tree_close_pkg(pkg_ctx);
                        }
                        tree_close_cat(cat_ctx);
                }
@@ -2304,7 +2318,7 @@ tree_foreach_pkg
                 * (sorted) cache, the callback can be empty for tree_match_atom
                 * when it wants to build a cache first */
                if (origcb != NULL)
-                       ret = tree_foreach_pkg_fast(ctx, origcb, origpriv, 
ctx->query_atom);
+                       ret = tree_foreach_pkg_fast(ctx, origcb, origpriv, 
query);
        }
 
        return ret;
@@ -2506,13 +2520,11 @@ tree_match_atom(tree_ctx *ctx, const depend_atom 
*query, int flags)
        tree_cat_ctx *cat_ctx;
        tree_match_ctx *ret = NULL;
 
-       ctx->query_atom = NULL;  /* if caching, ensure it contains ALL pkgs */
-
        /* activate cache for future lookups, tree_match_atom relies on
         * cache behaviour from tree, which means all categories and
         * packages remain in memory until tree_close is being called */
        if (ctx->cache.categories == NULL)
-               tree_foreach_pkg_sorted(ctx, NULL, NULL, NULL);  /* force cache 
*/
+               tree_foreach_pkg_cached(ctx, NULL, NULL, NULL);  /* force cache 
*/
 
        ctx->do_sort = true;     /* often forces/enables cache usage */
 

diff --git a/libq/tree.h b/libq/tree.h
index 6ac0e44..d884475 100644
--- a/libq/tree.h
+++ b/libq/tree.h
@@ -171,12 +171,24 @@ char *tree_pkg_meta_get_int(tree_pkg_ctx *pkg_ctx, size_t 
offset, const char *ke
 tree_metadata_xml *tree_pkg_metadata(tree_pkg_ctx *pkg_ctx);
 void tree_close_metadata(tree_metadata_xml *meta_ctx);
 void tree_close_pkg(tree_pkg_ctx *pkg_ctx);
-int tree_foreach_pkg(tree_ctx *ctx, tree_pkg_cb callback, void *priv,
-               bool sort, const depend_atom *query);
+
+typedef enum _tree_foreach_type {
+       TREE_FOREACH_FAST,
+       TREE_FOREACH_SORT,
+       TREE_FOREACH_CACHE
+} tree_foreach_type;
+int tree_foreach_pkg_int(tree_ctx *ctx, tree_pkg_cb callback, void *priv,
+               tree_foreach_type mode, const depend_atom *query);
+#define tree_foreach_pkg(ctx, cb, priv, sort, query) \
+       tree_foreach_pkg_int(ctx, cb, priv, \
+                                                (sort) ? TREE_FOREACH_SORT : 
TREE_FOREACH_FAST, query)
 #define tree_foreach_pkg_fast(ctx, cb, priv, query) \
-       tree_foreach_pkg(ctx, cb, priv, false, query)
+       tree_foreach_pkg_int(ctx, cb, priv, TREE_FOREACH_FAST, query)
 #define tree_foreach_pkg_sorted(ctx, cb, priv, query) \
-       tree_foreach_pkg(ctx, cb, priv, true, query)
+       tree_foreach_pkg_int(ctx, cb, priv, TREE_FOREACH_SORT, query)
+#define tree_foreach_pkg_cached(ctx, cb, priv, query) \
+       tree_foreach_pkg_int(ctx, cb, priv, TREE_FOREACH_CACHE, query)
+
 set *tree_get_atoms(tree_ctx *ctx, bool fullcpv, set *satoms);
 depend_atom *tree_get_atom(tree_pkg_ctx *pkg_ctx, bool complete);
 tree_match_ctx *tree_match_atom(tree_ctx *t, const depend_atom *q, int flags);

Reply via email to