solver: make state pointers completely internal

the only bit of information needed in solver commit is the "hard"
topology sorting information for trigger ordering. fixes a bug in
"apk del" which uses the state pointers to do intermediate
calculations between solution solving and commit.
cute-signatures
Timo Teräs 2011-09-14 16:48:28 +03:00
parent 6b1a55825a
commit 803f55ece5
5 changed files with 32 additions and 41 deletions

View File

@ -94,6 +94,7 @@ struct apk_package {
size_t installed_size, size; size_t installed_size, size;
time_t build_time; time_t build_time;
unsigned repos; unsigned repos;
unsigned int topology_hard;
struct apk_checksum csum; struct apk_checksum csum;
}; };
APK_ARRAY(apk_package_array, struct apk_package *); APK_ARRAY(apk_package_array, struct apk_package *);

View File

@ -25,7 +25,6 @@ struct apk_changeset {
#define APK_SOLVERF_UPGRADE 0x0001 #define APK_SOLVERF_UPGRADE 0x0001
#define APK_SOLVERF_AVAILABLE 0x0002 #define APK_SOLVERF_AVAILABLE 0x0002
#define APK_SOLVERF_REINSTALL 0x0004 #define APK_SOLVERF_REINSTALL 0x0004
#define APK_SOLVERF_KEEP_STATE 0x8000
void apk_solver_set_name_flags(struct apk_name *name, void apk_solver_set_name_flags(struct apk_name *name,
unsigned short solver_flags); unsigned short solver_flags);
@ -34,7 +33,6 @@ int apk_solver_solve(struct apk_database *db,
struct apk_dependency_array *world, struct apk_dependency_array *world,
struct apk_package_array **solution, struct apk_package_array **solution,
struct apk_changeset *changeset); struct apk_changeset *changeset);
void apk_solver_free(struct apk_database *db);
int apk_solver_commit_changeset(struct apk_database *db, int apk_solver_commit_changeset(struct apk_database *db,
struct apk_changeset *changeset, struct apk_changeset *changeset,
struct apk_dependency_array *world); struct apk_dependency_array *world);

View File

