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 {
unsigned short conflicts;
unsigned int conflicts;
unsigned short max_dep_chain;
unsigned solver_flags : 4;
unsigned solver_flags_inheritable : 4;
unsigned seen : 1;
unsigned available : 1;
unsigned in_changeset : 1;
unsigned iif_triggered : 1;
unsigned max_dep_chain : 10;
};
#endif

View File

@ -104,15 +104,16 @@ struct apk_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) {
stats->bytes += change->new_pkg->installed_size;
stats->packages ++;
stats->packages++;
}
if (change->old_pkg != NULL)
stats->packages ++;
stats->packages++;
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++;
}
}
@ -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)
{
struct progress *prog = (struct progress *) ctx;
size_t partial = 0, percent;
size_t partial = 0, percent, total;
if (prog->pkg != NULL)
partial = muldiv(pkg_percent, prog->pkg->installed_size, APK_PROGRESS_SCALE);
percent = muldiv(100, prog->done.bytes + prog->done.packages + partial,
prog->total.bytes + prog->total.packages);
total = 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);
}

View File

@ -34,9 +34,9 @@ struct apk_solver_state {
struct apk_changeset *changeset;
struct list_head dirty_head;
struct list_head unresolved_head;
unsigned int solver_flags;
unsigned int errors;
unsigned int num_selections, num_solution_entries;
unsigned int solver_flags_inherit;
};
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_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,
@ -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)
{
unsigned int solver_flags_inherit = ss->solver_flags_inherit;
struct apk_name *name = dep->name;
int i;
@ -205,6 +213,10 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency
pkg0->ss.conflicts += !is_provided;
if (unlikely(pkg0->ss.available && pkg0->ss.conflicts))
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_package *pkgA = pA->pkg, *pkgB = pB->pkg;
unsigned int solver_flags;
int r;
/* Prefer existing package */
@ -319,7 +332,8 @@ static int compare_providers(struct apk_solver_state *ss,
return r;
/* 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) -
!!(pkgB->repos & db->available_repos);
if (r)
@ -328,7 +342,7 @@ static int compare_providers(struct apk_solver_state *ss,
/* Prefer installed */
/* 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);
if (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];
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);
ss->solver_flags_inherit = 0;
ss->num_selections++;
} else {
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,
.new_pkg = pkg,
.new_repository_tag = pkg->ipkg ? pkg->ipkg->repository_tag : 0,
.reinstall = !!(pkg->ss.solver_flags & APK_SOLVERF_REINSTALL),
#if 0
/* FIXME: setup reinstall and repository_tag for solution */
.reinstall = ps->inherited_reinstall ||
((name->ss.solver_flags_local | ss->solver_flags) & APK_SOLVERF_REINSTALL),
.repository_tag = get_tag(db, pinning, repos),
/* FIXME: repository_tag from pinning */
.new_repository_tag = get_tag(db, pinning, repos),
#endif
};
if (change->new_pkg == NULL)
@ -585,7 +600,6 @@ int apk_solver_solve(struct apk_database *db,
memset(ss, 0, sizeof(*ss));
ss->db = db;
ss->changeset = changeset;
ss->solver_flags = solver_flags;
list_init(&ss->dirty_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 */
dbg_printf("applying world\n");
ss->solver_flags_inherit = solver_flags;
for (i = 0; i < world->num; i++) {
struct apk_dependency *dep = &world->item[i];
name = dep->name;
@ -601,6 +616,7 @@ int apk_solver_solve(struct apk_database *db,
name->ss.preferred_pinning = BIT(dep->repository_tag);
apply_constraint(ss, dep);
}
ss->solver_flags_inherit = 0;
dbg_printf("applying world [finished]\n");
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