Skip to content

Commit 1da9bef

Browse files
committed
Improve choice rule generation
New strategy: take the package update map into account when creating choice rules. This simplifies the code quite a bit. Also check at the end of the solving if a choice rule led to two packages providing the same thing. In that case, break the choice rule and re-run the solver.
1 parent ce9dda7 commit 1da9bef

2 files changed

Lines changed: 88 additions & 126 deletions

File tree

src/rules.c

Lines changed: 43 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -3255,6 +3255,12 @@ solver_rule2rules(Solver *solv, Id rid, Queue *q, int recursive)
32553255

32563256

32573257
/* check if the newest versions of pi still provides the dependency we're looking for */
3258+
/* pi: installed package
3259+
* r: rule for the dependency
3260+
* m: map with all positive elements of r
3261+
* return 0: at least one provider
3262+
* return 1: the newest versions do not provide the dependency
3263+
*/
32583264
static int
32593265
solver_choicerulecheck(Solver *solv, Id pi, Rule *r, Map *m, Queue *q)
32603266
{
@@ -3303,94 +3309,6 @@ solver_choicerulecheck(Solver *solv, Id pi, Rule *r, Map *m, Queue *q)
33033309
return 1; /* none of the new packages provided it */
33043310
}
33053311

3306-
static int
3307-
solver_choicerulecheck2(Solver *solv, Id pi, Id pt, Queue *q)
3308-
{
3309-
Pool *pool = solv->pool;
3310-
Rule *ur;
3311-
Id p, pp;
3312-
int i;
3313-
3314-
if (!q->count || q->elements[0] != pi)
3315-
{
3316-
if (q->count)
3317-
queue_empty(q);
3318-
ur = solv->rules + solv->updaterules + (pi - pool->installed->start);
3319-
if (!ur->p)
3320-
ur = solv->rules + solv->featurerules + (pi - pool->installed->start);
3321-
if (!ur->p)
3322-
return 1; /* orphaned, thus newest */
3323-
queue_push2(q, pi, 0);
3324-
FOR_RULELITERALS(p, pp, ur)
3325-
if (p > 0 && p != pi)
3326-
queue_push(q, p);
3327-
queue_push(q, pi);
3328-
}
3329-
if (q->count <= 3)
3330-
return q->count == 3 && q->elements[2] == pt ? 1 : 0;
3331-
if (!q->elements[1])
3332-
{
3333-
queue_deleten(q, 0, 2);
3334-
policy_filter_unwanted(solv, q, POLICY_MODE_CHOOSE);
3335-
queue_unshift(q, 1); /* filter mark */
3336-
queue_unshift(q, pi);
3337-
}
3338-
for (i = 2; i < q->count; i++)
3339-
if (q->elements[i] == pt)
3340-
return 1;
3341-
return 0; /* not newest */
3342-
}
3343-
3344-
static int
3345-
solver_choicerulecheck3(Solver *solv, Id pt, Queue *q)
3346-
{
3347-
Pool *pool = solv->pool;
3348-
Id p, pp;
3349-
int i;
3350-
3351-
if (!q->count || q->elements[0] != pt)
3352-
{
3353-
Solvable *s = pool->solvables + pt;
3354-
if (q->count)
3355-
queue_empty(q);
3356-
/* no installed package, so check all with same name */
3357-
queue_push2(q, pt, 0);
3358-
FOR_PROVIDES(p, pp, s->name)
3359-
if (pool->solvables[p].name == s->name && p != pt)
3360-
queue_push(q, p);
3361-
queue_push(q, pt);
3362-
}
3363-
if (q->count <= 3)
3364-
return q->count == 3 && q->elements[2] == pt ? 1 : 0;
3365-
if (!q->elements[1])
3366-
{
3367-
queue_deleten(q, 0, 2);
3368-
policy_filter_unwanted(solv, q, POLICY_MODE_CHOOSE);
3369-
queue_unshift(q, 1); /* filter mark */
3370-
queue_unshift(q, pt);
3371-
}
3372-
for (i = 2; i < q->count; i++)
3373-
if (q->elements[i] == pt)
3374-
return 1;
3375-
return 0; /* not newest */
3376-
}
3377-
3378-
static inline void
3379-
queue_removeelement(Queue *q, Id el)
3380-
{
3381-
int i, j;
3382-
for (i = 0; i < q->count; i++)
3383-
if (q->elements[i] == el)
3384-
break;
3385-
if (i < q->count)
3386-
{
3387-
for (j = i++; i < q->count; i++)
3388-
if (q->elements[i] != el)
3389-
q->elements[j++] = q->elements[i];
3390-
queue_truncate(q, j);
3391-
}
3392-
}
3393-
33943312
static Id
33953313
choicerule_find_installed(Pool *pool, Id p)
33963314
{
@@ -3439,14 +3357,14 @@ solver_addchoicerules(Solver *solv)
34393357
Pool *pool = solv->pool;
34403358
Map m, mneg;
34413359
Rule *r;
3442-
Queue q, qi, qcheck, qcheck2, infoq;
3360+
Queue q, qi, qcheck, infoq;
34433361
int i, j, rid, havechoice, negcnt;
34443362
Id p, d, pp, p2;
34453363
Solvable *s;
34463364
Id lastaddedp, lastaddedd;
34473365
int lastaddedcnt;
34483366
unsigned int now;
3449-
int isnewest = 0;
3367+
int isinstalled;
34503368

34513369
solv->choicerules = solv->nrules;
34523370
if (!pool->installed)
@@ -3458,7 +3376,6 @@ solver_addchoicerules(Solver *solv)
34583376
queue_init(&q);
34593377
queue_init(&qi);
34603378
queue_init(&qcheck);
3461-
queue_init(&qcheck2);
34623379
queue_init(&infoq);
34633380
map_init(&m, pool->nsolvables);
34643381
map_init(&mneg, pool->nsolvables);
@@ -3478,20 +3395,28 @@ solver_addchoicerules(Solver *solv)
34783395
if (r->p >= 0 || ((r->d == 0 || r->d == -1) && r->w2 <= 0))
34793396
continue; /* only look at requires rules */
34803397
/* solver_printrule(solv, SOLV_DEBUG_RESULT, r); */
3481-
queue_empty(&q);
34823398
queue_empty(&qi);
34833399
havechoice = 0;
3400+
isinstalled = 0;
34843401
FOR_RULELITERALS(p, pp, r)
34853402
{
34863403
if (p < 0)
3487-
continue;
3404+
{
3405+
Solvable *s = pool->solvables - p;
3406+
p2 = s->repo == pool->installed ? -p : 0;
3407+
if (p2)
3408+
{
3409+
if (!(solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, p2 - solv->installed->start))))
3410+
isinstalled = 1;
3411+
}
3412+
continue;
3413+
}
34883414
s = pool->solvables + p;
34893415
if (!s->repo)
34903416
continue;
34913417
if (s->repo == pool->installed)
34923418
{
34933419
queue_push2(&qi, p, p);
3494-
queue_push(&q, p);
34953420
continue;
34963421
}
34973422
/* find an installed package p2 that we can update/downgrade to p */
@@ -3503,7 +3428,6 @@ solver_addchoicerules(Solver *solv)
35033428
if (policy_is_illegal(solv, pool->solvables + p2, s, 0))
35043429
continue;
35053430
queue_push2(&qi, p2, p);
3506-
queue_push(&q, p);
35073431
continue;
35083432
}
35093433
/* package p is independent of the installed ones */
@@ -3512,54 +3436,47 @@ solver_addchoicerules(Solver *solv)
35123436
#if 0
35133437
printf("havechoice: %d qcount %d qicount %d\n", havechoice, q.count, qi.count);
35143438
#endif
3515-
if (!havechoice || !q.count || !qi.count)
3439+
if (!havechoice || !qi.count)
35163440
continue; /* no choice */
35173441

