solver: rewrite as deductive solver -- per name flags

Handle properly per-name preference flags, and add test cases
for testing those via fix applet.
cute-signatures
Timo Teräs 2013-06-12 08:45:29 +03:00
parent b8c44536ca
commit 426a12686e
9 changed files with 95 additions and 17 deletions

View File

@ -37,12 +37,14 @@ struct apk_solver_name_state {
}; };
struct apk_solver_package_state { struct apk_solver_package_state {
unsigned short conflicts; unsigned int conflicts;
unsigned short max_dep_chain;
unsigned solver_flags : 4;
unsigned solver_flags_inheritable : 4;
unsigned seen : 1; unsigned seen : 1;
unsigned available : 1; unsigned available : 1;
unsigned in_changeset : 1; unsigned in_changeset : 1;
unsigned iif_triggered : 1; unsigned iif_triggered : 1;
unsigned max_dep_chain : 10;
}; };
#endif #endif

View File

@ -104,15 +104,16 @@ struct apk_stats {
static void count_change(struct apk_change *change, struct apk_stats *stats) static void count_change(struct apk_change *change, struct apk_stats *stats)
{ {
if (change->new_pkg != change->old_pkg) { if (change->new_pkg != change->old_pkg || change->reinstall) {
if (change->new_pkg != NULL) { if (change->new_pkg != NULL) {
stats->bytes += change->new_pkg->installed_size; stats->bytes += change->new_pkg->installed_size;
stats->packages ++; stats->packages++;
} }
if (change->old_pkg != NULL) if (change->old_pkg != NULL)
stats->packages ++; stats->packages++;
stats->changes++; stats->changes++;
} else if (change->reinstall || change->new_repository_tag != change->old_repository_tag) { } else if (change->new_repository_tag != change->old_repository_tag) {
stats->packages++;
stats->changes++; stats->changes++;
} }
} }
@ -157,12 +158,16 @@ static void update_progress(struct progress *prog, size_t percent, int force)
static void progress_cb(void *ctx, size_t pkg_percent) static void progress_cb(void *ctx, size_t pkg_percent)
{ {
struct progress *prog = (struct progress *) ctx; struct progress *prog = (struct progress *) ctx;
size_t partial = 0, percent; size_t partial = 0, percent, total;
if (prog->pkg != NULL) if (prog->pkg != NULL)
partial = muldiv(pkg_percent, prog->pkg->installed_size, APK_PROGRESS_SCALE); partial = muldiv(pkg_percent, prog->pkg->installed_size, APK_PROGRESS_SCALE);
percent = muldiv(100, prog->done.bytes + prog->done.packages + partial, total = prog->total.bytes + prog->total.packages;
prog->total.bytes + prog->total.packages); if (total > 0)
percent = muldiv(100, prog->done.bytes + prog->done.packages + partial,
prog->total.bytes + prog->total.packages);
else
percent = 0;
update_progress(prog, percent, pkg_percent == 0); update_progress(prog, percent, pkg_percent == 0);
} }

View File

@ -34,9 +34,9 @@ struct apk_solver_state {
struct apk_changeset *changeset; struct apk_changeset *changeset;
struct list_head dirty_head; struct list_head dirty_head;
struct list_head unresolved_head; struct list_head unresolved_head;
unsigned int solver_flags;
unsigned int errors; unsigned int errors;
unsigned int num_selections, num_solution_entries; unsigned int num_selections, num_solution_entries;
unsigned int solver_flags_inherit;
}; };
static struct apk_provider provider_none = { static struct apk_provider provider_none = {
@ -48,6 +48,13 @@ void apk_solver_set_name_flags(struct apk_name *name,
unsigned short solver_flags, unsigned short solver_flags,
unsigned short solver_flags_inheritable) unsigned short solver_flags_inheritable)
{ {
int i;
for (i = 0; i < name->providers->num; i++) {
struct apk_package *pkg = name->providers->item[i].pkg;
pkg->ss.solver_flags |= solver_flags;
pkg->ss.solver_flags_inheritable |= solver_flags_inheritable;
}
} }
static void foreach_dependency(struct apk_solver_state *ss, struct apk_dependency_array *deps, static void foreach_dependency(struct apk_solver_state *ss, struct apk_dependency_array *deps,
@ -181,6 +188,7 @@ static void name_requirers_changed(struct apk_solver_state *ss, struct apk_name
static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency *dep) static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency *dep)
{ {
unsigned int solver_flags_inherit = ss->solver_flags_inherit;
struct apk_name *name = dep->name; struct apk_name *name = dep->name;
int i; int i;
@ -205,6 +213,10 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency
pkg0->ss.conflicts += !is_provided; pkg0->ss.conflicts += !is_provided;
if (unlikely(pkg0->ss.available && pkg0->ss.conflicts)) if (unlikely(pkg0->ss.available && pkg0->ss.conflicts))
disqualify_package(ss, pkg0, "conflicting dependency"); disqualify_package(ss, pkg0, "conflicting dependency");
if (is_provided) {
pkg0->ss.solver_flags |= solver_flags_inherit;
pkg0->ss.solver_flags_inheritable |= solver_flags_inherit;
}
} }
} }
@ -307,6 +319,7 @@ static int compare_providers(struct apk_solver_state *ss,
{ {
struct apk_database *db = ss->db; struct apk_database *db = ss->db;
struct apk_package *pkgA = pA->pkg, *pkgB = pB->pkg; struct apk_package *pkgA = pA->pkg, *pkgB = pB->pkg;
unsigned int solver_flags;
int r; int r;
/* Prefer existing package */ /* Prefer existing package */
@ -319,7 +332,8 @@ static int compare_providers(struct apk_solver_state *ss,
return r; return r;
/* Prefer available */ /* Prefer available */
if (ss->solver_flags & APK_SOLVERF_AVAILABLE) { solver_flags = pkgA->ss.solver_flags | pkgB->ss.solver_flags;
if (solver_flags & APK_SOLVERF_AVAILABLE) {
r = !!(pkgA->repos & db->available_repos) - r = !!(pkgA->repos & db->available_repos) -
!!(pkgB->repos & db->available_repos); !!(pkgB->repos & db->available_repos);
if (r) if (r)
@ -328,7 +342,7 @@ static int compare_providers(struct apk_solver_state *ss,
/* Prefer installed */ /* Prefer installed */
/* FIXME: check-per-name flags here too */ /* FIXME: check-per-name flags here too */
if (!(ss->solver_flags & APK_SOLVERF_UPGRADE)) { if (!(solver_flags & APK_SOLVERF_UPGRADE)) {
r = (pkgA->ipkg != NULL) - (pkgB->ipkg != NULL); r = (pkgA->ipkg != NULL) - (pkgB->ipkg != NULL);
if (r) if (r)
return r; return r;
@ -431,7 +445,9 @@ static void select_package(struct apk_solver_state *ss, struct apk_name *name)
struct apk_dependency *p = &pkg->provides->item[i]; struct apk_dependency *p = &pkg->provides->item[i];
assign_name(ss, p->name, APK_PROVIDER_FROM_PROVIDES(pkg, p)); assign_name(ss, p->name, APK_PROVIDER_FROM_PROVIDES(pkg, p));
} }
ss->solver_flags_inherit = pkg->ss.solver_flags_inheritable;
foreach_dependency(ss, pkg->depends, apply_constraint); foreach_dependency(ss, pkg->depends, apply_constraint);
ss->solver_flags_inherit = 0;
ss->num_selections++; ss->num_selections++;
} else { } else {
dbg_printf("selecting: %s [unassigned]\n", name->name); dbg_printf("selecting: %s [unassigned]\n", name->name);
@ -468,11 +484,10 @@ static void generate_change(struct apk_solver_state *ss, struct apk_name *name)
.old_repository_tag = opkg ? opkg->ipkg->repository_tag : 0, .old_repository_tag = opkg ? opkg->ipkg->repository_tag : 0,
.new_pkg = pkg, .new_pkg = pkg,
.new_repository_tag = pkg->ipkg ? pkg->ipkg->repository_tag : 0, .new_repository_tag = pkg->ipkg ? pkg->ipkg->repository_tag : 0,
.reinstall = !!(pkg->ss.solver_flags & APK_SOLVERF_REINSTALL),
#if 0 #if 0
/* FIXME: setup reinstall and repository_tag for solution */ /* FIXME: repository_tag from pinning */
.reinstall = ps->inherited_reinstall || .new_repository_tag = get_tag(db, pinning, repos),
((name->ss.solver_flags_local | ss->solver_flags) & APK_SOLVERF_REINSTALL),
.repository_tag = get_tag(db, pinning, repos),
#endif #endif
}; };
if (change->new_pkg == NULL) if (change->new_pkg == NULL)
@ -585,7 +600,6 @@ int apk_solver_solve(struct apk_database *db,
memset(ss, 0, sizeof(*ss)); memset(ss, 0, sizeof(*ss));
ss->db = db; ss->db = db;
ss->changeset = changeset; ss->changeset = changeset;
ss->solver_flags = solver_flags;
list_init(&ss->dirty_head); list_init(&ss->dirty_head);
list_init(&ss->unresolved_head); list_init(&ss->unresolved_head);
@ -594,6 +608,7 @@ int apk_solver_solve(struct apk_database *db,
/* FIXME: If filename specified, force to use it */ /* FIXME: If filename specified, force to use it */
dbg_printf("applying world\n"); dbg_printf("applying world\n");
ss->solver_flags_inherit = solver_flags;
for (i = 0; i < world->num; i++) { for (i = 0; i < world->num; i++) {
struct apk_dependency *dep = &world->item[i]; struct apk_dependency *dep = &world->item[i];
name = dep->name; name = dep->name;
@ -601,6 +616,7 @@ int apk_solver_solve(struct apk_database *db,
name->ss.preferred_pinning = BIT(dep->repository_tag); name->ss.preferred_pinning = BIT(dep->repository_tag);
apply_constraint(ss, dep); apply_constraint(ss, dep);
} }
ss->solver_flags_inherit = 0;
dbg_printf("applying world [finished]\n"); dbg_printf("applying world [finished]\n");
do { do {

9
test/fix1.test Normal file
View File

@ -0,0 +1,9 @@
@ARGS
--test-repo basic.repo
--test-instdb basic.installed
--test-world a
--upgrade
fix b
@EXPECT
(1/1) Upgrading b (1 -> 2)
OK: 0 MiB in 2 packages

9
test/fix2.test Normal file
View File

@ -0,0 +1,9 @@
@ARGS
--test-repo basic.repo
--test-instdb basic.installed
--test-world a
--upgrade
fix a
@EXPECT
(1/1) Upgrading a (1 -> 2)
OK: 0 MiB in 2 packages

11
test/fix3.test Normal file
View File

@ -0,0 +1,11 @@
@ARGS
--test-repo basic.repo
--test-instdb basic.installed
--test-world a
--upgrade
--depends
fix a
@EXPECT
(1/2) Upgrading b (1 -> 2)
(2/2) Upgrading a (1 -> 2)
OK: 0 MiB in 2 packages

8
test/fix4.test Normal file
View File

@ -0,0 +1,8 @@
@ARGS
--test-repo basic.repo
--test-instdb basic.installed
--test-world a
fix b
@EXPECT
(1/1) Re-installing b (1)
OK: 0 MiB in 2 packages

8
test/fix5.test Normal file
View File

@ -0,0 +1,8 @@
@ARGS
--test-repo basic.repo
--test-instdb basic.installed
--test-world a
fix a
@EXPECT
(1/1) Re-installing a (1)
OK: 0 MiB in 2 packages

10
test/fix6.test Normal file
View File

@ -0,0 +1,10 @@
@ARGS
--test-repo basic.repo
--test-instdb basic.installed
--test-world a
--depends
fix a
@EXPECT
(1/2) Re-installing b (1)
(2/2) Re-installing a (1)
OK: 0 MiB in 2 packages