From 2d757ccc60324e7bfcc07f6f46d7f38e30642fcb Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Wed, 21 Sep 2022 09:39:09 +0900 Subject: Imported Upstream version 0.7.22 --- src/knownid.h | 3 +- src/libsolv.ver | 1 + src/order.c | 196 ++++++++++++++++++++++++++++++++++++++++++------------ src/repo_write.c | 7 +- src/rules.c | 169 ++++++++++++---------------------------------- src/solver.c | 45 +++++++++++++ src/transaction.h | 2 + 7 files changed, 250 insertions(+), 173 deletions(-) (limited to 'src') diff --git a/src/knownid.h b/src/knownid.h index d131e78..2bb27b2 100644 --- a/src/knownid.h +++ b/src/knownid.h @@ -270,7 +270,8 @@ KNOWNID(SOLVABLE_TRACK_FEATURES, "solvable:track_features"), /* conda */ KNOWNID(SOLVABLE_ISDEFAULT, "solvable:isdefault"), KNOWNID(SOLVABLE_LANGONLY, "solvable:langonly"), -KNOWNID(UPDATE_COLLECTIONLIST, "update:collectionlist"), /* list of UPDATE_COLLECTION (actually packages) and UPDATE_MODULE */ +KNOWNID(UPDATE_COLLECTIONLIST, "update:collectionlist"), /* list of UPDATE_COLLECTION (actually packages) and UPDATE_MODULE */ +KNOWNID(SOLVABLE_MULTIARCH, "solvable:multiarch"), /* debian multi-arch field */ KNOWNID(ID_NUM_INTERNAL, 0) diff --git a/src/libsolv.ver b/src/libsolv.ver index 51819fb..c77f8d3 100644 --- a/src/libsolv.ver +++ b/src/libsolv.ver @@ -434,6 +434,7 @@ SOLV_1.0 { transaction_order_add_choices; transaction_order_get_cycle; transaction_order_get_cycleids; + transaction_order_get_edges; transaction_print; transaction_type; local: diff --git a/src/order.c b/src/order.c index a6be968..f36e446 100644 --- a/src/order.c +++ b/src/order.c @@ -35,19 +35,23 @@ struct s_TransactionOrderdata { Id *invedgedata; int ninvedgedata; Queue *cycles; + Queue *edgedataq; /* from SOLVER_TRANSACTION_KEEP_ORDEREDGES */ }; #define TYPE_BROKEN (1<<0) #define TYPE_CON (1<<1) -#define TYPE_REQ_P (1<<2) -#define TYPE_PREREQ_P (1<<3) +/* uninstall edges */ +#define TYPE_REQ_UI (1<<4) +#define TYPE_PREREQ_UI (1<<5) +#define TYPE_REQ_UU (1<<6) +#define TYPE_PREREQ_UU (1<<7) -#define TYPE_SUG (1<<4) -#define TYPE_REC (1<<5) - -#define TYPE_REQ (1<<6) -#define TYPE_PREREQ (1<<7) +/* install edges */ +#define TYPE_SUG (1<<8) +#define TYPE_REC (1<<9) +#define TYPE_REQ (1<<10) +#define TYPE_PREREQ (1<<11) #define TYPE_CYCLETAIL (1<<16) #define TYPE_CYCLEHEAD (1<<17) @@ -70,6 +74,11 @@ transaction_clone_orderdata(Transaction *trans, Transaction *srctrans) trans->orderdata->cycles = solv_calloc(1, sizeof(Queue)); queue_init_clone(trans->orderdata->cycles, od->cycles); } + if (od->edgedataq) + { + trans->orderdata->edgedataq = solv_calloc(1, sizeof(Queue)); + queue_init_clone(trans->orderdata->edgedataq, od->edgedataq); + } } void @@ -85,6 +94,11 @@ transaction_free_orderdata(Transaction *trans) queue_free(od->cycles); od->cycles = solv_free(od->cycles); } + if (od->edgedataq) + { + queue_init(od->edgedataq); + od->edgedataq = solv_free(od->edgedataq); + } trans->orderdata = solv_free(trans->orderdata); } } @@ -100,6 +114,7 @@ struct orderdata { Queue cycles; Queue cyclesdata; int ncycles; + Queue edgedataq; }; static void @@ -212,27 +227,34 @@ addedge(struct orderdata *od, Id from, Id to, int type) } static inline int -havescripts(Pool *pool, Id solvid) +havescripts(Pool *pool, Id solvid, Queue *ignoreinst) { Solvable *s = pool->solvables + solvid; - const char *dep; if (s->requires) { Id req, *reqp; - int inpre = 0; reqp = s->repo->idarraydata + s->requires; + while ((req = *reqp++) != 0) + if (req == SOLVABLE_PREREQMARKER) + break; + if (!req) + return 0; while ((req = *reqp++) != 0) { - if (req == SOLVABLE_PREREQMARKER) + const char *dep = pool_id2str(pool, req); + if (*dep == '/' && strcmp(dep, "/sbin/ldconfig") != 0) { - inpre = 1; - continue; + if (ignoreinst && ignoreinst->count) + { + int i; + for (i = 0; i < ignoreinst->count; i++) + if (req == ignoreinst->elements[i]) + break; + if (i < ignoreinst->count) + continue; + } + return 1; } - if (!inpre) - continue; - dep = pool_id2str(pool, req); - if (*dep == '/' && strcmp(dep, "/sbin/ldconfig") != 0) - return 1; } } return 0; @@ -247,7 +269,7 @@ addsolvableedges(struct orderdata *od, Solvable *s) int i, j, pre, numins; Repo *installed = pool->installed; Solvable *s2; - Queue depq; + Queue depq, ignoreinst; int provbyinst; #if 0 @@ -255,9 +277,20 @@ addsolvableedges(struct orderdata *od, Solvable *s) #endif p = s - pool->solvables; queue_init(&depq); + queue_init(&ignoreinst); if (s->requires) { Id req, *reqp; + if (installed && s->repo == installed) + { + reqp = s->repo->idarraydata + s->requires; + while ((req = *reqp++) != 0) + if (req == SOLVABLE_PREREQMARKER) + { + solvable_lookup_idarray(s, SOLVABLE_PREREQ_IGNOREINST, &ignoreinst); + break; + } + } reqp = s->repo->idarraydata + s->requires; pre = TYPE_REQ; while ((req = *reqp++) != 0) @@ -267,6 +300,16 @@ addsolvableedges(struct orderdata *od, Solvable *s) pre = TYPE_PREREQ; continue; } + if (pre == TYPE_PREREQ && ignoreinst.count) + { + /* check if this req is filtered. assumes that ignoreinst.count is small */ + int i; + for (i = 0; i < ignoreinst.count; i++) + if (req == ignoreinst.elements[i]) + break; + if (i < ignoreinst.count) + continue; + } queue_empty(&depq); numins = 0; /* number of packages to be installed providing it */ provbyinst = 0; /* provided by kept package */ @@ -300,9 +343,9 @@ addsolvableedges(struct orderdata *od, Solvable *s) queue_pushunique(&depq, p2); } } - if (provbyinst) + if (provbyinst && s->repo == installed) { - /* prune to harmless ->inst edges */ + /* prune to harmless uninst->inst edges */ for (i = j = 0; i < depq.count; i++) if (pool->solvables[depq.elements[i]].repo != installed) depq.elements[j++] = depq.elements[i]; @@ -326,7 +369,7 @@ addsolvableedges(struct orderdata *od, Solvable *s) #if 0 printf("add interrreq uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, depq.elements[i]), pool_dep2str(pool, req), pool_solvid2str(pool, depq.elements[j])); #endif - addedge(od, depq.elements[i], depq.elements[j], pre == TYPE_PREREQ ? TYPE_PREREQ_P : TYPE_REQ_P); + addedge(od, depq.elements[i], depq.elements[j], pre == TYPE_PREREQ ? TYPE_PREREQ_UI : TYPE_REQ_UI); } } } @@ -344,7 +387,7 @@ addsolvableedges(struct orderdata *od, Solvable *s) if (pool->solvables[p2].repo != installed) { /* all elements of depq are installs, thus have different TEs */ - if (pool->solvables[p].repo != installed) + if (s->repo != installed) { #if 0 printf("add inst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, req), pool_solvid2str(pool, p2)); @@ -356,7 +399,7 @@ addsolvableedges(struct orderdata *od, Solvable *s) #if 0 printf("add uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, req), pool_solvid2str(pool, p2)); #endif - addedge(od, p, p2, pre == TYPE_PREREQ ? TYPE_PREREQ_P : TYPE_REQ_P); + addedge(od, p, p2, pre == TYPE_PREREQ ? TYPE_PREREQ_UI : TYPE_REQ_UI); } } else @@ -365,16 +408,16 @@ addsolvableedges(struct orderdata *od, Solvable *s) continue; /* no inst->uninst edges, please! */ /* uninst -> uninst edge. Those make trouble. Only add if we must */ - if (trans->transaction_installed[p - installed->start] && !havescripts(pool, p)) + if (trans->transaction_installed[p - installed->start] && !havescripts(pool, p, &ignoreinst)) { /* p is obsoleted by another package and has no scripts */ - /* we assume that the obsoletor is good enough to replace p */ + /* we assume that the obsoleter is good enough to replace p */ continue; } #if 0 printf("add uninst->uninst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, req), pool_solvid2str(pool, p2)); #endif - addedge(od, p2, p, pre == TYPE_PREREQ ? TYPE_PREREQ_P : TYPE_REQ_P); + addedge(od, p2, p, pre == TYPE_PREREQ ? TYPE_PREREQ_UU : TYPE_REQ_UU); } } } @@ -515,9 +558,25 @@ addsolvableedges(struct orderdata *od, Solvable *s) } } } + queue_free(&ignoreinst); queue_free(&depq); } +static inline int +scriptletedge(Pool *pool, struct orderdata *od, Id *cycle, int k) +{ + int deg = od->edgedata[cycle[k + 1] + 1]; + if ((deg & TYPE_REQ_UU) || (deg & TYPE_PREREQ_UU)) + { + /* the UU edges are reverse edges, so we have to check the next element for scripts */ + if (havescripts(pool, od->tes[cycle[k + 2]].p, 0)) + return 1; + deg &= ~(TYPE_REQ_UU | TYPE_PREREQ_UU); + } + if (deg && havescripts(pool, od->tes[cycle[k]].p, 0)) + return 1; + return 0; +} /* break an edge in a cycle */ static void @@ -533,23 +592,31 @@ breakcycle(struct orderdata *od, Id *cycle) for (k = 0; cycle[k + 1]; k += 2) { ddeg = od->edgedata[cycle[k + 1] + 1]; + /* map UU to UI for the comparison */ + if (ddeg & TYPE_REQ_UU) + { + ddeg ^= TYPE_REQ_UU; + ddeg |= TYPE_REQ_UI; + } + if (ddeg & TYPE_PREREQ_UU) + { + ddeg ^= TYPE_PREREQ_UU; + ddeg |= TYPE_PREREQ_UI; + } if (ddeg > ddegmax) ddegmax = ddeg; if (!k || ddeg < ddegmin) { l = k; ddegmin = ddeg; - continue; } - if (ddeg == ddegmin) + else if (ddeg == ddegmin) { - if (havescripts(pool, od->tes[cycle[l]].p) && !havescripts(pool, od->tes[cycle[k]].p)) + if (scriptletedge(pool, od, cycle, l) && !scriptletedge(pool, od, cycle, k)) { /* prefer k, as l comes from a package with contains scriptlets */ l = k; - continue; } - /* same edge value, check for prereq */ } } @@ -573,10 +640,11 @@ breakcycle(struct orderdata *od, Id *cycle) /* break that edge */ od->edgedata[cycle[l + 1] + 1] |= TYPE_BROKEN; -#if 1 - if (ddegmin < TYPE_REQ) + + IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS) + ; + else if (ddegmin < TYPE_REQ) return; -#endif /* cycle recorded, print it */ if (ddegmin >= TYPE_REQ && (ddegmax & TYPE_PREREQ) != 0) @@ -807,12 +875,7 @@ transaction_order(Transaction *trans, int flags) POOL_DEBUG(SOLV_DEBUG_STATS, "ordering transaction\n"); /* free old data if present */ if (trans->orderdata) - { - struct s_TransactionOrderdata *od = trans->orderdata; - od->tes = solv_free(od->tes); - od->invedgedata = solv_free(od->invedgedata); - trans->orderdata = solv_free(trans->orderdata); - } + transaction_free_orderdata(trans); /* create a transaction element for every active component */ numte = 0; @@ -837,6 +900,8 @@ transaction_order(Transaction *trans, int flags) od.edgedata[0] = 0; od.nedgedata = 1; queue_init(&od.cycles); + queue_init(&od.cyclesdata); + queue_init(&od.edgedataq); /* initialize TEs */ for (i = 0, te = od.tes + 1; i < tr->count; i++) @@ -974,6 +1039,14 @@ transaction_order(Transaction *trans, int flags) #if 0 dump_tes(&od); #endif + if ((flags & SOLVER_TRANSACTION_KEEP_ORDEREDGES) != 0) + { + queue_insertn(&od.edgedataq, 0, od.nedgedata, od.edgedata); + queue_insertn(&od.edgedataq, 0, numte, 0); + for (i = 1, te = od.tes + i; i < numte; i++, te++) + od.edgedataq.elements[i] = te->edges + numte; + } + /* all edges are finally set up and there are no cycles, now the easy part. * Create an ordered transaction */ now = solv_timems(0); @@ -1143,7 +1216,7 @@ printf("free %s [%d]\n", pool_solvid2str(pool, te2->p), temedianr[od.invedgedata POOL_DEBUG(SOLV_DEBUG_STATS, "creating new transaction took %d ms\n", solv_timems(now)); POOL_DEBUG(SOLV_DEBUG_STATS, "transaction ordering took %d ms\n", solv_timems(start)); - if ((flags & (SOLVER_TRANSACTION_KEEP_ORDERDATA | SOLVER_TRANSACTION_KEEP_ORDERCYCLES)) != 0) + if ((flags & (SOLVER_TRANSACTION_KEEP_ORDERDATA | SOLVER_TRANSACTION_KEEP_ORDERCYCLES | SOLVER_TRANSACTION_KEEP_ORDEREDGES)) != 0) { struct s_TransactionOrderdata *tod; trans->orderdata = tod = solv_calloc(1, sizeof(*trans->orderdata)); @@ -1158,7 +1231,7 @@ printf("free %s [%d]\n", pool_solvid2str(pool, te2->p), temedianr[od.invedgedata queue_insertn(cycles, cycles->count, od.cycles.count, od.cycles.elements); queue_push(cycles, od.cycles.count / 4); } - if ((flags & SOLVER_TRANSACTION_KEEP_ORDERDATA) != 0) + if ((flags & (SOLVER_TRANSACTION_KEEP_ORDERDATA | SOLVER_TRANSACTION_KEEP_ORDEREDGES)) != 0) { tod->tes = od.tes; tod->ntes = numte; @@ -1167,10 +1240,16 @@ printf("free %s [%d]\n", pool_solvid2str(pool, te2->p), temedianr[od.invedgedata od.tes = 0; od.invedgedata = 0; } + if ((flags & SOLVER_TRANSACTION_KEEP_ORDEREDGES) != 0) + { + Queue *edgedataq = tod->edgedataq = solv_calloc(1, sizeof(Queue)); + queue_init_clone(edgedataq, &od.edgedataq); + } } solv_free(od.tes); solv_free(od.invedgedata); queue_free(&od.cycles); + queue_free(&od.edgedataq); queue_free(&od.cyclesdata); } @@ -1375,7 +1454,7 @@ transaction_check_order(Transaction *trans) lastins = p; if (s->repo != pool->installed) MAPSET(&ins, p); - if (havescripts(pool, p)) + if (havescripts(pool, p, 0)) { MAPZERO(&seen); transaction_check_pkg(trans, p, p, &ins, &seen, 1, lastins, 0); @@ -1445,3 +1524,32 @@ transaction_order_get_cycle(Transaction *trans, Id cid, Queue *q) return severity; } +void +transaction_order_get_edges(Transaction *trans, Id p, Queue *q, int unbroken) +{ + struct s_TransactionOrderdata *od = trans->orderdata; + struct s_TransactionElement *te; + int i; + Queue *eq; + + queue_empty(q); + if (!od || !od->edgedataq) + return; + for (i = 1, te = od->tes + i; i < od->ntes; i++, te++) + if (te->p == p) + break; + if (i == od->ntes) + return; + eq = od->edgedataq; + for (i = eq->elements[i]; eq->elements[i]; i += 2) + { + int type = eq->elements[i + 1]; + if (unbroken) + { + type &= ~(TYPE_BROKEN | TYPE_CYCLETAIL | TYPE_CYCLEHEAD); + if (type == 0) + continue; + } + queue_push2(q, od->tes[eq->elements[i]].p, type); + } +} diff --git a/src/repo_write.c b/src/repo_write.c index b3a6bbc..a73eebf 100644 --- a/src/repo_write.c +++ b/src/repo_write.c @@ -1179,9 +1179,9 @@ repowriter_set_userdata(Repowriter *writer, const void *data, int len) { writer->userdata = solv_free(writer->userdata); writer->userdatalen = 0; - if (len < 0 || len >= 65536) + if (len <= 0) return; - writer->userdata = len ? solv_memdup(data, len) : 0; + writer->userdata = solv_memdup(data, len); writer->userdatalen = len; } @@ -1249,6 +1249,9 @@ repowriter_write(Repowriter *writer, FILE *fp) Id type_constantid = 0; + /* sanity checks */ + if (writer->userdatalen < 0 || writer->userdatalen >= 65536) + return pool_error(pool, -1, "illegal userdata length: %d", writer->userdatalen); memset(&cbdata, 0, sizeof(cbdata)); cbdata.pool = pool; diff --git a/src/rules.c b/src/rules.c index a260c2d..2c56959 100644 --- a/src/rules.c +++ b/src/rules.c @@ -3255,6 +3255,12 @@ solver_rule2rules(Solver *solv, Id rid, Queue *q, int recursive) /* check if the newest versions of pi still provides the dependency we're looking for */ +/* pi: installed package + * r: rule for the dependency + * m: map with all positive elements of r + * return 0: at least one provider + * return 1: the newest versions do not provide the dependency + */ static int solver_choicerulecheck(Solver *solv, Id pi, Rule *r, Map *m, Queue *q) { @@ -3303,94 +3309,6 @@ solver_choicerulecheck(Solver *solv, Id pi, Rule *r, Map *m, Queue *q) return 1; /* none of the new packages provided it */ } -static int -solver_choicerulecheck2(Solver *solv, Id pi, Id pt, Queue *q) -{ - Pool *pool = solv->pool; - Rule *ur; - Id p, pp; - int i; - - if (!q->count || q->elements[0] != pi) - { - if (q->count) - queue_empty(q); - ur = solv->rules + solv->updaterules + (pi - pool->installed->start); - if (!ur->p) - ur = solv->rules + solv->featurerules + (pi - pool->installed->start); - if (!ur->p) - return 1; /* orphaned, thus newest */ - queue_push2(q, pi, 0); - FOR_RULELITERALS(p, pp, ur) - if (p > 0 && p != pi) - queue_push(q, p); - queue_push(q, pi); - } - if (q->count <= 3) - return q->count == 3 && q->elements[2] == pt ? 1 : 0; - if (!q->elements[1]) - { - queue_deleten(q, 0, 2); - policy_filter_unwanted(solv, q, POLICY_MODE_CHOOSE); - queue_unshift(q, 1); /* filter mark */ - queue_unshift(q, pi); - } - for (i = 2; i < q->count; i++) - if (q->elements[i] == pt) - return 1; - return 0; /* not newest */ -} - -static int -solver_choicerulecheck3(Solver *solv, Id pt, Queue *q) -{ - Pool *pool = solv->pool; - Id p, pp; - int i; - - if (!q->count || q->elements[0] != pt) - { - Solvable *s = pool->solvables + pt; - if (q->count) - queue_empty(q); - /* no installed package, so check all with same name */ - queue_push2(q, pt, 0); - FOR_PROVIDES(p, pp, s->name) - if (pool->solvables[p].name == s->name && p != pt) - queue_push(q, p); - queue_push(q, pt); - } - if (q->count <= 3) - return q->count == 3 && q->elements[2] == pt ? 1 : 0; - if (!q->elements[1]) - { - queue_deleten(q, 0, 2); - policy_filter_unwanted(solv, q, POLICY_MODE_CHOOSE); - queue_unshift(q, 1); /* filter mark */ - queue_unshift(q, pt); - } - for (i = 2; i < q->count; i++) - if (q->elements[i] == pt) - return 1; - return 0; /* not newest */ -} - -static inline void -queue_removeelement(Queue *q, Id el) -{ - int i, j; - for (i = 0; i < q->count; i++) - if (q->elements[i] == el) - break; - if (i < q->count) - { - for (j = i++; i < q->count; i++) - if (q->elements[i] != el) - q->elements[j++] = q->elements[i]; - queue_truncate(q, j); - } -} - static Id choicerule_find_installed(Pool *pool, Id p) { @@ -3439,14 +3357,14 @@ solver_addchoicerules(Solver *solv) Pool *pool = solv->pool; Map m, mneg; Rule *r; - Queue q, qi, qcheck, qcheck2, infoq; + Queue q, qi, qcheck, infoq; int i, j, rid, havechoice, negcnt; Id p, d, pp, p2; Solvable *s; Id lastaddedp, lastaddedd; int lastaddedcnt; unsigned int now; - int isnewest = 0; + int isinstalled; solv->choicerules = solv->nrules; if (!pool->installed) @@ -3458,7 +3376,6 @@ solver_addchoicerules(Solver *solv) queue_init(&q); queue_init(&qi); queue_init(&qcheck); - queue_init(&qcheck2); queue_init(&infoq); map_init(&m, pool->nsolvables); map_init(&mneg, pool->nsolvables); @@ -3478,20 +3395,28 @@ solver_addchoicerules(Solver *solv) if (r->p >= 0 || ((r->d == 0 || r->d == -1) && r->w2 <= 0)) continue; /* only look at requires rules */ /* solver_printrule(solv, SOLV_DEBUG_RESULT, r); */ - queue_empty(&q); queue_empty(&qi); havechoice = 0; + isinstalled = 0; FOR_RULELITERALS(p, pp, r) { if (p < 0) - continue; + { + Solvable *s = pool->solvables - p; + p2 = s->repo == pool->installed ? -p : 0; + if (p2) + { + if (!(solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, p2 - solv->installed->start)))) + isinstalled = 1; + } + continue; + } s = pool->solvables + p; if (!s->repo) continue; if (s->repo == pool->installed) { queue_push2(&qi, p, p); - queue_push(&q, p); continue; } /* find an installed package p2 that we can update/downgrade to p */ @@ -3503,7 +3428,6 @@ solver_addchoicerules(Solver *solv) if (policy_is_illegal(solv, pool->solvables + p2, s, 0)) continue; queue_push2(&qi, p2, p); - queue_push(&q, p); continue; } /* package p is independent of the installed ones */ @@ -3512,47 +3436,31 @@ solver_addchoicerules(Solver *solv) #if 0 printf("havechoice: %d qcount %d qicount %d\n", havechoice, q.count, qi.count); #endif - if (!havechoice || !q.count || !qi.count) + if (!havechoice || !qi.count) continue; /* no choice */ FOR_RULELITERALS(p, pp, r) if (p > 0) MAPSET(&m, p); - isnewest = 1; - FOR_RULELITERALS(p, pp, r) - { - if (p > 0) - break; - p2 = choicerule_find_installed(pool, -p); - if (p2 && !solver_choicerulecheck2(solv, p2, -p, &qcheck2)) - { - isnewest = 0; - break; - } - if (!p2 && !solver_choicerulecheck3(solv, -p, &qcheck2)) - { - isnewest = 0; - break; - } - } - /* do extra checking */ - for (i = j = 0; i < qi.count; i += 2) + if (!isinstalled) { - p2 = qi.elements[i]; - if (!p2) - continue; - if (isnewest && solver_choicerulecheck(solv, p2, r, &m, &qcheck)) + /* do extra checking for packages related to installed packages */ + for (i = j = 0; i < qi.count; i += 2) { - /* oops, remove element p from q */ - queue_removeelement(&q, qi.elements[i + 1]); - continue; + p2 = qi.elements[i]; + if (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, p2 - solv->installed->start))) + { + if (solver_choicerulecheck(solv, p2, r, &m, &qcheck)) + continue; + } + qi.elements[j++] = p2; + qi.elements[j++] = qi.elements[i + 1]; } - qi.elements[j++] = p2; + queue_truncate(&qi, j); } - queue_truncate(&qi, j); - if (!q.count || !qi.count) + if (!qi.count) { FOR_RULELITERALS(p, pp, r) if (p > 0) @@ -3560,6 +3468,15 @@ solver_addchoicerules(Solver *solv) continue; } + queue_empty(&q); + /* split q from qi */ + for (i = j = 0; i < qi.count; i += 2) + { + queue_push(&q, qi.elements[i + 1]); + qi.elements[j++] = qi.elements[i]; + } + queue_truncate(&qi, j); + /* now check the update rules of the installed package. * if all packages of the update rules are contained in @@ -3579,6 +3496,7 @@ solver_addchoicerules(Solver *solv) break; if (p) break; + /* speed improvement: only check each package once */ for (j = i + 1; j < qi.count; j++) if (qi.elements[i] == qi.elements[j]) qi.elements[j] = 0; @@ -3636,7 +3554,6 @@ solver_addchoicerules(Solver *solv) queue_free(&q); queue_free(&qi); queue_free(&qcheck); - queue_free(&qcheck2); queue_free(&infoq); map_free(&m); map_free(&mneg); diff --git a/src/solver.c b/src/solver.c index 23285ff..28341d6 100644 --- a/src/solver.c +++ b/src/solver.c @@ -2620,6 +2620,43 @@ resolve_orphaned(Solver *solv, int level, int disablerules, Queue *dq, int *reru return level; } +int +solver_check_unneeded_choicerules(Solver *solv) +{ + Pool *pool = solv->pool; + Rule *r, *or; + Id p, pp, p2, pp2; + int i; + int havedisabled = 0; + + /* check if some choice rules could have been broken */ + for (i = solv->choicerules, r = solv->rules + i; i < solv->choicerules_end; i++, r++) + { + if (r->d < 0) + continue; + or = solv->rules + solv->choicerules_info[i - solv->choicerules]; + if (or->d < 0) + continue; + FOR_RULELITERALS(p, pp, or) + { + if (p < 0 || solv->decisionmap[p] <= 0) + continue; + FOR_RULELITERALS(p2, pp2, r) + if (p2 == p) + break; + if (!p2) + { + /* did not find p in choice rule, disable it */ + POOL_DEBUG(SOLV_DEBUG_SOLVER, "disabling unneeded choice rule #%d\n", i); + solver_disablechoicerules(solv, r); + havedisabled = 1; + break; + } + } + } + return havedisabled; +} + /*------------------------------------------------------------------- * * solver_run_sat @@ -2805,6 +2842,14 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) continue; } + if (solv->choicerules != solv->choicerules_end && solver_check_unneeded_choicerules(solv)) + { + POOL_DEBUG(SOLV_DEBUG_SOLVER, "did choice rule minimization, rerunning solver\n"); + solver_reset(solv); + level = 0; /* restart from scratch */ + continue; + } + if (solv->solution_callback) { solv->solution_callback(solv, solv->solution_callback_data); diff --git a/src/transaction.h b/src/transaction.h index 5b01354..001412d 100644 --- a/src/transaction.h +++ b/src/transaction.h @@ -86,6 +86,7 @@ typedef struct s_Transaction { /* order flags */ #define SOLVER_TRANSACTION_KEEP_ORDERDATA (1 << 0) #define SOLVER_TRANSACTION_KEEP_ORDERCYCLES (1 << 1) +#define SOLVER_TRANSACTION_KEEP_ORDEREDGES (1 << 2) /* cycle severities */ #define SOLVER_ORDERCYCLE_HARMLESS 0 @@ -137,6 +138,7 @@ extern void transaction_check_order(Transaction *trans); /* order cycle introspection */ extern void transaction_order_get_cycleids(Transaction *trans, Queue *q, int minseverity); extern int transaction_order_get_cycle(Transaction *trans, Id cid, Queue *q); +extern void transaction_order_get_edges(Transaction *trans, Id p, Queue *q, int unbroken); extern void transaction_free_orderdata(Transaction *trans); extern void transaction_clone_orderdata(Transaction *trans, Transaction *srctrans); -- cgit v1.2.3