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
parent
6b1a55825a
commit
803f55ece5
|
@ -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 *);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
61
src/solver.c
61
src/solver.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue