Gitlab has been upgraded to v13.9 🎉. Enjoy

Commit 41fb3a4f authored by Timo Teräs's avatar Timo Teräs

solver, db: repository pinning improvements

* solver internally calculates now using tags; not repository masks
* installeddb now contains the tag name where the package came from
  -> we can now handle upgrades properly
* the pinning is still a preference, and not strictly enforced;
  versioned dependencies may overrule preference
parent 29064d88
...@@ -120,7 +120,7 @@ static int add_main(void *ctx, struct apk_database *db, int argc, char **argv) ...@@ -120,7 +120,7 @@ static int add_main(void *ctx, struct apk_database *db, int argc, char **argv)
if (virtpkg == NULL) { if (virtpkg == NULL) {
apk_deps_add(&world, &dep); apk_deps_add(&world, &dep);
apk_solver_set_name_flags(dep.name, apk_solver_set_name_flags(dep.name,
actx->solver_flags | APK_SOLVERF_PREFER_TAG, actx->solver_flags,
actx->solver_flags); actx->solver_flags);
} else { } else {
apk_deps_add(&virtpkg->depends, &dep); apk_deps_add(&virtpkg->depends, &dep);
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#endif #endif
#define APK_MAX_REPOS 32 #define APK_MAX_REPOS 32
#define APK_MAX_TAGS 16
#define APK_CACHE_CSUM_BYTES 4 #define APK_CACHE_CSUM_BYTES 4
extern const char * const apk_index_gz; extern const char * const apk_index_gz;
...@@ -121,6 +122,9 @@ struct apk_db_options { ...@@ -121,6 +122,9 @@ struct apk_db_options {
struct list_head repository_list; struct list_head repository_list;
}; };
#define APK_DEFAULT_REPOSITORY_TAG 0
#define APK_DEFAULT_PINNING_MASK BIT(APK_DEFAULT_REPOSITORY_TAG)
struct apk_repository_tag { struct apk_repository_tag {
unsigned int allowed_repos; unsigned int allowed_repos;
apk_blob_t *name; apk_blob_t *name;
...@@ -143,7 +147,7 @@ struct apk_database { ...@@ -143,7 +147,7 @@ struct apk_database {
struct apk_dependency_array *world; struct apk_dependency_array *world;
struct apk_string_array *protected_paths; struct apk_string_array *protected_paths;
struct apk_repository repos[APK_MAX_REPOS]; struct apk_repository repos[APK_MAX_REPOS];
struct apk_repository_tag repo_tags[APK_MAX_REPOS]; struct apk_repository_tag repo_tags[APK_MAX_TAGS];
struct apk_id_cache id_cache; struct apk_id_cache id_cache;
struct { struct {
...@@ -173,7 +177,7 @@ typedef union apk_database_or_void { ...@@ -173,7 +177,7 @@ typedef union apk_database_or_void {
struct apk_name *apk_db_get_name(struct apk_database *db, apk_blob_t name); struct apk_name *apk_db_get_name(struct apk_database *db, apk_blob_t name);
struct apk_name *apk_db_query_name(struct apk_database *db, apk_blob_t name); struct apk_name *apk_db_query_name(struct apk_database *db, apk_blob_t name);
int apk_db_get_tag_id(struct apk_database *db, apk_blob_t tag); int apk_db_get_tag_id(struct apk_database *db, apk_blob_t tag);
int apk_db_get_tag_id_by_repos(struct apk_database *db, unsigned int repos);
struct apk_db_dir *apk_db_dir_query(struct apk_database *db, struct apk_db_dir *apk_db_dir_query(struct apk_database *db,
apk_blob_t name); apk_blob_t name);
struct apk_db_file *apk_db_file_query(struct apk_database *db, struct apk_db_file *apk_db_file_query(struct apk_database *db,
......
...@@ -68,6 +68,7 @@ APK_ARRAY(apk_dependency_array, struct apk_dependency); ...@@ -68,6 +68,7 @@ APK_ARRAY(apk_dependency_array, struct apk_dependency);
struct apk_installed_package { struct apk_installed_package {
struct apk_package *pkg; struct apk_package *pkg;
unsigned int run_all_triggers : 1; unsigned int run_all_triggers : 1;
unsigned int repository_tag : 6;
unsigned short replaces_priority; unsigned short replaces_priority;
struct list_head installed_pkgs_list; struct list_head installed_pkgs_list;
struct list_head trigger_pkgs_list; struct list_head trigger_pkgs_list;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
struct apk_change { struct apk_change {
struct apk_package *oldpkg; struct apk_package *oldpkg;
struct apk_package *newpkg; struct apk_package *newpkg;
unsigned short repository_tag;
}; };
APK_ARRAY(apk_change_array, struct apk_change); APK_ARRAY(apk_change_array, struct apk_change);
...@@ -25,7 +26,6 @@ struct apk_changeset { ...@@ -25,7 +26,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_PREFER_TAG 0x0008
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,
......
...@@ -754,6 +754,9 @@ int apk_db_index_read(struct apk_database *db, struct apk_bstream *bs, int repo) ...@@ -754,6 +754,9 @@ int apk_db_index_read(struct apk_database *db, struct apk_bstream *bs, int repo)
case 'q': case 'q':
ipkg->replaces_priority = apk_blob_pull_uint(&l, 10); ipkg->replaces_priority = apk_blob_pull_uint(&l, 10);
break; break;
case 'p':
ipkg->repository_tag = apk_db_get_tag_id(db, l);
break;
default: default:
if (r != 0 && !(apk_flags & APK_FORCE)) { if (r != 0 && !(apk_flags & APK_FORCE)) {
/* Installed db should not have unsupported fields */ /* Installed db should not have unsupported fields */
...@@ -800,7 +803,11 @@ static int apk_db_write_fdb(struct apk_database *db, struct apk_ostream *os) ...@@ -800,7 +803,11 @@ static int apk_db_write_fdb(struct apk_database *db, struct apk_ostream *os)
apk_blob_push_uint(&bbuf, ipkg->replaces_priority, 10); apk_blob_push_uint(&bbuf, ipkg->replaces_priority, 10);
apk_blob_push_blob(&bbuf, APK_BLOB_STR("\n")); apk_blob_push_blob(&bbuf, APK_BLOB_STR("\n"));
} }
if (ipkg->repository_tag) {
apk_blob_push_blob(&bbuf, APK_BLOB_STR("p:"));
apk_blob_push_blob(&bbuf, *db->repo_tags[ipkg->repository_tag].name);
apk_blob_push_blob(&bbuf, APK_BLOB_STR("\n"));
}
hlist_for_each_entry(diri, c1, &ipkg->owned_dirs, pkg_dirs_list) { hlist_for_each_entry(diri, c1, &ipkg->owned_dirs, pkg_dirs_list) {
apk_blob_push_blob(&bbuf, APK_BLOB_STR("F:")); apk_blob_push_blob(&bbuf, APK_BLOB_STR("F:"));
apk_blob_push_blob(&bbuf, APK_BLOB_PTR_LEN(diri->dir->name, diri->dir->namelen)); apk_blob_push_blob(&bbuf, APK_BLOB_PTR_LEN(diri->dir->name, diri->dir->namelen));
...@@ -1551,17 +1558,6 @@ int apk_db_get_tag_id(struct apk_database *db, apk_blob_t tag) ...@@ -1551,17 +1558,6 @@ int apk_db_get_tag_id(struct apk_database *db, apk_blob_t tag)
return -1; return -1;
} }
int apk_db_get_tag_id_by_repos(struct apk_database *db, unsigned int repos)
{
int i;
for (i = 0; i < db->num_repo_tags; i++) {
if (db->repo_tags[i].allowed_repos & repos)
return i;
}
return -1;
}
static int fire_triggers(apk_hash_item item, void *ctx) static int fire_triggers(apk_hash_item item, void *ctx)
{ {
struct apk_database *db = (struct apk_database *) ctx; struct apk_database *db = (struct apk_database *) ctx;
......
...@@ -739,7 +739,7 @@ int apk_pkg_add_info(struct apk_database *db, struct apk_package *pkg, ...@@ -739,7 +739,7 @@ int apk_pkg_add_info(struct apk_database *db, struct apk_package *pkg,
pkg->commit = apk_blob_cstr(value); pkg->commit = apk_blob_cstr(value);
break; break;
case 'F': case 'M': case 'R': case 'Z': case 'r': case 'q': case 'F': case 'M': case 'R': case 'Z': case 'r': case 'q':
case 'a': case 'a': case 'p':
/* installed db entries which are handled in database.c */ /* installed db entries which are handled in database.c */
return 1; return 1;
default: default:
......
...@@ -48,10 +48,12 @@ struct apk_name_state { ...@@ -48,10 +48,12 @@ struct apk_name_state {
struct apk_package *chosen; struct apk_package *chosen;
struct apk_score minimum_penalty; struct apk_score minimum_penalty;
unsigned int topology_last_touched; unsigned int topology_last_touched;
unsigned int allowed_repos, preferred_repos;
unsigned short requirers; unsigned short requirers;
unsigned short install_ifs; unsigned short install_ifs;
unsigned short preferred_pinning;
unsigned short allowed_pinning;
unsigned int solver_flags_local : 4; unsigned int solver_flags_local : 4;
unsigned int solver_flags_local_mask : 4; unsigned int solver_flags_local_mask : 4;
unsigned int solver_flags_inherited : 4; unsigned int solver_flags_inherited : 4;
...@@ -320,32 +322,41 @@ static void foreach_dependency(struct apk_solver_state *ss, struct apk_dependenc ...@@ -320,32 +322,41 @@ static void foreach_dependency(struct apk_solver_state *ss, struct apk_dependenc
func(ss, &deps->item[i]); func(ss, &deps->item[i]);
} }
static unsigned int get_pinning_mask_repos(struct apk_database *db, unsigned short pinning_mask)
{
unsigned int repository_mask = 0;
int i;
for (i = 0; i < db->num_repo_tags && pinning_mask; i++) {
if (!(BIT(i) & pinning_mask))
continue;
pinning_mask &= ~BIT(i);
repository_mask |= db->repo_tags[i].allowed_repos;
}
return repository_mask;
}
static int compare_package_preference(unsigned short solver_flags, static int compare_package_preference(unsigned short solver_flags,
unsigned int preferred_repos, unsigned int preferred_repos,
struct apk_package *pkgA, struct apk_package *pkgA,
struct apk_package *pkgB) struct apk_package *pkgB,
struct apk_database *db)
{ {
unsigned int a_repos, b_repos;
/* specified on command line directly */ /* specified on command line directly */
if (pkgA->filename && !pkgB->filename) if (pkgA->filename && !pkgB->filename)
return 1; return 1;
if (pkgB->filename && !pkgA->filename) if (pkgB->filename && !pkgA->filename)
return -1; return -1;
if (solver_flags & APK_SOLVERF_PREFER_TAG) { /* Is there a difference in pinning preference? */
/* preferred repository pinning */ a_repos = pkgA->repos | (pkgA->ipkg ? db->repo_tags[pkgA->ipkg->repository_tag].allowed_repos : 0);
if ((pkgA->repos & preferred_repos) && !(pkgB->repos & preferred_repos)) b_repos = pkgB->repos | (pkgB->ipkg ? db->repo_tags[pkgB->ipkg->repository_tag].allowed_repos : 0);
return 1; if ((a_repos & preferred_repos) && !(b_repos & preferred_repos))
if ((pkgB->repos & preferred_repos) && !(pkgA->repos & preferred_repos)) return 1;
return -1; if ((b_repos & preferred_repos) && !(a_repos & preferred_repos))
} else { return -1;
/* preferred repository pinning */
if ((pkgA->ipkg || (pkgA->repos & preferred_repos)) &&
!(pkgB->ipkg || (pkgB->repos & preferred_repos)))
return 1;
if ((pkgB->ipkg || (pkgB->repos & preferred_repos)) &&
!(pkgA->ipkg || (pkgA->repos & preferred_repos)))
return -1;
}
if (solver_flags & APK_SOLVERF_AVAILABLE) { if (solver_flags & APK_SOLVERF_AVAILABLE) {
if (pkgA->repos != 0 && pkgB->repos == 0) if (pkgA->repos != 0 && pkgB->repos == 0)
...@@ -390,12 +401,13 @@ static int get_preference(struct apk_solver_state *ss, ...@@ -390,12 +401,13 @@ static int get_preference(struct apk_solver_state *ss,
unsigned short name_flags = ns->solver_flags_local unsigned short name_flags = ns->solver_flags_local
| ns->solver_flags_inherited | ns->solver_flags_inherited
| ss->solver_flags; | ss->solver_flags;
unsigned int preferred_repos = ns->preferred_repos; unsigned short preferred_pinning;
unsigned int preferred_repos;
unsigned short preference = 0; unsigned short preference = 0;
int i; int i;
if (preferred_repos == 0) preferred_pinning = ns->preferred_pinning ?: APK_DEFAULT_PINNING_MASK;
preferred_repos = ss->db->repo_tags[0].allowed_repos; preferred_repos = get_pinning_mask_repos(ss->db, preferred_pinning);
for (i = 0; i < name->pkgs->num; i++) { for (i = 0; i < name->pkgs->num; i++) {
struct apk_package *pkg0 = name->pkgs->item[i]; struct apk_package *pkg0 = name->pkgs->item[i];
...@@ -404,9 +416,8 @@ static int get_preference(struct apk_solver_state *ss, ...@@ -404,9 +416,8 @@ static int get_preference(struct apk_solver_state *ss,
if (pkg0 == pkg || ps0 == NULL) if (pkg0 == pkg || ps0 == NULL)
continue; continue;
if (compare_package_preference(name_flags, if (compare_package_preference(name_flags, preferred_repos,
preferred_repos, pkg, pkg0, ss->db) < 0) {
pkg, pkg0) < 0) {
if (installable_only) { if (installable_only) {
if (ss->topology_position > pkg0->topology_hard && if (ss->topology_position > pkg0->topology_hard &&
!(ps0->flags & APK_PKGSTF_DECIDED)) !(ps0->flags & APK_PKGSTF_DECIDED))
...@@ -441,13 +452,21 @@ static int update_name_state(struct apk_solver_state *ss, struct apk_name *name) ...@@ -441,13 +452,21 @@ static int update_name_state(struct apk_solver_state *ss, struct apk_name *name)
struct apk_package *best_pkg = NULL, *preferred_pkg = NULL; struct apk_package *best_pkg = NULL, *preferred_pkg = NULL;
struct apk_package_state *preferred_ps = NULL; struct apk_package_state *preferred_ps = NULL;
unsigned int best_topology = 0; unsigned int best_topology = 0;
unsigned int allowed_repos = ns->allowed_repos | ss->db->repo_tags[0].allowed_repos;
unsigned int preferred_repos = ns->preferred_repos;
unsigned short name_flags = ns->solver_flags_local unsigned short name_flags = ns->solver_flags_local
| ns->solver_flags_inherited | ns->solver_flags_inherited
| ss->solver_flags; | ss->solver_flags;
unsigned short preferred_pinning, allowed_pinning;
unsigned int preferred_repos, allowed_repos;
int i, options = 0, skipped_options = 0; int i, options = 0, skipped_options = 0;
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;
subscore(&ss->minimum_penalty, &ns->minimum_penalty); subscore(&ss->minimum_penalty, &ns->minimum_penalty);
ns->minimum_penalty = (struct apk_score) { 0, 0 }; ns->minimum_penalty = (struct apk_score) { 0, 0 };
...@@ -469,9 +488,8 @@ static int update_name_state(struct apk_solver_state *ss, struct apk_name *name) ...@@ -469,9 +488,8 @@ static int update_name_state(struct apk_solver_state *ss, struct apk_name *name)
if ((preferred_pkg == NULL) || if ((preferred_pkg == NULL) ||
(ps0->conflicts < preferred_ps->conflicts) || (ps0->conflicts < preferred_ps->conflicts) ||
(ps0->conflicts == preferred_ps->conflicts && (ps0->conflicts == preferred_ps->conflicts &&
compare_package_preference(name_flags, compare_package_preference(name_flags, preferred_repos,
preferred_repos, pkg0, preferred_pkg, ss->db) > 0)) {
pkg0, preferred_pkg) > 0)) {
preferred_pkg = pkg0; preferred_pkg = pkg0;
preferred_ps = ps0; preferred_ps = ps0;
} }
...@@ -702,7 +720,8 @@ static void inherit_name_state(struct apk_name *to, struct apk_name *from) ...@@ -702,7 +720,8 @@ static void inherit_name_state(struct apk_name *to, struct apk_name *from)
tns->solver_flags_inherited |= tns->solver_flags_inherited |=
fns->solver_flags_inherited | fns->solver_flags_inherited |
(fns->solver_flags_local & fns->solver_flags_local_mask); (fns->solver_flags_local & fns->solver_flags_local_mask);
tns->allowed_repos |= fns->allowed_repos;
tns->allowed_pinning |= fns->allowed_pinning | fns->preferred_pinning;
} }
static void inherit_name_state_wrapper(struct apk_package *rdepend, void *ctx) static void inherit_name_state_wrapper(struct apk_package *rdepend, void *ctx)
...@@ -719,7 +738,7 @@ static int has_inherited_state(struct apk_name *name) ...@@ -719,7 +738,7 @@ static int has_inherited_state(struct apk_name *name)
return 0; return 0;
if (ns->solver_flags_inherited || (ns->solver_flags_local & ns->solver_flags_local_mask)) if (ns->solver_flags_inherited || (ns->solver_flags_local & ns->solver_flags_local_mask))
return 1; return 1;
if (ns->allowed_repos) if (ns->allowed_pinning)
return 1; return 1;
return 0; return 0;
} }
...@@ -729,7 +748,7 @@ static void recalculate_inherted_name_state(struct apk_name *name) ...@@ -729,7 +748,7 @@ static void recalculate_inherted_name_state(struct apk_name *name)
struct apk_name_state *ns = name_to_ns(name); struct apk_name_state *ns = name_to_ns(name);
ns->solver_flags_inherited = 0; ns->solver_flags_inherited = 0;
ns->allowed_repos = 0; ns->allowed_pinning = 0;
foreach_locked_reverse_dependency(name, inherit_name_state_wrapper, name); foreach_locked_reverse_dependency(name, inherit_name_state_wrapper, name);
} }
...@@ -754,13 +773,10 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency ...@@ -754,13 +773,10 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency
} }
if (dep->repository_tag) { if (dep->repository_tag) {
unsigned int allowed_repos; dbg_printf("%s: adding pinnings %d\n",
dbg_printf("%s: enabling repository tag %d\n",
dep->name->name, dep->repository_tag); dep->name->name, dep->repository_tag);
allowed_repos = ss->db->repo_tags[dep->repository_tag].allowed_repos; ns->preferred_pinning = BIT(dep->repository_tag);
ns->allowed_repos |= allowed_repos; ns->allowed_pinning |= BIT(dep->repository_tag);
ns->preferred_repos |= allowed_repos;
} }
for (i = 0; i < name->pkgs->num; i++) { for (i = 0; i < name->pkgs->num; i++) {
...@@ -944,6 +960,19 @@ static int compare_change(const void *p1, const void *p2) ...@@ -944,6 +960,19 @@ static int compare_change(const void *p1, const void *p2)
c2->newpkg->topology_hard; 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, static int generate_changeset(struct apk_database *db,
struct apk_package_array *solution, struct apk_package_array *solution,
struct apk_changeset *changeset, struct apk_changeset *changeset,
...@@ -999,6 +1028,7 @@ static int generate_changeset(struct apk_database *db, ...@@ -999,6 +1028,7 @@ static int generate_changeset(struct apk_database *db,
break; break;
} }
changeset->changes->item[ci].newpkg = pkg; changeset->changes->item[ci].newpkg = pkg;
changeset->changes->item[ci].repository_tag = get_tag(db, ns->allowed_pinning, pkg->repos);
ci++; ci++;
} }
} }
...@@ -1130,23 +1160,16 @@ static void print_change(struct apk_database *db, ...@@ -1130,23 +1160,16 @@ static void print_change(struct apk_database *db,
struct apk_package *newpkg = change->newpkg; struct apk_package *newpkg = change->newpkg;
const char *msg = NULL; const char *msg = NULL;
char status[32], n[512], *nameptr; char status[32], n[512], *nameptr;
int r, tag; int r;
snprintf(status, sizeof(status), "(%i/%i)", cur+1, total); snprintf(status, sizeof(status), "(%i/%i)", cur+1, total);
status[sizeof(status) - 1] = 0; status[sizeof(status) - 1] = 0;
if (newpkg != NULL) { name = newpkg ? newpkg->name : oldpkg->name;
name = newpkg->name; if (change->repository_tag > 0) {
tag = apk_db_get_tag_id_by_repos(db, newpkg->repos);
} else {
name = oldpkg->name;
tag = apk_db_get_tag_id_by_repos(db, oldpkg->repos);
}
if (tag > 0) {
snprintf(n, sizeof(n), "%s@" BLOB_FMT, snprintf(n, sizeof(n), "%s@" BLOB_FMT,
name->name, name->name,
BLOB_PRINTF(*db->repo_tags[tag].name)); BLOB_PRINTF(*db->repo_tags[change->repository_tag].name));
n[sizeof(n) - 1] = 0; n[sizeof(n) - 1] = 0;
nameptr = n; nameptr = n;
} else { } else {
...@@ -1403,6 +1426,8 @@ int apk_solver_commit_changeset(struct apk_database *db, ...@@ -1403,6 +1426,8 @@ int apk_solver_commit_changeset(struct apk_database *db,
&prog); &prog);
if (r != 0) if (r != 0)
break; break;
if (change->newpkg)
change->newpkg->ipkg->repository_tag = change->repository_tag;
} }
count_change(change, &prog.done); count_change(change, &prog.done);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment