From: Michael Schroeder Date: Tue, 12 May 2015 14:04:20 +0000 (+0200) Subject: Rework rules handling X-Git-Tag: 0.6.11~28 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b0dda2ba2fceb11d9d39cd1f8627256f7e1eb32a;p=thirdparty%2Flibsolv.git Rework rules handling Instead of having a bastard solver_addrule which wither takes an offset into whatprovides or a direct literal, we now have two functions: solver_addrule2 will add a rule with one or two literals solver_addrulen will add a rule specified by an offset into whatprovides This should make the code cleaner, faster, and less memory is used also. This commit also adds a pool_ids2whatprovides function. --- diff --git a/src/libsolv.ver b/src/libsolv.ver index c795b7ac..b8d9764d 100644 --- a/src/libsolv.ver +++ b/src/libsolv.ver @@ -74,6 +74,7 @@ SOLV_1.0 { pool_id2langid; pool_id2rel; pool_id2str; + pool_ids2whatprovides; pool_intersect_evrs; pool_isemptyupdatejob; pool_job2solvables; diff --git a/src/pool.c b/src/pool.c index fd154063..1d795afa 100644 --- a/src/pool.c +++ b/src/pool.c @@ -560,15 +560,15 @@ pool_freewhatprovides(Pool *pool) * returns: Offset into whatprovidesdata * */ + Id -pool_queuetowhatprovides(Pool *pool, Queue *q) +pool_ids2whatprovides(Pool *pool, Id *ids, int count) { Offset off; - int count = q->count; if (count == 0) /* queue empty -> 1 */ return 1; - if (count == 1 && q->elements[0] == SYSTEMSOLVABLE) + if (count == 1 && *ids == SYSTEMSOLVABLE) return 2; /* extend whatprovidesdata if needed, +1 for 0-termination */ @@ -581,7 +581,7 @@ pool_queuetowhatprovides(Pool *pool, Queue *q) /* copy queue to next free slot */ off = pool->whatprovidesdataoff; - memcpy(pool->whatprovidesdata + pool->whatprovidesdataoff, q->elements, count * sizeof(Id)); + memcpy(pool->whatprovidesdata + pool->whatprovidesdataoff, ids, count * sizeof(Id)); /* adapt count and 0-terminate */ pool->whatprovidesdataoff += count; @@ -591,6 +591,17 @@ pool_queuetowhatprovides(Pool *pool, Queue *q) return (Id)off; } +Id +pool_queuetowhatprovides(Pool *pool, Queue *q) +{ + int count = q->count; + if (count == 0) /* queue empty -> 1 */ + return 1; + if (count == 1 && q->elements[0] == SYSTEMSOLVABLE) + return 2; + return pool_ids2whatprovides(pool, q->elements, count); +} + /*************************************************************************/ diff --git a/src/pool.h b/src/pool.h index f6e5d290..900b6a57 100644 --- a/src/pool.h +++ b/src/pool.h @@ -306,6 +306,7 @@ extern void pool_addfileprovides(Pool *pool); extern void pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst); extern void pool_freewhatprovides(Pool *pool); extern Id pool_queuetowhatprovides(Pool *pool, Queue *q); +extern Id pool_ids2whatprovides(Pool *pool, Id *ids, int count); extern Id pool_searchlazywhatprovidesq(Pool *pool, Id d); extern Id pool_addrelproviders(Pool *pool, Id d); diff --git a/src/rules.c b/src/rules.c index cbf31380..779a08f8 100644 --- a/src/rules.c +++ b/src/rules.c @@ -31,7 +31,8 @@ #define RULES_BLOCK 63 -static void addpkgruleinfo(Solver *solv, Id p, Id d, int type, Id dep); +static void addpkgruleinfon(Solver *solv, Id p, Id d, int type, Id dep); +static void addpkgruleinfo2(Solver *solv, Id p1, Id p2, int type, Id dep); static void solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded); /*------------------------------------------------------------------- @@ -274,70 +275,65 @@ hashrule(Solver *solv, Id p, Id d, int n) * always returns a rule for non-pkg rules */ +/* add a rule with one or two literals */ Rule * -solver_addrule(Solver *solv, Id p, Id d) +solver_addrule2(Solver *solv, Id p1, Id p2) { Pool *pool = solv->pool; - Rule *r = 0; - Id *dp = 0; - - int n = 0; /* number of literals in rule - 1 - 0 = direct assertion (single literal) - 1 = binary rule - >1 = multi-literal rule - */ - - /* it often happenes that requires lead to adding the same pkg rule - * multiple times, so we prune those duplicates right away to make - * the work for unifyrules a bit easier */ - - if (!solv->pkgrules_end) /* we add pkg rules */ + Rule *r; + if (!solv->pkgrules_end) /* normalize if we add pkg rules */ { + if (p2 && p1 > p2) + { + /* switch p1 and p2 */ + Id o = p1; + p1 = p2; + p2 = o; + } r = solv->rules + solv->nrules - 1; /* get the last added rule */ - if (r->p == p && r->d == d && (d != 0 || !r->w2)) + if (r->p == p1 && !r->d && r->w2 == p2) return r; } - - /* compute number of literals (n) in rule */ - if (d < 0) - { - if (p == -d) - return 0; /* rule is self-fulfilling */ - if (p == d) - d = 0; /* normalize to assertion */ - else - n = 1; /* binary rule */ - } - else if (d > 0) + solv->rules = solv_extend(solv->rules, solv->nrules, 1, sizeof(Rule), RULES_BLOCK); + r = solv->rules + solv->nrules++; /* point to rule space */ + r->p = p1; + r->d = 0; + r->w1 = p1; + r->w2 = p2; + r->n1 = 0; + r->n2 = 0; + IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION) { - for (dp = pool->whatprovidesdata + d; *dp; dp++, n++) - if (*dp == -p) - return 0; /* rule is self-fulfilling */ - if (n == 1) /* convert to binary rule */ - d = dp[-1]; + POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, " Add rule: "); + solver_printrule(solv, SOLV_DEBUG_RULE_CREATION, r); } + return r; +} - if (n == 1 && p > d && !solv->pkgrules_end) - { - /* put smallest literal first so we can find dups */ - n = p; p = d; d = n; /* p <-> d */ - n = 1; /* re-set n, was used as temp var */ - } +/* add rule with at least 3 literals, d is offset into whatprovides array */ +Rule * +solver_addrulen(Solver *solv, Id p, Id d) +{ + Pool *pool = solv->pool; + Rule *r = 0; + Id *dp; - /* - * check for duplicate (r is only set if we're adding pkg rules) - */ - if (r) + /* check that we have at least 3 literals */ + if (d < 2 || !pool->whatprovidesdata[d]) + return solver_addrule2(solv, p, 0); + if (!pool->whatprovidesdata[d + 1]) + return solver_addrule2(solv, p, pool->whatprovidesdata[d]); + + /* it often happenes that requires lead to adding the same pkg rule + * multiple times, so we prune those duplicates right away to make + * the work for unifyrules a bit easier */ + if (!solv->pkgrules_end) /* we add pkg rules */ { - /* check if the last added rule (r) is exactly the same as what we're looking for. */ - if (n == 1 && !r->d && r->p == p && r->w2 == d) - return r; - /* have n-ary rule with same first literal, check other literals */ - if (n > 1 && r->d && r->p == p) + r = solv->rules + solv->nrules - 1; + if (r->p == p) { - /* Rule where d is an offset in whatprovidesdata */ Id *dp2; - if (d == r->d) + if (r->d == d) return r; dp2 = pool->whatprovidesdata + r->d; for (dp = pool->whatprovidesdata + d; *dp; dp++, dp2++) @@ -348,36 +344,22 @@ solver_addrule(Solver *solv, Id p, Id d) } } + /* check if rule is self-fulfilling */ + for (dp = pool->whatprovidesdata + d; *dp; dp++) + if (*dp == -p) + return 0; /* rule is self-fulfilling */ + /* * allocate new rule r */ solv->rules = solv_extend(solv->rules, solv->nrules, 1, sizeof(Rule), RULES_BLOCK); r = solv->rules + solv->nrules++; /* point to rule space */ - r->p = p; - if (n == 0) - { - /* direct assertion, no watch needed */ - r->d = 0; - r->w1 = p; - r->w2 = 0; - } - else if (n == 1) - { - /* binary rule */ - r->d = 0; - r->w1 = p; - r->w2 = d; - } - else - { - r->d = d; - r->w1 = p; - r->w2 = pool->whatprovidesdata[d]; - } + r->d = d; + r->w1 = p; + r->w2 = pool->whatprovidesdata[d]; r->n1 = 0; r->n2 = 0; - IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION) { POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, " Add rule: "); @@ -432,7 +414,7 @@ makemultiversionconflict(Solver *solv, Id n, Id con) queue_push(&q, p); } if (q.count == 1) - n = -n; /* no other package found, generate normal conflict */ + n = 0; /* no other package found, normal conflict handling */ else n = pool_queuetowhatprovides(pool, &q); queue_free(&q); @@ -440,12 +422,21 @@ makemultiversionconflict(Solver *solv, Id n, Id con) } static inline void -addpkgrule(Solver *solv, Id p, Id d, int type, Id dep) +addpkgrulen(Solver *solv, Id p, Id d, int type, Id dep) +{ + if (!solv->ruleinfoq) + solver_addrulen(solv, p, d); + else + addpkgruleinfon(solv, p, d, type, dep); +} + +static inline void +addpkgrule2(Solver *solv, Id p1, Id p2, int type, Id dep) { if (!solv->ruleinfoq) - solver_addrule(solv, p, d); + solver_addrule2(solv, p1, p2); else - addpkgruleinfo(solv, p, d, type, dep); + addpkgruleinfo2(solv, p1, p2, type, dep); } #ifdef ENABLE_LINKED_PKGS @@ -467,19 +458,19 @@ addlinks(Solver *solv, Solvable *s, Id req, Queue *qr, Id prv, Queue *qp, Map *m #endif if (qr->count == 1) - addpkgrule(solv, qr->elements[0], -(s - pool->solvables), SOLVER_RULE_PKG_REQUIRES, req); + addpkgrule2(solv, -(s - pool->solvables), qr->elements[0], SOLVER_RULE_PKG_REQUIRES, req); else - addpkgrule(solv, -(s - pool->solvables), pool_queuetowhatprovides(pool, qr), SOLVER_RULE_PKG_REQUIRES, req); + addpkgrulen(solv, -(s - pool->solvables), pool_queuetowhatprovides(pool, qr), SOLVER_RULE_PKG_REQUIRES, req); if (qp->count > 1) { Id d = pool_queuetowhatprovides(pool, qp); for (i = 0; i < qr->count; i++) - addpkgrule(solv, -qr->elements[i], d, SOLVER_RULE_PKG_REQUIRES, prv); + addpkgrulen(solv, -qr->elements[i], d, SOLVER_RULE_PKG_REQUIRES, prv); } else if (qp->count) { for (i = 0; i < qr->count; i++) - addpkgrule(solv, qp->elements[0], -qr->elements[i], SOLVER_RULE_PKG_REQUIRES, prv); + addpkgrule2(solv, -qr->elements[i], qp->elements[0], SOLVER_RULE_PKG_REQUIRES, prv); } if (!m) return; /* nothing more to do if called from getpkgruleinfos() */ @@ -528,17 +519,6 @@ add_package_link(Solver *solv, Solvable *s, Map *m, Queue *workq) #ifdef ENABLE_COMPLEX_DEPS -static inline Id -pool_idstowhatprovides(Pool *pool, int count, Id *elements) -{ - /* hack: create fake queue 'q' so that we can call pool_queuetowhatprovides */ - Queue q; - memset(&q, 0, sizeof(q)); - q.count = count; - q.elements = elements; - return pool_queuetowhatprovides(pool, &q); -} - static void add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *workq, Map *m) { @@ -561,7 +541,7 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w else { POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", pool_solvid2str(pool, p), p, pool_dep2str(pool, dep)); - addpkgrule(solv, -p, 0, type == SOLVER_RULE_PKG_REQUIRES ? SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP : type, dep); + addpkgrule2(solv, -p, 0, type == SOLVER_RULE_PKG_REQUIRES ? SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP : type, dep); } queue_free(&bq); return; @@ -597,10 +577,10 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w { /* nothing provides req! */ POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", pool_solvid2str(pool, p), p, pool_dep2str(pool, dep)); - addpkgrule(solv, -p, 0, SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP, dep); + addpkgrule2(solv, -p, 0, SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP, dep); continue; } - addpkgrule(solv, -p, dp - pool->whatprovidesdata, SOLVER_RULE_PKG_REQUIRES, dep); + addpkgrulen(solv, -p, dp - pool->whatprovidesdata, SOLVER_RULE_PKG_REQUIRES, dep); /* push all non-visited providers on the work queue */ if (m) for (; *dp; dp++) @@ -623,16 +603,13 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w if (type == SOLVER_RULE_PKG_CONFLICTS) { if (pool->forbidselfconflicts && !is_otherproviders_dep(pool, dep)) - addpkgrule(solv, -p, 0, SOLVER_RULE_PKG_SELF_CONFLICT, dep); + addpkgrule2(solv, -p, 0, SOLVER_RULE_PKG_SELF_CONFLICT, dep); continue; } - addpkgrule(solv, -p, 0, type, dep); + addpkgrule2(solv, -p, 0, type, dep); continue; } - if (p2 > 0) - addpkgrule(solv, p2, -p, type, dep); /* hack so that we don't need pool_queuetowhatprovides */ - else - addpkgrule(solv, -p, p2, type, dep); + addpkgrule2(solv, -p, p2, type, dep); if (m && p2 > 0 && !MAPTST(m, p2)) queue_push(workq, p2); } @@ -678,7 +655,7 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w break; if (j == qcnt) { - addpkgrule(solv, qele[0], pool_idstowhatprovides(pool, qcnt - 1, qele + 1), type, dep); + addpkgrulen(solv, qele[0], pool_ids2whatprovides(pool, qele + 1, qcnt - 1), type, dep); if (m) for (j = 0; j < qcnt; j++) if (qele[j] > 0 && !MAPTST(m, qele[j])) @@ -768,7 +745,7 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) : !pool_installable(pool, s)) { POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s [%d] is not installable\n", pool_solvid2str(pool, n), n); - addpkgrule(solv, -n, 0, SOLVER_RULE_PKG_NOT_INSTALLABLE, 0); + addpkgrule2(solv, -n, 0, SOLVER_RULE_PKG_NOT_INSTALLABLE, 0); } } @@ -825,7 +802,7 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) if (!*dp) { POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", pool_solvid2str(pool, n), n, pool_dep2str(pool, req)); - addpkgrule(solv, -n, 0, SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP, req); + addpkgrule2(solv, -n, 0, SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP, req); continue; } @@ -838,7 +815,7 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) /* add 'requires' dependency */ /* rule: (-requestor|provider1|provider2|...|providerN) */ - addpkgrule(solv, -n, dp - pool->whatprovidesdata, SOLVER_RULE_PKG_REQUIRES, req); + addpkgrulen(solv, -n, dp - pool->whatprovidesdata, SOLVER_RULE_PKG_REQUIRES, req); /* push all non-visited providers on the work queue */ if (m) @@ -892,16 +869,23 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) { if (!pool->forbidselfconflicts || is_otherproviders_dep(pool, con)) continue; - addpkgrule(solv, -n, 0, SOLVER_RULE_PKG_SELF_CONFLICT, con); + addpkgrule2(solv, -n, 0, SOLVER_RULE_PKG_SELF_CONFLICT, con); continue; } if (ispatch && solv->multiversion.size && MAPTST(&solv->multiversion, p) && ISRELDEP(con)) { /* our patch conflicts with a multiversion package */ - p = -makemultiversionconflict(solv, p, con); + Id d = makemultiversionconflict(solv, p, con); + if (d) + { + addpkgrulen(solv, -n, d, SOLVER_RULE_PKG_CONFLICTS, con); + continue; + } } + if (p == SYSTEMSOLVABLE) + p = 0; /* rule: -n|-p: either solvable _or_ provider of conflict */ - addpkgrule(solv, -n, p == SYSTEMSOLVABLE ? 0 : -p, SOLVER_RULE_PKG_CONFLICTS, con); + addpkgrule2(solv, -n, -p, SOLVER_RULE_PKG_CONFLICTS, con); } } } @@ -934,10 +918,12 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) continue; if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps)) continue; + if (p == SYSTEMSOLVABLE) + p = 0; if (!isinstalled) - addpkgrule(solv, -n, -p, SOLVER_RULE_PKG_OBSOLETES, obs); + addpkgrule2(solv, -n, -p, SOLVER_RULE_PKG_OBSOLETES, obs); else - addpkgrule(solv, -n, -p, SOLVER_RULE_PKG_INSTALLED_OBSOLETES, obs); + addpkgrule2(solv, -n, -p, SOLVER_RULE_PKG_INSTALLED_OBSOLETES, obs); } } } @@ -963,10 +949,12 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) continue; if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps)) continue; + if (p == SYSTEMSOLVABLE) + p = 0; if (s->name == ps->name) - addpkgrule(solv, -n, -p, SOLVER_RULE_PKG_SAME_NAME, 0); + addpkgrule2(solv, -n, -p, SOLVER_RULE_PKG_SAME_NAME, 0); else - addpkgrule(solv, -n, -p, SOLVER_RULE_PKG_IMPLICIT_OBSOLETES, s->name); + addpkgrule2(solv, -n, -p, SOLVER_RULE_PKG_IMPLICIT_OBSOLETES, s->name); } } } @@ -1238,7 +1226,7 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all) { /* a linked pseudo package. As it is linked, we do not need an update rule */ /* nevertheless we set specialupdaters so we can update */ - solver_addrule(solv, 0, 0); + solver_addrule2(solv, 0, 0); if (!allow_all && qs.count) { if (p != -SYSTEMSOLVABLE) @@ -1309,16 +1297,25 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all) { /* could fallthrough, but then we would do pool_queuetowhatprovides twice */ queue_free(&qs); - solver_addrule(solv, p, d); /* allow update of s */ + solver_addrulen(solv, p, d); /* allow update of s */ return; } } } if (qs.count && p == -SYSTEMSOLVABLE) p = queue_shift(&qs); - d = qs.count ? pool_queuetowhatprovides(pool, &qs) : 0; - queue_free(&qs); - solver_addrule(solv, p, d); /* allow update of s */ + if (qs.count > 1) + { + d = pool_queuetowhatprovides(pool, &qs); + queue_free(&qs); + solver_addrulen(solv, p, d); /* allow update of s */ + } + else + { + d = qs.count ? qs.elements[0] : 0; + queue_free(&qs); + solver_addrule2(solv, p, d); /* allow update of s */ + } } static inline void @@ -1547,7 +1544,10 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) if (installed && pool->solvables[p].repo == installed && !haveinstalled) continue; /* installed package not in lock-step */ } - solver_addrule(solv, -p, lsq.count ? pool_queuetowhatprovides(pool, &lsq) : 0); + if (lsq.count < 2) + solver_addrule2(solv, -p, lsq.count ? lsq.elements[0] : 0); + else + solver_addrulen(solv, -p, pool_queuetowhatprovides(pool, &lsq)); } } queue_free(&lsq); @@ -1814,13 +1814,13 @@ solver_addduprules(Solver *solv, Map *addedmap) break; } if (!ip) - solver_addrule(solv, -p, 0); /* no match, sorry */ + solver_addrule2(solv, -p, 0); /* no match, sorry */ else MAPSET(&solv->dupmap, p); /* for best rules processing */ } } else if (!MAPTST(&solv->dupmap, p)) - solver_addrule(solv, -p, 0); + solver_addrule2(solv, -p, 0); } } solv->duprules_end = solv->nrules; @@ -2378,86 +2378,74 @@ solver_reenablepolicyrules_cleandeps(Solver *solv, Id pkg) ***/ static void -addpkgruleinfo(Solver *solv, Id p, Id d, int type, Id dep) +addpkgruleinfon(Solver *solv, Id p, Id d, int type, Id dep) { Pool *pool = solv->pool; Rule *r; - Id w2, op, od, ow2; + Id od, w2 = 0; + + /* check that we have at least 3 literals */ + if (d < 2 || !pool->whatprovidesdata[d]) + return addpkgruleinfo2(solv, p, 0, type, dep); + if (!pool->whatprovidesdata[d + 1]) + return addpkgruleinfo2(solv, p, pool->whatprovidesdata[d], type, dep); /* check if this creates the rule we're searching for */ r = solv->rules + solv->ruleinfoq->elements[0]; - op = r->p; od = r->d < 0 ? -r->d - 1 : r->d; - ow2 = 0; - - /* normalize */ - w2 = d > 0 ? 0 : d; - if (p < 0 && d > 0 && (!pool->whatprovidesdata[d] || !pool->whatprovidesdata[d + 1])) - { - w2 = pool->whatprovidesdata[d]; - d = 0; - } - if (p > 0 && d < 0) /* this hack is used for package links and complex deps */ - { - w2 = p; - p = d; - } - - if (d > 0) - { - if (p != op && !od) - return; - if (d != od) - { - Id *dp = pool->whatprovidesdata + d; - Id *odp = pool->whatprovidesdata + od; - while (*dp) - if (*dp++ != *odp++) - return; - if (*odp) - return; - } - w2 = 0; - /* handle multiversion conflict rules */ - if (p < 0 && pool->whatprovidesdata[d] < 0) - { - w2 = pool->whatprovidesdata[d]; - /* XXX: free memory */ - } - } - else + if (p != r->p && !od) + return; + if (d != od) { - if (od) + Id *dp = pool->whatprovidesdata + d; + Id *odp = pool->whatprovidesdata + od; + while (*dp) + if (*dp++ != *odp++) + return; + if (*odp) return; - ow2 = r->w2; - if (p > w2) - { - if (w2 != op || p != ow2) - return; - } - else - { - if (p != op || w2 != ow2) - return; - } - /* should use a different type instead */ - if (type == SOLVER_RULE_PKG_CONFLICTS && !w2) - w2 = -SYSTEMSOLVABLE; } + /* handle multiversion conflict rules */ + if (p < 0 && pool->whatprovidesdata[d] < 0 && type == SOLVER_RULE_PKG_CONFLICTS) + w2 = pool->whatprovidesdata[d]; /* yep, rule matches. record info */ queue_push(solv->ruleinfoq, type); - if (type == SOLVER_RULE_PKG_SAME_NAME) + queue_push(solv->ruleinfoq, p < 0 ? -p : 0); + queue_push(solv->ruleinfoq, w2 < 0 ? -w2 : 0); + queue_push(solv->ruleinfoq, dep); +} + +static void +addpkgruleinfo2(Solver *solv, Id p1, Id p2, int type, Id dep) +{ + Rule *r; + Id op1 = p1, op2 = p2; + + /* normalize */ + if (op2 && op1 > op2) { - /* we normalize same name order */ - queue_push(solv->ruleinfoq, op < 0 ? -op : 0); - queue_push(solv->ruleinfoq, ow2 < 0 ? -ow2 : 0); + Id o = op1; + op1 = op2; + op2 = o; } - else + /* check if this creates the rule we're searching for */ + r = solv->rules + solv->ruleinfoq->elements[0]; + if (r->p == op1 && r->w2 == op2 && (!r->d || r->d == -1)) { - queue_push(solv->ruleinfoq, p < 0 ? -p : 0); - queue_push(solv->ruleinfoq, w2 < 0 ? -w2 : 0); + if (type == SOLVER_RULE_PKG_CONFLICTS && !p2) + p2 = -SYSTEMSOLVABLE; + if (type == SOLVER_RULE_PKG_SAME_NAME) + { + /* we normalize same name order */ + p1 = op1; + p2 = op2; + } + /* yep, rule matches. record info */ + queue_push(solv->ruleinfoq, type); + queue_push(solv->ruleinfoq, p1 < 0 ? -p1 : 0); + queue_push(solv->ruleinfoq, p2 < 0 ? -p2 : 0); + queue_push(solv->ruleinfoq, dep); } - queue_push(solv->ruleinfoq, dep); } static int @@ -3072,7 +3060,7 @@ solver_addchoicerules(Solver *solv) lastaddedd = d; lastaddedcnt = q.count; - solver_addrule(solv, r->p, d); + solver_addrulen(solv, r->p, d); queue_push(&solv->weakruleq, solv->nrules - 1); solv->choicerules_ref[solv->nrules - 1 - solv->choicerules] = rid; #if 0 @@ -3204,7 +3192,10 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs) if (q.count == oldcnt) continue; /* nothing filtered */ p2 = queue_shift(&q); - solver_addrule(solv, p2, q.count ? pool_queuetowhatprovides(pool, &q) : 0); + if (q.count < 2) + solver_addrule2(solv, p2, q.count ? q.elements[0] : 0); + else + solver_addrulen(solv, p2, pool_queuetowhatprovides(pool, &q)); queue_push(&r2pkg, -(solv->jobrules + j)); } } @@ -3271,7 +3262,10 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs) } } p2 = queue_shift(&q); - solver_addrule(solv, p2, q.count ? pool_queuetowhatprovides(pool, &q) : 0); + if (q.count < 2) + solver_addrule2(solv, p2, q.count ? q.elements[0] : 0); + else + solver_addrulen(solv, p2, pool_queuetowhatprovides(pool, &q)); queue_push(&r2pkg, p); } } @@ -3485,11 +3479,10 @@ for (j = 0; j < qq.count; j++) if (group != groupk && k > groupstart) { /* add the rule */ - Queue qhelper; - memset(&qhelper, 0, sizeof(qhelper)); - qhelper.count = k - groupstart; - qhelper.elements = qq.elements + groupstart; - solver_addrule(solv, -p, pool_queuetowhatprovides(pool, &qhelper)); + if (k - groupstart == 1) + solver_addrule2(solv, -p, qq.elements[groupstart]); + else + solver_addrulen(solv, -p, pool_ids2whatprovides(pool, qq.elements + groupstart, k - groupstart)); queue_push(&yumobsinfoq, qo.elements[i]); } groupstart = k + 1; diff --git a/src/rules.h b/src/rules.h index 8f55af36..69b60067 100644 --- a/src/rules.h +++ b/src/rules.h @@ -99,7 +99,8 @@ solver_enablerule(struct _Solver *solv, Rule *r) r->d = -r->d - 1; } -extern Rule *solver_addrule(struct _Solver *solv, Id p, Id d); +extern Rule *solver_addrule2(struct _Solver *solv, Id p1, Id p2); +extern Rule *solver_addrulen(struct _Solver *solv, Id p, Id d); extern void solver_unifyrules(struct _Solver *solv); extern int solver_rulecmp(struct _Solver *solv, Rule *r1, Rule *r2); extern void solver_shrinkrules(struct _Solver *solv, int nrules); diff --git a/src/solver.c b/src/solver.c index caef1422..1d4b8a23 100644 --- a/src/solver.c +++ b/src/solver.c @@ -1335,7 +1335,7 @@ setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id rul POOL_DEBUG(SOLV_DEBUG_ANALYZE, "reverting decisions (level %d -> %d)\n", level, l); level = l; revert(solv, level); - r = solver_addrule(solv, p, d); + r = solver_addrulen(solv, p, d); assert(r); assert(solv->learnt_why.count == (r - solv->rules) - solv->learntrules); queue_push(&solv->learnt_why, why); @@ -3136,9 +3136,18 @@ solver_calculate_noobsmap(Pool *pool, Queue *job, Map *multiversionmap) * add a rule created by a job, record job number and weak flag */ static inline void -solver_addjobrule(Solver *solv, Id p, Id d, Id job, int weak) +solver_addjobrule2(Solver *solv, Id p1, Id p2, Id job, int weak) { - solver_addrule(solv, p, d); + solver_addrule2(solv, p1, p2); + queue_push(&solv->ruletojob, job); + if (weak) + queue_push(&solv->weakruleq, solv->nrules - 1); +} + +static inline void +solver_addjobrulen(Solver *solv, Id p, Id d, Id job, int weak) +{ + solver_addrulen(solv, p, d); queue_push(&solv->ruletojob, job); if (weak) queue_push(&solv->weakruleq, solv->nrules - 1); @@ -3338,6 +3347,39 @@ deduceq2addedmap(Solver *solv, Map *addedmap) } } +#ifdef ENABLE_COMPLEX_DEPS +static int +add_complex_jobrules(Solver *solv, Id dep, int flags, int jobidx, int weak) +{ + Pool *pool = solv->pool; + Queue bq; + int i, j; + + queue_init(&bq); + i = pool_normalize_complex_dep(pool, dep, &bq, flags | CPLXDEPS_EXPAND); + if (i == 0 || i == 1) + { + queue_free(&bq); + if (i == 0) + solver_addjobrule2(solv, -SYSTEMSOLVABLE, 0, jobidx, weak); + return 0; + } + for (i = 0; i < bq.count; i++) + { + if (!bq.elements[i]) + continue; + for (j = 0; bq.elements[i + j + 1]; j++) + ; + if (j > 1) + solver_addjobrulen(solv, bq.elements[i], pool_ids2whatprovides(pool, bq.elements + i + 1, j), jobidx, weak); + else + solver_addjobrule2(solv, bq.elements[i], bq.elements[i + 1], jobidx, weak); + i += j + 1; + } + queue_free(&bq); + return 1; +} +#endif /* * @@ -3697,7 +3739,7 @@ solver_solve(Solver *solv, Queue *job) { if (s->repo != installed) { - solver_addrule(solv, 0, 0); /* create dummy rule */ + solver_addrule2(solv, 0, 0); /* create dummy rule */ continue; } solver_addupdaterule(solv, s, 1); /* allow s to be updated */ @@ -3725,7 +3767,7 @@ solver_solve(Solver *solv, Queue *job) if (s->repo != installed) { - solver_addrule(solv, 0, 0); /* create dummy rule */ + solver_addrule2(solv, 0, 0); /* create dummy rule */ continue; } solver_addupdaterule(solv, s, 0); /* allowall = 0: downgrades not allowed */ @@ -3776,6 +3818,15 @@ solver_solve(Solver *solv, Queue *job) p = what; d = 0; } +#ifdef ENABLE_COMPLEX_DEPS + else if ((select == SOLVER_SOLVABLE_PROVIDES || select == SOLVER_SOLVABLE_NAME) && pool_is_complex_dep(pool, what)) + { + if (add_complex_jobrules(solv, what, select == SOLVER_SOLVABLE_NAME ? CPLXDEPS_NAME : 0, i, weak)) + if (how & SOLVER_FORCEBEST) + hasbestinstalljob = 1; + break; + } +#endif else { queue_empty(&q); @@ -3806,7 +3857,7 @@ solver_solve(Solver *solv, Queue *job) queue_pushunique(solv->installsuppdepq, rd->evr == 0 ? rd->name : what); } } - solver_addjobrule(solv, p, d, i, weak); + solver_addjobrulen(solv, p, d, i, weak); if (how & SOLVER_FORCEBEST) hasbestinstalljob = 1; break; @@ -3819,21 +3870,21 @@ solver_solve(Solver *solv, Queue *job) if (select == SOLVER_SOLVABLE_ALL) /* hmmm ;) */ { FOR_POOL_SOLVABLES(p) - solver_addjobrule(solv, -p, 0, i, weak); + solver_addjobrule2(solv, -p, 0, i, weak); } else if (select == SOLVER_SOLVABLE_REPO) { Repo *repo = pool_id2repo(pool, what); if (repo) FOR_REPO_SOLVABLES(repo, p, s) - solver_addjobrule(solv, -p, 0, i, weak); + solver_addjobrule2(solv, -p, 0, i, weak); } FOR_JOB_SELECT(p, pp, select, what) { s = pool->solvables + p; if (installed && s->repo == installed) name = !name ? s->name : -1; - solver_addjobrule(solv, -p, 0, i, weak); + solver_addjobrule2(solv, -p, 0, i, weak); } /* special case for "erase a specific solvable": we also * erase all other solvables with that name, so that they @@ -3861,7 +3912,7 @@ solver_solve(Solver *solv, Queue *job) if (solv->rules[j].p == -p) break; if (j == k) - solver_addjobrule(solv, -p, 0, i, weak); /* remove by id */ + solver_addjobrule2(solv, -p, 0, i, weak); /* remove by id */ } } break; @@ -3887,17 +3938,17 @@ solver_solve(Solver *solv, Queue *job) if (select == SOLVER_SOLVABLE_ALL) { FOR_POOL_SOLVABLES(p) - solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak); + solver_addjobrule2(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak); } else if (select == SOLVER_SOLVABLE_REPO) { Repo *repo = pool_id2repo(pool, what); if (repo) FOR_REPO_SOLVABLES(repo, p, s) - solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak); + solver_addjobrule2(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak); } FOR_JOB_SELECT(p, pp, select, what) - solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak); + solver_addjobrule2(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak); break; case SOLVER_DISTUPGRADE: POOL_DEBUG(SOLV_DEBUG_JOB, "job: distupgrade %s\n", solver_select2str(pool, select, what));