summaryrefslogtreecommitdiff
path: root/src/solver.c
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2012-02-15 13:57:36 +0200
committerTimo Teräs <timo.teras@iki.fi>2012-02-15 13:57:36 +0200
commit41fb3a4f9e5949a66fedc069f94b75c18614728d (patch)
treeff3ce7bcba056015a01edabc9e55d50894b9eb2a /src/solver.c
parent29064d88f3a972b69a006d7a8092159bd65ef03f (diff)
downloadapk-tools-41fb3a4f9e5949a66fedc069f94b75c18614728d.tar.gz
apk-tools-41fb3a4f9e5949a66fedc069f94b75c18614728d.tar.bz2
apk-tools-41fb3a4f9e5949a66fedc069f94b75c18614728d.tar.xz
apk-tools-41fb3a4f9e5949a66fedc069f94b75c18614728d.zip
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
Diffstat (limited to 'src/solver.c')
-rw-r--r--src/solver.c121
1 files changed, 73 insertions, 48 deletions
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);