35183442
FOR_RULELITERALS(p, pp, r)
35193443
if (p > 0)
35203444
MAPSET(&m, p);
35213445

3522-
isnewest = 1;
3523-
FOR_RULELITERALS(p, pp, r)
3524-
{
3525-
if (p > 0)
3526-
break;
3527-
p2 = choicerule_find_installed(pool, -p);
3528-
if (p2 && !solver_choicerulecheck2(solv, p2, -p, &qcheck2))
3529-
{
3530-
isnewest = 0;
3531-
break;
3532-
}
3533-
if (!p2 && !solver_choicerulecheck3(solv, -p, &qcheck2))
3534-
{
3535-
isnewest = 0;
3536-
break;
3537-
}
3538-
}
3539-
/* do extra checking */
3540-
for (i = j = 0; i < qi.count; i += 2)
3446+
if (!isinstalled)
35413447
{
3542-
p2 = qi.elements[i];
3543-
if (!p2)
3544-
continue;
3545-
if (isnewest && solver_choicerulecheck(solv, p2, r, &m, &qcheck))
3448+
/* do extra checking for packages related to installed packages */
3449+
for (i = j = 0; i < qi.count; i += 2)
35463450
{
3547-
/* oops, remove element p from q */
3548-
queue_removeelement(&q, qi.elements[i + 1]);
3549-
continue;
3451+
p2 = qi.elements[i];
3452+
if (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, p2 - solv->installed->start)))
3453+
{
3454+
if (solver_choicerulecheck(solv, p2, r, &m, &qcheck))
3455+
continue;
3456+
}
3457+
qi.elements[j++] = p2;
3458+
qi.elements[j++] = qi.elements[i + 1];
35503459
}
3551-
qi.elements[j++] = p2;
3460+
queue_truncate(&qi, j);
35523461
}
3553-
queue_truncate(&qi, j);
35543462

