Skip to content

Commit 61f0141

Browse files
committed
lib: fix virtual package lookup performance
Instead of having a dict with pkgvers as keys and iterating over all keys to match virtual packages, change the map to have pkgnames as keys, which hold another dict with all the old keys and values for a given package name. This significantly speeds up XBPS, since for every package it would iterate over the whole virtual package map. With recent changes to xbps-src, where it generates cmd: and py3: virtual packages, the number of virtual packages in the map has been growing a lot.
1 parent 3ace245 commit 61f0141

File tree

4 files changed

+238
-80
lines changed

4 files changed

+238
-80
lines changed

include/xbps_api_impl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ int HIDDEN xbps_register_pkg(struct xbps_handle *, xbps_dictionary_t);
113113
char HIDDEN *xbps_archive_get_file(struct archive *, struct archive_entry *);
114114
xbps_dictionary_t HIDDEN xbps_archive_get_dictionary(struct archive *,
115115
struct archive_entry *);
116-
const char HIDDEN *vpkg_user_conf(struct xbps_handle *, const char *, bool);
116+
const char HIDDEN *vpkg_user_conf(struct xbps_handle *, const char *);
117117
xbps_array_t HIDDEN xbps_get_pkg_fulldeptree(struct xbps_handle *,
118118
const char *, bool);
119119
struct xbps_repo HIDDEN *xbps_regget_repo(struct xbps_handle *,

lib/conf.c

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,47 @@
5151
* Functions for parsing xbps configuration files.
5252
*/
5353

54+
static int
55+
vpkg_map_add(xbps_dictionary_t d, const char *pkgname, const char *vpkgver, const char *provider)
56+
{
57+
xbps_dictionary_t providers;
58+
bool alloc = false;
59+
int r;
60+
61+
providers = xbps_dictionary_get(d, pkgname);
62+
if (!providers) {
63+
providers = xbps_dictionary_create();
64+
if (!providers)
65+
return -ENOMEM;
66+
alloc = true;
67+
if (!xbps_dictionary_set(d, pkgname, providers)) {
68+
r = errno ? -errno : -ENOMEM;
69+
goto err;
70+
}
71+
}
72+
73+
if (!xbps_dictionary_set_cstring(providers, vpkgver, provider)) {
74+
r = errno ? -errno : -ENOMEM;
75+
goto err;
76+
}
77+
78+
r = 0;
79+
err:
80+
if (alloc)
81+
xbps_object_release(providers);
82+
return r;
83+
}
84+
5485
static int
5586
store_virtualpkg(struct xbps_handle *xhp, const char *path, size_t line, char *val)
5687
{
88+
char namebuf[XBPS_NAME_SIZE];
89+
char pkgverbuf[XBPS_NAME_SIZE + sizeof("-99999_1")];
90+
const char *vpkgname, *vpkgver, *provider;
5791
char *p;
92+
int r;
93+
94+
5895
/*
5996
* Parse strings delimited by ':' i.e
6097
* <left>:<right>
@@ -66,13 +103,25 @@ store_virtualpkg(struct xbps_handle *xhp, const char *path, size_t line, char *v
66103
return 0;
67104
}
68105
*p++ = '\0';
106+
provider = p;
107+
108+
if (xbps_pkg_name(namebuf, sizeof(namebuf), val)) {
109+
vpkgname = namebuf;
110+
vpkgver = val;
111+
} else {
112+
vpkgname = val;
113+
snprintf(pkgverbuf, sizeof(pkgverbuf), "%s-99999_1", vpkgname);
114+
vpkgver = pkgverbuf;
115+
}
69116

70-
if (!xbps_dictionary_set_cstring(xhp->vpkgd, val, p))
71-
return -errno;
72-
if (!xbps_dictionary_set_cstring(xhp->vpkgd_conf, val, p))
73-
return -errno;
117+
r = vpkg_map_add(xhp->vpkgd, vpkgname, vpkgver, provider);
118+
if (r < 0)
119+
return r;
120+
r = vpkg_map_add(xhp->vpkgd_conf, vpkgname, vpkgver, provider);
121+
if (r < 0)
122+
return r;
74123
xbps_dbg_printf("%s: added virtualpkg %s for %s\n", path, val, p);
75-
return 1;
124+
return 0;
76125
}
77126

78127
static void

lib/pkgdb.c

Lines changed: 75 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include <string.h>
3636
#include <unistd.h>
3737

38+
#include "xbps.h"
3839
#include "xbps_api_impl.h"
3940

4041
/**
@@ -145,26 +146,35 @@ pkgdb_map_vpkgs(struct xbps_handle *xhp)
145146
{
146147
xbps_object_iterator_t iter;
147148
xbps_object_t obj;
148-
int rv = 0;
149+
int r = 0;
149150

150151
if (!xbps_dictionary_count(xhp->pkgdb))
151152
return 0;
152153

153154
if (xhp->vpkgd == NULL) {
154155
xhp->vpkgd = xbps_dictionary_create();
155-
assert(xhp->vpkgd);
156+
if (!xhp->vpkgd) {
157+
r = -errno;
158+
xbps_error_printf("failed to create dictionary\n");
159+
return r;
160+
}
156161
}
162+
157163
/*
158164
* This maps all pkgs that have virtualpkgs in pkgdb.
159165
*/
160166
iter = xbps_dictionary_iterator(xhp->pkgdb);
161-
assert(iter);
167+
if (!iter) {
168+
r = -errno;
169+
xbps_error_printf("failed to create iterator");
170+
goto out;
171+
}
162172

163173
while ((obj = xbps_object_iterator_next(iter))) {
164174
xbps_array_t provides;
165175
xbps_dictionary_t pkgd;
166176
const char *pkgver = NULL;
167-
char pkgname[XBPS_NAME_SIZE] = {0};
177+
const char *pkgname = NULL;
168178
unsigned int cnt;
169179

170180
pkgd = xbps_dictionary_get_keysym(xhp->pkgdb, obj);
@@ -174,26 +184,53 @@ pkgdb_map_vpkgs(struct xbps_handle *xhp)
174184
continue;
175185

176186
xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver);
177-
if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver)) {
178-
rv = EINVAL;
179-
goto out;
180-
}
187+
xbps_dictionary_get_cstring_nocopy(pkgd, "pkgname", &pkgname);
188+
assert(pkgname);
189+
181190
for (unsigned int i = 0; i < cnt; i++) {
191+
char vpkgname[XBPS_NAME_SIZE];
182192
const char *vpkg = NULL;
193+
xbps_dictionary_t providers;
194+
bool alloc = false;
183195

184196
xbps_array_get_cstring_nocopy(provides, i, &vpkg);
185-
if (!xbps_dictionary_set_cstring(xhp->vpkgd, vpkg, pkgname)) {
186-
xbps_dbg_printf("%s: set_cstring vpkg "
187-
"%s pkgname %s\n", __func__, vpkg, pkgname);
188-
rv = EINVAL;
197+
if (!xbps_pkg_name(vpkgname, sizeof(vpkgname), vpkg)) {
198+
xbps_warn_printf("%s: invalid provides: %s\n", pkgver, vpkg);
199+
continue;
200+
}
201+
202+
providers = xbps_dictionary_get(xhp->vpkgd, vpkgname);
203+
if (!providers) {
204+
providers = xbps_dictionary_create();
205+
if (!providers) {
206+
r = -errno;
207+
xbps_error_printf("failed to create dictionary\n");
208+
goto out;
209+
}
210+
if (!xbps_dictionary_set(xhp->vpkgd, vpkgname, providers)) {
211+
r = -errno;
212+
xbps_error_printf("failed to set dictionary entry\n");
213+
xbps_object_release(providers);
214+
goto out;
215+
}
216+
alloc = true;
217+
}
218+
219+
if (!xbps_dictionary_set_cstring(providers, vpkg, pkgname)) {
220+
r = -errno;
221+
xbps_error_printf("failed to set dictionary entry\n");
222+
if (alloc)
223+
xbps_object_release(providers);
189224
goto out;
190225
}
226+
if (alloc)
227+
xbps_object_release(providers);
191228
xbps_dbg_printf("[pkgdb] added vpkg %s for %s\n", vpkg, pkgname);
192229
}
193230
}
194231
out:
195232
xbps_object_iterator_release(iter);
196-
return rv;
233+
return r;
197234
}
198235

