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: Mon, 14 Jun 2021 09:34:19
Message-Id: 1623166127.9a4c654be5e759b4bb0fed1ac802a57fb1cb5c30.grobian@gentoo
1 commit: 9a4c654be5e759b4bb0fed1ac802a57fb1cb5c30
2 Author: Fabian Groffen <grobian <AT> gentoo <DOT> org>
3 AuthorDate: Tue Jun 8 15:28:47 2021 +0000
4 Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org>
5 CommitDate: Tue Jun 8 15:28:47 2021 +0000
6 URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=9a4c654b
7
8 libq/tree: build cache for Packages/binpkgs
9
10 Because we cannot trust Packages file to be in sorted order, and the
11 order isn't what we want (most recent match on top), we have to sort the
12 pkgs found in Packages, so make that exploit the cache, which will speed
13 up any subsequent tree_match_atom calls, which is good.
14
15 Do the same for binpkg trees, since they also cannot be cached
16 otherwise.
17
18 Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>
19
20 libq/tree.c | 180 ++++++++++++++++++++++++++++++------------------------------
21 libq/tree.h | 1 +
22 2 files changed, 90 insertions(+), 91 deletions(-)
23
24 diff --git a/libq/tree.c b/libq/tree.c
25 index 358b1f2..d7ec882 100644
26 --- a/libq/tree.c
27 +++ b/libq/tree.c
28 @@ -312,8 +312,29 @@ tree_next_cat(tree_ctx *ctx)
29
30 if (ctx->do_sort) {
31 if (ctx->cat_de == NULL) {
32 - ctx->cat_cnt = scandirat(ctx->tree_fd,
33 - ".", &ctx->cat_de, tree_filter_cat, alphasort);
34 + if (ctx->cache.all_categories) {
35 + char **cats;
36 + size_t i;
37 + size_t len;
38 + struct dirent **ret;
39 +
40 + /* exploit the cache instead of reading from directory */
41 + ctx->cat_cnt = cnt_set(ctx->cache.categories);
42 + ctx->cat_de = ret = xmalloc(sizeof(*ret) * ctx->cat_cnt);
43 + list_set(ctx->cache.categories, &cats);
44 + for (i = 0; i < ctx->cat_cnt; i++) {
45 + len = strlen(cats[i]) + 1;
46 + ret[i] = xzalloc(sizeof(*de) + len);
47 + snprintf(ret[i]->d_name, len, "%s", cats[i]);
48 + }
49 + if (i > 1)
50 + qsort(ret, ctx->cat_cnt, sizeof(*ret),
51 + (int (*)(const void *, const void *))alphasort);
52 + free(cats);
53 + } else {
54 + ctx->cat_cnt = scandirat(ctx->tree_fd,
55 + ".", &ctx->cat_de, tree_filter_cat, alphasort);
56 + }
57 ctx->cat_cur = 0;
58 }
59
60 @@ -1511,7 +1532,7 @@ tree_foreach_pkg(tree_ctx *ctx, tree_pkg_cb callback, void *priv,
61 ctx->cat_de = NULL;
62 ctx->cat_cur = 0;
63 ctx->cat_cnt = 0;
64 - ctx->do_sort = 0;
65 + ctx->do_sort = false;
66
67 return ret;
68 }
69 @@ -1624,77 +1645,33 @@ tree_get_atoms(tree_ctx *ctx, bool fullcpv, set *satoms)
70 return state.cpf;
71 }
72
73 -struct tree_match_pkgs_cb_ctx {
74 - int flags;
75 - tree_match_ctx *ret;
76 -};
77 -
78 static int
79 -tree_match_atom_packages_cb(tree_pkg_ctx *ctx, void *priv)
80 +tree_match_atom_cache_populate_cb(tree_pkg_ctx *ctx, void *priv)
81 {
82 - struct tree_match_pkgs_cb_ctx *rctx = priv;
83 - depend_atom *a;
84 - tree_match_ctx *n;
85 -
86 - /* skip anything after finding first match */
87 - if (rctx->flags & TREE_MATCH_FIRST && rctx->ret != NULL)
88 - return 1;
89 -
90 - a = tree_get_atom(ctx, rctx->flags & TREE_MATCH_FULL_ATOM);
91 -
92 - /* skip virtual category if not requested */
93 - if (!(rctx->flags & TREE_MATCH_VIRTUAL) &&
94 - strcmp(a->CATEGORY, "virtual") == 0)
95 - return 1;
96 -
97 - n = xzalloc(sizeof(tree_match_ctx));
98 - n->free_atom = true;
99 - n->atom = atom_clone(a);
100 - snprintf(n->path, sizeof(n->path), "%s/%s/%s.tbz2",
101 - (char *)ctx->cat_ctx->ctx->path, ctx->cat_ctx->name, ctx->name);
102 - if (rctx->flags & TREE_MATCH_METADATA) {
103 - n->meta = xmalloc(sizeof(*n->meta));
104 - /* for Packages, all pointers to meta here are to the in memory
105 - * copy of the Packages file, so these pointers can just be
106 - * copied since the tree has to remain open, thus the pointers
107 - * will stay valid */
108 - memcpy(n->meta, ctx->cat_ctx->ctx->pkgs, sizeof(*n->meta));
109 + set *cache = priv;
110 + tree_cat_ctx *cat_ctx;
111 + tree_pkg_ctx *pkg;
112 + tree_ctx *tctx = ctx->cat_ctx->ctx;
113 + depend_atom *atom = tree_get_atom(ctx, true);
114 +
115 + (void)priv;
116 +
117 + cat_ctx = get_set(atom->CATEGORY, cache);
118 + if (cat_ctx == NULL) {
119 + cat_ctx = tree_open_cat(tctx, ".");
120 + add_set_value(atom->CATEGORY, cat_ctx, cache);
121 + /* get a pointer from the set */
122 + cat_ctx->name = contains_set(atom->CATEGORY, cache);
123 }
124
125 - n->next = rctx->ret;
126 - rctx->ret = n;
127 -
128 - return 0;
129 -}
130 -
131 -static int
132 -tree_match_atom_binpkg_cb(tree_pkg_ctx *ctx, void *priv)
133 -{
134 - struct tree_match_pkgs_cb_ctx *rctx = priv;
135 - depend_atom *a;
136 - tree_match_ctx *n;
137 -
138 - /* skip anything after finding first match */
139 - if (rctx->flags & TREE_MATCH_FIRST && rctx->ret != NULL)
140 - return 1;
141 -
142 - a = tree_get_atom(ctx, rctx->flags & TREE_MATCH_FULL_ATOM);
143 -
144 - /* skip virtual category if not requested */
145 - if (!(rctx->flags & TREE_MATCH_VIRTUAL) &&
146 - strcmp(a->CATEGORY, "virtual") == 0)
147 - return 1;
148 -
149 - n = xzalloc(sizeof(tree_match_ctx));
150 - n->free_atom = true;
151 - n->atom = atom_clone(a);
152 - snprintf(n->path, sizeof(n->path), "%s/%s/%s.tbz2",
153 - (char *)ctx->cat_ctx->ctx->path, ctx->cat_ctx->name, ctx->name);
154 - if (rctx->flags & TREE_MATCH_METADATA)
155 - n->meta = tree_pkg_read(ctx);
156 -
157 - n->next = rctx->ret;
158 - rctx->ret = n;
159 + /* FIXME: this really could use a set */
160 + cat_ctx->pkg_cnt++;
161 + cat_ctx->pkg_ctxs = xrealloc(cat_ctx->pkg_ctxs,
162 + sizeof(*cat_ctx->pkg_ctxs) * cat_ctx->pkg_cnt);
163 + cat_ctx->pkg_ctxs[cat_ctx->pkg_cnt - 1] =
164 + pkg = tree_open_pkg(cat_ctx, atom->PF);
165 + pkg->atom = atom_clone(atom);
166 + pkg->name = pkg->atom->PF;
167
168 return 0;
169 }
170 @@ -1707,24 +1684,48 @@ tree_match_atom(tree_ctx *ctx, depend_atom *query, int flags)
171 tree_match_ctx *ret = NULL;
172 depend_atom *atom;
173
174 - if (ctx->cachetype == CACHE_PACKAGES) {
175 - struct tree_match_pkgs_cb_ctx rctx;
176 - /* Packages needs to be serviced separately because it doesn't
177 - * use a tree internally, but reads off of the Packages file */
178 - rctx.flags = flags;
179 - rctx.ret = NULL;
180 - ctx->query_atom = query;
181 - tree_foreach_packages(ctx, tree_match_atom_packages_cb, &rctx);
182 - ctx->query_atom = NULL;
183 - return rctx.ret;
184 - } else if (ctx->cachetype == CACHE_BINPKGS) {
185 - struct tree_match_pkgs_cb_ctx rctx;
186 - /* this sulks, but binpkgs modify the pkg_ctx->name to strip off
187 - * .tbz2, and that makes it non-reusable */
188 - rctx.flags = flags;
189 - rctx.ret = NULL;
190 - tree_foreach_pkg(ctx, tree_match_atom_binpkg_cb, &rctx, true, query);
191 - return rctx.ret;
192 + ctx->do_sort = true; /* sort uses buffer, which cache relies on */
193 + ctx->query_atom = NULL; /* ensure the cache contains ALL pkgs */
194 +
195 + if ((ctx->cachetype == CACHE_PACKAGES || ctx->cachetype == CACHE_BINPKGS)
196 + && ctx->cache.categories == NULL)
197 + {
198 + set *cache;
199 + DECLARE_ARRAY(cats);
200 + size_t n;
201 +
202 + /* Reading these formats requires us to traverse the tree for
203 + * each operation, so we better cache the entire thing in one
204 + * go. Packages in addition may not store the atoms sorted
205 + * (it's a file with content after all) and since we rely on
206 + * this for latest and first match, it is important that we sort
207 + * the contents so we're sure */
208 +
209 + cache = ctx->cache.categories;
210 + if (ctx->cache.categories != NULL)
211 + ctx->cache.categories = NULL;
212 + else
213 + cache = create_set();
214 +
215 + if (ctx->cachetype == CACHE_PACKAGES)
216 + tree_foreach_packages(ctx,
217 + tree_match_atom_cache_populate_cb, cache);
218 + else /* BINPKG */
219 + tree_foreach_pkg(ctx,
220 + tree_match_atom_cache_populate_cb, cache, true, NULL);
221 + ctx->do_sort = true; /* turn it back on */
222 + ctx->cache.all_categories = true;
223 +
224 + ctx->cache.categories = cache;
225 +
226 + /* loop through all categories, and sort the pkgs */
227 + values_set(cache, cats);
228 + array_for_each(cats, n, cat_ctx) {
229 + if (cat_ctx->pkg_cnt > 1) {
230 + qsort(cat_ctx->pkg_ctxs, cat_ctx->pkg_cnt,
231 + sizeof(*cat_ctx->pkg_ctxs), tree_pkg_compar);
232 + }
233 + }
234 }
235
236 /* activate cache for future lookups, tree_match_atom relies on
237 @@ -1733,9 +1734,6 @@ tree_match_atom(tree_ctx *ctx, depend_atom *query, int flags)
238 if (ctx->cache.categories == NULL)
239 ctx->cache.categories = create_set();
240
241 - ctx->do_sort = true; /* sort uses buffer, which cache relies on */
242 - ctx->query_atom = NULL; /* ensure the cache contains ALL pkgs */
243 -
244 #define search_cat(C) \
245 { \
246 char *lastpn = NULL; \
247
248 diff --git a/libq/tree.h b/libq/tree.h
249 index 5a12c92..8741bad 100644
250 --- a/libq/tree.h
251 +++ b/libq/tree.h
252 @@ -48,6 +48,7 @@ struct tree_ctx {
253 depend_atom *query_atom;
254 struct tree_cache {
255 set *categories;
256 + bool all_categories:1;
257 } cache;
258 };