solver: record repository tag, and flags in solution

name state could get overwritten later, so we can't use that when
generating the changeset.
cute-signatures
Timo Teräs 2012-02-16 10:50:52 +02:00
parent 7399f1950f
commit 0800d7e050
5 changed files with 116 additions and 71 deletions

View File

@ -12,10 +12,18 @@
#ifndef APK_SOLVER_H
#define APK_SOLVER_H
struct apk_solution_entry {
struct apk_package *pkg;
unsigned short repository_tag : 15;
unsigned reinstall : 1;
};
APK_ARRAY(apk_solution_array, struct apk_solution_entry);
struct apk_change {
struct apk_package *oldpkg;
struct apk_package *newpkg;
unsigned short repository_tag;
unsigned short repository_tag : 15;
unsigned reinstall : 1;
};
APK_ARRAY(apk_change_array, struct apk_change);
@ -33,13 +41,13 @@ void apk_solver_set_name_flags(struct apk_name *name,
int apk_solver_solve(struct apk_database *db,
unsigned short solver_flags,
struct apk_dependency_array *world,
struct apk_package_array **solution,
struct apk_solution_array **solution,
struct apk_changeset *changeset);
int apk_solver_commit_changeset(struct apk_database *db,
struct apk_changeset *changeset,
struct apk_dependency_array *world);
void apk_solver_print_errors(struct apk_database *db,
struct apk_package_array *solution,
struct apk_solution_array *solution,
struct apk_dependency_array *world,
int unsatisfiable);
int apk_solver_commit(struct apk_database *db,

View File

@ -125,7 +125,7 @@ static int del_main(void *pctx, struct apk_database *db, int argc, char **argv)
struct del_ctx *ctx = (struct del_ctx *) pctx;
struct apk_name **name;
struct apk_changeset changeset = {};
struct apk_package_array *solution = NULL;
struct apk_solution_array *solution = NULL;
struct not_deleted_ctx ndctx = {};
int i, r = 0;
@ -145,7 +145,7 @@ static int del_main(void *pctx, struct apk_database *db, int argc, char **argv)
if (r == 0 || (apk_flags & APK_FORCE)) {
/* check for non-deleted package names */
for (i = 0; i < solution->num; i++) {
struct apk_package *pkg = solution->item[i];
struct apk_package *pkg = solution->item[i].pkg;
pkg->name->state_ptr = pkg;
pkg->state_int = 0;
}
@ -165,7 +165,7 @@ static int del_main(void *pctx, struct apk_database *db, int argc, char **argv)
} else {
apk_solver_print_errors(db, solution, ctx->world, r);
}
apk_package_array_free(&solution);
apk_solution_array_free(&solution);
apk_dependency_array_free(&ctx->world);
return r;

View File

@ -76,7 +76,7 @@ struct apk_solver_state {
unsigned int solver_flags : 4;
unsigned int refresh_name_states : 1;
struct apk_package_array *best_solution;
struct apk_solution_array *best_solution;
struct apk_score best_score;
};
@ -337,6 +337,7 @@ static unsigned int get_pinning_mask_repos(struct apk_database *db, unsigned sho
static int compare_package_preference(unsigned short solver_flags,
unsigned int preferred_repos,
unsigned int allowed_repos,
struct apk_package *pkgA,
struct apk_package *pkgB,
struct apk_database *db)
@ -357,6 +358,12 @@ static int compare_package_preference(unsigned short solver_flags,
if ((b_repos & preferred_repos) && !(a_repos & preferred_repos))
return -1;
/* Difference in allowed repositories? */
if ((a_repos & allowed_repos) && !(b_repos & allowed_repos))
return 1;
if ((b_repos & allowed_repos) && !(a_repos & allowed_repos))
return -1;
if (solver_flags & APK_SOLVERF_AVAILABLE) {
if (pkgA->repos != 0 && pkgB->repos == 0)
return 1;
@ -400,13 +407,18 @@ 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 short preferred_pinning;
unsigned int preferred_repos;
unsigned short preferred_pinning, allowed_pinning;
unsigned int preferred_repos, allowed_repos;
unsigned short preference = 0;
int i;
int i, r;
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;
for (i = 0; i < name->pkgs->num; i++) {
struct apk_package *pkg0 = name->pkgs->item[i];
@ -415,15 +427,17 @@ 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, ss->db) < 0) {
if (installable_only) {
if (ss->topology_position > pkg0->topology_hard &&
!(ps0->flags & APK_PKGSTF_DECIDED))
preference++;
} else
preference++;
}
if (installable_only &&
(ss->topology_position <= pkg0->topology_hard ||
(ps0->flags & APK_PKGSTF_DECIDED)))
continue;
r = compare_package_preference(name_flags,
preferred_repos,
allowed_repos,
pkg, pkg0, ss->db);
if (r < 0)
preference += -r;
}
return preference;
@ -487,7 +501,9 @@ 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,
compare_package_preference(name_flags,
preferred_repos,
allowed_repos,
pkg0, preferred_pkg, ss->db) > 0)) {
preferred_pkg = pkg0;
preferred_ps = ps0;
@ -896,22 +912,50 @@ static int expand_branch(struct apk_solver_state *ss)
return 0;
}
static void record_solution(struct apk_solver_state *ss)
static int get_tag(struct apk_database *db, unsigned short pinning_mask, unsigned int repos)
{
struct apk_package *pkg;
struct apk_package_state *ps;
int i;
apk_package_array_resize(&ss->best_solution, ss->assigned_names);
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 void record_solution(struct apk_solver_state *ss)
{
struct apk_database *db = ss->db;
struct apk_package *pkg;
struct apk_package_state *ps;
struct apk_name_state *ns;
int i;
apk_solution_array_resize(&ss->best_solution, ss->assigned_names);
i = 0;
pkg = ss->latest_decision;
while (pkg != NULL) {
ps = pkg_to_ps(pkg);
ns = name_to_ns(pkg->name);
if (ps->flags & APK_PKGSTF_INSTALL) {
unsigned short pinning;
unsigned int repos;
if (i >= ss->assigned_names)
abort();
ss->best_solution->item[i++] = pkg;
pinning = ns->allowed_pinning | ns->preferred_pinning | APK_DEFAULT_PINNING_MASK;
repos = pkg->repos | (pkg->ipkg ? db->repo_tags[pkg->ipkg->repository_tag].allowed_repos : 0);
ss->best_solution->item[i++] = (struct apk_solution_entry){
.pkg = pkg,
.reinstall = !!((ns->solver_flags_local | ns->solver_flags_inherited |
ss->solver_flags) & APK_SOLVERF_REINSTALL),
.repository_tag = get_tag(db, pinning, repos),
};
}
dbg_printf("record_solution: " PKG_VER_FMT ": %sINSTALL\n",
@ -920,16 +964,16 @@ static void record_solution(struct apk_solver_state *ss)
pkg = ps->backtrack;
}
apk_package_array_resize(&ss->best_solution, i);
apk_solution_array_resize(&ss->best_solution, i);
ss->best_score = ss->score;
}
static int compare_package_name(const void *p1, const void *p2)
static int compare_solution_entry(const void *p1, const void *p2)
{
const struct apk_package **c1 = (const struct apk_package **) p1;
const struct apk_package **c2 = (const struct apk_package **) p2;
const struct apk_solution_entry *c1 = (const struct apk_solution_entry *) p1;
const struct apk_solution_entry *c2 = (const struct apk_solution_entry *) p2;
return strcmp((*c1)->name->name, (*c2)->name->name);
return strcmp(c1->pkg->name->name, c2->pkg->name->name);
}
static int compare_change(const void *p1, const void *p2)
@ -955,21 +999,8 @@ 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_solution_array *solution,
struct apk_changeset *changeset,
unsigned short solver_flags)
{
@ -981,13 +1012,13 @@ static int generate_changeset(struct apk_database *db,
/* calculate change set size */
for (i = 0; i < solution->num; i++) {
pkg = solution->item[i];
pkg = solution->item[i].pkg;
ns = name_to_ns(pkg->name);
ns->chosen = pkg;
ns->in_changeset = 1;
if ((pkg->ipkg == NULL) ||
((ns->solver_flags_local | ns->solver_flags_inherited |
solver_flags) & APK_SOLVERF_REINSTALL))
solution->item[i].reinstall ||
solution->item[i].repository_tag != pkg->ipkg->repository_tag)
num_installs++;
}
list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) {
@ -1008,13 +1039,13 @@ static int generate_changeset(struct apk_database *db,
}
}
for (i = 0; i < solution->num; i++) {
pkg = solution->item[i];
pkg = solution->item[i].pkg;
name = pkg->name;
ns = name_to_ns(name);
if ((pkg->ipkg == NULL) ||
((ns->solver_flags_local | ns->solver_flags_inherited |
solver_flags) & APK_SOLVERF_REINSTALL)) {
solution->item[i].reinstall ||
solution->item[i].repository_tag != pkg->ipkg->repository_tag){
for (j = 0; j < name->pkgs->num; j++) {
pkg0 = name->pkgs->item[j];
if (pkg0->ipkg == NULL)
@ -1023,7 +1054,8 @@ 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);
changeset->changes->item[ci].repository_tag = solution->item[i].repository_tag;
changeset->changes->item[ci].reinstall = solution->item[i].reinstall;
ci++;
}
}
@ -1075,7 +1107,7 @@ static void apk_solver_free(struct apk_database *db)
int apk_solver_solve(struct apk_database *db,
unsigned short solver_flags,
struct apk_dependency_array *world,
struct apk_package_array **solution,
struct apk_solution_array **solution,
struct apk_changeset *changeset)
{
struct apk_solver_state *ss;
@ -1134,10 +1166,10 @@ int apk_solver_solve(struct apk_database *db,
}
if (solution != NULL) {
qsort(ss->best_solution->item, ss->best_solution->num,
sizeof(struct apk_package *), compare_package_name);
sizeof(struct apk_solution_entry), compare_solution_entry);
*solution = ss->best_solution;
} else {
apk_package_array_free(&ss->best_solution);
apk_solution_array_free(&ss->best_solution);
}
r = ss->best_score.unsatisfiable;
apk_solver_free(db);
@ -1179,6 +1211,10 @@ static void print_change(struct apk_database *db,
apk_message("%s Purging %s (" BLOB_FMT ")",
status, nameptr,
BLOB_PRINTF(*oldpkg->version));
} else if (newpkg == oldpkg && !change->reinstall) {
apk_message("%s Updating pinning %s (" BLOB_FMT ")",
status, nameptr,
BLOB_PRINTF(*oldpkg->version));
} else {
r = apk_pkg_version_compare(newpkg, oldpkg);
switch (r) {
@ -1415,10 +1451,11 @@ int apk_solver_commit_changeset(struct apk_database *db,
prog.pkg = change->newpkg;
if (!(apk_flags & APK_SIMULATE)) {
r = apk_db_install_pkg(db,
change->oldpkg, change->newpkg,
(apk_flags & APK_PROGRESS) ? progress_cb : NULL,
&prog);
if (change->oldpkg != change->newpkg || change->reinstall)
r = apk_db_install_pkg(db,
change->oldpkg, change->newpkg,
(apk_flags & APK_PROGRESS) ? progress_cb : NULL,
&prog);
if (r != 0)
break;
if (change->newpkg)
@ -1482,7 +1519,7 @@ static void print_dep_errors(struct apk_database *db, char *label, struct apk_de
}
void apk_solver_print_errors(struct apk_database *db,
struct apk_package_array *solution,
struct apk_solution_array *solution,
struct apk_dependency_array *world,
int unsatisfiable)
{
@ -1491,15 +1528,15 @@ void apk_solver_print_errors(struct apk_database *db,
apk_error("%d unsatisfiable dependencies:", unsatisfiable);
for (i = 0; i < solution->num; i++) {
struct apk_package *pkg = solution->item[i];
struct apk_package *pkg = solution->item[i].pkg;
pkg->name->state_ptr = pkg;
}
print_dep_errors(db, "world", world);
for (i = 0; i < solution->num; i++) {
struct apk_package *pkg = solution->item[i];
struct apk_package *pkg = solution->item[i].pkg;
char pkgtext[256];
snprintf(pkgtext, sizeof(pkgtext), PKG_VER_FMT, PKG_VER_PRINTF(solution->item[i]));
snprintf(pkgtext, sizeof(pkgtext), PKG_VER_FMT, PKG_VER_PRINTF(pkg));
print_dep_errors(db, pkgtext, pkg->depends);
}
}
@ -1509,7 +1546,7 @@ int apk_solver_commit(struct apk_database *db,
struct apk_dependency_array *world)
{
struct apk_changeset changeset = {};
struct apk_package_array *solution = NULL;
struct apk_solution_array *solution = NULL;
int r;
if (apk_db_check_world(db, world) != 0) {
@ -1529,7 +1566,7 @@ int apk_solver_commit(struct apk_database *db,
/* Failure -- print errors */
apk_solver_print_errors(db, solution, world, r);
}
apk_package_array_free(&solution);
apk_solution_array_free(&solution);
return r;
}

View File

@ -119,7 +119,7 @@ static void print_dep_errors(struct apk_database *db, char *label, struct apk_de
}
static void print_errors_in_solution(struct apk_database *db, int unsatisfiable,
struct apk_package_array *solution)
struct apk_solution_array *solution)
{
int i;
@ -127,15 +127,15 @@ static void print_errors_in_solution(struct apk_database *db, int unsatisfiable,
unsatisfiable, solution->num);
for (i = 0; i < solution->num; i++) {
struct apk_package *pkg = solution->item[i];
struct apk_package *pkg = solution->item[i].pkg;
pkg->name->state_ptr = pkg;
}
print_dep_errors(db, "world", db->world);
for (i = 0; i < solution->num; i++) {
struct apk_package *pkg = solution->item[i];
struct apk_package *pkg = solution->item[i].pkg;
char pkgtext[256];
snprintf(pkgtext, sizeof(pkgtext), PKG_VER_FMT, PKG_VER_PRINTF(solution->item[i]));
snprintf(pkgtext, sizeof(pkgtext), PKG_VER_FMT, PKG_VER_PRINTF(pkg));
print_dep_errors(db, pkgtext, pkg->depends);
}
@ -145,7 +145,7 @@ static int test_main(void *pctx, struct apk_database *db, int argc, char **argv)
{
struct test_ctx *ctx = (struct test_ctx *) pctx;
struct apk_bstream *bs;
struct apk_package_array *solution = NULL;
struct apk_solution_array *solution = NULL;
struct apk_changeset changeset = {};
apk_blob_t b;
int i, r;

View File

@ -45,7 +45,7 @@ int apk_do_self_upgrade(struct apk_database *db, unsigned short solver_flags)
{
struct apk_name *name;
struct apk_changeset changeset = {};
struct apk_package_array *solution = NULL;
struct apk_solution_array *solution = NULL;
int r;
name = apk_db_get_name(db, APK_BLOB_STR("apk-tools"));
@ -83,7 +83,7 @@ int apk_do_self_upgrade(struct apk_database *db, unsigned short solver_flags)
exit(1);
ret:
apk_package_array_free(&solution);
apk_solution_array_free(&solution);
apk_change_array_free(&changeset.changes);
db->performing_self_update = 0;