From 41fb3a4f9e5949a66fedc069f94b75c18614728d Mon Sep 17 00:00:00 2001 From: Timo Teräs Date: Wed, 15 Feb 2012 13:57:36 +0200 Subject: solver, db: repository pinning improvements * solver internally calculates now using tags; not repository masks * installeddb now contains the tag name where the package came from -> we can now handle upgrades properly * the pinning is still a preference, and not strictly enforced; versioned dependencies may overrule preference --- src/add.c | 2 +- src/apk_database.h | 8 +++- src/apk_package.h | 1 + src/apk_solver.h | 2 +- src/database.c | 20 ++++----- src/package.c | 2 +- src/solver.c | 121 ++++++++++++++++++++++++++++++++--------------------- 7 files changed, 91 insertions(+), 65 deletions(-) (limited to 'src') diff --git a/src/add.c b/src/add.c index 238a388..36f51cf 100644 --- a/src/add.c +++ b/src/add.c @@ -120,7 +120,7 @@ static int add_main(void *ctx, struct apk_database *db, int argc, char **argv) if (virtpkg == NULL) { apk_deps_add(&world, &dep); apk_solver_set_name_flags(dep.name, - actx->solver_flags | APK_SOLVERF_PREFER_TAG, + actx->solver_flags, actx->solver_flags); } else { apk_deps_add(&virtpkg->depends, &dep); diff --git a/src/apk_database.h b/src/apk_database.h index 690b757..37dc557 100644 --- a/src/apk_database.h +++ b/src/apk_database.h @@ -35,6 +35,7 @@ #endif #define APK_MAX_REPOS 32 +#define APK_MAX_TAGS 16 #define APK_CACHE_CSUM_BYTES 4 extern const char * const apk_index_gz; @@ -121,6 +122,9 @@ struct apk_db_options { struct list_head repository_list; }; +#define APK_DEFAULT_REPOSITORY_TAG 0 +#define APK_DEFAULT_PINNING_MASK BIT(APK_DEFAULT_REPOSITORY_TAG) + struct apk_repository_tag { unsigned int allowed_repos; apk_blob_t *name; @@ -143,7 +147,7 @@ struct apk_database { struct apk_dependency_array *world; struct apk_string_array *protected_paths; struct apk_repository repos[APK_MAX_REPOS]; - struct apk_repository_tag repo_tags[APK_MAX_REPOS]; + struct apk_repository_tag repo_tags[APK_MAX_TAGS]; struct apk_id_cache id_cache; struct { @@ -173,7 +177,7 @@ typedef union apk_database_or_void { struct apk_name *apk_db_get_name(struct apk_database *db, apk_blob_t name); struct apk_name *apk_db_query_name(struct apk_database *db, apk_blob_t name); int apk_db_get_tag_id(struct apk_database *db, apk_blob_t tag); -int apk_db_get_tag_id_by_repos(struct apk_database *db, unsigned int repos); + struct apk_db_dir *apk_db_dir_query(struct apk_database *db, apk_blob_t name); struct apk_db_file *apk_db_file_query(struct apk_database *db, diff --git a/src/apk_package.h b/src/apk_package.h index 4fc6910..4f8cec0 100644 --- a/src/apk_package.h +++ b/src/apk_package.h @@ -68,6 +68,7 @@ APK_ARRAY(apk_dependency_array, struct apk_dependency); struct apk_installed_package { struct apk_package *pkg; unsigned int run_all_triggers : 1; + unsigned int repository_tag : 6; unsigned short replaces_priority; struct list_head installed_pkgs_list; struct list_head trigger_pkgs_list; diff --git a/src/apk_solver.h b/src/apk_solver.h index 235ac0c..7dd2914 100644 --- a/src/apk_solver.h +++ b/src/apk_solver.h @@ -15,6 +15,7 @@ struct apk_change { struct apk_package *oldpkg; struct apk_package *newpkg; + unsigned short repository_tag; }; APK_ARRAY(apk_change_array, struct apk_change); @@ -25,7 +26,6 @@ struct apk_changeset { #define APK_SOLVERF_UPGRADE 0x0001 #define APK_SOLVERF_AVAILABLE 0x0002 #define APK_SOLVERF_REINSTALL 0x0004 -#define APK_SOLVERF_PREFER_TAG 0x0008 void apk_solver_set_name_flags(struct apk_name *name, unsigned short solver_flags, diff --git a/src/database.c b/src/database.c index 35479d4..11f705d 100644 --- a/src/database.c +++ b/src/database.c @@ -754,6 +754,9 @@ int apk_db_index_read(struct apk_database *db, struct apk_bstream *bs, int repo) case 'q': ipkg->replaces_priority = apk_blob_pull_uint(&l, 10); break; + case 'p': + ipkg->repository_tag = apk_db_get_tag_id(db, l); + break; default: if (r != 0 && !(apk_flags & APK_FORCE)) { /* Installed db should not have unsupported fields */ @@ -800,7 +803,11 @@ static int apk_db_write_fdb(struct apk_database *db, struct apk_ostream *os) apk_blob_push_uint(&bbuf, ipkg->replaces_priority, 10); apk_blob_push_blob(&bbuf, APK_BLOB_STR("\n")); } - + if (ipkg->repository_tag) { + apk_blob_push_blob(&bbuf, APK_BLOB_STR("p:")); + apk_blob_push_blob(&bbuf, *db->repo_tags[ipkg->repository_tag].name); + apk_blob_push_blob(&bbuf, APK_BLOB_STR("\n")); + } hlist_for_each_entry(diri, c1, &ipkg->owned_dirs, pkg_dirs_list) { apk_blob_push_blob(&bbuf, APK_BLOB_STR("F:")); apk_blob_push_blob(&bbuf, APK_BLOB_PTR_LEN(diri->dir->name, diri->dir->namelen)); @@ -1551,17 +1558,6 @@ int apk_db_get_tag_id(struct apk_database *db, apk_blob_t tag) return -1; } -int apk_db_get_tag_id_by_repos(struct apk_database *db, unsigned int repos) -{ - int i; - - for (i = 0; i < db->num_repo_tags; i++) { - if (db->repo_tags[i].allowed_repos & repos) - return i; - } - return -1; -} - static int fire_triggers(apk_hash_item item, void *ctx) { struct apk_database *db = (struct apk_database *) ctx; diff --git a/src/package.c b/src/package.c index 1c85e12..a162038 100644 --- a/src/package.c +++ b/src/package.c @@ -739,7 +739,7 @@ int apk_pkg_add_info(struct apk_database *db, struct apk_package *pkg, pkg->commit = apk_blob_cstr(value); break; case 'F': case 'M': case 'R': case 'Z': case 'r': case 'q': - case 'a': + case 'a': case 'p': /* installed db entries which are handled in database.c */ return 1; default: diff --git a/src/solver.c b/src/solver.c index ba98ca6..e233f3b 100644 --- a/src/solver.c +++ b/src/solver.c @@ -48,10 +48,12 @@ struct apk_name_state { struct apk_package *chosen; struct apk_score minimum_penalty; unsigned int topology_last_touched; - unsigned int allowed_repos, preferred_repos; unsigned short requirers; unsigned short install_ifs; + unsigned short preferred_pinning; + unsigned short allowed_pinning; + unsigned int solver_flags_local : 4; unsigned int solver_flags_local_mask : 4; unsigned int solver_flags_inherited : 4; @@ -320,32 +322,41 @@ static void foreach_dependency(struct apk_solver_state *ss, struct apk_dependenc func(ss, &deps->item[i]); } +static unsigned int get_pinning_mask_repos(struct apk_database *db, unsigned short pinning_mask) +{ + unsigned int repository_mask = 0; + int i; + + for (i = 0; i < db->num_repo_tags && pinning_mask; i++) { + if (!(BIT(i) & pinning_mask)) + continue; + pinning_mask &= ~BIT(i); + repository_mask |= db->repo_tags[i].allowed_repos; + } + return repository_mask; +} + static int compare_package_preference(unsigned short solver_flags, unsigned int preferred_repos, struct apk_package *pkgA, - struct apk_package *pkgB) + struct apk_package *pkgB, + struct apk_database *db) { + unsigned int a_repos, b_repos; + /* specified on command line directly */ if (pkgA->filename && !pkgB->filename) return 1; if (pkgB->filename && !pkgA->filename) return -1; - if (solver_flags & APK_SOLVERF_PREFER_TAG) { - /* preferred repository pinning */ - if ((pkgA->repos & preferred_repos) && !(pkgB->repos & preferred_repos)) - return 1; - if ((pkgB->repos & preferred_repos) && !(pkgA->repos & preferred_repos)) - return -1; - } else { - /* preferred repository pinning */ - if ((pkgA->ipkg || (pkgA->repos & preferred_repos)) && - !(pkgB->ipkg || (pkgB->repos & preferred_repos))) - return 1; - if ((pkgB->ipkg || (pkgB->repos & preferred_repos)) && - !(pkgA->ipkg || (pkgA->repos & preferred_repos))) - return -1; - } + /* Is there a difference in pinning preference? */ + a_repos = pkgA->repos | (pkgA->ipkg ? db->repo_tags[pkgA->ipkg->repository_tag].allowed_repos : 0); + b_repos = pkgB->repos | (pkgB->ipkg ? db->repo_tags[pkgB->ipkg->repository_tag].allowed_repos : 0); + if ((a_repos & preferred_repos) && !(b_repos & preferred_repos)) + return 1; + if ((b_repos & preferred_repos) && !(a_repos & preferred_repos)) + return -1; if (solver_flags & APK_SOLVERF_AVAILABLE) { if (pkgA->repos != 0 && pkgB->repos == 0) @@ -390,12 +401,13 @@ static int get_preference(struct apk_solver_state *ss, unsigned short name_flags = ns->solver_flags_local | ns->solver_flags_inherited | ss->solver_flags; - unsigned int preferred_repos = ns->preferred_repos; + unsigned short preferred_pinning; + unsigned int preferred_repos; unsigned short preference = 0; int i; - if (preferred_repos == 0) - preferred_repos = ss->db->repo_tags[0].allowed_repos; + preferred_pinning = ns->preferred_pinning ?: APK_DEFAULT_PINNING_MASK; + preferred_repos = get_pinning_mask_repos(ss->db, preferred_pinning); for (i = 0; i < name->pkgs->num; i++) { struct apk_package *pkg0 = name->pkgs->item[i]; @@ -404,9 +416,8 @@ static int get_preference(struct apk_solver_state *ss, if (pkg0 == pkg || ps0 == NULL) continue; - if (compare_package_preference(name_flags, - preferred_repos, - pkg, pkg0) < 0) { + if (compare_package_preference(name_flags, preferred_repos, + pkg, pkg0, ss->db) < 0) { if (installable_only) { if (ss->topology_position > pkg0->topology_hard && !(ps0->flags & APK_PKGSTF_DECIDED)) @@ -441,13 +452,21 @@ static int update_name_state(struct apk_solver_state *ss, struct apk_name *name) struct apk_package *best_pkg = NULL, *preferred_pkg = NULL; struct apk_package_state *preferred_ps = NULL; unsigned int best_topology = 0; - unsigned int allowed_repos = ns->allowed_repos | ss->db->repo_tags[0].allowed_repos; - unsigned int preferred_repos = ns->preferred_repos; unsigned short name_flags = ns->solver_flags_local | ns->solver_flags_inherited | ss->solver_flags; + unsigned short preferred_pinning, allowed_pinning; + unsigned int preferred_repos, allowed_repos; int i, options = 0, skipped_options = 0; + preferred_pinning = ns->preferred_pinning ?: APK_DEFAULT_PINNING_MASK; + preferred_repos = get_pinning_mask_repos(ss->db, preferred_pinning); + allowed_pinning = ns->allowed_pinning | ns->preferred_pinning | APK_DEFAULT_PINNING_MASK; + if (preferred_pinning != allowed_pinning) + allowed_repos = get_pinning_mask_repos(ss->db, allowed_pinning); + else + allowed_repos = preferred_repos; + subscore(&ss->minimum_penalty, &ns->minimum_penalty); ns->minimum_penalty = (struct apk_score) { 0, 0 }; @@ -469,9 +488,8 @@ static int update_name_state(struct apk_solver_state *ss, struct apk_name *name) if ((preferred_pkg == NULL) || (ps0->conflicts < preferred_ps->conflicts) || (ps0->conflicts == preferred_ps->conflicts && - compare_package_preference(name_flags, - preferred_repos, - pkg0, preferred_pkg) > 0)) { + compare_package_preference(name_flags, preferred_repos, + pkg0, preferred_pkg, ss->db) > 0)) { preferred_pkg = pkg0; preferred_ps = ps0; } @@ -702,7 +720,8 @@ static void inherit_name_state(struct apk_name *to, struct apk_name *from) tns->solver_flags_inherited |= fns->solver_flags_inherited | (fns->solver_flags_local & fns->solver_flags_local_mask); - tns->allowed_repos |= fns->allowed_repos; + + tns->allowed_pinning |= fns->allowed_pinning | fns->preferred_pinning; } static void inherit_name_state_wrapper(struct apk_package *rdepend, void *ctx) @@ -719,7 +738,7 @@ static int has_inherited_state(struct apk_name *name) return 0; if (ns->solver_flags_inherited || (ns->solver_flags_local & ns->solver_flags_local_mask)) return 1; - if (ns->allowed_repos) + if (ns->allowed_pinning) return 1; return 0; } @@ -729,7 +748,7 @@ static void recalculate_inherted_name_state(struct apk_name *name) struct apk_name_state *ns = name_to_ns(name); ns->solver_flags_inherited = 0; - ns->allowed_repos = 0; + ns->allowed_pinning = 0; foreach_locked_reverse_dependency(name, inherit_name_state_wrapper, name); } @@ -754,13 +773,10 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency } if (dep->repository_tag) { - unsigned int allowed_repos; - - dbg_printf("%s: enabling repository tag %d\n", + dbg_printf("%s: adding pinnings %d\n", dep->name->name, dep->repository_tag); - allowed_repos = ss->db->repo_tags[dep->repository_tag].allowed_repos; - ns->allowed_repos |= allowed_repos; - ns->preferred_repos |= allowed_repos; + ns->preferred_pinning = BIT(dep->repository_tag); + ns->allowed_pinning |= BIT(dep->repository_tag); } for (i = 0; i < name->pkgs->num; i++) { @@ -944,6 +960,19 @@ static int compare_change(const void *p1, const void *p2) c2->newpkg->topology_hard; } +static int get_tag(struct apk_database *db, unsigned short pinning_mask, unsigned int repos) +{ + int i; + + for (i = 0; i < db->num_repo_tags; i++) { + if (!(BIT(i) & pinning_mask)) + continue; + if (db->repo_tags[i].allowed_repos & repos) + return i; + } + return APK_DEFAULT_REPOSITORY_TAG; +} + static int generate_changeset(struct apk_database *db, struct apk_package_array *solution, struct apk_changeset *changeset, @@ -999,6 +1028,7 @@ static int generate_changeset(struct apk_database *db, break; } changeset->changes->item[ci].newpkg = pkg; + changeset->changes->item[ci].repository_tag = get_tag(db, ns->allowed_pinning, pkg->repos); ci++; } } @@ -1130,23 +1160,16 @@ static void print_change(struct apk_database *db, struct apk_package *newpkg = change->newpkg; const char *msg = NULL; char status[32], n[512], *nameptr; - int r, tag; + int r; snprintf(status, sizeof(status), "(%i/%i)", cur+1, total); status[sizeof(status) - 1] = 0; - if (newpkg != NULL) { - name = newpkg->name; - tag = apk_db_get_tag_id_by_repos(db, newpkg->repos); - } else { - name = oldpkg->name; - tag = apk_db_get_tag_id_by_repos(db, oldpkg->repos); - } - - if (tag > 0) { + name = newpkg ? newpkg->name : oldpkg->name; + if (change->repository_tag > 0) { snprintf(n, sizeof(n), "%s@" BLOB_FMT, name->name, - BLOB_PRINTF(*db->repo_tags[tag].name)); + BLOB_PRINTF(*db->repo_tags[change->repository_tag].name)); n[sizeof(n) - 1] = 0; nameptr = n; } else { @@ -1403,6 +1426,8 @@ int apk_solver_commit_changeset(struct apk_database *db, &prog); if (r != 0) break; + if (change->newpkg) + change->newpkg->ipkg->repository_tag = change->repository_tag; } count_change(change, &prog.done); -- cgit v1.2.3-60-g2f50