Skip to content

Commit

Permalink
Rework multiversion orphaned handling
Browse files Browse the repository at this point in the history
We now create a (-p|u1|u2|u3) dup rule for multiversion orphans.
We also test keeporphans/allowuninstall with dup.
  • Loading branch information
mlschroe committed Dec 11, 2015
1 parent e674e4b commit 98352a5
Show file tree
Hide file tree
Showing 5 changed files with 343 additions and 64 deletions.
106 changes: 47 additions & 59 deletions src/rules.c
Original file line number Diff line number Diff line change
Expand Up @@ -1157,17 +1157,19 @@ finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
if (!qs->count)
{
if (allow_all)
return 0; /* orphaned, don't create feature rule */
return 0; /* orphaned, don't create feature rule */
/* check if this is an orphaned package */
policy_findupdatepackages(solv, s, qs, 1);
if (!qs->count)
return 0; /* orphaned, don't create update rule */
return 0; /* orphaned, don't create update rule */
qs->count = 0;
return -SYSTEMSOLVABLE; /* supported but not installable */
}
if (allow_all)
return s - pool->solvables;
/* check if it is ok to keep the installed package */
if (solv->dupmap.size && MAPTST(&solv->dupmap, s - pool->solvables))
return s - pool->solvables;
for (i = 0; i < qs->count; i++)
{
Solvable *ns = pool->solvables + qs->elements[i];
Expand All @@ -1178,6 +1180,7 @@ finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
return -SYSTEMSOLVABLE;
}

#if 0
/* add packages from the dup repositories to the update candidates
* this isn't needed for the global dup mode as all packages are
* from dup repos in that case */
Expand All @@ -1201,6 +1204,7 @@ addduppackages(Solver *solv, Solvable *s, Queue *qs)
}
queue_free(&dupqs);
}
#endif

/*-------------------------------------------------------------------
*
Expand All @@ -1218,26 +1222,23 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all)
Id p, d;
Queue qs;
Id qsbuf[64];
int isorphaned = 0;

queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
p = s - pool->solvables;
/* find update candidates for 's' */
if (solv->dupmap_all)
if (solv->dupmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))
p = finddistupgradepackages(solv, s, &qs, allow_all);
else
{
policy_findupdatepackages(solv, s, &qs, allow_all);
if (!allow_all && solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
addduppackages(solv, s, &qs);
}
policy_findupdatepackages(solv, s, &qs, allow_all);

#ifdef ENABLE_LINKED_PKGS
if (solv->instbuddy && solv->instbuddy[s - pool->solvables - solv->installed->start])
{
const char *name = pool_id2str(pool, s->name);
if (strncmp(name, "pattern:", 8) == 0 || strncmp(name, "application:", 12) == 0)
{
/* a linked pseudo package. As it is linked, we do not need an update rule */
/* a linked pseudo package. As it is linked, we do not need an update/feature rule */
/* nevertheless we set specialupdaters so we can update */
solver_addrule(solv, 0, 0, 0);
if (!allow_all && qs.count)
Expand All @@ -1254,11 +1255,14 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all)
}
#endif

if (!allow_all && !p && solv->dupmap_all)
if (!allow_all && !p) /* !p implies qs.count == 0 */
{
queue_push(&solv->orphaned, s - pool->solvables); /* an orphaned package */
if (solv->keep_orphans && !(solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, s - pool->solvables - solv->installed->start))))
p = s - pool->solvables; /* keep this orphaned package installed */
queue_free(&qs);
solver_addrule(solv, p, 0, 0);
return;
}