199236
static int
@@ -398,13 +435,17 @@ generate_full_revdeps_tree(struct xbps_handle *xhp)
398435
{
399436
xbps_object_t obj;
400437
xbps_object_iterator_t iter;
438+
xbps_dictionary_t vpkg_cache;
401439

402440
if (xhp->pkgdb_revdeps)
403441
return;
404442

405443
xhp->pkgdb_revdeps = xbps_dictionary_create();
406444
assert(xhp->pkgdb_revdeps);
407445

446+
vpkg_cache = xbps_dictionary_create();
447+
assert(vpkg_cache);
448+
408449
iter = xbps_dictionary_iterator(xhp->pkgdb);
409450
assert(iter);
410451

@@ -421,20 +462,33 @@ generate_full_revdeps_tree(struct xbps_handle *xhp)
421462
xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver);
422463
for (unsigned int i = 0; i < xbps_array_count(rundeps); i++) {
423464
xbps_array_t pkg;
424-
const char *pkgdep = NULL, *vpkgname = NULL;
425-
char *v, curpkgname[XBPS_NAME_SIZE];
465+
const char *pkgdep = NULL, *v;
466+
char curpkgname[XBPS_NAME_SIZE];
426467
bool alloc = false;
427468

428469
xbps_array_get_cstring_nocopy(rundeps, i, &pkgdep);
429470
if ((!xbps_pkgpattern_name(curpkgname, sizeof(curpkgname), pkgdep)) &&
430471
(!xbps_pkg_name(curpkgname, sizeof(curpkgname), pkgdep))) {
431472
abort();
432473
}
433-
vpkgname = vpkg_user_conf(xhp, curpkgname, false);
434-
if (vpkgname == NULL) {
435-
v = strdup(curpkgname);
436-
} else {
437-
v = strdup(vpkgname);
474+
475+
/* TODO: this is kind of a workaround, to avoid calling vpkg_user_conf
476+
* over and over again for the same packages which is slow. A better
477+
* solution for itself vpkg_user_conf being slow should probably be
478+
* implemented at some point.
479+
*/
480+
if (!xbps_dictionary_get_cstring_nocopy(vpkg_cache, curpkgname, &v)) {
481+
const char *vpkgname = vpkg_user_conf(xhp, curpkgname);
482+
if (vpkgname) {
483+
v = vpkgname;
484+
} else {
485+
v = curpkgname;
486+
}
487+
errno = 0;
488+
if (!xbps_dictionary_set_cstring_nocopy(vpkg_cache, curpkgname, v)) {
489+
xbps_error_printf("%s\n", strerror(errno ? errno : ENOMEM));
490+
abort();
491+
}
438492
}
439493

440494
pkg = xbps_dictionary_get(xhp->pkgdb_revdeps, v);
@@ -446,12 +500,12 @@ generate_full_revdeps_tree(struct xbps_handle *xhp)
446500
xbps_array_add_cstring_nocopy(pkg, pkgver);
447501
xbps_dictionary_set(xhp->pkgdb_revdeps, v, pkg);
448502
}
449-
free(v);
450503
if (alloc)
451504
xbps_object_release(pkg);
452505
}
453506
}
454507
xbps_object_iterator_release(iter);
508+
xbps_object_release(vpkg_cache);
455509
}
456510

457511
xbps_array_t

0 commit comments

Comments
 (0)