Gentoo Archives: gentoo-commits

From: Fabian Groffen <grobian@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage-utils:master commit in: libq/
Date: Sun, 19 Jan 2020 09:49:48
Message-Id: 1579427178.dadb2666f54fed0478e0914d9fc4349f27730d58.grobian@gentoo
1 commit: dadb2666f54fed0478e0914d9fc4349f27730d58
2 Author: Fabian Groffen <grobian <AT> gentoo <DOT> org>
3 AuthorDate: Sun Jan 19 09:46:18 2020 +0000
4 Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org>
5 CommitDate: Sun Jan 19 09:46:18 2020 +0000
6 URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=dadb2666
7
8 libq/tree: add initial tree_match_atom with caching
9
10 tree_match_atom is meant for retrieving the best matching element from a
11 tree based on a query. It caches the underlying packages it traverses,
12 such that repetitive lookups will benefit from previous lookups. This
13 comes in handy for recursive scenarios such as when
14 calculating/resolving dependencies.
15
16 Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>
17
18 libq/tree.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
19 libq/tree.h | 4 ++++
20 2 files changed, 84 insertions(+)
21
22 diff --git a/libq/tree.c b/libq/tree.c
23 index 0df2e0d..f87e751 100644
24 --- a/libq/tree.c
25 +++ b/libq/tree.c
26 @@ -148,6 +148,24 @@ tree_open_binpkg(const char *sroot, const char *spkg)
27 void
28 tree_close(tree_ctx *ctx)
29 {
30 + if (ctx->cache.categories != NULL) {
31 + DECLARE_ARRAY(t);
32 + size_t n;
33 + tree_cat_ctx *cat;
34 +
35 + values_set(ctx->cache.categories, t);
36 + free_set(ctx->cache.categories);
37 + ctx->cache.categories = NULL; /* must happen before close_cat */
38 +
39 + array_for_each(t, n, cat) {
40 + /* ensure we cleanup all pkgs */
41 + cat->pkg_cur = 0;
42 + tree_close_cat(cat);
43 + }
44 +
45 + xarrayfree_int(t);
46 + }
47 +
48 closedir(ctx->dir);
49 /* closedir() above does this for us: */
50 /* close(ctx->tree_fd); */
51 @@ -212,6 +230,21 @@ tree_open_cat(tree_ctx *ctx, const char *name)
52 int fd;
53 DIR *dir;
54
55 + /* lookup in the cache, if any */
56 + if (ctx->cache.categories != NULL) {
57 + cat_ctx = get_set(name, ctx->cache.categories);
58 + if (cat_ctx != NULL) {
59 + /* reset state so it can be re-iterated (sort benefits the
60 + * most here) */
61 + if (ctx->do_sort) {
62 + cat_ctx->pkg_cur = 0;
63 + } else {
64 + rewinddir(cat_ctx->dir);
65 + }
66 + return cat_ctx;
67 + }
68 + }
69 +
70 /* Cannot use O_PATH as we want to use fdopendir() */
71 fd = openat(ctx->tree_fd, name, O_RDONLY | O_CLOEXEC);
72 if (fd == -1)
73 @@ -229,6 +262,13 @@ tree_open_cat(tree_ctx *ctx, const char *name)
74 cat_ctx->dir = dir;
75 cat_ctx->ctx = ctx;
76 cat_ctx->pkg_ctxs = NULL;
77 +
78 + if (ctx->cache.categories != NULL) {
79 + add_set_value(name, cat_ctx, ctx->cache.categories);
80 + /* ensure name doesn't expire after this instantiation is closed */
81 + cat_ctx->name = contains_set(name, ctx->cache.categories);
82 + }
83 +
84 return cat_ctx;
85 }
86
87 @@ -289,6 +329,14 @@ tree_next_cat(tree_ctx *ctx)
88 void
89 tree_close_cat(tree_cat_ctx *cat_ctx)
90 {
91 + if (cat_ctx->ctx->cache.categories != NULL &&
92 + contains_set(cat_ctx->name, cat_ctx->ctx->cache.categories))
93 + return;
94 +
95 + /* cleanup unreturned pkgs when sorted (or cache in use) */
96 + while (cat_ctx->pkg_cur < cat_ctx->pkg_cnt)
97 + tree_close_pkg(cat_ctx->pkg_ctxs[cat_ctx->pkg_cur++]);
98 +
99 closedir(cat_ctx->dir);
100 /* closedir() above does this for us: */
101 /* close(ctx->fd); */
102 @@ -1439,3 +1487,35 @@ tree_get_atoms(tree_ctx *ctx, bool fullcpv, set *satoms)
103
104 return state.cpf;
105 }
106 +
107 +tree_pkg_ctx *
108 +tree_match_atom(tree_ctx *ctx, depend_atom *a)
109 +{
110 + tree_cat_ctx *cat_ctx;
111 + tree_pkg_ctx *pkg_ctx;
112 + depend_atom *atom;
113 +
114 + if (ctx->cache.categories == NULL)
115 + ctx->cache.categories = create_set();
116 +
117 + if (a->P == NULL) {
118 + return NULL;
119 + } else if (a->CATEGORY == NULL) {
120 + /* loop through all cats and recurse */
121 + /* TODO: some day */
122 + return NULL;
123 + } else {
124 + /* try CAT, and PN for latest version */
125 + if ((cat_ctx = tree_open_cat(ctx, a->CATEGORY)) == NULL)
126 + return NULL;
127 + ctx->do_sort = true; /* sort uses buffer, which cache relies on */
128 + ctx->query_atom = NULL; /* ensure the cache contains ALL pkgs */
129 + while ((pkg_ctx = tree_next_pkg(cat_ctx)) != NULL) {
130 + atom = tree_get_atom(pkg_ctx, a->SLOT != NULL);
131 + if (atom_compare(atom, a) == EQUAL)
132 + return pkg_ctx;
133 + }
134 +
135 + return NULL;
136 + }
137 +}
138
139 diff --git a/libq/tree.h b/libq/tree.h
140 index 6627e80..eaee7ad 100644
141 --- a/libq/tree.h
142 +++ b/libq/tree.h
143 @@ -44,6 +44,9 @@ struct tree_ctx {
144 char *pkgs;
145 size_t pkgslen;
146 depend_atom *query_atom;
147 + struct tree_cache {
148 + set *categories;
149 + } cache;
150 };
151
152 /* Category context */
153 @@ -135,5 +138,6 @@ int tree_foreach_pkg(tree_ctx *ctx, tree_pkg_cb callback, void *priv,
154 tree_foreach_pkg(ctx, cb, priv, true, query);
155 set *tree_get_atoms(tree_ctx *ctx, bool fullcpv, set *satoms);
156 depend_atom *tree_get_atom(tree_pkg_ctx *pkg_ctx, bool complete);
157 +tree_pkg_ctx *tree_match_atom(tree_ctx *t, depend_atom *a);
158
159 #endif