if (!allow_all && qs.count && solv->multiversion.size)
Expand All @@ -1271,7 +1275,7 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all)
if (i < qs.count)
{
/* filter out all multiversion packages as they don't update */
d = pool_queuetowhatprovides(pool, &qs);
d = pool_queuetowhatprovides(pool, &qs); /* save qs away */
for (j = i; i < qs.count; i++)
{
if (MAPTST(&solv->multiversion, qs.elements[i]))
Expand All @@ -1290,31 +1294,39 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all)
}
qs.elements[j++] = qs.elements[i];
}
if (j < qs.count)
if (j < qs.count) /* filtered at least one package? */
{
if (d && solv->installed && s->repo == solv->installed &&
(solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, s - pool->solvables - solv->installed->start))))
if (j == 0 && p == -SYSTEMSOLVABLE)
{
/* this is a multiversion orphan */
queue_push(&solv->orphaned, s - pool->solvables);
if (!solv->specialupdaters)
solv->specialupdaters = solv_calloc(solv->installed->end - solv->installed->start, sizeof(Id));
solv->specialupdaters[s - pool->solvables - solv->installed->start] = d;
}
if (j == 0 && p == -SYSTEMSOLVABLE && solv->dupmap_all)
{
queue_push(&solv->orphaned, s - pool->solvables); /* also treat as orphaned */
j = qs.count;
if (solv->keep_orphans && !(solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, s - pool->solvables - solv->installed->start))))
{
/* we need to keep the orphan */
queue_free(&qs);
solver_addrule(solv, s - pool->solvables, 0, 0);
return;
}
/* we can drop it as long as we update */
isorphaned = 1;
j = qs.count; /* force the update */
}
qs.count = j;
}
else if (p != -SYSTEMSOLVABLE)
{
/* could fallthrough, but then we would do pool_queuetowhatprovides twice */
queue_free(&qs);
solver_addrule(solv, p, 0, d); /* allow update of s */
solver_addrule(solv, s - pool->solvables, 0, d); /* allow update of s */
return;
}
}
}
if (!isorphaned && p == -SYSTEMSOLVABLE && solv->dupmap.size)
p = s - pool->solvables; /* let the dup rules sort it out */
if (qs.count && p == -SYSTEMSOLVABLE)
p = queue_shift(&qs);
if (qs.count > 1)
Expand Down Expand Up @@ -1792,29 +1804,6 @@ solver_freedupmaps(Solver *solv)
* policy's priority pruning code. sigh. */
}

static int
is_multiversion_orphan(Solver *solv, Id p)
{
Pool *pool = solv->pool;
Solvable *s = pool->solvables + p;
Rule *r = solv->rules + solv->updaterules + (p - solv->installed->start);
Id l, pp;
if (!r->p)
return 0;
FOR_RULELITERALS(l, pp, r)
{
Solvable *ps = pool->solvables + l;
/* see multiversion code in solver_addupdaterule */
if (!MAPTST(&solv->multiversion, l))
return 0;
if (solv->keepexplicitobsoletes && ps->name != s->name)
return 0;
if (ps->name == s->name && ps->evr == s->evr && ps->arch == s->arch)
return 0;
}
return 1;
}

void
solver_addduprules(Solver *solv, Map *addedmap)
{
Expand All @@ -1823,6 +1812,7 @@ solver_addduprules(Solver *solv, Map *addedmap)
Id p, pp;
Solvable *s, *ps;
int first, i;
Rule *r;

solv->duprules = solv->nrules;
for (i = 1; i < pool->nsolvables; i++)
Expand Down Expand Up @@ -1859,24 +1849,22 @@ solver_addduprules(Solver *solv, Map *addedmap)
if (is->evr == ps->evr && solvable_identical(ps, is))
break;
}
if (!ip && solv->keep_orphans)
if (ip)
{
/* is this an orphan we should keep? */
Rule *r = solv->rules + solv->featurerules + (p - installed->start);
if (!r->p)
r += solv->updaterules - solv->featurerules;
if (r->p == p && !r->d)
ip = p;
else if (solv->dupmap_all && solv->multiversion.size)
{
if (is_multiversion_orphan(solv, p))
ip = p;
}
/* ok, found a good one. we may keep this package. */
MAPSET(&solv->dupmap, p); /* for best rules processing */
continue;
}
if (!ip)
solver_addrule(solv, -p, 0, 0); /* no match, sorry */
else
MAPSET(&solv->dupmap, p); /* for best rules processing */
r = solv->rules + solv->updaterules + (p - installed->start);
if (!r->p)
r = solv->rules + solv->featurerules + (p - installed->start);
if (r->p && solv->specialupdaters && solv->specialupdaters[p - installed->start])
{
/* this is a multiversion orphan, we're good if an update is installed */
solver_addrule(solv, -p, 0, solv->specialupdaters[p - installed->start]);
continue;
}
solver_addrule(solv, -p, 0, 0); /* no match, sorry */
}
}
else if (!MAPTST(&solv->dupmap, p))
Expand Down
16 changes: 11 additions & 5 deletions src/solver.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ autouninstall(Solver *solv, Id *problem)
if (v > lastfeature)
lastfeature = v;
/* prefer orphaned packages in dup mode */
if (solv->dupmap_all && solv->keep_orphans)
if (solv->keep_orphans)
{
r = solv->rules + v;
if (!r->d && r->p == (solv->installed->start + (v - solv->updaterules)))
Expand Down Expand Up @@ -2725,7 +2725,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)

