diff --git a/libpkgconf/cache.c b/libpkgconf/cache.c index 259577d..16190b5 100644 --- a/libpkgconf/cache.c +++ b/libpkgconf/cache.c @@ -29,6 +29,46 @@ * be shared across threads. */ +static int +cache_member_cmp(const void *a, const void *b) +{ + const char *key = a; + const pkgconf_pkg_t *pkg = *(void **) b; + + return strcmp(key, pkg->id); +} + +static int +cache_member_sort_cmp(const void *a, const void *b) +{ + const pkgconf_pkg_t *pkgA = *(void **) a; + const pkgconf_pkg_t *pkgB = *(void **) b; + + if (pkgA == NULL) + return 1; + + if (pkgB == NULL) + return -1; + + return strcmp(pkgA->id, pkgB->id); +} + +static void +cache_dump(const pkgconf_client_t *client) +{ + size_t i; + + PKGCONF_TRACE(client, "dumping package cache contents"); + + for (i = 0; i < client->cache_count; i++) + { + const pkgconf_pkg_t *pkg = client->cache_table[i]; + + PKGCONF_TRACE(client, "%zu: %p(%s)", + i, pkg, pkg == NULL ? "NULL" : pkg->id); + } +} + /* * !doc * @@ -46,17 +86,16 @@ pkgconf_pkg_t * pkgconf_cache_lookup(pkgconf_client_t *client, const char *id) { - pkgconf_node_t *node; + pkgconf_pkg_t **pkg; - PKGCONF_FOREACH_LIST_ENTRY(client->pkg_cache.head, node) + pkg = bsearch(id, client->cache_table, + client->cache_count, sizeof (void *), + cache_member_cmp); + + if (pkg != NULL) { - pkgconf_pkg_t *pkg = node->data; - - if (!strcmp(pkg->id, id)) - { - PKGCONF_TRACE(client, "found: %s @%p", id, pkg); - return pkgconf_pkg_ref(client, pkg); - } + PKGCONF_TRACE(client, "found: %s @%p", id, *pkg); + return pkgconf_pkg_ref(client, *pkg); } PKGCONF_TRACE(client, "miss: %s", id); @@ -82,12 +121,19 @@ pkgconf_cache_add(pkgconf_client_t *client, pkgconf_pkg_t *pkg) return; pkgconf_pkg_ref(client, pkg); - pkgconf_node_insert(&pkg->cache_iter, pkg, &client->pkg_cache); PKGCONF_TRACE(client, "added @%p to cache", pkg); /* mark package as cached */ pkg->flags |= PKGCONF_PKG_PROPF_CACHED; + + ++client->cache_count; + client->cache_table = reallocarray(client->cache_table, + client->cache_count, sizeof (void *)); + client->cache_table[client->cache_count - 1] = pkg; + + qsort(client->cache_table, client->cache_count, + sizeof(void *), cache_member_sort_cmp); } /* @@ -112,7 +158,31 @@ pkgconf_cache_remove(pkgconf_client_t *client, pkgconf_pkg_t *pkg) PKGCONF_TRACE(client, "removed @%p from cache", pkg); - pkgconf_node_delete(&pkg->cache_iter, &client->pkg_cache); + pkgconf_pkg_t **slot; + + slot = bsearch(pkg->id, client->cache_table, + client->cache_count, sizeof (void *), + cache_member_cmp); + + if (slot == NULL) + return; + + *slot = NULL; + + qsort(client->cache_table, client->cache_count, + sizeof(void *), cache_member_sort_cmp); + + if (client->cache_table[client->cache_count - 1] != NULL) + { + PKGCONF_TRACE(client, "end of cache table refers to %p, not NULL", + client->cache_table[client->cache_count - 1]); + cache_dump(client); + abort(); + } + + client->cache_count--; + client->cache_table = reallocarray(client->cache_table, + client->cache_count, sizeof(void *)); } static inline void @@ -141,12 +211,17 @@ clear_dependency_matches(pkgconf_list_t *list) void pkgconf_cache_free(pkgconf_client_t *client) { - pkgconf_node_t *iter, *iter2; + pkgconf_pkg_t **cache_table; + size_t i, count; + + cache_table = reallocarray(NULL, client->cache_count, sizeof (void *)); + memcpy(cache_table, client->cache_table, + client->cache_count * sizeof (void *)); /* first we clear cached match pointers */ - PKGCONF_FOREACH_LIST_ENTRY(client->pkg_cache.head, iter) + for (i = 0, count = client->cache_count; i < count; i++) { - pkgconf_pkg_t *pkg = iter->data; + pkgconf_pkg_t *pkg = cache_table[i]; clear_dependency_matches(&pkg->required); clear_dependency_matches(&pkg->requires_private); @@ -155,13 +230,11 @@ pkgconf_cache_free(pkgconf_client_t *client) } /* now forcibly free everything */ - PKGCONF_FOREACH_LIST_ENTRY_SAFE(client->pkg_cache.head, iter2, iter) + for (i = 0, count = client->cache_count; i < count; i++) { - pkgconf_pkg_t *pkg = iter->data; + pkgconf_pkg_t *pkg = cache_table[i]; pkgconf_pkg_free(client, pkg); } - memset(&client->pkg_cache, 0, sizeof client->pkg_cache); - PKGCONF_TRACE(client, "cleared package cache"); } diff --git a/libpkgconf/libpkgconf.h b/libpkgconf/libpkgconf.h index 8036946..27c5597 100644 --- a/libpkgconf/libpkgconf.h +++ b/libpkgconf/libpkgconf.h @@ -128,8 +128,6 @@ struct pkgconf_path_ { #define PKGCONF_PKG_PROPF_VIRTUAL 0x10 struct pkgconf_pkg_ { - pkgconf_node_t cache_iter; - int refcount; char *id; char *filename; @@ -171,7 +169,6 @@ typedef bool (*pkgconf_error_handler_func_t)(const char *msg, const pkgconf_clie struct pkgconf_client_ { pkgconf_list_t dir_list; - pkgconf_list_t pkg_cache; pkgconf_list_t filter_libdirs; pkgconf_list_t filter_includedirs; @@ -198,6 +195,9 @@ struct pkgconf_client_ { bool already_sent_notice; uint64_t serial; + + pkgconf_pkg_t **cache_table; + size_t cache_count; }; struct pkgconf_cross_personality_ {