@ -142,8 +142,7 @@ static int del_main(void *pctx, struct apk_database *db, int argc, char **argv)
delete_from_world, ctx); delete_from_world, ctx);
} }
r = apk_solver_solve(db, APK_SOLVERF_KEEP_STATE, r = apk_solver_solve(db, 0, ctx->world, &solution, &changeset);
ctx->world, &solution, &changeset);
if (r == 0 || (apk_flags & APK_FORCE)) { if (r == 0 || (apk_flags & APK_FORCE)) {
/* check for non-deleted package names */ /* check for non-deleted package names */
for (i = 0; i < solution->num; i++) { for (i = 0; i < solution->num; i++) {
@ -167,7 +166,6 @@ static int del_main(void *pctx, struct apk_database *db, int argc, char **argv)
} else { } else {
apk_solver_print_errors(db, solution, ctx->world, r); apk_solver_print_errors(db, solution, ctx->world, r);
} }
apk_solver_free(db);
apk_package_array_free(&solution); apk_package_array_free(&solution);
apk_dependency_array_free(&ctx->world); apk_dependency_array_free(&ctx->world);

View File

@ -33,7 +33,7 @@
struct apk_package_state { struct apk_package_state {
struct apk_package *backtrack; struct apk_package *backtrack;
unsigned int topology_hard, topology_soft; unsigned int topology_soft;
unsigned short flags; unsigned short flags;
unsigned short conflicts; unsigned short conflicts;
unsigned short cur_unsatisfiable; unsigned short cur_unsatisfiable;
@ -158,17 +158,17 @@ static void sort_hard_dependencies(struct apk_solver_state *ss, struct apk_packa
pkg->state_ptr = calloc(1, sizeof(struct apk_package_state)); pkg->state_ptr = calloc(1, sizeof(struct apk_package_state));
ps = pkg_to_ps(pkg); ps = pkg_to_ps(pkg);
if (ps->topology_hard) if (pkg->topology_hard)
return; return;
ps->topology_hard = -1; pkg->topology_hard = -1;
/* Consider hard dependencies only */ /* Consider hard dependencies only */
foreach_dependency_pkg(ss, pkg->depends, sort_hard_dependencies); foreach_dependency_pkg(ss, pkg->depends, sort_hard_dependencies);
foreach_dependency_pkg(ss, pkg->install_if, sort_hard_dependencies); foreach_dependency_pkg(ss, pkg->install_if, sort_hard_dependencies);
ps->topology_soft = ps->topology_hard = ++ss->num_topology_positions; ps->topology_soft = pkg->topology_hard = ++ss->num_topology_positions;
dbg_printf(PKG_VER_FMT ": topology_hard=%d\n", dbg_printf(PKG_VER_FMT ": topology_hard=%d\n",
PKG_VER_PRINTF(pkg), ps->topology_hard); PKG_VER_PRINTF(pkg), pkg->topology_hard);
} }
static void sort_soft_dependencies(struct apk_solver_state *ss, struct apk_package *pkg) static void sort_soft_dependencies(struct apk_solver_state *ss, struct apk_package *pkg)
@ -178,7 +178,7 @@ static void sort_soft_dependencies(struct apk_solver_state *ss, struct apk_packa
sort_hard_dependencies(ss, pkg); sort_hard_dependencies(ss, pkg);
ps = pkg_to_ps(pkg); ps = pkg_to_ps(pkg);
if (ps->topology_soft != ps->topology_hard) if (ps->topology_soft != pkg->topology_hard)
return; return;
ps->topology_soft = -1; ps->topology_soft = -1;
@ -246,7 +246,7 @@ static int get_pkg_expansion_flags(struct apk_solver_state *ss, struct apk_packa
struct apk_package_state *ps0 = pkg_to_ps(pkg0); struct apk_package_state *ps0 = pkg_to_ps(pkg0);
if (pkg0 == pkg || ps0 == NULL || if (pkg0 == pkg || ps0 == NULL ||
ps0->topology_hard > ss->topology_position || pkg0->topology_hard > ss->topology_position ||
(ps0->flags & APK_PKGSTF_DECIDED) || (ps0->flags & APK_PKGSTF_DECIDED) ||
ps0->conflicts != 0) ps0->conflicts != 0)
continue; continue;
@ -318,7 +318,7 @@ static int update_name_state(struct apk_solver_state *ss,
struct apk_package_state *ps0 = pkg_to_ps(pkg0); struct apk_package_state *ps0 = pkg_to_ps(pkg0);
if (ps0 == NULL || if (ps0 == NULL ||
ps0->topology_hard >= ss->topology_position || pkg0->topology_hard >= ss->topology_position ||
(ps0->flags & APK_PKGSTF_DECIDED)) (ps0->flags & APK_PKGSTF_DECIDED))
continue; continue;
@ -332,8 +332,8 @@ static int update_name_state(struct apk_solver_state *ss,
if (ps0->topology_soft < ss->topology_position && if (ps0->topology_soft < ss->topology_position &&
ps0->topology_soft > best_topology) ps0->topology_soft > best_topology)
best_pkg = pkg0, best_topology = ps0->topology_soft; best_pkg = pkg0, best_topology = ps0->topology_soft;
else if (ps0->topology_hard > best_topology) else if (pkg0->topology_hard > best_topology)
best_pkg = pkg0, best_topology = ps0->topology_hard; best_pkg = pkg0, best_topology = pkg0->topology_hard;
} }
if (options == 0 && skipped_options == 0) { if (options == 0 && skipped_options == 0) {
@ -434,7 +434,7 @@ static void undo_decision(struct apk_solver_state *ss,
if (ps->flags & APK_PKGSTF_INSTALLIF) if (ps->flags & APK_PKGSTF_INSTALLIF)
ss->topology_position = ps->topology_soft; ss->topology_position = ps->topology_soft;
else else
ss->topology_position = ps->topology_hard; ss->topology_position = pkg->topology_hard;
if (ps->flags & APK_PKGSTF_INSTALL) { if (ps->flags & APK_PKGSTF_INSTALL) {
ss->assigned_names--; ss->assigned_names--;
@ -465,7 +465,7 @@ static void push_decision(struct apk_solver_state *ss, struct apk_package *pkg,
ss->topology_position = ps->topology_soft; ss->topology_position = ps->topology_soft;
} else { } else {
ps->flags &= ~APK_PKGSTF_INSTALLIF; ps->flags &= ~APK_PKGSTF_INSTALLIF;
ss->topology_position = ps->topology_hard; ss->topology_position = pkg->topology_hard;
} }
ss->latest_decision = pkg; ss->latest_decision = pkg;
@ -534,7 +534,7 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency
struct apk_package_state *ps0 = pkg_to_ps(pkg0); struct apk_package_state *ps0 = pkg_to_ps(pkg0);
if (ps0 == NULL || if (ps0 == NULL ||
ps0->topology_hard >= ss->topology_position) pkg0->topology_hard >= ss->topology_position)
continue; continue;
if (!apk_dep_is_satisfied(dep, pkg0)) { if (!apk_dep_is_satisfied(dep, pkg0)) {
@ -565,7 +565,7 @@ static void undo_constraint(struct apk_solver_state *ss, struct apk_dependency *
struct apk_package *pkg0 = name->pkgs->item[i]; struct apk_package *pkg0 = name->pkgs->item[i];
struct apk_package_state *ps0 = pkg_to_ps(pkg0); struct apk_package_state *ps0 = pkg_to_ps(pkg0);
if (ps0->topology_hard >= ss->topology_position) if (pkg0->topology_hard >= ss->topology_position)
continue; continue;
if (!apk_dep_is_satisfied(dep, pkg0)) { if (!apk_dep_is_satisfied(dep, pkg0)) {
@ -597,8 +597,8 @@ static int expand_branch(struct apk_solver_state *ss)
if (pkg_to_ps(ns->chosen)->topology_soft < ss->topology_position && if (pkg_to_ps(ns->chosen)->topology_soft < ss->topology_position &&
pkg_to_ps(ns->chosen)->topology_soft > topology0) pkg_to_ps(ns->chosen)->topology_soft > topology0)
pkg0 = ns->chosen, topology0 = pkg_to_ps(pkg0)->topology_soft; pkg0 = ns->chosen, topology0 = pkg_to_ps(pkg0)->topology_soft;
else if (pkg_to_ps(ns->chosen)->topology_hard > topology0) else if (ns->chosen->topology_hard > topology0)
pkg0 = ns->chosen, topology0 = pkg_to_ps(pkg0)->topology_hard; pkg0 = ns->chosen, topology0 = pkg0->topology_hard;
} }
if (pkg0 == NULL) { if (pkg0 == NULL) {
dbg_printf("expand_branch: list is empty (%d unsatisfied)\n", dbg_printf("expand_branch: list is empty (%d unsatisfied)\n",
@ -660,8 +660,8 @@ static int compare_change(const void *p1, const void *p2)
if (c1->newpkg == NULL) { if (c1->newpkg == NULL) {
if (c2->newpkg == NULL) if (c2->newpkg == NULL)
/* both deleted - reverse topology order */ /* both deleted - reverse topology order */
return pkg_to_ps(c2->oldpkg)->topology_hard - return c2->oldpkg->topology_hard -
pkg_to_ps(c1->oldpkg)->topology_hard; c1->oldpkg->topology_hard;
/* c1 deleted, c2 installed -> c2 first*/ /* c1 deleted, c2 installed -> c2 first*/
return -1; return -1;
@ -670,8 +670,8 @@ static int compare_change(const void *p1, const void *p2)
/* c1 installed, c2 deleted -> c1 first*/ /* c1 installed, c2 deleted -> c1 first*/
return 1; return 1;
return pkg_to_ps(c1->newpkg)->topology_hard - return c1->newpkg->topology_hard -
pkg_to_ps(c2->newpkg)->topology_hard; c2->newpkg->topology_hard;
} }
static int generate_changeset(struct apk_database *db, static int generate_changeset(struct apk_database *db,
@ -763,6 +763,12 @@ void apk_solver_set_name_flags(struct apk_name *name,
ns->solver_flags = solver_flags; ns->solver_flags = solver_flags;
} }
static void apk_solver_free(struct apk_database *db)
{
apk_hash_foreach(&db->available.names, free_state, NULL);
apk_hash_foreach(&db->available.packages, free_package, NULL);
}
int apk_solver_solve(struct apk_database *db, int apk_solver_solve(struct apk_database *db,
unsigned short solver_flags, unsigned short solver_flags,
struct apk_dependency_array *world, struct apk_dependency_array *world,
@ -826,20 +832,12 @@ int apk_solver_solve(struct apk_database *db,
else else
apk_package_array_free(&ss->best_solution); apk_package_array_free(&ss->best_solution);
if (!(solver_flags & APK_SOLVERF_KEEP_STATE)) apk_solver_free(db);
apk_solver_free(db);
free(ss); free(ss);
return r; return r;
} }
void apk_solver_free(struct apk_database *db)
{
apk_hash_foreach(&db->available.names, free_state, NULL);
apk_hash_foreach(&db->available.packages, free_package, NULL);
}
static void print_change(struct apk_database *db, static void print_change(struct apk_database *db,
struct apk_change *change, struct apk_change *change,
int cur, int total) int cur, int total)
@ -1013,7 +1011,7 @@ static int compare_package(const void *p1, const void *p2)
struct apk_package *pkg1 = *(struct apk_package **) p1; struct apk_package *pkg1 = *(struct apk_package **) p1;
struct apk_package *pkg2 = *(struct apk_package **) p2; struct apk_package *pkg2 = *(struct apk_package **) p2;
return pkg_to_ps(pkg1)->topology_hard - pkg_to_ps(pkg2)->topology_hard; return pkg1->topology_hard - pkg2->topology_hard;
} }
static void run_triggers(struct apk_database *db) static void run_triggers(struct apk_database *db)
@ -1186,7 +1184,7 @@ int apk_solver_commit(struct apk_database *db,
struct apk_package_array *solution = NULL; struct apk_package_array *solution = NULL;
int r; int r;
r = apk_solver_solve(db, APK_SOLVERF_KEEP_STATE | solver_flags, r = apk_solver_solve(db, solver_flags,
world, &solution, &changeset); world, &solution, &changeset);
if (r < 0) if (r < 0)
return r; return r;
@ -1200,7 +1198,6 @@ int apk_solver_commit(struct apk_database *db,
apk_solver_print_errors(db, solution, world, r); apk_solver_print_errors(db, solution, world, r);
} }
apk_package_array_free(&solution); apk_package_array_free(&solution);
apk_solver_free(db);
return r; return r;
} }

View File

@ -52,8 +52,7 @@ int apk_do_self_upgrade(struct apk_database *db, unsigned short solver_flags)
apk_solver_set_name_flags(name, solver_flags); apk_solver_set_name_flags(name, solver_flags);
db->performing_self_update = 1; db->performing_self_update = 1;
r = apk_solver_solve(db, APK_SOLVERF_KEEP_STATE, r = apk_solver_solve(db, 0, db->world, &solution, &changeset);
db->world, &solution, &changeset);
if (r != 0) { if (r != 0) {
if (apk_flags & APK_FORCE) if (apk_flags & APK_FORCE)
r = 0; r = 0;
@ -72,7 +71,6 @@ int apk_do_self_upgrade(struct apk_database *db, unsigned short solver_flags)
apk_message("Upgrading critical system libraries and apk-tools:"); apk_message("Upgrading critical system libraries and apk-tools:");
apk_solver_commit_changeset(db, &changeset, db->world); apk_solver_commit_changeset(db, &changeset, db->world);
apk_solver_free(db);
apk_db_close(db); apk_db_close(db);
apk_message("Continuing the upgrade transaction with new apk-tools:"); apk_message("Continuing the upgrade transaction with new apk-tools:");
@ -85,7 +83,6 @@ int apk_do_self_upgrade(struct apk_database *db, unsigned short solver_flags)
exit(1); exit(1);
ret: ret:
apk_solver_free(db);
apk_package_array_free(&solution); apk_package_array_free(&solution);
apk_change_array_free(&changeset.changes); apk_change_array_free(&changeset.changes);
db->performing_self_update = 0; db->performing_self_update = 0;