if (!solv->decisioncnt_orphan)
solv->decisioncnt_orphan = solv->decisionq.count;
if (solv->dupmap_all && solv->installed)
if (solv->installed && (solv->orphaned.count || solv->brokenorphanrules))
{
int installedone = 0;

Expand Down Expand Up @@ -3632,7 +3632,9 @@ solver_solve(Solver *solv, Queue *job)
if (how & SOLVER_FORCEBEST)
solv->bestupdatemap_all = 1;
}
if (!solv->dupmap_all || solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size)
if ((how & SOLVER_TARGETED) != 0)
needduprules = 1;
if (!solv->dupmap_all || solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size || solv->keep_orphans)
needduprules = 1;
break;
default:
Expand Down Expand Up @@ -3747,9 +3749,13 @@ solver_solve(Solver *solv, Queue *job)
* check for and remove duplicate
*/
r = solv->rules + solv->nrules - 1; /* r: update rule */
if (!r->p)
continue;
sr = r - (installed->end - installed->start); /* sr: feature rule */
if (!r->p)
{
if (sr->p)
memset(sr, 0, sizeof(*sr)); /* no feature rules without update rules */
continue;
}
/* it's also orphaned if the feature rule consists just of the installed package */
if (!solv->dupmap_all && sr->p == i && !sr->d && !sr->w2)
queue_push(&solv->orphaned, i);
Expand Down
91 changes: 91 additions & 0 deletions test/testcases/distupgrade/dup_multiversion1
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# test dup with multiversion packages
#
# part 1: simple update
repo system 0 testtags <inline>
#>=Pkg: a 1 1 i686
repo available 0 testtags <inline>
#>=Pkg: a 2 1 i686
system i686 * system

job multiversion name a
job distupgrade all packages
# a-1-1 is treated as orphaned and stays behind
result transaction,problems <inline>
#>install a-2-1.i686@available

nextjob

job multiversion name a
job distupgrade repo available
# a-1-1 is treated as orphaned and stays behind
result transaction,problems <inline>
#>install a-2-1.i686@available


### same with keeporphans

nextjob

solverflags keeporphans
job multiversion name a
job distupgrade all packages
# a-1-1 is treated as orphaned and stays behind
result transaction,problems <inline>
#>install a-2-1.i686@available


nextjob

solverflags keeporphans
job multiversion name a
job distupgrade repo available
# a-1-1 is treated as orphaned and stays behind
result transaction,problems <inline>
#>install a-2-1.i686@available


### same with allowuninstall

nextjob

solverflags allowuninstall
job multiversion name a
job distupgrade all packages
# a-1-1 is treated as orphaned and stays behind
result transaction,problems <inline>
#>install a-2-1.i686@available


nextjob

solverflags allowuninstall
job multiversion name a
job distupgrade repo available
# a-1-1 is treated as orphaned and stays behind
result transaction,problems <inline>
#>install a-2-1.i686@available


### same with allowuninstall and keeporphans

nextjob

solverflags allowuninstall keeporphans
job multiversion name a
job distupgrade all packages
# a-1-1 is treated as orphaned and stays behind
result transaction,problems <inline>
#>install a-2-1.i686@available


nextjob

solverflags allowuninstall keeporphans
job multiversion name a
job distupgrade repo available
# a-1-1 is treated as orphaned and stays behind
result transaction,problems <inline>
#>install a-2-1.i686@available



0 comments on commit 98352a5

Please sign in to comment.