3555-
if (!q.count || !qi.count)
3463+
if (!qi.count)
35563464
{
35573465
FOR_RULELITERALS(p, pp, r)
35583466
if (p > 0)
35593467
MAPCLR(&m, p);
35603468
continue;
35613469
}
35623470

3471+
queue_empty(&q);
3472+
/* split q from qi */
3473+
for (i = j = 0; i < qi.count; i += 2)
3474+
{
3475+
queue_push(&q, qi.elements[i + 1]);
3476+
qi.elements[j++] = qi.elements[i];
3477+
}
3478+
queue_truncate(&qi, j);
3479+
35633480

35643481
/* now check the update rules of the installed package.
35653482
* if all packages of the update rules are contained in
@@ -3579,6 +3496,7 @@ solver_addchoicerules(Solver *solv)
35793496
break;
35803497
if (p)
35813498
break;
3499+
/* speed improvement: only check each package once */
35823500
for (j = i + 1; j < qi.count; j++)
35833501
if (qi.elements[i] == qi.elements[j])
35843502
qi.elements[j] = 0;
@@ -3636,7 +3554,6 @@ solver_addchoicerules(Solver *solv)
36363554
queue_free(&q);
36373555
queue_free(&qi);
36383556
queue_free(&qcheck);
3639-
queue_free(&qcheck2);
36403557
queue_free(&infoq);
36413558
map_free(&m);
36423559
map_free(&mneg);

src/solver.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2620,6 +2620,43 @@ resolve_orphaned(Solver *solv, int level, int disablerules, Queue *dq, int *reru
26202620
return level;
26212621
}
26222622

2623+
int
2624+
solver_check_unneeded_choicerules(Solver *solv)
2625+
{
2626+
Pool *pool = solv->pool;
2627+
Rule *r, *or;
2628+
Id p, pp, p2, pp2;
2629+
int i;
2630+
int havedisabled = 0;
2631+
2632+
/* check if some choice rules could have been broken */
2633+
for (i = solv->choicerules, r = solv->rules + i; i < solv->choicerules_end; i++, r++)
2634+
{
2635+
if (r->d < 0)
2636+
continue;
2637+
or = solv->rules + solv->choicerules_info[i - solv->choicerules];
2638+
if (or->d < 0)
2639+
continue;
2640+
FOR_RULELITERALS(p, pp, or)
2641+
{
2642+
if (p < 0 || solv->decisionmap[p] <= 0)
2643+
continue;
2644+
FOR_RULELITERALS(p2, pp2, r)
2645+
if (p2 == p)
2646+
break;
2647+
if (!p2)
2648+
{
2649+
/* did not find p in choice rule, disable it */
2650+
POOL_DEBUG(SOLV_DEBUG_SOLVER, "disabling unneeded choice rule #%d\n", i);
2651+
solver_disablechoicerules(solv, r);
2652+
havedisabled = 1;
2653+
break;
2654+
}
2655+
}
2656+
}
2657+
return havedisabled;
2658+
}
2659+
26232660
/*-------------------------------------------------------------------
26242661
*
26252662
* solver_run_sat
@@ -2805,6 +2842,14 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
28052842
continue;
28062843
}
28072844

2845+
if (solv->choicerules != solv->choicerules_end && solver_check_unneeded_choicerules(solv))
2846+
{
2847+
POOL_DEBUG(SOLV_DEBUG_SOLVER, "did choice rule minimization, rerunning solver\n");
2848+
solver_reset(solv);
2849+
level = 0; /* restart from scratch */
2850+
continue;
2851+
}
2852+
28082853
if (solv->solution_callback)
28092854
{
28102855
solv->solution_callback(solv, solv->solution_callback_data);

0 commit comments

Comments
 (0)