1 /* 2 * Copyright (c) 2007-2008, Novell Inc. 3 * 4 * This program is licensed under the BSD license, read LICENSE.BSD 5 * for further information 6 */ 7 8 /* 9 * solver.c 10 * 11 * SAT based dependency solver 12 */ 13 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <unistd.h> 17 #include <string.h> 18 #include <assert.h> 19 20 #include "solver.h" 21 #include "solver_private.h" 22 #include "bitmap.h" 23 #include "pool.h" 24 #include "util.h" 25 #include "policy.h" 26 #include "poolarch.h" 27 #include "solverdebug.h" 28 29 #define RULES_BLOCK 63 30 31 /******************************************************************** 32 * 33 * dependency check helpers 34 * 35 */ 36 37 /*------------------------------------------------------------------- 38 * handle split provides 39 * 40 * a splitprovides dep looks like 41 * namespace:splitprovides(pkg REL_WITH path) 42 * and is only true if pkg is installed and contains the specified path. 43 * we also make sure that pkg is selected for an update, otherwise the 44 * update would always be forced onto the user. 45 */ 46 int 47 solver_splitprovides(Solver *solv, Id dep) 48 { 49 Pool *pool = solv->pool; 50 Id p, pp; 51 Reldep *rd; 52 Solvable *s; 53 54 if (!solv->dosplitprovides || !solv->installed || (!solv->updatemap_all && !solv->updatemap.size)) 55 return 0; 56 if (!ISRELDEP(dep)) 57 return 0; 58 rd = GETRELDEP(pool, dep); 59 if (rd->flags != REL_WITH) 60 return 0; 61 FOR_PROVIDES(p, pp, dep) 62 { 63 /* here we have packages that provide the correct name and contain the path, 64 * now do extra filtering */ 65 s = pool->solvables + p; 66 if (s->repo == solv->installed && s->name == rd->name && 67 (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, p - solv->installed->start)))) 68 return 1; 69 } 70 return 0; 71 } 72 73 74 /*------------------------------------------------------------------- 75 * solver_dep_installed 76 */ 77 78 int 79 solver_dep_installed(Solver *solv, Id dep) 80 { 81 #if 0 82 Pool *pool = solv->pool; 83 Id p, pp; 84 85 if (ISRELDEP(dep)) 86 { 87 Reldep *rd = GETRELDEP(pool, dep); 88 if (rd->flags == REL_AND) 89 { 90 if (!solver_dep_installed(solv, rd->name)) 91 return 0; 92 return solver_dep_installed(solv, rd->evr); 93 } 94 if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED) 95 return solver_dep_installed(solv, rd->evr); 96 } 97 FOR_PROVIDES(p, pp, dep) 98 { 99 if (p == SYSTEMSOLVABLE || (solv->installed && pool->solvables[p].repo == solv->installed)) 100 return 1; 101 } 102 #endif 103 return 0; 104 } 105 106 /* mirrors solver_dep_installed, but returns 2 if a 107 * dependency listed in solv->installsuppdepq was involved */ 108 static int 109 solver_check_installsuppdepq_dep(Solver *solv, Id dep) 110 { 111 Pool *pool = solv->pool; 112 Id p, pp; 113 Queue *q; 114 115 if (ISRELDEP(dep)) 116 { 117 Reldep *rd = GETRELDEP(pool, dep); 118 if (rd->flags == REL_AND) 119 { 120 int r2, r1 = solver_check_installsuppdepq_dep(solv, rd->name); 121 if (!r1) 122 return 0; 123 r2 = solver_check_installsuppdepq_dep(solv, rd->evr); 124 if (!r2) 125 return 0; 126 return r1 == 2 || r2 == 2 ? 2 : 1; 127 } 128 if (rd->flags == REL_OR) 129 { 130 int r2, r1 = solver_check_installsuppdepq_dep(solv, rd->name); 131 r2 = solver_check_installsuppdepq_dep(solv, rd->evr); 132 if (!r1 && !r2) 133 return 0; 134 return r1 == 2 || r2 == 2 ? 2 : 1; 135 } 136 if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) 137 return solver_splitprovides(solv, rd->evr); 138 if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED) 139 return solver_dep_installed(solv, rd->evr); 140 if (rd->flags == REL_NAMESPACE && (q = solv->installsuppdepq) != 0) 141 { 142 int i; 143 for (i = 0; i < q->count; i++) 144 if (q->elements[i] == dep || q->elements[i] == rd->name) 145 return 2; 146 } 147 } 148 FOR_PROVIDES(p, pp, dep) 149 if (solv->decisionmap[p] > 0) 150 return 1; 151 return 0; 152 } 153 154 static int 155 solver_check_installsuppdepq(Solver *solv, Solvable *s) 156 { 157 Id sup, *supp; 158 supp = s->repo->idarraydata + s->supplements; 159 while ((sup = *supp++) != 0) 160 if (solver_check_installsuppdepq_dep(solv, sup) == 2) 161 return 1; 162 return 0; 163 } 164 165 static Id 166 autouninstall(Solver *solv, Id *problem) 167 { 168 Pool *pool = solv->pool; 169 int i; 170 int lastfeature = 0, lastupdate = 0; 171 Id v; 172 Id extraflags = -1; 173 174 for (i = 0; (v = problem[i]) != 0; i++) 175 { 176 if (v < 0) 177 extraflags &= solv->job.elements[-v - 1]; 178 if (v >= solv->featurerules && v < solv->featurerules_end) 179 if (v > lastfeature) 180 lastfeature = v; 181 if (v >= solv->updaterules && v < solv->updaterules_end) 182 { 183 /* check if identical to feature rule */ 184 Id p = solv->rules[v].p; 185 Rule *r; 186 if (p <= 0) 187 continue; 188 r = solv->rules + solv->featurerules + (p - solv->installed->start); 189 if (!r->p) 190 { 191 /* update rule == feature rule */ 192 if (v > lastfeature) 193 lastfeature = v; 194 continue; 195 } 196 if (v > lastupdate) 197 lastupdate = v; 198 } 199 } 200 if (!lastupdate && !lastfeature) 201 return 0; 202 v = lastupdate ? lastupdate : lastfeature; 203 POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "allowuninstall disabling "); 204 solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + v); 205 solver_disableproblem(solv, v); 206 if (extraflags != -1 && (extraflags & SOLVER_CLEANDEPS) != 0 && solv->cleandepsmap.size) 207 { 208 /* add the package to the updatepkgs list, this will automatically turn 209 * on cleandeps mode */ 210 Id p = solv->rules[v].p; 211 if (!solv->cleandeps_updatepkgs) 212 { 213 solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue)); 214 queue_init(solv->cleandeps_updatepkgs); 215 } 216 if (p > 0) 217 { 218 int oldupdatepkgscnt = solv->cleandeps_updatepkgs->count; 219 queue_pushunique(solv->cleandeps_updatepkgs, p); 220 if (solv->cleandeps_updatepkgs->count != oldupdatepkgscnt) 221 solver_disablepolicyrules(solv); 222 } 223 } 224 return v; 225 } 226 227 /************************************************************************/ 228 229 /* 230 * enable/disable learnt rules 231 * 232 * we have enabled or disabled some of our rules. We now reenable all 233 * of our learnt rules except the ones that were learnt from rules that 234 * are now disabled. 235 */ 236 static void 237 enabledisablelearntrules(Solver *solv) 238 { 239 Pool *pool = solv->pool; 240 Rule *r; 241 Id why, *whyp; 242 int i; 243 244 POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "enabledisablelearntrules called\n"); 245 for (i = solv->learntrules, r = solv->rules + i; i < solv->nrules; i++, r++) 246 { 247 whyp = solv->learnt_pool.elements + solv->learnt_why.elements[i - solv->learntrules]; 248 while ((why = *whyp++) != 0) 249 { 250 assert(why > 0 && why < i); 251 if (solv->rules[why].d < 0) 252 break; 253 } 254 /* why != 0: we found a disabled rule, disable the learnt rule */ 255 if (why && r->d >= 0) 256 { 257 IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS) 258 { 259 POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "disabling "); 260 solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r); 261 } 262 solver_disablerule(solv, r); 263 } 264 else if (!why && r->d < 0) 265 { 266 IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS) 267 { 268 POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "re-enabling "); 269 solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r); 270 } 271 solver_enablerule(solv, r); 272 } 273 } 274 } 275 276 277 /* 278 * make assertion rules into decisions 279 * 280 * Go through rules and add direct assertions to the decisionqueue. 281 * If we find a conflict, disable rules and add them to problem queue. 282 */ 283 284 static void 285 makeruledecisions(Solver *solv) 286 { 287 Pool *pool = solv->pool; 288 int i, ri, ii; 289 Rule *r, *rr; 290 Id v, vv; 291 int decisionstart; 292 int record_proof = 1; 293 int oldproblemcount; 294 int havedisabled = 0; 295 296 /* The system solvable is always installed first */ 297 assert(solv->decisionq.count == 0); 298 queue_push(&solv->decisionq, SYSTEMSOLVABLE); 299 queue_push(&solv->decisionq_why, 0); 300 solv->decisionmap[SYSTEMSOLVABLE] = 1; /* installed at level '1' */ 301 302 decisionstart = solv->decisionq.count; 303 for (;;) 304 { 305 /* if we needed to re-run, back up decisions to decisionstart */ 306 while (solv->decisionq.count > decisionstart) 307 { 308 v = solv->decisionq.elements[--solv->decisionq.count]; 309 --solv->decisionq_why.count; 310 vv = v > 0 ? v : -v; 311 solv->decisionmap[vv] = 0; 312 } 313 314 /* note that the ruleassertions queue is ordered */ 315 for (ii = 0; ii < solv->ruleassertions.count; ii++) 316 { 317 ri = solv->ruleassertions.elements[ii]; 318 r = solv->rules + ri; 319 320 if (havedisabled && ri >= solv->learntrules) 321 { 322 /* just started with learnt rule assertions. If we have disabled 323 * some rules, adapt the learnt rule status */ 324 enabledisablelearntrules(solv); 325 havedisabled = 0; 326 } 327 328 if (r->d < 0 || !r->p || r->w2) /* disabled, dummy or no assertion */ 329 continue; 330 331 /* do weak rules in phase 2 */ 332 if (ri < solv->learntrules && MAPTST(&solv->weakrulemap, ri)) 333 continue; 334 335 v = r->p; 336 vv = v > 0 ? v : -v; 337 338 if (!solv->decisionmap[vv]) /* if not yet decided */ 339 { 340 queue_push(&solv->decisionq, v); 341 queue_push(&solv->decisionq_why, r - solv->rules); 342 solv->decisionmap[vv] = v > 0 ? 1 : -1; 343 IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE) 344 { 345 Solvable *s = solv->pool->solvables + vv; 346 if (v < 0) 347 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (assertion)\n", pool_solvable2str(solv->pool, s)); 348 else 349 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing %s (assertion)\n", pool_solvable2str(solv->pool, s)); 350 } 351 continue; 352 } 353 354 /* check against previous decision: is there a conflict? */ 355 if (v > 0 && solv->decisionmap[vv] > 0) /* ok to install */ 356 continue; 357 if (v < 0 && solv->decisionmap[vv] < 0) /* ok to remove */ 358 continue; 359 360 /* 361 * found a conflict! 362 * 363 * The rule (r) we're currently processing says something 364 * different (v = r->p) than a previous decision (decisionmap[abs(v)]) 365 * on this literal 366 */ 367 368 if (ri >= solv->learntrules) 369 { 370 /* conflict with a learnt rule */ 371 /* can happen when packages cannot be installed for multiple reasons. */ 372 /* we disable the learnt rule in this case */ 373 /* (XXX: we should really call analyze_unsolvable_rule here!) */ 374 solver_disablerule(solv, r); 375 continue; 376 } 377 378 /* 379 * find the decision which is the "opposite" of the rule 380 */ 381 for (i = 0; i < solv->decisionq.count; i++) 382 if (solv->decisionq.elements[i] == -v) 383 break; 384 assert(i < solv->decisionq.count); /* assert that we found it */ 385 oldproblemcount = solv->problems.count; 386 387 /* 388 * conflict with system solvable ? 389 */ 390 if (v == -SYSTEMSOLVABLE) 391 { 392 if (record_proof) 393 { 394 queue_push(&solv->problems, solv->learnt_pool.count); 395 queue_push(&solv->learnt_pool, ri); 396 queue_push(&solv->learnt_pool, 0); 397 } 398 else 399 queue_push(&solv->problems, 0); 400 POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with system solvable, disabling rule #%d\n", ri); 401 if (ri >= solv->jobrules && ri < solv->jobrules_end) 402 v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1); 403 else 404 v = ri; 405 queue_push(&solv->problems, v); 406 queue_push(&solv->problems, 0); 407 if (solv->allowuninstall && v >= solv->featurerules && v < solv->updaterules_end) 408 solv->problems.count = oldproblemcount; 409 solver_disableproblem(solv, v); 410 havedisabled = 1; 411 break; /* start over */ 412 } 413 414 assert(solv->decisionq_why.elements[i] > 0); 415 416 /* 417 * conflict with an rpm rule ? 418 */ 419 if (solv->decisionq_why.elements[i] < solv->rpmrules_end) 420 { 421 if (record_proof) 422 { 423 queue_push(&solv->problems, solv->learnt_pool.count); 424 queue_push(&solv->learnt_pool, ri); 425 queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]); 426 queue_push(&solv->learnt_pool, 0); 427 } 428 else 429 queue_push(&solv->problems, 0); 430 assert(v > 0 || v == -SYSTEMSOLVABLE); 431 POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with rpm rule, disabling rule #%d\n", ri); 432 if (ri >= solv->jobrules && ri < solv->jobrules_end) 433 v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1); 434 else 435 v = ri; 436 queue_push(&solv->problems, v); 437 queue_push(&solv->problems, 0); 438 if (solv->allowuninstall && v >= solv->featurerules && v < solv->updaterules_end) 439 solv->problems.count = oldproblemcount; 440 solver_disableproblem(solv, v); 441 havedisabled = 1; 442 break; /* start over */ 443 } 444 445 /* 446 * conflict with another job or update/feature rule 447 */ 448 449 /* record proof */ 450 if (record_proof) 451 { 452 queue_push(&solv->problems, solv->learnt_pool.count); 453 queue_push(&solv->learnt_pool, ri); 454 queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]); 455 queue_push(&solv->learnt_pool, 0); 456 } 457 else 458 queue_push(&solv->problems, 0); 459 460 POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflicting update/job assertions over literal %d\n", vv); 461 462 /* 463 * push all of our rules (can only be feature or job rules) 464 * asserting this literal on the problem stack 465 */ 466 for (i = solv->featurerules, rr = solv->rules + i; i < solv->learntrules; i++, rr++) 467 { 468 if (rr->d < 0 /* disabled */ 469 || rr->w2) /* or no assertion */ 470 continue; 471 if (rr->p != vv /* not affecting the literal */ 472 && rr->p != -vv) 473 continue; 474 if (MAPTST(&solv->weakrulemap, i)) /* weak: silently ignore */ 475 continue; 476 477 POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i); 478 solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + i); 479 480 v = i; 481 if (i >= solv->jobrules && i < solv->jobrules_end) 482 v = -(solv->ruletojob.elements[i - solv->jobrules] + 1); 483 queue_push(&solv->problems, v); 484 } 485 queue_push(&solv->problems, 0); 486 487 if (solv->allowuninstall && (v = autouninstall(solv, solv->problems.elements + oldproblemcount + 1)) != 0) 488 solv->problems.count = oldproblemcount; 489 490 for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++) 491 solver_disableproblem(solv, solv->problems.elements[i]); 492 havedisabled = 1; 493 break; /* start over */ 494 } 495 if (ii < solv->ruleassertions.count) 496 continue; 497 498 /* 499 * phase 2: now do the weak assertions 500 */ 501 for (ii = 0; ii < solv->ruleassertions.count; ii++) 502 { 503 ri = solv->ruleassertions.elements[ii]; 504 r = solv->rules + ri; 505 if (r->d < 0 || r->w2) /* disabled or no assertion */ 506 continue; 507 if (ri >= solv->learntrules || !MAPTST(&solv->weakrulemap, ri)) /* skip non-weak */ 508 continue; 509 v = r->p; 510 vv = v > 0 ? v : -v; 511 512 if (!solv->decisionmap[vv]) /* if not yet decided */ 513 { 514 queue_push(&solv->decisionq, v); 515 queue_push(&solv->decisionq_why, r - solv->rules); 516 solv->decisionmap[vv] = v > 0 ? 1 : -1; 517 IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE) 518 { 519 Solvable *s = solv->pool->solvables + vv; 520 if (v < 0) 521 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (weak assertion)\n", pool_solvable2str(solv->pool, s)); 522 else 523 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing %s (weak assertion)\n", pool_solvable2str(solv->pool, s)); 524 } 525 continue; 526 } 527 /* check against previous decision: is there a conflict? */ 528 if (v > 0 && solv->decisionmap[vv] > 0) 529 continue; 530 if (v < 0 && solv->decisionmap[vv] < 0) 531 continue; 532 533 POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "assertion conflict, but I am weak, disabling "); 534 solver_printrule(solv, SOLV_DEBUG_UNSOLVABLE, r); 535 536 if (ri >= solv->jobrules && ri < solv->jobrules_end) 537 v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1); 538 else 539 v = ri; 540 solver_disableproblem(solv, v); 541 if (v < 0) 542 solver_reenablepolicyrules(solv, -v); 543 havedisabled = 1; 544 break; /* start over */ 545 } 546 if (ii == solv->ruleassertions.count) 547 break; /* finished! */ 548 } 549 } 550 551 552 /********************************************************************/ 553 /* watches */ 554 555 556 /*------------------------------------------------------------------- 557 * makewatches 558 * 559 * initial setup for all watches 560 */ 561 562 static void 563 makewatches(Solver *solv) 564 { 565 Rule *r; 566 int i; 567 int nsolvables = solv->pool->nsolvables; 568 569 solv_free(solv->watches); 570 /* lower half for removals, upper half for installs */ 571 solv->watches = solv_calloc(2 * nsolvables, sizeof(Id)); 572 #if 1 573 /* do it reverse so rpm rules get triggered first (XXX: obsolete?) */ 574 for (i = 1, r = solv->rules + solv->nrules - 1; i < solv->nrules; i++, r--) 575 #else 576 for (i = 1, r = solv->rules + 1; i < solv->nrules; i++, r++) 577 #endif 578 { 579 if (!r->w2) /* assertions do not need watches */ 580 continue; 581 582 /* see addwatches_rule(solv, r) */ 583 r->n1 = solv->watches[nsolvables + r->w1]; 584 solv->watches[nsolvables + r->w1] = r - solv->rules; 585 586 r->n2 = solv->watches[nsolvables + r->w2]; 587 solv->watches[nsolvables + r->w2] = r - solv->rules; 588 } 589 } 590 591 592 /*------------------------------------------------------------------- 593 * 594 * add watches (for a new learned rule) 595 * sets up watches for a single rule 596 * 597 * see also makewatches() above. 598 */ 599 600 static inline void 601 addwatches_rule(Solver *solv, Rule *r) 602 { 603 int nsolvables = solv->pool->nsolvables; 604 605 r->n1 = solv->watches[nsolvables + r->w1]; 606 solv->watches[nsolvables + r->w1] = r - solv->rules; 607 608 r->n2 = solv->watches[nsolvables + r->w2]; 609 solv->watches[nsolvables + r->w2] = r - solv->rules; 610 } 611 612 613 /********************************************************************/ 614 /* 615 * rule propagation 616 */ 617 618 619 /* shortcuts to check if a literal (positive or negative) assignment 620 * evaluates to 'true' or 'false' 621 */ 622 #define DECISIONMAP_TRUE(p) ((p) > 0 ? (decisionmap[p] > 0) : (decisionmap[-p] < 0)) 623 #define DECISIONMAP_FALSE(p) ((p) > 0 ? (decisionmap[p] < 0) : (decisionmap[-p] > 0)) 624 #define DECISIONMAP_UNDEF(p) (decisionmap[(p) > 0 ? (p) : -(p)] == 0) 625 626 /*------------------------------------------------------------------- 627 * 628 * propagate 629 * 630 * make decision and propagate to all rules 631 * 632 * Evaluate each term affected by the decision (linked through watches). 633 * If we find unit rules we make new decisions based on them. 634 * 635 * return : 0 = everything is OK 636 * rule = conflict found in this rule 637 */ 638 639 static Rule * 640 propagate(Solver *solv, int level) 641 { 642 Pool *pool = solv->pool; 643 Id *rp, *next_rp; /* rule pointer, next rule pointer in linked list */ 644 Rule *r; /* rule */ 645 Id p, pkg, other_watch; 646 Id *dp; 647 Id *decisionmap = solv->decisionmap; 648 649 Id *watches = solv->watches + pool->nsolvables; /* place ptr in middle */ 650 651 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate -----\n"); 652 653 /* foreach non-propagated decision */ 654 while (solv->propagate_index < solv->decisionq.count) 655 { 656 /* 657 * 'pkg' was just decided 658 * negate because our watches trigger if literal goes FALSE 659 */ 660 pkg = -solv->decisionq.elements[solv->propagate_index++]; 661 662 IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE) 663 { 664 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagate for decision %d level %d\n", -pkg, level); 665 solver_printruleelement(solv, SOLV_DEBUG_PROPAGATE, 0, -pkg); 666 } 667 668 /* foreach rule where 'pkg' is now FALSE */ 669 for (rp = watches + pkg; *rp; rp = next_rp) 670 { 671 r = solv->rules + *rp; 672 if (r->d < 0) 673 { 674 /* rule is disabled, goto next */ 675 if (pkg == r->w1) 676 next_rp = &r->n1; 677 else 678 next_rp = &r->n2; 679 continue; 680 } 681 682 IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE) 683 { 684 POOL_DEBUG(SOLV_DEBUG_PROPAGATE," watch triggered "); 685 solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r); 686 } 687 688 /* 'pkg' was just decided (was set to FALSE) 689 * 690 * now find other literal watch, check clause 691 * and advance on linked list 692 */ 693 if (pkg == r->w1) 694 { 695 other_watch = r->w2; 696 next_rp = &r->n1; 697 } 698 else 699 { 700 other_watch = r->w1; 701 next_rp = &r->n2; 702 } 703 704 /* 705 * This term is already true (through the other literal) 706 * so we have nothing to do 707 */ 708 if (DECISIONMAP_TRUE(other_watch)) 709 continue; 710 711 /* 712 * The other literal is FALSE or UNDEF 713 * 714 */ 715 716 if (r->d) 717 { 718 /* Not a binary clause, try to move our watch. 719 * 720 * Go over all literals and find one that is 721 * not other_watch 722 * and not FALSE 723 * 724 * (TRUE is also ok, in that case the rule is fulfilled) 725 */ 726 if (r->p /* we have a 'p' */ 727 && r->p != other_watch /* which is not watched */ 728 && !DECISIONMAP_FALSE(r->p)) /* and not FALSE */ 729 { 730 p = r->p; 731 } 732 else /* go find a 'd' to make 'true' */ 733 { 734 /* foreach p in 'd' 735 we just iterate sequentially, doing it in another order just changes the order of decisions, not the decisions itself 736 */ 737 for (dp = pool->whatprovidesdata + r->d; (p = *dp++) != 0;) 738 { 739 if (p != other_watch /* which is not watched */ 740 && !DECISIONMAP_FALSE(p)) /* and not FALSE */ 741 break; 742 } 743 } 744 745 if (p) 746 { 747 /* 748 * if we found some p that is UNDEF or TRUE, move 749 * watch to it 750 */ 751 IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE) 752 { 753 if (p > 0) 754 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, " -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, p)); 755 else 756 POOL_DEBUG(SOLV_DEBUG_PROPAGATE," -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, -p)); 757 } 758 759 *rp = *next_rp; 760 next_rp = rp; 761 762 if (pkg == r->w1) 763 { 764 r->w1 = p; 765 r->n1 = watches[p]; 766 } 767 else 768 { 769 r->w2 = p; 770 r->n2 = watches[p]; 771 } 772 watches[p] = r - solv->rules; 773 continue; 774 } 775 /* search failed, thus all unwatched literals are FALSE */ 776 777 } /* not binary */ 778 779 /* 780 * unit clause found, set literal other_watch to TRUE 781 */ 782 783 if (DECISIONMAP_FALSE(other_watch)) /* check if literal is FALSE */ 784 return r; /* eek, a conflict! */ 785 786 IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE) 787 { 788 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, " unit "); 789 solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r); 790 } 791 792 if (other_watch > 0) 793 decisionmap[other_watch] = level; /* install! */ 794 else 795 decisionmap[-other_watch] = -level; /* remove! */ 796 797 queue_push(&solv->decisionq, other_watch); 798 queue_push(&solv->decisionq_why, r - solv->rules); 799 800 IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE) 801 { 802 if (other_watch > 0) 803 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, " -> decided to install %s\n", pool_solvid2str(pool, other_watch)); 804 else 805 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, " -> decided to conflict %s\n", pool_solvid2str(pool, -other_watch)); 806 } 807 808 } /* foreach rule involving 'pkg' */ 809 810 } /* while we have non-decided decisions */ 811 812 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate end-----\n"); 813 814 return 0; /* all is well */ 815 } 816 817 818 /********************************************************************/ 819 /* Analysis */ 820 821 /*------------------------------------------------------------------- 822 * 823 * analyze 824 * and learn 825 */ 826 827 static int 828 analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *whyp) 829 { 830 Pool *pool = solv->pool; 831 Queue r; 832 Id r_buf[4]; 833 int rlevel = 1; 834 Map seen; /* global? */ 835 Id d, v, vv, *dp, why; 836 int l, i, idx; 837 int num = 0, l1num = 0; 838 int learnt_why = solv->learnt_pool.count; 839 Id *decisionmap = solv->decisionmap; 840 841 queue_init_buffer(&r, r_buf, sizeof(r_buf)/sizeof(*r_buf)); 842 843 POOL_DEBUG(SOLV_DEBUG_ANALYZE, "ANALYZE at %d ----------------------\n", level); 844 map_init(&seen, pool->nsolvables); 845 idx = solv->decisionq.count; 846 for (;;) 847 { 848 IF_POOLDEBUG (SOLV_DEBUG_ANALYZE) 849 solver_printruleclass(solv, SOLV_DEBUG_ANALYZE, c); 850 queue_push(&solv->learnt_pool, c - solv->rules); 851 d = c->d < 0 ? -c->d - 1 : c->d; 852 dp = d ? pool->whatprovidesdata + d : 0; 853 /* go through all literals of the rule */ 854 for (i = -1; ; i++) 855 { 856 if (i == -1) 857 v = c->p; 858 else if (d == 0) 859 v = i ? 0 : c->w2; 860 else 861 v = *dp++; 862 if (v == 0) 863 break; 864 865 if (DECISIONMAP_TRUE(v)) /* the one true literal */ 866 continue; 867 vv = v > 0 ? v : -v; 868 if (MAPTST(&seen, vv)) 869 continue; 870 l = solv->decisionmap[vv]; 871 if (l < 0) 872 l = -l; 873 MAPSET(&seen, vv); /* mark that we also need to look at this literal */ 874 if (l == 1) 875 l1num++; /* need to do this one in level1 pass */ 876 else if (l == level) 877 num++; /* need to do this one as well */ 878 else 879 { 880 queue_push(&r, v); /* not level1 or conflict level, add to new rule */ 881 if (l > rlevel) 882 rlevel = l; 883 } 884 } 885 l1retry: 886 if (!num && !--l1num) 887 break; /* all level 1 literals done */ 888 889 /* find the next literal to investigate */ 890 /* (as num + l1num > 0, we know that we'll always find one) */ 891 for (;;) 892 { 893 assert(idx > 0); 894 v = solv->decisionq.elements[--idx]; 895 vv = v > 0 ? v : -v; 896 if (MAPTST(&seen, vv)) 897 break; 898 } 899 MAPCLR(&seen, vv); 900 901 if (num && --num == 0) 902 { 903 *pr = -v; /* so that v doesn't get lost */ 904 if (!l1num) 905 break; 906 POOL_DEBUG(SOLV_DEBUG_ANALYZE, "got %d involved level 1 decisions\n", l1num); 907 /* clear non-l1 bits from seen map */ 908 for (i = 0; i < r.count; i++) 909 { 910 v = r.elements[i]; 911 MAPCLR(&seen, v > 0 ? v : -v); 912 } 913 /* only level 1 marks left in seen map */ 914 l1num++; /* as l1retry decrements it */ 915 goto l1retry; 916 } 917 918 why = solv->decisionq_why.elements[idx]; 919 if (why <= 0) /* just in case, maybe for SYSTEMSOLVABLE */ 920 goto l1retry; 921 c = solv->rules + why; 922 } 923 map_free(&seen); 924 925 if (r.count == 0) 926 *dr = 0; 927 else if (r.count == 1 && r.elements[0] < 0) 928 *dr = r.elements[0]; 929 else 930 *dr = pool_queuetowhatprovides(pool, &r); 931 IF_POOLDEBUG (SOLV_DEBUG_ANALYZE) 932 { 933 POOL_DEBUG(SOLV_DEBUG_ANALYZE, "learned rule for level %d (am %d)\n", rlevel, level); 934 solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, *pr); 935 for (i = 0; i < r.count; i++) 936 solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, r.elements[i]); 937 } 938 /* push end marker on learnt reasons stack */ 939 queue_push(&solv->learnt_pool, 0); 940 if (whyp) 941 *whyp = learnt_why; 942 queue_free(&r); 943 solv->stats_learned++; 944 return rlevel; 945 } 946 947 948 /*------------------------------------------------------------------- 949 * 950 * solver_reset 951 * 952 * reset all solver decisions 953 * called after rules have been enabled/disabled 954 */ 955 956 void 957 solver_reset(Solver *solv) 958 { 959 Pool *pool = solv->pool; 960 int i; 961 Id v; 962 963 /* rewind all decisions */ 964 for (i = solv->decisionq.count - 1; i >= 0; i--) 965 { 966 v = solv->decisionq.elements[i]; 967 solv->decisionmap[v > 0 ? v : -v] = 0; 968 } 969 queue_empty(&solv->decisionq_why); 970 queue_empty(&solv->decisionq); 971 solv->recommends_index = -1; 972 solv->propagate_index = 0; 973 queue_empty(&solv->branches); 974 975 /* adapt learnt rule status to new set of enabled/disabled rules */ 976 enabledisablelearntrules(solv); 977 978 /* redo all assertion rule decisions */ 979 makeruledecisions(solv); 980 POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "decisions so far: %d\n", solv->decisionq.count); 981 } 982 983 984 /*------------------------------------------------------------------- 985 * 986 * analyze_unsolvable_rule 987 * 988 * recursion helper used by analyze_unsolvable 989 */ 990 991 static void 992 analyze_unsolvable_rule(Solver *solv, Rule *r, Id *lastweakp, Map *rseen) 993 { 994 Pool *pool = solv->pool; 995 int i; 996 Id why = r - solv->rules; 997 998 IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE) 999 solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, r); 1000 if (solv->learntrules && why >= solv->learntrules) 1001 { 1002 if (MAPTST(rseen, why - solv->learntrules)) 1003 return; 1004 MAPSET(rseen, why - solv->learntrules); 1005 for (i = solv->learnt_why.elements[why - solv->learntrules]; solv->learnt_pool.elements[i]; i++) 1006 if (solv->learnt_pool.elements[i] > 0) 1007 analyze_unsolvable_rule(solv, solv->rules + solv->learnt_pool.elements[i], lastweakp, rseen); 1008 return; 1009 } 1010 if (MAPTST(&solv->weakrulemap, why)) 1011 if (!*lastweakp || why > *lastweakp) 1012 *lastweakp = why; 1013 /* do not add rpm rules to problem */ 1014 if (why < solv->rpmrules_end) 1015 return; 1016 /* turn rule into problem */ 1017 if (why >= solv->jobrules && why < solv->jobrules_end) 1018 why = -(solv->ruletojob.elements[why - solv->jobrules] + 1); 1019 /* normalize dup/infarch rules */ 1020 if (why > solv->infarchrules && why < solv->infarchrules_end) 1021 { 1022 Id name = pool->solvables[-solv->rules[why].p].name; 1023 while (why > solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name) 1024 why--; 1025 } 1026 if (why > solv->duprules && why < solv->duprules_end) 1027 { 1028 Id name = pool->solvables[-solv->rules[why].p].name; 1029 while (why > solv->duprules && pool->solvables[-solv->rules[why - 1].p].name == name) 1030 why--; 1031 } 1032 1033 /* return if problem already countains our rule */ 1034 if (solv->problems.count) 1035 { 1036 for (i = solv->problems.count - 1; i >= 0; i--) 1037 if (solv->problems.elements[i] == 0) /* end of last problem reached? */ 1038 break; 1039 else if (solv->problems.elements[i] == why) 1040 return; 1041 } 1042 queue_push(&solv->problems, why); 1043 } 1044 1045 1046 /*------------------------------------------------------------------- 1047 * 1048 * analyze_unsolvable 1049 * 1050 * We know that the problem is not solvable. Record all involved 1051 * rules (i.e. the "proof") into solv->learnt_pool. 1052 * Record the learnt pool index and all non-rpm rules into 1053 * solv->problems. (Our solutions to fix the problems are to 1054 * disable those rules.) 1055 * 1056 * If the proof contains at least one weak rule, we disable the 1057 * last of them. 1058 * 1059 * Otherwise we return 0 if disablerules is not set or disable 1060 * _all_ of the problem rules and return 1. 1061 * 1062 * return: 1 - disabled some rules, try again 1063 * 0 - hopeless 1064 */ 1065 1066 static int 1067 analyze_unsolvable(Solver *solv, Rule *cr, int disablerules) 1068 { 1069 Pool *pool = solv->pool; 1070 Rule *r; 1071 Map seen; /* global to speed things up? */ 1072 Map rseen; 1073 Id d, v, vv, *dp, why; 1074 int l, i, idx; 1075 Id *decisionmap = solv->decisionmap; 1076 int oldproblemcount; 1077 int oldlearntpoolcount; 1078 Id lastweak; 1079 int record_proof = 1; 1080 1081 POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "ANALYZE UNSOLVABLE ----------------------\n"); 1082 solv->stats_unsolvable++; 1083 oldproblemcount = solv->problems.count; 1084 oldlearntpoolcount = solv->learnt_pool.count; 1085 1086 /* make room for proof index */ 1087 /* must update it later, as analyze_unsolvable_rule would confuse 1088 * it with a rule index if we put the real value in already */ 1089 queue_push(&solv->problems, 0); 1090 1091 r = cr; 1092 map_init(&seen, pool->nsolvables); 1093 map_init(&rseen, solv->learntrules ? solv->nrules - solv->learntrules : 0); 1094 if (record_proof) 1095 queue_push(&solv->learnt_pool, r - solv->rules); 1096 lastweak = 0; 1097 analyze_unsolvable_rule(solv, r, &lastweak, &rseen); 1098 d = r->d < 0 ? -r->d - 1 : r->d; 1099 dp = d ? pool->whatprovidesdata + d : 0; 1100 for (i = -1; ; i++) 1101 { 1102 if (i == -1) 1103 v = r->p; 1104 else if (d == 0) 1105 v = i ? 0 : r->w2; 1106 else 1107 v = *dp++; 1108 if (v == 0) 1109 break; 1110 if (DECISIONMAP_TRUE(v)) /* the one true literal */ 1111 continue; 1112 vv = v > 0 ? v : -v; 1113 l = solv->decisionmap[vv]; 1114 if (l < 0) 1115 l = -l; 1116 MAPSET(&seen, vv); 1117 } 1118 idx = solv->decisionq.count; 1119 while (idx > 0) 1120 { 1121 v = solv->decisionq.elements[--idx]; 1122 vv = v > 0 ? v : -v; 1123 if (!MAPTST(&seen, vv)) 1124 continue; 1125 why = solv->decisionq_why.elements[idx]; 1126 assert(why > 0); 1127 if (record_proof) 1128 queue_push(&solv->learnt_pool, why); 1129 r = solv->rules + why; 1130 analyze_unsolvable_rule(solv, r, &lastweak, &rseen); 1131 d = r->d < 0 ? -r->d - 1 : r->d; 1132 dp = d ? pool->whatprovidesdata + d : 0; 1133 for (i = -1; ; i++) 1134 { 1135 if (i == -1) 1136 v = r->p; 1137 else if (d == 0) 1138 v = i ? 0 : r->w2; 1139 else 1140 v = *dp++; 1141 if (v == 0) 1142 break; 1143 if (DECISIONMAP_TRUE(v)) /* the one true literal */ 1144 continue; 1145 vv = v > 0 ? v : -v; 1146 l = solv->decisionmap[vv]; 1147 if (l < 0) 1148 l = -l; 1149 MAPSET(&seen, vv); 1150 } 1151 } 1152 map_free(&seen); 1153 map_free(&rseen); 1154 queue_push(&solv->problems, 0); /* mark end of this problem */ 1155 1156 if (lastweak) 1157 { 1158 /* disable last weak rule */ 1159 solv->problems.count = oldproblemcount; 1160 solv->learnt_pool.count = oldlearntpoolcount; 1161 if (lastweak >= solv->jobrules && lastweak < solv->jobrules_end) 1162 v = -(solv->ruletojob.elements[lastweak - solv->jobrules] + 1); 1163 else 1164 v = lastweak; 1165 POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "disabling "); 1166 solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + lastweak); 1167 if (lastweak >= solv->choicerules && lastweak < solv->choicerules_end) 1168 solver_disablechoicerules(solv, solv->rules + lastweak); 1169 solver_disableproblem(solv, v); 1170 if (v < 0) 1171 solver_reenablepolicyrules(solv, -v); 1172 solver_reset(solv); 1173 return 1; 1174 } 1175 1176 if (solv->allowuninstall && (v = autouninstall(solv, solv->problems.elements + oldproblemcount + 1)) != 0) 1177 { 1178 solv->problems.count = oldproblemcount; 1179 solv->learnt_pool.count = oldlearntpoolcount; 1180 solver_reset(solv); 1181 return 1; 1182 } 1183 1184 /* finish proof */ 1185 if (record_proof) 1186 { 1187 queue_push(&solv->learnt_pool, 0); 1188 solv->problems.elements[oldproblemcount] = oldlearntpoolcount; 1189 } 1190 1191 /* + 2: index + trailing zero */ 1192 if (disablerules && oldproblemcount + 2 < solv->problems.count) 1193 { 1194 for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++) 1195 solver_disableproblem(solv, solv->problems.elements[i]); 1196 /* XXX: might want to enable all weak rules again */ 1197 solver_reset(solv); 1198 return 1; 1199 } 1200 POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "UNSOLVABLE\n"); 1201 return 0; 1202 } 1203 1204 1205 /********************************************************************/ 1206 /* Decision revert */ 1207 1208 /*------------------------------------------------------------------- 1209 * 1210 * revert 1211 * revert decisionq to a level 1212 */ 1213 1214 static void 1215 revert(Solver *solv, int level) 1216 { 1217 Pool *pool = solv->pool; 1218 Id v, vv; 1219 while (solv->decisionq.count) 1220 { 1221 v = solv->decisionq.elements[solv->decisionq.count - 1]; 1222 vv = v > 0 ? v : -v; 1223 if (solv->decisionmap[vv] <= level && solv->decisionmap[vv] >= -level) 1224 break; 1225 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "reverting decision %d at %d\n", v, solv->decisionmap[vv]); 1226 solv->decisionmap[vv] = 0; 1227 solv->decisionq.count--; 1228 solv->decisionq_why.count--; 1229 solv->propagate_index = solv->decisionq.count; 1230 } 1231 while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] <= -level) 1232 { 1233 solv->branches.count--; 1234 while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] >= 0) 1235 solv->branches.count--; 1236 } 1237 solv->recommends_index = -1; 1238 } 1239 1240 1241 /*------------------------------------------------------------------- 1242 * 1243 * watch2onhighest - put watch2 on literal with highest level 1244 */ 1245 1246 static inline void 1247 watch2onhighest(Solver *solv, Rule *r) 1248 { 1249 int l, wl = 0; 1250 Id d, v, *dp; 1251 1252 d = r->d < 0 ? -r->d - 1 : r->d; 1253 if (!d) 1254 return; /* binary rule, both watches are set */ 1255 dp = solv->pool->whatprovidesdata + d; 1256 while ((v = *dp++) != 0) 1257 { 1258 l = solv->decisionmap[v < 0 ? -v : v]; 1259 if (l < 0) 1260 l = -l; 1261 if (l > wl) 1262 { 1263 r->w2 = dp[-1]; 1264 wl = l; 1265 } 1266 } 1267 } 1268 1269 1270 /*------------------------------------------------------------------- 1271 * 1272 * setpropagatelearn 1273 * 1274 * add free decision (solvable to install) to decisionq 1275 * increase level and propagate decision 1276 * return if no conflict. 1277 * 1278 * in conflict case, analyze conflict rule, add resulting 1279 * rule to learnt rule set, make decision from learnt 1280 * rule (always unit) and re-propagate. 1281 * 1282 * returns the new solver level or 0 if unsolvable 1283 * 1284 */ 1285 1286 static int 1287 setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id ruleid) 1288 { 1289 Pool *pool = solv->pool; 1290 Rule *r; 1291 Id p = 0, d = 0; 1292 int l, why; 1293 1294 assert(ruleid >= 0); 1295 if (decision) 1296 { 1297 level++; 1298 if (decision > 0) 1299 solv->decisionmap[decision] = level; 1300 else 1301 solv->decisionmap[-decision] = -level; 1302 queue_push(&solv->decisionq, decision); 1303 queue_push(&solv->decisionq_why, -ruleid); /* <= 0 -> free decision */ 1304 } 1305 for (;;) 1306 { 1307 r = propagate(solv, level); 1308 if (!r) 1309 break; 1310 if (level == 1) 1311 return analyze_unsolvable(solv, r, disablerules); 1312 POOL_DEBUG(SOLV_DEBUG_ANALYZE, "conflict with rule #%d\n", (int)(r - solv->rules)); 1313 l = analyze(solv, level, r, &p, &d, &why); /* learnt rule in p and d */ 1314 assert(l > 0 && l < level); 1315 POOL_DEBUG(SOLV_DEBUG_ANALYZE, "reverting decisions (level %d -> %d)\n", level, l); 1316 level = l; 1317 revert(solv, level); 1318 r = solver_addrule(solv, p, d); 1319 assert(r); 1320 assert(solv->learnt_why.count == (r - solv->rules) - solv->learntrules); 1321 queue_push(&solv->learnt_why, why); 1322 if (d) 1323 { 1324 /* at least 2 literals, needs watches */ 1325 watch2onhighest(solv, r); 1326 addwatches_rule(solv, r); 1327 } 1328 else 1329 { 1330 /* learnt rule is an assertion */ 1331 queue_push(&solv->ruleassertions, r - solv->rules); 1332 } 1333 /* the new rule is unit by design */ 1334 solv->decisionmap[p > 0 ? p : -p] = p > 0 ? level : -level; 1335 queue_push(&solv->decisionq, p); 1336 queue_push(&solv->decisionq_why, r - solv->rules); 1337 IF_POOLDEBUG (SOLV_DEBUG_ANALYZE) 1338 { 1339 POOL_DEBUG(SOLV_DEBUG_ANALYZE, "decision: "); 1340 solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, p); 1341 POOL_DEBUG(SOLV_DEBUG_ANALYZE, "new rule: "); 1342 solver_printrule(solv, SOLV_DEBUG_ANALYZE, r); 1343 } 1344 } 1345 return level; 1346 } 1347 1348 1349 /*------------------------------------------------------------------- 1350 * 1351 * select and install 1352 * 1353 * install best package from the queue. We add an extra package, inst, if 1354 * provided. See comment in weak install section. 1355 * 1356 * returns the new solver level or 0 if unsolvable 1357 * 1358 */ 1359 1360 static int 1361 selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid) 1362 { 1363 Pool *pool = solv->pool; 1364 Id p; 1365 int i; 1366 1367 if (dq->count > 1) 1368 policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE); 1369 if (dq->count > 1) 1370 { 1371 /* XXX: didn't we already do that? */ 1372 /* XXX: shouldn't we prefer installed packages? */ 1373 /* XXX: move to policy.c? */ 1374 /* choose the supplemented one */ 1375 for (i = 0; i < dq->count; i++) 1376 if (solver_is_supplementing(solv, pool->solvables + dq->elements[i])) 1377 { 1378 dq->elements[0] = dq->elements[i]; 1379 dq->count = 1; 1380 break; 1381 } 1382 } 1383 if (dq->count > 1) 1384 { 1385 /* multiple candidates, open a branch */ 1386 for (i = 1; i < dq->count; i++) 1387 queue_push(&solv->branches, dq->elements[i]); 1388 queue_push(&solv->branches, -level); 1389 } 1390 p = dq->elements[0]; 1391 1392 POOL_DEBUG(SOLV_DEBUG_POLICY, "installing %s\n", pool_solvid2str(pool, p)); 1393 1394 return setpropagatelearn(solv, level, p, disablerules, ruleid); 1395 } 1396 1397 1398 /********************************************************************/ 1399 /* Main solver interface */ 1400 1401 1402 /*------------------------------------------------------------------- 1403 * 1404 * solver_create 1405 * create solver structure 1406 * 1407 * pool: all available solvables 1408 * installed: installed Solvables 1409 * 1410 * 1411 * Upon solving, rules are created to flag the Solvables 1412 * of the 'installed' Repo as installed. 1413 */ 1414 1415 Solver * 1416 solver_create(Pool *pool) 1417 { 1418 Solver *solv; 1419 solv = (Solver *)solv_calloc(1, sizeof(Solver)); 1420 solv->pool = pool; 1421 solv->installed = pool->installed; 1422 1423 solv->allownamechange = 1; 1424 1425 solv->dup_allowdowngrade = 1; 1426 solv->dup_allownamechange = 1; 1427 solv->dup_allowarchchange = 1; 1428 solv->dup_allowvendorchange = 1; 1429 1430 queue_init(&solv->ruletojob); 1431 queue_init(&solv->decisionq); 1432 queue_init(&solv->decisionq_why); 1433 queue_init(&solv->problems); 1434 queue_init(&solv->orphaned); 1435 queue_init(&solv->learnt_why); 1436 queue_init(&solv->learnt_pool); 1437 queue_init(&solv->branches); 1438 queue_init(&solv->weakruleq); 1439 queue_init(&solv->ruleassertions); 1440 queue_init(&solv->addedmap_deduceq); 1441 1442 queue_push(&solv->learnt_pool, 0); /* so that 0 does not describe a proof */ 1443 1444 map_init(&solv->recommendsmap, pool->nsolvables); 1445 map_init(&solv->suggestsmap, pool->nsolvables); 1446 map_init(&solv->noupdate, solv->installed ? solv->installed->end - solv->installed->start : 0); 1447 solv->recommends_index = 0; 1448 1449 solv->decisionmap = (Id *)solv_calloc(pool->nsolvables, sizeof(Id)); 1450 solv->nrules = 1; 1451 solv->rules = solv_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK); 1452 memset(solv->rules, 0, sizeof(Rule)); 1453 1454 return solv; 1455 } 1456 1457 1458 /*------------------------------------------------------------------- 1459 * 1460 * solver_free 1461 */ 1462 1463 void 1464 solver_free(Solver *solv) 1465 { 1466 queue_free(&solv->job); 1467 queue_free(&solv->ruletojob); 1468 queue_free(&solv->decisionq); 1469 queue_free(&solv->decisionq_why); 1470 queue_free(&solv->learnt_why); 1471 queue_free(&solv->learnt_pool); 1472 queue_free(&solv->problems); 1473 queue_free(&solv->solutions); 1474 queue_free(&solv->orphaned); 1475 queue_free(&solv->branches); 1476 queue_free(&solv->weakruleq); 1477 queue_free(&solv->ruleassertions); 1478 queue_free(&solv->addedmap_deduceq); 1479 if (solv->cleandeps_updatepkgs) 1480 { 1481 queue_free(solv->cleandeps_updatepkgs); 1482 solv->cleandeps_updatepkgs = solv_free(solv->cleandeps_updatepkgs); 1483 } 1484 if (solv->cleandeps_mistakes) 1485 { 1486 queue_free(solv->cleandeps_mistakes); 1487 solv->cleandeps_mistakes = solv_free(solv->cleandeps_mistakes); 1488 } 1489 if (solv->update_targets) 1490 { 1491 queue_free(solv->update_targets); 1492 solv->update_targets = solv_free(solv->update_targets); 1493 } 1494 if (solv->installsuppdepq) 1495 { 1496 queue_free(solv->installsuppdepq); 1497 solv->installsuppdepq = solv_free(solv->installsuppdepq); 1498 } 1499 1500 map_free(&solv->recommendsmap); 1501 map_free(&solv->suggestsmap); 1502 map_free(&solv->noupdate); 1503 map_free(&solv->weakrulemap); 1504 map_free(&solv->multiversion); 1505 1506 map_free(&solv->updatemap); 1507 map_free(&solv->bestupdatemap); 1508 map_free(&solv->fixmap); 1509 map_free(&solv->dupmap); 1510 map_free(&solv->dupinvolvedmap); 1511 map_free(&solv->droporphanedmap); 1512 map_free(&solv->cleandepsmap); 1513 1514 solv_free(solv->decisionmap); 1515 solv_free(solv->rules); 1516 solv_free(solv->watches); 1517 solv_free(solv->obsoletes); 1518 solv_free(solv->obsoletes_data); 1519 solv_free(solv->multiversionupdaters); 1520 solv_free(solv->choicerules_ref); 1521 solv_free(solv->bestrules_pkg); 1522 solv_free(solv); 1523 } 1524 1525 int 1526 solver_get_flag(Solver *solv, int flag) 1527 { 1528 switch (flag) 1529 { 1530 case SOLVER_FLAG_ALLOW_DOWNGRADE: 1531 return solv->allowdowngrade; 1532 case SOLVER_FLAG_ALLOW_NAMECHANGE: 1533 return solv->allownamechange; 1534 case SOLVER_FLAG_ALLOW_ARCHCHANGE: 1535 return solv->allowarchchange; 1536 case SOLVER_FLAG_ALLOW_VENDORCHANGE: 1537 return solv->allowvendorchange; 1538 case SOLVER_FLAG_ALLOW_UNINSTALL: 1539 return solv->allowuninstall; 1540 case SOLVER_FLAG_NO_UPDATEPROVIDE: 1541 return solv->noupdateprovide; 1542 case SOLVER_FLAG_SPLITPROVIDES: 1543 return solv->dosplitprovides; 1544 case SOLVER_FLAG_IGNORE_RECOMMENDED: 1545 return solv->dontinstallrecommended; 1546 case SOLVER_FLAG_ADD_ALREADY_RECOMMENDED: 1547 return solv->addalreadyrecommended; 1548 case SOLVER_FLAG_NO_INFARCHCHECK: 1549 return solv->noinfarchcheck; 1550 case SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES: 1551 return solv->keepexplicitobsoletes; 1552 case SOLVER_FLAG_BEST_OBEY_POLICY: 1553 return solv->bestobeypolicy; 1554 case SOLVER_FLAG_NO_AUTOTARGET: 1555 return solv->noautotarget; 1556 default: 1557 break; 1558 } 1559 return -1; 1560 } 1561 1562 int 1563 solver_set_flag(Solver *solv, int flag, int value) 1564 { 1565 int old = solver_get_flag(solv, flag); 1566 switch (flag) 1567 { 1568 case SOLVER_FLAG_ALLOW_DOWNGRADE: 1569 solv->allowdowngrade = value; 1570 break; 1571 case SOLVER_FLAG_ALLOW_NAMECHANGE: 1572 solv->allownamechange = value; 1573 break; 1574 case SOLVER_FLAG_ALLOW_ARCHCHANGE: 1575 solv->allowarchchange = value; 1576 break; 1577 case SOLVER_FLAG_ALLOW_VENDORCHANGE: 1578 solv->allowvendorchange = value; 1579 break; 1580 case SOLVER_FLAG_ALLOW_UNINSTALL: 1581 solv->allowuninstall = value; 1582 break; 1583 case SOLVER_FLAG_NO_UPDATEPROVIDE: 1584 solv->noupdateprovide = value; 1585 break; 1586 case SOLVER_FLAG_SPLITPROVIDES: 1587 solv->dosplitprovides = value; 1588 break; 1589 case SOLVER_FLAG_IGNORE_RECOMMENDED: 1590 solv->dontinstallrecommended = value; 1591 break; 1592 case SOLVER_FLAG_ADD_ALREADY_RECOMMENDED: 1593 solv->addalreadyrecommended = value; 1594 break; 1595 case SOLVER_FLAG_NO_INFARCHCHECK: 1596 solv->noinfarchcheck = value; 1597 break; 1598 case SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES: 1599 solv->keepexplicitobsoletes = value; 1600 break; 1601 case SOLVER_FLAG_BEST_OBEY_POLICY: 1602 solv->bestobeypolicy = value; 1603 break; 1604 case SOLVER_FLAG_NO_AUTOTARGET: 1605 solv->noautotarget = value; 1606 break; 1607 default: 1608 break; 1609 } 1610 return old; 1611 } 1612 1613 int 1614 cleandeps_check_mistakes(Solver *solv, int level) 1615 { 1616 Pool *pool = solv->pool; 1617 Rule *r; 1618 Id p, pp; 1619 int i; 1620 int mademistake = 0; 1621 1622 if (!solv->cleandepsmap.size) 1623 return 0; 1624 /* check for mistakes */ 1625 for (i = solv->installed->start; i < solv->installed->end; i++) 1626 { 1627 if (!MAPTST(&solv->cleandepsmap, i - solv->installed->start)) 1628 continue; 1629 r = solv->rules + solv->featurerules + (i - solv->installed->start); 1630 /* a mistake is when the featurerule is true but the updaterule is false */ 1631 if (!r->p) 1632 continue; 1633 FOR_RULELITERALS(p, pp, r) 1634 if (p > 0 && solv->decisionmap[p] > 0) 1635 break; 1636 if (!p) 1637 continue; /* feature rule is not true */ 1638 r = solv->rules + solv->updaterules + (i - solv->installed->start); 1639 if (!r->p) 1640 continue; 1641 FOR_RULELITERALS(p, pp, r) 1642 if (p > 0 && solv->decisionmap[p] > 0) 1643 break; 1644 if (p) 1645 continue; /* update rule is true */ 1646 POOL_DEBUG(SOLV_DEBUG_SOLVER, "cleandeps mistake: "); 1647 solver_printruleclass(solv, SOLV_DEBUG_SOLVER, r); 1648 POOL_DEBUG(SOLV_DEBUG_SOLVER, "feature rule: "); 1649 solver_printruleclass(solv, SOLV_DEBUG_SOLVER, solv->rules + solv->featurerules + (i - solv->installed->start)); 1650 if (!solv->cleandeps_mistakes) 1651 { 1652 solv->cleandeps_mistakes = solv_calloc(1, sizeof(Queue)); 1653 queue_init(solv->cleandeps_mistakes); 1654 } 1655 queue_push(solv->cleandeps_mistakes, i); 1656 MAPCLR(&solv->cleandepsmap, i - solv->installed->start); 1657 solver_reenablepolicyrules_cleandeps(solv, i); 1658 mademistake = 1; 1659 } 1660 if (mademistake) 1661 solver_reset(solv); 1662 return mademistake; 1663 } 1664 1665 static void 1666 prune_to_update_targets(Solver *solv, Id *cp, Queue *q) 1667 { 1668 int i, j; 1669 Id p, *cp2; 1670 for (i = j = 0; i < q->count; i++) 1671 { 1672 p = q->elements[i]; 1673 for (cp2 = cp; *cp2; cp2++) 1674 if (*cp2 == p) 1675 { 1676 q->elements[j++] = p; 1677 break; 1678 } 1679 } 1680 queue_truncate(q, j); 1681 } 1682 1683 /*------------------------------------------------------------------- 1684 * 1685 * solver_run_sat 1686 * 1687 * all rules have been set up, now actually run the solver 1688 * 1689 */ 1690 1691 void 1692 solver_run_sat(Solver *solv, int disablerules, int doweak) 1693 { 1694 Queue dq; /* local decisionqueue */ 1695 Queue dqs; /* local decisionqueue for supplements */ 1696 int systemlevel; 1697 int level, olevel; 1698 Rule *r; 1699 int i, j, n; 1700 Solvable *s; 1701 Pool *pool = solv->pool; 1702 Id p, pp, *dp; 1703 int minimizationsteps; 1704 int installedpos = solv->installed ? solv->installed->start : 0; 1705 1706 IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION) 1707 { 1708 POOL_DEBUG (SOLV_DEBUG_RULE_CREATION, "number of rules: %d\n", solv->nrules); 1709 for (i = 1; i < solv->nrules; i++) 1710 solver_printruleclass(solv, SOLV_DEBUG_RULE_CREATION, solv->rules + i); 1711 } 1712 1713 POOL_DEBUG(SOLV_DEBUG_SOLVER, "initial decisions: %d\n", solv->decisionq.count); 1714 1715 /* start SAT algorithm */ 1716 level = 1; 1717 systemlevel = level + 1; 1718 POOL_DEBUG(SOLV_DEBUG_SOLVER, "solving...\n"); 1719 1720 queue_init(&dq); 1721 queue_init(&dqs); 1722 1723 /* 1724 * here's the main loop: 1725 * 1) propagate new decisions (only needed once) 1726 * 2) fulfill jobs 1727 * 3) try to keep installed packages 1728 * 4) fulfill all unresolved rules 1729 * 5) install recommended packages 1730 * 6) minimalize solution if we had choices 1731 * if we encounter a problem, we rewind to a safe level and restart 1732 * with step 1 1733 */ 1734 1735 minimizationsteps = 0; 1736 for (;;) 1737 { 1738 /* 1739 * initial propagation of the assertions 1740 */ 1741 if (level == 1) 1742 { 1743 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagating (propagate_index: %d; size decisionq: %d)...\n", solv->propagate_index, solv->decisionq.count); 1744 if ((r = propagate(solv, level)) != 0) 1745 { 1746 if (analyze_unsolvable(solv, r, disablerules)) 1747 continue; 1748 level = 0; 1749 break; /* unsolvable */ 1750 } 1751 } 1752 1753 /* 1754 * resolve jobs first 1755 */ 1756 if (level < systemlevel) 1757 { 1758 POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n"); 1759 for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++) 1760 { 1761 Id l; 1762 if (r->d < 0) /* ignore disabled rules */ 1763 continue; 1764 queue_empty(&dq); 1765 FOR_RULELITERALS(l, pp, r) 1766 { 1767 if (l < 0) 1768 { 1769 if (solv->decisionmap[-l] <= 0) 1770 break; 1771 } 1772 else 1773 { 1774 if (solv->decisionmap[l] > 0) 1775 break; 1776 if (solv->decisionmap[l] == 0) 1777 queue_push(&dq, l); 1778 } 1779 } 1780 if (l || !dq.count) 1781 continue; 1782 /* prune to installed if not updating */ 1783 if (dq.count > 1 && solv->installed && !solv->updatemap_all && 1784 !(solv->job.elements[solv->ruletojob.elements[i - solv->jobrules]] & SOLVER_ORUPDATE)) 1785 { 1786 int j, k; 1787 for (j = k = 0; j < dq.count; j++) 1788 { 1789 Solvable *s = pool->solvables + dq.elements[j]; 1790 if (s->repo == solv->installed) 1791 { 1792 dq.elements[k++] = dq.elements[j]; 1793 if (solv->updatemap.size && MAPTST(&solv->updatemap, dq.elements[j] - solv->installed->start)) 1794 { 1795 k = 0; /* package wants to be updated, do not prune */ 1796 break; 1797 } 1798 } 1799 } 1800 if (k) 1801 dq.count = k; 1802 } 1803 olevel = level; 1804 level = selectandinstall(solv, level, &dq, disablerules, i); 1805 if (level == 0) 1806 break; 1807 if (level <= olevel) 1808 break; 1809 } 1810 if (level == 0) 1811 break; /* unsolvable */ 1812 systemlevel = level + 1; 1813 if (i < solv->jobrules_end) 1814 continue; 1815 solv->decisioncnt_update = solv->decisionq.count; 1816 solv->decisioncnt_keep = solv->decisionq.count; 1817 } 1818 1819 /* 1820 * installed packages 1821 */ 1822 if (level < systemlevel && solv->installed && solv->installed->nsolvables && !solv->installed->disabled) 1823 { 1824 Repo *installed = solv->installed; 1825 int pass; 1826 1827 POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving installed packages\n"); 1828 /* we use two passes if we need to update packages 1829 * to create a better user experience */ 1830 for (pass = solv->updatemap.size ? 0 : 1; pass < 2; pass++) 1831 { 1832 int passlevel = level; 1833 if (pass == 1) 1834 solv->decisioncnt_keep = solv->decisionq.count; 1835 /* start with installedpos, the position that gave us problems last time */ 1836 for (i = installedpos, n = installed->start; n < installed->end; i++, n++) 1837 { 1838 Rule *rr; 1839 Id d; 1840 1841 if (i == installed->end) 1842 i = installed->start; 1843 s = pool->solvables + i; 1844 if (s->repo != installed) 1845 continue; 1846 1847 if (solv->decisionmap[i] > 0) 1848 continue; 1849 if (!pass && solv->updatemap.size && !MAPTST(&solv->updatemap, i - installed->start)) 1850 continue; /* updates first */ 1851 r = solv->rules + solv->updaterules + (i - installed->start); 1852 rr = r; 1853 if (!rr->p || rr->d < 0) /* disabled -> look at feature rule */ 1854 rr -= solv->installed->end - solv->installed->start; 1855 if (!rr->p) /* identical to update rule? */ 1856 rr = r; 1857 if (!rr->p) 1858 continue; /* orpaned package */ 1859 1860 /* XXX: noupdate check is probably no longer needed, as all jobs should 1861 * already be satisfied */ 1862 /* Actually we currently still need it because of erase jobs */ 1863 /* if noupdate is set we do not look at update candidates */ 1864 queue_empty(&dq); 1865 if (!MAPTST(&solv->noupdate, i - installed->start) && (solv->decisionmap[i] < 0 || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || rr->p != i)) 1866 { 1867 if (solv->multiversion.size && solv->multiversionupdaters 1868 && (d = solv->multiversionupdaters[i - installed->start]) != 0) 1869 { 1870 /* special multiversion handling, make sure best version is chosen */ 1871 queue_push(&dq, i); 1872 while ((p = pool->whatprovidesdata[d++]) != 0) 1873 if (solv->decisionmap[p] >= 0) 1874 queue_push(&dq, p); 1875 if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start]) 1876 prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq); 1877 if (dq.count) 1878 { 1879 policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE); 1880 p = dq.elements[0]; 1881 if (p != i && solv->decisionmap[p] == 0) 1882 { 1883 rr = solv->rules + solv->featurerules + (i - solv->installed->start); 1884 if (!rr->p) /* update rule == feature rule? */ 1885 rr = rr - solv->featurerules + solv->updaterules; 1886 dq.count = 1; 1887 } 1888 else 1889 dq.count = 0; 1890 } 1891 } 1892 else 1893 { 1894 /* update to best package */ 1895 FOR_RULELITERALS(p, pp, rr) 1896 { 1897 if (solv->decisionmap[p] > 0) 1898 { 1899 dq.count = 0; /* already fulfilled */ 1900 break; 1901 } 1902 if (!solv->decisionmap[p]) 1903 queue_push(&dq, p); 1904 } 1905 } 1906 } 1907 if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start]) 1908 prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq); 1909 /* install best version */ 1910 if (dq.count) 1911 { 1912 olevel = level; 1913 level = selectandinstall(solv, level, &dq, disablerules, rr - solv->rules); 1914 if (level == 0) 1915 { 1916 queue_free(&dq); 1917 queue_free(&dqs); 1918 return; 1919 } 1920 if (level <= olevel) 1921 { 1922 if (level == 1 || level < passlevel) 1923 break; /* trouble */ 1924 if (level < olevel) 1925 n = installed->start; /* redo all */ 1926 i--; 1927 n--; 1928 continue; 1929 } 1930 } 1931 /* if still undecided keep package */ 1932 if (solv->decisionmap[i] == 0) 1933 { 1934 olevel = level; 1935 if (solv->cleandepsmap.size && MAPTST(&solv->cleandepsmap, i - installed->start)) 1936 { 1937 #if 0 1938 POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, i)); 1939 level = setpropagatelearn(solv, level, -i, disablerules, 0); 1940 #else 1941 continue; 1942 #endif 1943 } 1944 else 1945 { 1946 POOL_DEBUG(SOLV_DEBUG_POLICY, "keeping %s\n", pool_solvid2str(pool, i)); 1947 level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules); 1948 } 1949 if (level == 0) 1950 break; 1951 if (level <= olevel) 1952 { 1953 if (level == 1 || level < passlevel) 1954 break; /* trouble */ 1955 if (level < olevel) 1956 n = installed->start; /* redo all */ 1957 i--; 1958 n--; 1959 continue; /* retry with learnt rule */ 1960 } 1961 } 1962 } 1963 if (n < installed->end) 1964 { 1965 installedpos = i; /* retry problem solvable next time */ 1966 break; /* ran into trouble */ 1967 } 1968 installedpos = installed->start; /* reset installedpos */ 1969 } 1970 if (level == 0) 1971 break; /* unsolvable */ 1972 systemlevel = level + 1; 1973 if (pass < 2) 1974 continue; /* had trouble, retry */ 1975 } 1976 1977 if (level < systemlevel) 1978 systemlevel = level; 1979 1980 /* 1981 * decide 1982 */ 1983 solv->decisioncnt_resolve = solv->decisionq.count; 1984 POOL_DEBUG(SOLV_DEBUG_POLICY, "deciding unresolved rules\n"); 1985 for (i = 1, n = 1; n < solv->nrules; i++, n++) 1986 { 1987 if (i == solv->nrules) 1988 i = 1; 1989 r = solv->rules + i; 1990 if (r->d < 0) /* ignore disabled rules */ 1991 continue; 1992 queue_empty(&dq); 1993 if (r->d == 0) 1994 { 1995 /* binary or unary rule */ 1996 /* need two positive undecided literals */ 1997 if (r->p < 0 || r->w2 <= 0) 1998 continue; 1999 if (solv->decisionmap[r->p] || solv->decisionmap[r->w2]) 2000 continue; 2001 queue_push(&dq, r->p); 2002 queue_push(&dq, r->w2); 2003 } 2004 else 2005 { 2006 /* make sure that 2007 * all negative literals are installed 2008 * no positive literal is installed 2009 * i.e. the rule is not fulfilled and we 2010 * just need to decide on the positive literals 2011 */ 2012 if (r->p < 0) 2013 { 2014 if (solv->decisionmap[-r->p] <= 0) 2015 continue; 2016 } 2017 else 2018 { 2019 if (solv->decisionmap[r->p] > 0) 2020 continue; 2021 if (solv->decisionmap[r->p] == 0) 2022 queue_push(&dq, r->p); 2023 } 2024 dp = pool->whatprovidesdata + r->d; 2025 while ((p = *dp++) != 0) 2026 { 2027 if (p < 0) 2028 { 2029 if (solv->decisionmap[-p] <= 0) 2030 break; 2031 } 2032 else 2033 { 2034 if (solv->decisionmap[p] > 0) 2035 break; 2036 if (solv->decisionmap[p] == 0) 2037 queue_push(&dq, p); 2038 } 2039 } 2040 if (p) 2041 continue; 2042 } 2043 IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE) 2044 { 2045 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "unfulfilled "); 2046 solver_printruleclass(solv, SOLV_DEBUG_PROPAGATE, r); 2047 } 2048 /* dq.count < 2 cannot happen as this means that 2049 * the rule is unit */ 2050 assert(dq.count > 1); 2051 2052 /* prune to cleandeps packages */ 2053 if (solv->cleandepsmap.size && solv->installed) 2054 { 2055 Repo *installed = solv->installed; 2056 for (j = 0; j < dq.count; j++) 2057 if (pool->solvables[dq.elements[j]].repo == installed && MAPTST(&solv->cleandepsmap, dq.elements[j] - installed->start)) 2058 break; 2059 if (j < dq.count) 2060 { 2061 dq.elements[0] = dq.elements[j]; 2062 queue_truncate(&dq, 1); 2063 } 2064 } 2065 2066 olevel = level; 2067 level = selectandinstall(solv, level, &dq, disablerules, r - solv->rules); 2068 if (level == 0) 2069 break; /* unsolvable */ 2070 if (level < systemlevel || level == 1) 2071 break; /* trouble */ 2072 /* something changed, so look at all rules again */ 2073 n = 0; 2074 } 2075 2076 if (n != solv->nrules) /* ran into trouble? */ 2077 { 2078 if (level == 0) 2079 break; /* unsolvable */ 2080 continue; /* start over */ 2081 } 2082 2083 /* at this point we have a consistent system. now do the extras... */ 2084 2085 /* first decide leftover cleandeps packages */ 2086 if (solv->cleandepsmap.size && solv->installed) 2087 { 2088 for (p = solv->installed->start; p < solv->installed->end; p++) 2089 { 2090 s = pool->solvables + p; 2091 if (s->repo != solv->installed) 2092 continue; 2093 if (solv->decisionmap[p] == 0 && MAPTST(&solv->cleandepsmap, p - solv->installed->start)) 2094 { 2095 POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, p)); 2096 olevel = level; 2097 level = setpropagatelearn(solv, level, -p, 0, 0); 2098 if (level < olevel) 2099 break; 2100 } 2101 } 2102 if (p < solv->installed->end) 2103 continue; 2104 } 2105 2106 solv->decisioncnt_weak = solv->decisionq.count; 2107 if (doweak) 2108 { 2109 int qcount; 2110 2111 POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended packages\n"); 2112 queue_empty(&dq); /* recommended packages */ 2113 queue_empty(&dqs); /* supplemented packages */ 2114 for (i = 1; i < pool->nsolvables; i++) 2115 { 2116 if (solv->decisionmap[i] < 0) 2117 continue; 2118 if (solv->decisionmap[i] > 0) 2119 { 2120 /* installed, check for recommends */ 2121 Id *recp, rec, pp, p; 2122 s = pool->solvables + i; 2123 if (!solv->addalreadyrecommended && s->repo == solv->installed) 2124 continue; 2125 /* XXX need to special case AND ? */ 2126 if (s->recommends) 2127 { 2128 recp = s->repo->idarraydata + s->recommends; 2129 while ((rec = *recp++) != 0) 2130 { 2131 qcount = dq.count; 2132 FOR_PROVIDES(p, pp, rec) 2133 { 2134 if (solv->decisionmap[p] > 0) 2135 { 2136 dq.count = qcount; 2137 break; 2138 } 2139 else if (solv->decisionmap[p] == 0) 2140 { 2141 if (solv->dupmap_all && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start)))) 2142 continue; 2143 queue_pushunique(&dq, p); 2144 } 2145 } 2146 } 2147 } 2148 } 2149 else 2150 { 2151 s = pool->solvables + i; 2152 if (!s->supplements) 2153 continue; 2154 if (!pool_installable(pool, s)) 2155 continue; 2156 if (!solver_is_supplementing(solv, s)) 2157 continue; 2158 if (solv->dupmap_all && solv->installed && s->repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, i - solv->installed->start)))) 2159 continue; 2160 queue_push(&dqs, i); 2161 } 2162 } 2163 2164 /* filter out all packages obsoleted by installed packages */ 2165 /* this is no longer needed if we have reverse obsoletes */ 2166 if ((dqs.count || dq.count) && solv->installed) 2167 { 2168 Map obsmap; 2169 Id obs, *obsp, po, ppo; 2170 2171 map_init(&obsmap, pool->nsolvables); 2172 for (p = solv->installed->start; p < solv->installed->end; p++) 2173 { 2174 s = pool->solvables + p; 2175 if (s->repo != solv->installed || !s->obsoletes) 2176 continue; 2177 if (solv->decisionmap[p] <= 0) 2178 continue; 2179 if (solv->multiversion.size && MAPTST(&solv->multiversion, p)) 2180 continue; 2181 obsp = s->repo->idarraydata + s->obsoletes; 2182 /* foreach obsoletes */ 2183 while ((obs = *obsp++) != 0) 2184 FOR_PROVIDES(po, ppo, obs) 2185 MAPSET(&obsmap, po); 2186 } 2187 for (i = j = 0; i < dqs.count; i++) 2188 if (!MAPTST(&obsmap, dqs.elements[i])) 2189 dqs.elements[j++] = dqs.elements[i]; 2190 dqs.count = j; 2191 for (i = j = 0; i < dq.count; i++) 2192 if (!MAPTST(&obsmap, dq.elements[i])) 2193 dq.elements[j++] = dq.elements[i]; 2194 dq.count = j; 2195 map_free(&obsmap); 2196 } 2197 2198 /* filter out all already supplemented packages if requested */ 2199 if (!solv->addalreadyrecommended && dqs.count) 2200 { 2201 int dosplitprovides_old = solv->dosplitprovides; 2202 /* turn off all new packages */ 2203 for (i = 0; i < solv->decisionq.count; i++) 2204 { 2205 p = solv->decisionq.elements[i]; 2206 if (p < 0) 2207 continue; 2208 s = pool->solvables + p; 2209 if (s->repo && s->repo != solv->installed) 2210 solv->decisionmap[p] = -solv->decisionmap[p]; 2211 } 2212 solv->dosplitprovides = 0; 2213 /* filter out old supplements */ 2214 for (i = j = 0; i < dqs.count; i++) 2215 { 2216 p = dqs.elements[i]; 2217 s = pool->solvables + p; 2218 if (!s->supplements) 2219 continue; 2220 if (!solver_is_supplementing(solv, s)) 2221 dqs.elements[j++] = p; 2222 else if (solv->installsuppdepq && solver_check_installsuppdepq(solv, s)) 2223 dqs.elements[j++] = p; 2224 } 2225 dqs.count = j; 2226 /* undo turning off */ 2227 for (i = 0; i < solv->decisionq.count; i++) 2228 { 2229 p = solv->decisionq.elements[i]; 2230 if (p < 0) 2231 continue; 2232 s = pool->solvables + p; 2233 if (s->repo && s->repo != solv->installed) 2234 solv->decisionmap[p] = -solv->decisionmap[p]; 2235 } 2236 solv->dosplitprovides = dosplitprovides_old; 2237 } 2238 2239 /* multiversion doesn't mix well with supplements. 2240 * filter supplemented packages where we already decided 2241 * to install a different version (see bnc#501088) */ 2242 if (dqs.count && solv->multiversion.size) 2243 { 2244 for (i = j = 0; i < dqs.count; i++) 2245 { 2246 p = dqs.elements[i]; 2247 if (MAPTST(&solv->multiversion, p)) 2248 { 2249 Id p2, pp2; 2250 s = pool->solvables + p; 2251 FOR_PROVIDES(p2, pp2, s->name) 2252 if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name) 2253 break; 2254 if (p2) 2255 continue; /* ignore this package */ 2256 } 2257 dqs.elements[j++] = p; 2258 } 2259 dqs.count = j; 2260 } 2261 2262 /* make dq contain both recommended and supplemented pkgs */ 2263 if (dqs.count) 2264 { 2265 for (i = 0; i < dqs.count; i++) 2266 queue_pushunique(&dq, dqs.elements[i]); 2267 } 2268 2269 if (dq.count) 2270 { 2271 Map dqmap; 2272 int decisioncount = solv->decisionq.count; 2273 2274 if (dq.count == 1) 2275 { 2276 /* simple case, just one package. no need to choose to best version */ 2277 p = dq.elements[0]; 2278 if (dqs.count) 2279 POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p)); 2280 else 2281 POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p)); 2282 level = setpropagatelearn(solv, level, p, 0, 0); 2283 if (level == 0) 2284 break; 2285 continue; /* back to main loop */ 2286 } 2287 2288 /* filter packages, this gives us the best versions */ 2289 policy_filter_unwanted(solv, &dq, POLICY_MODE_RECOMMEND); 2290 2291 /* create map of result */ 2292 map_init(&dqmap, pool->nsolvables); 2293 for (i = 0; i < dq.count; i++) 2294 MAPSET(&dqmap, dq.elements[i]); 2295 2296 /* install all supplemented packages */ 2297 for (i = 0; i < dqs.count; i++) 2298 { 2299 p = dqs.elements[i]; 2300 if (solv->decisionmap[p] || !MAPTST(&dqmap, p)) 2301 continue; 2302 POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p)); 2303 olevel = level; 2304 level = setpropagatelearn(solv, level, p, 0, 0); 2305 if (level <= olevel) 2306 break; 2307 } 2308 if (i < dqs.count || solv->decisionq.count < decisioncount) 2309 { 2310 map_free(&dqmap); 2311 if (level == 0) 2312 break; 2313 continue; 2314 } 2315 2316 /* install all recommended packages */ 2317 /* more work as we want to created branches if multiple 2318 * choices are valid */ 2319 for (i = 0; i < decisioncount; i++) 2320 { 2321 Id rec, *recp, pp; 2322 p = solv->decisionq.elements[i]; 2323 if (p < 0) 2324 continue; 2325 s = pool->solvables + p; 2326 if (!s->repo || (!solv->addalreadyrecommended && s->repo == solv->installed)) 2327 continue; 2328 if (!s->recommends) 2329 continue; 2330 recp = s->repo->idarraydata + s->recommends; 2331 while ((rec = *recp++) != 0) 2332 { 2333 queue_empty(&dq); 2334 FOR_PROVIDES(p, pp, rec) 2335 { 2336 if (solv->decisionmap[p] > 0) 2337 { 2338 dq.count = 0; 2339 break; 2340 } 2341 else if (solv->decisionmap[p] == 0 && MAPTST(&dqmap, p)) 2342 queue_pushunique(&dq, p); 2343 } 2344 if (!dq.count) 2345 continue; 2346 if (dq.count > 1) 2347 { 2348 /* multiple candidates, open a branch */ 2349 for (i = 1; i < dq.count; i++) 2350 queue_push(&solv->branches, dq.elements[i]); 2351 queue_push(&solv->branches, -level); 2352 } 2353 p = dq.elements[0]; 2354 POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p)); 2355 olevel = level; 2356 level = setpropagatelearn(solv, level, p, 0, 0); 2357 if (level <= olevel || solv->decisionq.count < decisioncount) 2358 break; /* we had to revert some decisions */ 2359 } 2360 if (rec) 2361 break; /* had a problem above, quit loop */ 2362 } 2363 map_free(&dqmap); 2364 if (level == 0) 2365 break; 2366 continue; /* back to main loop so that all deps are checked */ 2367 } 2368 } 2369 2370 solv->decisioncnt_orphan = solv->decisionq.count; 2371 if (solv->dupmap_all && solv->installed) 2372 { 2373 int installedone = 0; 2374 2375 /* let's see if we can install some unsupported package */ 2376 POOL_DEBUG(SOLV_DEBUG_SOLVER, "deciding orphaned packages\n"); 2377 for (i = 0; i < solv->orphaned.count; i++) 2378 { 2379 p = solv->orphaned.elements[i]; 2380 if (solv->decisionmap[p]) 2381 continue; /* already decided */ 2382 if (solv->droporphanedmap_all) 2383 continue; 2384 if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start)) 2385 continue; 2386 POOL_DEBUG(SOLV_DEBUG_SOLVER, "keeping orphaned %s\n", pool_solvid2str(pool, p)); 2387 olevel = level; 2388 level = setpropagatelearn(solv, level, p, 0, 0); 2389 installedone = 1; 2390 if (level < olevel) 2391 break; 2392 } 2393 if (installedone || i < solv->orphaned.count) 2394 { 2395 if (level == 0) 2396 break; 2397 continue; /* back to main loop */ 2398 } 2399 for (i = 0; i < solv->orphaned.count; i++) 2400 { 2401 p = solv->orphaned.elements[i]; 2402 if (solv->decisionmap[p]) 2403 continue; /* already decided */ 2404 POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing orphaned %s\n", pool_solvid2str(pool, p)); 2405 olevel = level; 2406 level = setpropagatelearn(solv, level, -p, 0, 0); 2407 if (level < olevel) 2408 break; 2409 } 2410 if (i < solv->orphaned.count) 2411 { 2412 if (level == 0) 2413 break; 2414 continue; /* back to main loop */ 2415 } 2416 } 2417 2418 if (solv->installed && solv->cleandepsmap.size) 2419 { 2420 if (cleandeps_check_mistakes(solv, level)) 2421 { 2422 level = 1; /* restart from scratch */ 2423 systemlevel = level + 1; 2424 continue; 2425 } 2426 } 2427 2428 if (solv->solution_callback) 2429 { 2430 solv->solution_callback(solv, solv->solution_callback_data); 2431 if (solv->branches.count) 2432 { 2433 int i = solv->branches.count - 1; 2434 int l = -solv->branches.elements[i]; 2435 Id why; 2436 2437 for (; i > 0; i--) 2438 if (solv->branches.elements[i - 1] < 0) 2439 break; 2440 p = solv->branches.elements[i]; 2441 POOL_DEBUG(SOLV_DEBUG_SOLVER, "branching with %s\n", pool_solvid2str(pool, p)); 2442 queue_empty(&dq); 2443 for (j = i + 1; j < solv->branches.count; j++) 2444 queue_push(&dq, solv->branches.elements[j]); 2445 solv->branches.count = i; 2446 level = l; 2447 revert(solv, level); 2448 if (dq.count > 1) 2449 for (j = 0; j < dq.count; j++) 2450 queue_push(&solv->branches, dq.elements[j]); 2451 olevel = level; 2452 why = -solv->decisionq_why.elements[solv->decisionq_why.count]; 2453 assert(why >= 0); 2454 level = setpropagatelearn(solv, level, p, disablerules, why); 2455 if (level == 0) 2456 break; 2457 continue; 2458 } 2459 /* all branches done, we're finally finished */ 2460 break; 2461 } 2462 2463 /* auto-minimization step */ 2464 if (solv->branches.count) 2465 { 2466 int l = 0, lasti = -1, lastl = -1; 2467 Id why; 2468 2469 p = 0; 2470 for (i = solv->branches.count - 1; i >= 0; i--) 2471 { 2472 p = solv->branches.elements[i]; 2473 if (p < 0) 2474 l = -p; 2475 else if (p > 0 && solv->decisionmap[p] > l + 1) 2476 { 2477 lasti = i; 2478 lastl = l; 2479 } 2480 } 2481 if (lasti >= 0) 2482 { 2483 /* kill old solvable so that we do not loop */ 2484 p = solv->branches.elements[lasti]; 2485 solv->branches.elements[lasti] = 0; 2486 POOL_DEBUG(SOLV_DEBUG_SOLVER, "minimizing %d -> %d with %s\n", solv->decisionmap[p], lastl, pool_solvid2str(pool, p)); 2487 minimizationsteps++; 2488 2489 level = lastl; 2490 revert(solv, level); 2491 why = -solv->decisionq_why.elements[solv->decisionq_why.count]; 2492 assert(why >= 0); 2493 olevel = level; 2494 level = setpropagatelearn(solv, level, p, disablerules, why); 2495 if (level == 0) 2496 break; 2497 continue; /* back to main loop */ 2498 } 2499 } 2500 /* no minimization found, we're finally finished! */ 2501 break; 2502 } 2503 2504 POOL_DEBUG(SOLV_DEBUG_STATS, "solver statistics: %d learned rules, %d unsolvable, %d minimization steps\n", solv->stats_learned, solv->stats_unsolvable, minimizationsteps); 2505 2506 POOL_DEBUG(SOLV_DEBUG_STATS, "done solving.\n\n"); 2507 queue_free(&dq); 2508 queue_free(&dqs); 2509 if (level == 0) 2510 { 2511 /* unsolvable */ 2512 solv->decisioncnt_update = solv->decisionq.count; 2513 solv->decisioncnt_keep = solv->decisionq.count; 2514 solv->decisioncnt_resolve = solv->decisionq.count; 2515 solv->decisioncnt_weak = solv->decisionq.count; 2516 solv->decisioncnt_orphan = solv->decisionq.count; 2517 } 2518 #if 0 2519 solver_printdecisionq(solv, SOLV_DEBUG_RESULT); 2520 #endif 2521 } 2522 2523 2524 /*------------------------------------------------------------------- 2525 * 2526 * remove disabled conflicts 2527 * 2528 * purpose: update the decisionmap after some rules were disabled. 2529 * this is used to calculate the suggested/recommended package list. 2530 * Also returns a "removed" list to undo the discisionmap changes. 2531 */ 2532 2533 static void 2534 removedisabledconflicts(Solver *solv, Queue *removed) 2535 { 2536 Pool *pool = solv->pool; 2537 int i, n; 2538 Id p, why, *dp; 2539 Id new; 2540 Rule *r; 2541 Id *decisionmap = solv->decisionmap; 2542 2543 queue_empty(removed); 2544 for (i = 0; i < solv->decisionq.count; i++) 2545 { 2546 p = solv->decisionq.elements[i]; 2547 if (p > 0) 2548 continue; /* conflicts only, please */ 2549 why = solv->decisionq_why.elements[i]; 2550 if (why == 0) 2551 { 2552 /* no rule involved, must be a orphan package drop */ 2553 continue; 2554 } 2555 /* we never do conflicts on free decisions, so there 2556 * must have been an unit rule */ 2557 assert(why > 0); 2558 r = solv->rules + why; 2559 if (r->d < 0 && decisionmap[-p]) 2560 { 2561 /* rule is now disabled, remove from decisionmap */ 2562 POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing conflict for package %s[%d]\n", pool_solvid2str(pool, -p), -p); 2563 queue_push(removed, -p); 2564 queue_push(removed, decisionmap[-p]); 2565 decisionmap[-p] = 0; 2566 } 2567 } 2568 if (!removed->count) 2569 return; 2570 /* we removed some confliced packages. some of them might still 2571 * be in conflict, so search for unit rules and re-conflict */ 2572 new = 0; 2573 for (i = n = 1, r = solv->rules + i; n < solv->nrules; i++, r++, n++) 2574 { 2575 if (i == solv->nrules) 2576 { 2577 i = 1; 2578 r = solv->rules + i; 2579 } 2580 if (r->d < 0) 2581 continue; 2582 if (!r->w2) 2583 { 2584 if (r->p < 0 && !decisionmap[-r->p]) 2585 new = r->p; 2586 } 2587 else if (!r->d) 2588 { 2589 /* binary rule */ 2590 if (r->p < 0 && decisionmap[-r->p] == 0 && DECISIONMAP_FALSE(r->w2)) 2591 new = r->p; 2592 else if (r->w2 < 0 && decisionmap[-r->w2] == 0 && DECISIONMAP_FALSE(r->p)) 2593 new = r->w2; 2594 } 2595 else 2596 { 2597 if (r->p < 0 && decisionmap[-r->p] == 0) 2598 new = r->p; 2599 if (new || DECISIONMAP_FALSE(r->p)) 2600 { 2601 dp = pool->whatprovidesdata + r->d; 2602 while ((p = *dp++) != 0) 2603 { 2604 if (new && p == new) 2605 continue; 2606 if (p < 0 && decisionmap[-p] == 0) 2607 { 2608 if (new) 2609 { 2610 new = 0; 2611 break; 2612 } 2613 new = p; 2614 } 2615 else if (!DECISIONMAP_FALSE(p)) 2616 { 2617 new = 0; 2618 break; 2619 } 2620 } 2621 } 2622 } 2623 if (new) 2624 { 2625 POOL_DEBUG(SOLV_DEBUG_SOLVER, "re-conflicting package %s[%d]\n", pool_solvid2str(pool, -new), -new); 2626 decisionmap[-new] = -1; 2627 new = 0; 2628 n = 0; /* redo all rules */ 2629 } 2630 } 2631 } 2632 2633 static inline void 2634 undo_removedisabledconflicts(Solver *solv, Queue *removed) 2635 { 2636 int i; 2637 for (i = 0; i < removed->count; i += 2) 2638 solv->decisionmap[removed->elements[i]] = removed->elements[i + 1]; 2639 } 2640 2641 2642 /*------------------------------------------------------------------- 2643 * 2644 * weaken solvable dependencies 2645 */ 2646 2647 static void 2648 weaken_solvable_deps(Solver *solv, Id p) 2649 { 2650 int i; 2651 Rule *r; 2652 2653 for (i = 1, r = solv->rules + i; i < solv->rpmrules_end; i++, r++) 2654 { 2655 if (r->p != -p) 2656 continue; 2657 if ((r->d == 0 || r->d == -1) && r->w2 < 0) 2658 continue; /* conflict */ 2659 queue_push(&solv->weakruleq, i); 2660 } 2661 } 2662 2663 2664 /********************************************************************/ 2665 /* main() */ 2666 2667 2668 void 2669 solver_calculate_multiversionmap(Pool *pool, Queue *job, Map *multiversionmap) 2670 { 2671 int i; 2672 Id how, what, select; 2673 Id p, pp; 2674 for (i = 0; i < job->count; i += 2) 2675 { 2676 how = job->elements[i]; 2677 if ((how & SOLVER_JOBMASK) != SOLVER_MULTIVERSION) 2678 continue; 2679 what = job->elements[i + 1]; 2680 select = how & SOLVER_SELECTMASK; 2681 if (!multiversionmap->size) 2682 map_grow(multiversionmap, pool->nsolvables); 2683 if (select == SOLVER_SOLVABLE_ALL) 2684 { 2685 FOR_POOL_SOLVABLES(p) 2686 MAPSET(multiversionmap, p); 2687 } 2688 else if (select == SOLVER_SOLVABLE_REPO) 2689 { 2690 Solvable *s; 2691 Repo *repo = pool_id2repo(pool, what); 2692 if (repo) 2693 FOR_REPO_SOLVABLES(repo, p, s) 2694 MAPSET(multiversionmap, p); 2695 } 2696 FOR_JOB_SELECT(p, pp, select, what) 2697 MAPSET(multiversionmap, p); 2698 } 2699 } 2700 2701 void 2702 solver_calculate_noobsmap(Pool *pool, Queue *job, Map *multiversionmap) 2703 { 2704 solver_calculate_multiversionmap(pool, job, multiversionmap); 2705 } 2706 2707 /* 2708 * add a rule created by a job, record job number and weak flag 2709 */ 2710 static inline void 2711 solver_addjobrule(Solver *solv, Id p, Id d, Id job, int weak) 2712 { 2713 solver_addrule(solv, p, d); 2714 queue_push(&solv->ruletojob, job); 2715 if (weak) 2716 queue_push(&solv->weakruleq, solv->nrules - 1); 2717 } 2718 2719 static inline void 2720 add_cleandeps_package(Solver *solv, Id p) 2721 { 2722 if (!solv->cleandeps_updatepkgs) 2723 { 2724 solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue)); 2725 queue_init(solv->cleandeps_updatepkgs); 2726 } 2727 queue_pushunique(solv->cleandeps_updatepkgs, p); 2728 } 2729 2730 static void 2731 add_update_target(Solver *solv, Id p, Id how) 2732 { 2733 Pool *pool = solv->pool; 2734 Solvable *s = pool->solvables + p; 2735 Repo *installed = solv->installed; 2736 Id pi, pip; 2737 if (!solv->update_targets) 2738 { 2739 solv->update_targets = solv_calloc(1, sizeof(Queue)); 2740 queue_init(solv->update_targets); 2741 } 2742 if (s->repo == installed) 2743 { 2744 queue_push2(solv->update_targets, p, p); 2745 return; 2746 } 2747 FOR_PROVIDES(pi, pip, s->name) 2748 { 2749 Solvable *si = pool->solvables + pi; 2750 if (si->repo != installed || si->name != s->name) 2751 continue; 2752 if (how & SOLVER_FORCEBEST) 2753 { 2754 if (!solv->bestupdatemap.size) 2755 map_grow(&solv->bestupdatemap, installed->end - installed->start); 2756 MAPSET(&solv->bestupdatemap, pi - installed->start); 2757 } 2758 if (how & SOLVER_CLEANDEPS) 2759 add_cleandeps_package(solv, pi); 2760 queue_push2(solv->update_targets, pi, p); 2761 /* check if it's ok to keep the installed package */ 2762 if (s->evr == si->evr && solvable_identical(s, si)) 2763 queue_push2(solv->update_targets, pi, pi); 2764 } 2765 if (s->obsoletes) 2766 { 2767 Id obs, *obsp = s->repo->idarraydata + s->obsoletes; 2768 while ((obs = *obsp++) != 0) 2769 { 2770 FOR_PROVIDES(pi, pip, obs) 2771 { 2772 Solvable *si = pool->solvables + pi; 2773 if (si->repo != installed) 2774 continue; 2775 if (si->name == s->name) 2776 continue; /* already handled above */ 2777 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs)) 2778 continue; 2779 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si)) 2780 continue; 2781 if (how & SOLVER_FORCEBEST) 2782 { 2783 if (!solv->bestupdatemap.size) 2784 map_grow(&solv->bestupdatemap, installed->end - installed->start); 2785 MAPSET(&solv->bestupdatemap, pi - installed->start); 2786 } 2787 if (how & SOLVER_CLEANDEPS) 2788 add_cleandeps_package(solv, pi); 2789 queue_push2(solv->update_targets, pi, p); 2790 } 2791 } 2792 } 2793 } 2794 2795 static int 2796 transform_update_targets_sortfn(const void *ap, const void *bp, void *dp) 2797 { 2798 const Id *a = ap; 2799 const Id *b = bp; 2800 if (a[0] - b[0]) 2801 return a[0] - b[0]; 2802 return a[1] - b[1]; 2803 } 2804 2805 static void 2806 transform_update_targets(Solver *solv) 2807 { 2808 Repo *installed = solv->installed; 2809 Queue *update_targets = solv->update_targets; 2810 int i, j; 2811 Id p, q, lastp, lastq; 2812 2813 if (!update_targets->count) 2814 { 2815 queue_free(update_targets); 2816 solv->update_targets = solv_free(update_targets); 2817 return; 2818 } 2819 if (update_targets->count > 2) 2820 solv_sort(update_targets->elements, update_targets->count >> 1, 2 * sizeof(Id), transform_update_targets_sortfn, solv); 2821 queue_insertn(update_targets, 0, installed->end - installed->start, 0); 2822 lastp = lastq = 0; 2823 for (i = j = installed->end - installed->start; i < update_targets->count; i += 2) 2824 { 2825 if ((p = update_targets->elements[i]) != lastp) 2826 { 2827 if (!solv->updatemap.size) 2828 map_grow(&solv->updatemap, installed->end - installed->start); 2829 MAPSET(&solv->updatemap, p - installed->start); 2830 update_targets->elements[j++] = 0; /* finish old set */ 2831 update_targets->elements[p - installed->start] = j; /* start new set */ 2832 lastp = p; 2833 lastq = 0; 2834 } 2835 if ((q = update_targets->elements[i + 1]) != lastq) 2836 { 2837 update_targets->elements[j++] = q; 2838 lastq = q; 2839 } 2840 } 2841 queue_truncate(update_targets, j); 2842 queue_push(update_targets, 0); /* finish last set */ 2843 } 2844 2845 2846 static void 2847 addedmap2deduceq(Solver *solv, Map *addedmap) 2848 { 2849 Pool *pool = solv->pool; 2850 int i, j; 2851 Id p; 2852 Rule *r; 2853 2854 queue_empty(&solv->addedmap_deduceq); 2855 for (i = 2, j = solv->rpmrules_end - 1; i < pool->nsolvables && j > 0; j--) 2856 { 2857 r = solv->rules + j; 2858 if (r->p >= 0) 2859 continue; 2860 if ((r->d == 0 || r->d == -1) && r->w2 < 0) 2861 continue; 2862 p = -r->p; 2863 if (!MAPTST(addedmap, p)) 2864 { 2865 /* should never happen, but... */ 2866 if (!solv->addedmap_deduceq.count || solv->addedmap_deduceq.elements[solv->addedmap_deduceq.count - 1] != -p) 2867 queue_push(&solv->addedmap_deduceq, -p); 2868 continue; 2869 } 2870 for (; i < p; i++) 2871 if (MAPTST(addedmap, i)) 2872 queue_push(&solv->addedmap_deduceq, i); 2873 if (i == p) 2874 i++; 2875 } 2876 for (; i < pool->nsolvables; i++) 2877 if (MAPTST(addedmap, i)) 2878 queue_push(&solv->addedmap_deduceq, i); 2879 j = 0; 2880 for (i = 2; i < pool->nsolvables; i++) 2881 if (MAPTST(addedmap, i)) 2882 j++; 2883 } 2884 2885 static void 2886 deduceq2addedmap(Solver *solv, Map *addedmap) 2887 { 2888 int j; 2889 Id p; 2890 Rule *r; 2891 for (j = solv->rpmrules_end - 1; j > 0; j--) 2892 { 2893 r = solv->rules + j; 2894 if (r->d < 0 && r->p) 2895 solver_enablerule(solv, r); 2896 if (r->p >= 0) 2897 continue; 2898 if ((r->d == 0 || r->d == -1) && r->w2 < 0) 2899 continue; 2900 p = -r->p; 2901 MAPSET(addedmap, p); 2902 } 2903 for (j = 0; j < solv->addedmap_deduceq.count; j++) 2904 { 2905 p = solv->addedmap_deduceq.elements[j]; 2906 if (p > 0) 2907 MAPSET(addedmap, p); 2908 else 2909 MAPCLR(addedmap, p); 2910 } 2911 } 2912 2913 2914 /* 2915 * 2916 * solve job queue 2917 * 2918 */ 2919 2920 int 2921 solver_solve(Solver *solv, Queue *job) 2922 { 2923 Pool *pool = solv->pool; 2924 Repo *installed = solv->installed; 2925 int i; 2926 int oldnrules, initialnrules; 2927 Map addedmap; /* '1' == have rpm-rules for solvable */ 2928 Map installcandidatemap; 2929 Id how, what, select, name, weak, p, pp, d; 2930 Queue q; 2931 Solvable *s; 2932 Rule *r; 2933 int now, solve_start; 2934 int hasdupjob = 0; 2935 int hasbestinstalljob = 0; 2936 2937 solve_start = solv_timems(0); 2938 2939 /* log solver options */ 2940 POOL_DEBUG(SOLV_DEBUG_STATS, "solver started\n"); 2941 POOL_DEBUG(SOLV_DEBUG_STATS, "dosplitprovides=%d, noupdateprovide=%d, noinfarchcheck=%d\n", solv->dosplitprovides, solv->noupdateprovide, solv->noinfarchcheck); 2942 POOL_DEBUG(SOLV_DEBUG_STATS, "allowuninstall=%d, allowdowngrade=%d, allownamechange=%d, allowarchchange=%d, allowvendorchange=%d\n", solv->allowuninstall, solv->allowdowngrade, solv->allownamechange, solv->allowarchchange, solv->allowvendorchange); 2943 POOL_DEBUG(SOLV_DEBUG_STATS, "promoteepoch=%d, forbidselfconflicts=%d\n", pool->promoteepoch, pool->forbidselfconflicts); 2944 POOL_DEBUG(SOLV_DEBUG_STATS, "obsoleteusesprovides=%d, implicitobsoleteusesprovides=%d, obsoleteusescolors=%d\n", pool->obsoleteusesprovides, pool->implicitobsoleteusesprovides, pool->obsoleteusescolors); 2945 POOL_DEBUG(SOLV_DEBUG_STATS, "dontinstallrecommended=%d, addalreadyrecommended=%d\n", solv->dontinstallrecommended, solv->addalreadyrecommended); 2946 2947 /* create whatprovides if not already there */ 2948 if (!pool->whatprovides) 2949 pool_createwhatprovides(pool); 2950 2951 /* create obsolete index */ 2952 policy_create_obsolete_index(solv); 2953 2954 /* remember job */ 2955 queue_free(&solv->job); 2956 queue_init_clone(&solv->job, job); 2957 solv->pooljobcnt = pool->pooljobs.count; 2958 if (pool->pooljobs.count) 2959 queue_insertn(&solv->job, 0, pool->pooljobs.count, pool->pooljobs.elements); 2960 job = &solv->job; 2961 2962 /* free old stuff */ 2963 if (solv->update_targets) 2964 { 2965 queue_free(solv->update_targets); 2966 solv->update_targets = solv_free(solv->update_targets); 2967 } 2968 if (solv->cleandeps_updatepkgs) 2969 { 2970 queue_free(solv->cleandeps_updatepkgs); 2971 solv->cleandeps_updatepkgs = solv_free(solv->cleandeps_updatepkgs); 2972 } 2973 queue_empty(&solv->ruleassertions); 2974 solv->bestrules_pkg = solv_free(solv->bestrules_pkg); 2975 solv->choicerules_ref = solv_free(solv->choicerules_ref); 2976 if (solv->noupdate.size) 2977 map_empty(&solv->noupdate); 2978 if (solv->multiversion.size) 2979 { 2980 map_free(&solv->multiversion); 2981 map_init(&solv->multiversion, 0); 2982 } 2983 solv->updatemap_all = 0; 2984 if (solv->updatemap.size) 2985 { 2986 map_free(&solv->updatemap); 2987 map_init(&solv->updatemap, 0); 2988 } 2989 solv->bestupdatemap_all = 0; 2990 if (solv->bestupdatemap.size) 2991 { 2992 map_free(&solv->bestupdatemap); 2993 map_init(&solv->bestupdatemap, 0); 2994 } 2995 solv->fixmap_all = 0; 2996 if (solv->fixmap.size) 2997 { 2998 map_free(&solv->fixmap); 2999 map_init(&solv->fixmap, 0); 3000 } 3001 solv->dupmap_all = 0; 3002 if (solv->dupmap.size) 3003 { 3004 map_free(&solv->dupmap); 3005 map_init(&solv->dupmap, 0); 3006 } 3007 if (solv->dupinvolvedmap.size) 3008 { 3009 map_free(&solv->dupinvolvedmap); 3010 map_init(&solv->dupinvolvedmap, 0); 3011 } 3012 solv->droporphanedmap_all = 0; 3013 if (solv->droporphanedmap.size) 3014 { 3015 map_free(&solv->droporphanedmap); 3016 map_init(&solv->droporphanedmap, 0); 3017 } 3018 if (solv->cleandepsmap.size) 3019 { 3020 map_free(&solv->cleandepsmap); 3021 map_init(&solv->cleandepsmap, 0); 3022 } 3023 3024 queue_empty(&solv->weakruleq); 3025 solv->watches = solv_free(solv->watches); 3026 queue_empty(&solv->ruletojob); 3027 if (solv->decisionq.count) 3028 memset(solv->decisionmap, 0, pool->nsolvables * sizeof(Id)); 3029 queue_empty(&solv->decisionq); 3030 queue_empty(&solv->decisionq_why); 3031 solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0; 3032 queue_empty(&solv->learnt_why); 3033 queue_empty(&solv->learnt_pool); 3034 queue_empty(&solv->branches); 3035 solv->propagate_index = 0; 3036 queue_empty(&solv->problems); 3037 queue_empty(&solv->solutions); 3038 queue_empty(&solv->orphaned); 3039 solv->stats_learned = solv->stats_unsolvable = 0; 3040 if (solv->recommends_index) 3041 { 3042 map_empty(&solv->recommendsmap); 3043 map_empty(&solv->suggestsmap); 3044 solv->recommends_index = 0; 3045 } 3046 solv->multiversionupdaters = solv_free(solv->multiversionupdaters); 3047 3048 3049 /* 3050 * create basic rule set of all involved packages 3051 * use addedmap bitmap to make sure we don't create rules twice 3052 */ 3053 3054 /* create multiversion map if needed */ 3055 solver_calculate_multiversionmap(pool, job, &solv->multiversion); 3056 3057 map_init(&addedmap, pool->nsolvables); 3058 MAPSET(&addedmap, SYSTEMSOLVABLE); 3059 3060 map_init(&installcandidatemap, pool->nsolvables); 3061 queue_init(&q); 3062 3063 now = solv_timems(0); 3064 /* 3065 * create rules for all package that could be involved with the solving 3066 * so called: rpm rules 3067 * 3068 */ 3069 initialnrules = solv->rpmrules_end ? solv->rpmrules_end : 1; 3070 if (initialnrules > 1) 3071 deduceq2addedmap(solv, &addedmap); 3072 if (solv->nrules != initialnrules) 3073 solver_shrinkrules(solv, initialnrules); 3074 solv->nrules = initialnrules; 3075 solv->rpmrules_end = 0; 3076 3077 if (installed) 3078 { 3079 /* check for update/verify jobs as they need to be known early */ 3080 for (i = 0; i < job->count; i += 2) 3081 { 3082 how = job->elements[i]; 3083 what = job->elements[i + 1]; 3084 select = how & SOLVER_SELECTMASK; 3085 switch (how & SOLVER_JOBMASK) 3086 { 3087 case SOLVER_VERIFY: 3088 if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid)) 3089 solv->fixmap_all = 1; 3090 FOR_JOB_SELECT(p, pp, select, what) 3091 { 3092 s = pool->solvables + p; 3093 if (s->repo != installed) 3094 continue; 3095 if (!solv->fixmap.size) 3096 map_grow(&solv->fixmap, installed->end - installed->start); 3097 MAPSET(&solv->fixmap, p - installed->start); 3098 } 3099 break; 3100 case SOLVER_UPDATE: 3101 if (select == SOLVER_SOLVABLE_ALL) 3102 { 3103 solv->updatemap_all = 1; 3104 if (how & SOLVER_FORCEBEST) 3105 solv->bestupdatemap_all = 1; 3106 if (how & SOLVER_CLEANDEPS) 3107 { 3108 FOR_REPO_SOLVABLES(installed, p, s) 3109 add_cleandeps_package(solv, p); 3110 } 3111 } 3112 else if (select == SOLVER_SOLVABLE_REPO) 3113 { 3114 Repo *repo = pool_id2repo(pool, what); 3115 if (!repo) 3116 break; 3117 if (repo == installed && !(how & SOLVER_TARGETED)) 3118 { 3119 solv->updatemap_all = 1; 3120 if (how & SOLVER_FORCEBEST) 3121 solv->bestupdatemap_all = 1; 3122 if (how & SOLVER_CLEANDEPS) 3123 { 3124 FOR_REPO_SOLVABLES(installed, p, s) 3125 add_cleandeps_package(solv, p); 3126 } 3127 break; 3128 } 3129 if (solv->noautotarget && !(how & SOLVER_TARGETED)) 3130 break; 3131 /* targeted update */ 3132 FOR_REPO_SOLVABLES(repo, p, s) 3133 add_update_target(solv, p, how); 3134 } 3135 else 3136 { 3137 if (!(how & SOLVER_TARGETED)) 3138 { 3139 int targeted = 1; 3140 FOR_JOB_SELECT(p, pp, select, what) 3141 { 3142 s = pool->solvables + p; 3143 if (s->repo != installed) 3144 continue; 3145 if (!solv->updatemap.size) 3146 map_grow(&solv->updatemap, installed->end - installed->start); 3147 MAPSET(&solv->updatemap, p - installed->start); 3148 if (how & SOLVER_FORCEBEST) 3149 { 3150 if (!solv->bestupdatemap.size) 3151 map_grow(&solv->bestupdatemap, installed->end - installed->start); 3152 MAPSET(&solv->bestupdatemap, p - installed->start); 3153 } 3154 if (how & SOLVER_CLEANDEPS) 3155 add_cleandeps_package(solv, p); 3156 targeted = 0; 3157 } 3158 if (!targeted || solv->noautotarget) 3159 break; 3160 } 3161 FOR_JOB_SELECT(p, pp, select, what) 3162 add_update_target(solv, p, how); 3163 } 3164 break; 3165 default: 3166 break; 3167 } 3168 } 3169 3170 if (solv->update_targets) 3171 transform_update_targets(solv); 3172 3173 oldnrules = solv->nrules; 3174 FOR_REPO_SOLVABLES(installed, p, s) 3175 solver_addrpmrulesforsolvable(solv, s, &addedmap); 3176 POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules for installed solvables\n", solv->nrules - oldnrules); 3177 oldnrules = solv->nrules; 3178 FOR_REPO_SOLVABLES(installed, p, s) 3179 solver_addrpmrulesforupdaters(solv, s, &addedmap, 1); 3180 POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules for updaters of installed solvables\n", solv->nrules - oldnrules); 3181 } 3182 3183 /* 3184 * create rules for all packages involved in the job 3185 * (to be installed or removed) 3186 */ 3187 3188 oldnrules = solv->nrules; 3189 for (i = 0; i < job->count; i += 2) 3190 { 3191 how = job->elements[i]; 3192 what = job->elements[i + 1]; 3193 select = how & SOLVER_SELECTMASK; 3194 3195 switch (how & SOLVER_JOBMASK) 3196 { 3197 case SOLVER_INSTALL: 3198 FOR_JOB_SELECT(p, pp, select, what) 3199 { 3200 MAPSET(&installcandidatemap, p); 3201 solver_addrpmrulesforsolvable(solv, pool->solvables + p, &addedmap); 3202 } 3203 break; 3204 case SOLVER_DISTUPGRADE: 3205 if (select == SOLVER_SOLVABLE_ALL) 3206 { 3207 solv->dupmap_all = 1; 3208 solv->updatemap_all = 1; 3209 if (how & SOLVER_FORCEBEST) 3210 solv->bestupdatemap_all = 1; 3211 } 3212 if (!solv->dupmap_all) 3213 hasdupjob = 1; 3214 break; 3215 default: 3216 break; 3217 } 3218 } 3219 POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules for packages involved in a job\n", solv->nrules - oldnrules); 3220 3221 3222 /* 3223 * add rules for suggests, enhances 3224 */ 3225 oldnrules = solv->nrules; 3226 solver_addrpmrulesforweak(solv, &addedmap); 3227 POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules because of weak dependencies\n", solv->nrules - oldnrules); 3228 3229 /* 3230 * first pass done, we now have all the rpm rules we need. 3231 * unify existing rules before going over all job rules and 3232 * policy rules. 3233 * at this point the system is always solvable, 3234 * as an empty system (remove all packages) is a valid solution 3235 */ 3236 3237 IF_POOLDEBUG (SOLV_DEBUG_STATS) 3238 { 3239 int possible = 0, installable = 0; 3240 for (i = 1; i < pool->nsolvables; i++) 3241 { 3242 if (pool_installable(pool, pool->solvables + i)) 3243 installable++; 3244 if (MAPTST(&addedmap, i)) 3245 possible++; 3246 } 3247 POOL_DEBUG(SOLV_DEBUG_STATS, "%d of %d installable solvables considered for solving\n", possible, installable); 3248 } 3249 3250 if (solv->nrules > initialnrules) 3251 solver_unifyrules(solv); /* remove duplicate rpm rules */ 3252 solv->rpmrules_end = solv->nrules; /* mark end of rpm rules */ 3253 3254 if (solv->nrules > initialnrules) 3255 addedmap2deduceq(solv, &addedmap); /* so that we can recreate the addedmap */ 3256 3257 POOL_DEBUG(SOLV_DEBUG_STATS, "rpm rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024); 3258 POOL_DEBUG(SOLV_DEBUG_STATS, "rpm rule creation took %d ms\n", solv_timems(now)); 3259 3260 /* create dup maps if needed. We need the maps early to create our 3261 * update rules */ 3262 if (hasdupjob) 3263 solver_createdupmaps(solv); 3264 3265 /* 3266 * create feature rules 3267 * 3268 * foreach installed: 3269 * create assertion (keep installed, if no update available) 3270 * or 3271 * create update rule (A|update1(A)|update2(A)|...) 3272 * 3273 * those are used later on to keep a version of the installed packages in 3274 * best effort mode 3275 */ 3276 3277 solv->featurerules = solv->nrules; /* mark start of feature rules */ 3278 if (installed) 3279 { 3280 /* foreach possibly installed solvable */ 3281 for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++) 3282 { 3283 if (s->repo != installed) 3284 { 3285 solver_addrule(solv, 0, 0); /* create dummy rule */ 3286 continue; 3287 } 3288 solver_addupdaterule(solv, s, 1); /* allow s to be updated */ 3289 } 3290 /* make sure we accounted for all rules */ 3291 assert(solv->nrules - solv->featurerules == installed->end - installed->start); 3292 } 3293 solv->featurerules_end = solv->nrules; 3294 3295 /* 3296 * Add update rules for installed solvables 3297 * 3298 * almost identical to feature rules 3299 * except that downgrades/archchanges/vendorchanges are not allowed 3300 */ 3301 3302 solv->updaterules = solv->nrules; 3303 3304 if (installed) 3305 { /* foreach installed solvables */ 3306 /* we create all update rules, but disable some later on depending on the job */ 3307 for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++) 3308 { 3309 Rule *sr; 3310 3311 if (s->repo != installed) 3312 { 3313 solver_addrule(solv, 0, 0); /* create dummy rule */ 3314 continue; 3315 } 3316 solver_addupdaterule(solv, s, 0); /* allowall = 0: downgrades not allowed */ 3317 /* 3318 * check for and remove duplicate 3319 */ 3320 r = solv->rules + solv->nrules - 1; /* r: update rule */ 3321 sr = r - (installed->end - installed->start); /* sr: feature rule */ 3322 /* it's orphaned if there is no feature rule or the feature rule 3323 * consists just of the installed package */ 3324 if (!sr->p || (sr->p == i && !sr->d && !sr->w2)) 3325 queue_push(&solv->orphaned, i); 3326 if (!r->p) 3327 { 3328 assert(solv->dupmap_all && !sr->p); 3329 continue; 3330 } 3331 if (!solver_rulecmp(solv, r, sr)) 3332 memset(sr, 0, sizeof(*sr)); /* delete unneeded feature rule */ 3333 else 3334 solver_disablerule(solv, sr); /* disable feature rule */ 3335 } 3336 /* consistency check: we added a rule for _every_ installed solvable */ 3337 assert(solv->nrules - solv->updaterules == installed->end - installed->start); 3338 } 3339 solv->updaterules_end = solv->nrules; 3340 3341 3342 /* 3343 * now add all job rules 3344 */ 3345 3346 solv->jobrules = solv->nrules; 3347 for (i = 0; i < job->count; i += 2) 3348 { 3349 oldnrules = solv->nrules; 3350 3351 if (i && i == solv->pooljobcnt) 3352 POOL_DEBUG(SOLV_DEBUG_JOB, "end of pool jobs\n"); 3353 how = job->elements[i]; 3354 what = job->elements[i + 1]; 3355 weak = how & SOLVER_WEAK; 3356 select = how & SOLVER_SELECTMASK; 3357 switch (how & SOLVER_JOBMASK) 3358 { 3359 case SOLVER_INSTALL: 3360 POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sinstall %s\n", weak ? "weak " : "", solver_select2str(pool, select, what)); 3361 if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && installed) 3362 map_grow(&solv->cleandepsmap, installed->end - installed->start); 3363 if (select == SOLVER_SOLVABLE) 3364 { 3365 p = what; 3366 d = 0; 3367 } 3368 else 3369 { 3370 queue_empty(&q); 3371 FOR_JOB_SELECT(p, pp, select, what) 3372 queue_push(&q, p); 3373 if (!q.count) 3374 { 3375 /* no candidate found, make this an impossible rule */ 3376 queue_push(&q, -SYSTEMSOLVABLE); 3377 } 3378 p = queue_shift(&q); /* get first candidate */ 3379 d = !q.count ? 0 : pool_queuetowhatprovides(pool, &q); /* internalize */ 3380 } 3381 /* force install of namespace supplements hack */ 3382 if (select == SOLVER_SOLVABLE_PROVIDES && !d && (p == SYSTEMSOLVABLE || p == -SYSTEMSOLVABLE) && ISRELDEP(what)) 3383 { 3384 Reldep *rd = GETRELDEP(pool, what); 3385 if (rd->flags == REL_NAMESPACE) 3386 { 3387 p = SYSTEMSOLVABLE; 3388 if (!solv->installsuppdepq) 3389 { 3390 solv->installsuppdepq = solv_calloc(1, sizeof(Queue)); 3391 queue_init(solv->installsuppdepq); 3392 } 3393 queue_pushunique(solv->installsuppdepq, rd->evr == 0 ? rd->name : what); 3394 } 3395 } 3396 solver_addjobrule(solv, p, d, i, weak); 3397 if (how & SOLVER_FORCEBEST) 3398 hasbestinstalljob = 1; 3399 break; 3400 case SOLVER_ERASE: 3401 POOL_DEBUG(SOLV_DEBUG_JOB, "job: %s%serase %s\n", weak ? "weak " : "", how & SOLVER_CLEANDEPS ? "clean deps " : "", solver_select2str(pool, select, what)); 3402 if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && installed) 3403 map_grow(&solv->cleandepsmap, installed->end - installed->start); 3404 /* specific solvable: by id or by nevra */ 3405 name = (select == SOLVER_SOLVABLE || (select == SOLVER_SOLVABLE_NAME && ISRELDEP(what))) ? 0 : -1; 3406 if (select == SOLVER_SOLVABLE_ALL) /* hmmm ;) */ 3407 { 3408 FOR_POOL_SOLVABLES(p) 3409 solver_addjobrule(solv, -p, 0, i, weak); 3410 } 3411 else if (select == SOLVER_SOLVABLE_REPO) 3412 { 3413 Repo *repo = pool_id2repo(pool, what); 3414 if (repo) 3415 FOR_REPO_SOLVABLES(repo, p, s) 3416 solver_addjobrule(solv, -p, 0, i, weak); 3417 } 3418 FOR_JOB_SELECT(p, pp, select, what) 3419 { 3420 s = pool->solvables + p; 3421 if (installed && s->repo == installed) 3422 name = !name ? s->name : -1; 3423 solver_addjobrule(solv, -p, 0, i, weak); 3424 } 3425 /* special case for "erase a specific solvable": we also 3426 * erase all other solvables with that name, so that they 3427 * don't get picked up as replacement. 3428 * name is > 0 if exactly one installed solvable matched. 3429 */ 3430 /* XXX: look also at packages that obsolete this package? */ 3431 if (name > 0) 3432 { 3433 int j, k; 3434 k = solv->nrules; 3435 FOR_PROVIDES(p, pp, name) 3436 { 3437 s = pool->solvables + p; 3438 if (s->name != name) 3439 continue; 3440 /* keep other versions installed */ 3441 if (s->repo == installed) 3442 continue; 3443 /* keep installcandidates of other jobs */ 3444 if (MAPTST(&installcandidatemap, p)) 3445 continue; 3446 /* don't add the same rule twice */ 3447 for (j = oldnrules; j < k; j++) 3448 if (solv->rules[j].p == -p) 3449 break; 3450 if (j == k) 3451 solver_addjobrule(solv, -p, 0, i, weak); /* remove by id */ 3452 } 3453 } 3454 break; 3455 3456 case SOLVER_UPDATE: 3457 POOL_DEBUG(SOLV_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solver_select2str(pool, select, what)); 3458 break; 3459 case SOLVER_VERIFY: 3460 POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sverify %s\n", weak ? "weak " : "", solver_select2str(pool, select, what)); 3461 break; 3462 case SOLVER_WEAKENDEPS: 3463 POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sweaken deps %s\n", weak ? "weak " : "", solver_select2str(pool, select, what)); 3464 if (select != SOLVER_SOLVABLE) 3465 break; 3466 s = pool->solvables + what; 3467 weaken_solvable_deps(solv, what); 3468 break; 3469 case SOLVER_MULTIVERSION: 3470 POOL_DEBUG(SOLV_DEBUG_JOB, "job: %smultiversion %s\n", weak ? "weak " : "", solver_select2str(pool, select, what)); 3471 break; 3472 case SOLVER_LOCK: 3473 POOL_DEBUG(SOLV_DEBUG_JOB, "job: %slock %s\n", weak ? "weak " : "", solver_select2str(pool, select, what)); 3474 if (select == SOLVER_SOLVABLE_ALL) 3475 { 3476 FOR_POOL_SOLVABLES(p) 3477 solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak); 3478 } 3479 else if (select == SOLVER_SOLVABLE_REPO) 3480 { 3481 Repo *repo = pool_id2repo(pool, what); 3482 if (repo) 3483 FOR_REPO_SOLVABLES(repo, p, s) 3484 solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak); 3485 } 3486 FOR_JOB_SELECT(p, pp, select, what) 3487 solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak); 3488 break; 3489 case SOLVER_DISTUPGRADE: 3490 POOL_DEBUG(SOLV_DEBUG_JOB, "job: distupgrade %s\n", solver_select2str(pool, select, what)); 3491 break; 3492 case SOLVER_DROP_ORPHANED: 3493 POOL_DEBUG(SOLV_DEBUG_JOB, "job: drop orphaned %s\n", solver_select2str(pool, select, what)); 3494 if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid)) 3495 solv->droporphanedmap_all = 1; 3496 FOR_JOB_SELECT(p, pp, select, what) 3497 { 3498 s = pool->solvables + p; 3499 if (!installed || s->repo != installed) 3500 continue; 3501 if (!solv->droporphanedmap.size) 3502 map_grow(&solv->droporphanedmap, installed->end - installed->start); 3503 MAPSET(&solv->droporphanedmap, p - installed->start); 3504 } 3505 break; 3506 case SOLVER_USERINSTALLED: 3507 POOL_DEBUG(SOLV_DEBUG_JOB, "job: user installed %s\n", solver_select2str(pool, select, what)); 3508 break; 3509 default: 3510 POOL_DEBUG(SOLV_DEBUG_JOB, "job: unknown job\n"); 3511 break; 3512 } 3513 3514 /* 3515 * debug 3516 */ 3517 3518 IF_POOLDEBUG (SOLV_DEBUG_JOB) 3519 { 3520 int j; 3521 if (solv->nrules == oldnrules) 3522 POOL_DEBUG(SOLV_DEBUG_JOB, " - no rule created\n"); 3523 for (j = oldnrules; j < solv->nrules; j++) 3524 { 3525 POOL_DEBUG(SOLV_DEBUG_JOB, " - job "); 3526 solver_printrule(solv, SOLV_DEBUG_JOB, solv->rules + j); 3527 } 3528 } 3529 } 3530 assert(solv->ruletojob.count == solv->nrules - solv->jobrules); 3531 solv->jobrules_end = solv->nrules; 3532 3533 /* now create infarch and dup rules */ 3534 if (!solv->noinfarchcheck) 3535 { 3536 solver_addinfarchrules(solv, &addedmap); 3537 if (pool->obsoleteusescolors) 3538 { 3539 /* currently doesn't work well with infarch rules, so make 3540 * them weak */ 3541 for (i = solv->infarchrules; i < solv->infarchrules_end; i++) 3542 queue_push(&solv->weakruleq, i); 3543 } 3544 } 3545 else 3546 solv->infarchrules = solv->infarchrules_end = solv->nrules; 3547 3548 if (hasdupjob) 3549 solver_addduprules(solv, &addedmap); 3550 else 3551 solv->duprules = solv->duprules_end = solv->nrules; 3552 3553 if (solv->bestupdatemap_all || solv->bestupdatemap.size || hasbestinstalljob) 3554 solver_addbestrules(solv, hasbestinstalljob); 3555 else 3556 solv->bestrules = solv->bestrules_end = solv->nrules; 3557 3558 if (hasdupjob) 3559 solver_freedupmaps(solv); /* no longer needed */ 3560 3561 if (1) 3562 solver_addchoicerules(solv); 3563 else 3564 solv->choicerules = solv->choicerules_end = solv->nrules; 3565 3566 if (0) 3567 { 3568 for (i = solv->featurerules; i < solv->nrules; i++) 3569 solver_printruleclass(solv, SOLV_DEBUG_RESULT, solv->rules + i); 3570 } 3571 /* all rules created 3572 * -------------------------------------------------------------- 3573 * prepare for solving 3574 */ 3575 3576 /* free unneeded memory */ 3577 map_free(&addedmap); 3578 map_free(&installcandidatemap); 3579 queue_free(&q); 3580 3581 POOL_DEBUG(SOLV_DEBUG_STATS, "%d rpm rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules\n", solv->rpmrules_end - 1, solv->updaterules_end - solv->updaterules, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules, solv->choicerules_end - solv->choicerules, solv->bestrules_end - solv->bestrules); 3582 POOL_DEBUG(SOLV_DEBUG_STATS, "overall rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024); 3583 3584 /* create weak map */ 3585 map_init(&solv->weakrulemap, solv->nrules); 3586 for (i = 0; i < solv->weakruleq.count; i++) 3587 { 3588 p = solv->weakruleq.elements[i]; 3589 MAPSET(&solv->weakrulemap, p); 3590 } 3591 3592 /* enable cleandepsmap creation if we have updatepkgs */ 3593 if (solv->cleandeps_updatepkgs && !solv->cleandepsmap.size) 3594 map_grow(&solv->cleandepsmap, installed->end - installed->start); 3595 /* no mistakes */ 3596 if (solv->cleandeps_mistakes) 3597 { 3598 queue_free(solv->cleandeps_mistakes); 3599 solv->cleandeps_mistakes = solv_free(solv->cleandeps_mistakes); 3600 } 3601 3602 /* all new rules are learnt after this point */ 3603 solv->learntrules = solv->nrules; 3604 3605 /* create watches chains */ 3606 makewatches(solv); 3607 3608 /* create assertion index. it is only used to speed up 3609 * makeruledecsions() a bit */ 3610 for (i = 1, r = solv->rules + i; i < solv->nrules; i++, r++) 3611 if (r->p && !r->w2 && (r->d == 0 || r->d == -1)) 3612 queue_push(&solv->ruleassertions, i); 3613 3614 /* disable update rules that conflict with our job */ 3615 solver_disablepolicyrules(solv); 3616 3617 /* make initial decisions based on assertion rules */ 3618 makeruledecisions(solv); 3619 POOL_DEBUG(SOLV_DEBUG_SOLVER, "problems so far: %d\n", solv->problems.count); 3620 3621 /* 3622 * ******************************************** 3623 * solve! 3624 * ******************************************** 3625 */ 3626 3627 now = solv_timems(0); 3628 solver_run_sat(solv, 1, solv->dontinstallrecommended ? 0 : 1); 3629 POOL_DEBUG(SOLV_DEBUG_STATS, "solver took %d ms\n", solv_timems(now)); 3630 3631 /* 3632 * prepare solution queue if there were problems 3633 */ 3634 solver_prepare_solutions(solv); 3635 3636 POOL_DEBUG(SOLV_DEBUG_STATS, "final solver statistics: %d problems, %d learned rules, %d unsolvable\n", solv->problems.count / 2, solv->stats_learned, solv->stats_unsolvable); 3637 POOL_DEBUG(SOLV_DEBUG_STATS, "solver_solve took %d ms\n", solv_timems(solve_start)); 3638 3639 /* return number of problems */ 3640 return solv->problems.count ? solv->problems.count / 2 : 0; 3641 } 3642 3643 Transaction * 3644 solver_create_transaction(Solver *solv) 3645 { 3646 return transaction_create_decisionq(solv->pool, &solv->decisionq, &solv->multiversion); 3647 } 3648 3649 void solver_get_orphaned(Solver *solv, Queue *orphanedq) 3650 { 3651 queue_free(orphanedq); 3652 queue_init_clone(orphanedq, &solv->orphaned); 3653 } 3654 3655 void solver_get_recommendations(Solver *solv, Queue *recommendationsq, Queue *suggestionsq, int noselected) 3656 { 3657 Pool *pool = solv->pool; 3658 Queue redoq, disabledq; 3659 int goterase, i; 3660 Solvable *s; 3661 Rule *r; 3662 Map obsmap; 3663 3664 if (!recommendationsq && !suggestionsq) 3665 return; 3666 3667 map_init(&obsmap, pool->nsolvables); 3668 if (solv->installed) 3669 { 3670 Id obs, *obsp, p, po, ppo; 3671 for (p = solv->installed->start; p < solv->installed->end; p++) 3672 { 3673 s = pool->solvables + p; 3674 if (s->repo != solv->installed || !s->obsoletes) 3675 continue; 3676 if (solv->decisionmap[p] <= 0) 3677 continue; 3678 if (solv->multiversion.size && MAPTST(&solv->multiversion, p)) 3679 continue; 3680 obsp = s->repo->idarraydata + s->obsoletes; 3681 /* foreach obsoletes */ 3682 while ((obs = *obsp++) != 0) 3683 FOR_PROVIDES(po, ppo, obs) 3684 MAPSET(&obsmap, po); 3685 } 3686 } 3687 3688 queue_init(&redoq); 3689 queue_init(&disabledq); 3690 goterase = 0; 3691 /* disable all erase jobs (including weak "keep uninstalled" rules) */ 3692 for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++) 3693 { 3694 if (r->d < 0) /* disabled ? */ 3695 continue; 3696 if (r->p >= 0) /* install job? */ 3697 continue; 3698 queue_push(&disabledq, i); 3699 solver_disablerule(solv, r); 3700 goterase++; 3701 } 3702 3703 if (goterase) 3704 { 3705 enabledisablelearntrules(solv); 3706 removedisabledconflicts(solv, &redoq); 3707 } 3708 3709 /* 3710 * find recommended packages 3711 */ 3712 if (recommendationsq) 3713 { 3714 Id rec, *recp, p, pp; 3715 3716 queue_empty(recommendationsq); 3717 /* create map of all recommened packages */ 3718 solv->recommends_index = -1; 3719 MAPZERO(&solv->recommendsmap); 3720 3721 /* put all packages the solver already chose in the map */ 3722 if (solv->decisioncnt_weak) 3723 { 3724 for (i = solv->decisioncnt_weak; i < solv->decisioncnt_orphan; i++) 3725 { 3726 Id why; 3727 why = solv->decisionq_why.elements[i]; 3728 if (why) 3729 continue; /* forced by unit rule */ 3730 p = solv->decisionq.elements[i]; 3731 if (p < 0) 3732 continue; 3733 MAPSET(&solv->recommendsmap, p); 3734 } 3735 } 3736 3737 for (i = 0; i < solv->decisionq.count; i++) 3738 { 3739 p = solv->decisionq.elements[i]; 3740 if (p < 0) 3741 continue; 3742 s = pool->solvables + p; 3743 if (s->recommends) 3744 { 3745 recp = s->repo->idarraydata + s->recommends; 3746 while ((rec = *recp++) != 0) 3747 { 3748 FOR_PROVIDES(p, pp, rec) 3749 if (solv->decisionmap[p] > 0) 3750 break; 3751 if (p) 3752 { 3753 if (!noselected) 3754 { 3755 FOR_PROVIDES(p, pp, rec) 3756 if (solv->decisionmap[p] > 0) 3757 MAPSET(&solv->recommendsmap, p); 3758 } 3759 continue; /* p != 0: already fulfilled */ 3760 } 3761 FOR_PROVIDES(p, pp, rec) 3762 MAPSET(&solv->recommendsmap, p); 3763 } 3764 } 3765 } 3766 for (i = 1; i < pool->nsolvables; i++) 3767 { 3768 if (solv->decisionmap[i] < 0) 3769 continue; 3770 if (solv->decisionmap[i] > 0 && noselected) 3771 continue; 3772 if (MAPTST(&obsmap, i)) 3773 continue; 3774 s = pool->solvables + i; 3775 if (!MAPTST(&solv->recommendsmap, i)) 3776 { 3777 if (!s->supplements) 3778 continue; 3779 if (!pool_installable(pool, s)) 3780 continue; 3781 if (!solver_is_supplementing(solv, s)) 3782 continue; 3783 } 3784 queue_push(recommendationsq, i); 3785 } 3786 /* we use MODE_SUGGEST here so that repo prio is ignored */ 3787 policy_filter_unwanted(solv, recommendationsq, POLICY_MODE_SUGGEST); 3788 } 3789 3790 /* 3791 * find suggested packages 3792 */ 3793 3794 if (suggestionsq) 3795 { 3796 Id sug, *sugp, p, pp; 3797 3798 queue_empty(suggestionsq); 3799 /* create map of all suggests that are still open */ 3800 solv->recommends_index = -1; 3801 MAPZERO(&solv->suggestsmap); 3802 for (i = 0; i < solv->decisionq.count; i++) 3803 { 3804 p = solv->decisionq.elements[i]; 3805 if (p < 0) 3806 continue; 3807 s = pool->solvables + p; 3808 if (s->suggests) 3809 { 3810 sugp = s->repo->idarraydata + s->suggests; 3811 while ((sug = *sugp++) != 0) 3812 { 3813 FOR_PROVIDES(p, pp, sug) 3814 if (solv->decisionmap[p] > 0) 3815 break; 3816 if (p) 3817 { 3818 if (!noselected) 3819 { 3820 FOR_PROVIDES(p, pp, sug) 3821 if (solv->decisionmap[p] > 0) 3822 MAPSET(&solv->suggestsmap, p); 3823 } 3824 continue; /* already fulfilled */ 3825 } 3826 FOR_PROVIDES(p, pp, sug) 3827 MAPSET(&solv->suggestsmap, p); 3828 } 3829 } 3830 } 3831 for (i = 1; i < pool->nsolvables; i++) 3832 { 3833 if (solv->decisionmap[i] < 0) 3834 continue; 3835 if (solv->decisionmap[i] > 0 && noselected) 3836 continue; 3837 if (MAPTST(&obsmap, i)) 3838 continue; 3839 s = pool->solvables + i; 3840 if (!MAPTST(&solv->suggestsmap, i)) 3841 { 3842 if (!s->enhances) 3843 continue; 3844 if (!pool_installable(pool, s)) 3845 continue; 3846 if (!solver_is_enhancing(solv, s)) 3847 continue; 3848 } 3849 queue_push(suggestionsq, i); 3850 } 3851 policy_filter_unwanted(solv, suggestionsq, POLICY_MODE_SUGGEST); 3852 } 3853 3854 /* undo removedisabledconflicts */ 3855 if (redoq.count) 3856 undo_removedisabledconflicts(solv, &redoq); 3857 queue_free(&redoq); 3858 3859 /* undo job rule disabling */ 3860 for (i = 0; i < disabledq.count; i++) 3861 solver_enablerule(solv, solv->rules + disabledq.elements[i]); 3862 queue_free(&disabledq); 3863 map_free(&obsmap); 3864 } 3865 3866 3867 /***********************************************************************/ 3868 /* disk usage computations */ 3869 3870 /*------------------------------------------------------------------- 3871 * 3872 * calculate DU changes 3873 */ 3874 3875 void 3876 solver_calc_duchanges(Solver *solv, DUChanges *mps, int nmps) 3877 { 3878 Map installedmap; 3879 3880 solver_create_state_maps(solv, &installedmap, 0); 3881 pool_calc_duchanges(solv->pool, &installedmap, mps, nmps); 3882 map_free(&installedmap); 3883 } 3884 3885 3886 /*------------------------------------------------------------------- 3887 * 3888 * calculate changes in install size 3889 */ 3890 3891 int 3892 solver_calc_installsizechange(Solver *solv) 3893 { 3894 Map installedmap; 3895 int change; 3896 3897 solver_create_state_maps(solv, &installedmap, 0); 3898 change = pool_calc_installsizechange(solv->pool, &installedmap); 3899 map_free(&installedmap); 3900 return change; 3901 } 3902 3903 void 3904 solver_create_state_maps(Solver *solv, Map *installedmap, Map *conflictsmap) 3905 { 3906 pool_create_state_maps(solv->pool, &solv->decisionq, installedmap, conflictsmap); 3907 } 3908 3909 void 3910 solver_trivial_installable(Solver *solv, Queue *pkgs, Queue *res) 3911 { 3912 Pool *pool = solv->pool; 3913 Map installedmap; 3914 int i; 3915 pool_create_state_maps(pool, &solv->decisionq, &installedmap, 0); 3916 pool_trivial_installable_multiversionmap(pool, &installedmap, pkgs, res, solv->multiversion.size ? &solv->multiversion : 0); 3917 for (i = 0; i < res->count; i++) 3918 if (res->elements[i] != -1) 3919 { 3920 Solvable *s = pool->solvables + pkgs->elements[i]; 3921 if (!strncmp("patch:", pool_id2str(pool, s->name), 6) && solvable_is_irrelevant_patch(s, &installedmap)) 3922 res->elements[i] = -1; 3923 } 3924 map_free(&installedmap); 3925 } 3926 3927 /*------------------------------------------------------------------- 3928 * 3929 * decision introspection 3930 */ 3931 3932 int 3933 solver_get_decisionlevel(Solver *solv, Id p) 3934 { 3935 return solv->decisionmap[p]; 3936 } 3937 3938 void 3939 solver_get_decisionqueue(Solver *solv, Queue *decisionq) 3940 { 3941 queue_free(decisionq); 3942 queue_init_clone(decisionq, &solv->decisionq); 3943 } 3944 3945 int 3946 solver_get_lastdecisionblocklevel(Solver *solv) 3947 { 3948 Id p; 3949 if (solv->decisionq.count == 0) 3950 return 0; 3951 p = solv->decisionq.elements[solv->decisionq.count - 1]; 3952 if (p < 0) 3953 p = -p; 3954 return solv->decisionmap[p] < 0 ? -solv->decisionmap[p] : solv->decisionmap[p]; 3955 } 3956 3957 void 3958 solver_get_decisionblock(Solver *solv, int level, Queue *decisionq) 3959 { 3960 Id p; 3961 int i; 3962 3963 queue_empty(decisionq); 3964 for (i = 0; i < solv->decisionq.count; i++) 3965 { 3966 p = solv->decisionq.elements[i]; 3967 if (p < 0) 3968 p = -p; 3969 if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level) 3970 break; 3971 } 3972 if (i == solv->decisionq.count) 3973 return; 3974 for (i = 0; i < solv->decisionq.count; i++) 3975 { 3976 p = solv->decisionq.elements[i]; 3977 if (p < 0) 3978 p = -p; 3979 if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level) 3980 queue_push(decisionq, p); 3981 else 3982 break; 3983 } 3984 } 3985 3986 int 3987 solver_describe_decision(Solver *solv, Id p, Id *infop) 3988 { 3989 int i; 3990 Id pp, why; 3991 3992 if (infop) 3993 *infop = 0; 3994 if (!solv->decisionmap[p]) 3995 return SOLVER_REASON_UNRELATED; 3996 pp = solv->decisionmap[p] < 0 ? -p : p; 3997 for (i = 0; i < solv->decisionq.count; i++) 3998 if (solv->decisionq.elements[i] == pp) 3999 break; 4000 if (i == solv->decisionq.count) /* just in case... */ 4001 return SOLVER_REASON_UNRELATED; 4002 why = solv->decisionq_why.elements[i]; 4003 if (why > 0) 4004 { 4005 if (infop) 4006 *infop = why; 4007 return SOLVER_REASON_UNIT_RULE; 4008 } 4009 why = -why; 4010 if (i < solv->decisioncnt_update) 4011 { 4012 if (i == 0) 4013 { 4014 if (infop) 4015 *infop = SYSTEMSOLVABLE; 4016 return SOLVER_REASON_KEEP_INSTALLED; 4017 } 4018 if (infop) 4019 *infop = why; 4020 return SOLVER_REASON_RESOLVE_JOB; 4021 } 4022 if (i < solv->decisioncnt_keep) 4023 { 4024 if (why == 0 && pp < 0) 4025 return SOLVER_REASON_CLEANDEPS_ERASE; 4026 if (infop) 4027 { 4028 if (why >= solv->updaterules && why < solv->updaterules_end) 4029 *infop = why - solv->updaterules; 4030 else if (why >= solv->featurerules && why < solv->featurerules_end) 4031 *infop = why - solv->featurerules; 4032 } 4033 return SOLVER_REASON_UPDATE_INSTALLED; 4034 } 4035 if (i < solv->decisioncnt_resolve) 4036 { 4037 if (why == 0 && pp < 0) 4038 return SOLVER_REASON_CLEANDEPS_ERASE; 4039 if (infop) 4040 { 4041 if (why >= solv->updaterules && why < solv->updaterules_end) 4042 *infop = why - solv->updaterules; 4043 else if (why >= solv->featurerules && why < solv->featurerules_end) 4044 *infop = why - solv->featurerules; 4045 } 4046 return SOLVER_REASON_KEEP_INSTALLED; 4047 } 4048 if (i < solv->decisioncnt_weak) 4049 { 4050 if (infop) 4051 *infop = why; 4052 return SOLVER_REASON_RESOLVE; 4053 } 4054 if (solv->decisionq.count < solv->decisioncnt_orphan) 4055 return SOLVER_REASON_WEAKDEP; 4056 return SOLVER_REASON_RESOLVE_ORPHAN; 4057 } 4058 4059 4060 void 4061 solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq) 4062 { 4063 Pool *pool = solv->pool; 4064 int i; 4065 int level = solv->decisionmap[p]; 4066 int decisionno; 4067 Solvable *s; 4068 4069 queue_empty(whyq); 4070 if (level < 0) 4071 return; /* huh? */ 4072 for (decisionno = 0; decisionno < solv->decisionq.count; decisionno++) 4073 if (solv->decisionq.elements[decisionno] == p) 4074 break; 4075 if (decisionno == solv->decisionq.count) 4076 return; /* huh? */ 4077 if (decisionno < solv->decisioncnt_weak || decisionno >= solv->decisioncnt_orphan) 4078 return; /* huh? */ 4079 4080 /* 1) list all packages that recommend us */ 4081 for (i = 1; i < pool->nsolvables; i++) 4082 { 4083 Id *recp, rec, pp2, p2; 4084 if (solv->decisionmap[i] < 0 || solv->decisionmap[i] >= level) 4085 continue; 4086 s = pool->solvables + i; 4087 if (!s->recommends) 4088 continue; 4089 if (!solv->addalreadyrecommended && s->repo == solv->installed) 4090 continue; 4091 recp = s->repo->idarraydata + s->recommends; 4092 while ((rec = *recp++) != 0) 4093 { 4094 int found = 0; 4095 FOR_PROVIDES(p2, pp2, rec) 4096 { 4097 if (p2 == p) 4098 found = 1; 4099 else 4100 { 4101 /* if p2 is already installed, this recommends is ignored */ 4102 if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level) 4103 break; 4104 } 4105 } 4106 if (!p2 && found) 4107 { 4108 queue_push(whyq, SOLVER_REASON_RECOMMENDED); 4109 queue_push2(whyq, p2, rec); 4110 } 4111 } 4112 } 4113 /* 2) list all supplements */ 4114 s = pool->solvables + p; 4115 if (s->supplements && level > 0) 4116 { 4117 Id *supp, sup, pp2, p2; 4118 /* this is a hack. to use solver_dep_fulfilled we temporarily clear 4119 * everything above our level in the decisionmap */ 4120 for (i = decisionno; i < solv->decisionq.count; i++ ) 4121 { 4122 p2 = solv->decisionq.elements[i]; 4123 if (p2 > 0) 4124 solv->decisionmap[p2] = -solv->decisionmap[p2]; 4125 } 4126 supp = s->repo->idarraydata + s->supplements; 4127 while ((sup = *supp++) != 0) 4128 if (solver_dep_fulfilled(solv, sup)) 4129 { 4130 int found = 0; 4131 /* let's see if this is an easy supp */ 4132 FOR_PROVIDES(p2, pp2, sup) 4133 { 4134 if (!solv->addalreadyrecommended && solv->installed) 4135 { 4136 if (pool->solvables[p2].repo == solv->installed) 4137 continue; 4138 } 4139 if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level) 4140 { 4141 queue_push(whyq, SOLVER_REASON_SUPPLEMENTED); 4142 queue_push2(whyq, p2, sup); 4143 found = 1; 4144 } 4145 } 4146 if (!found) 4147 { 4148 /* hard case, just note dependency with no package */ 4149 queue_push(whyq, SOLVER_REASON_SUPPLEMENTED); 4150 queue_push2(whyq, 0, sup); 4151 } 4152 } 4153 for (i = decisionno; i < solv->decisionq.count; i++) 4154 { 4155 p2 = solv->decisionq.elements[i]; 4156 if (p2 > 0) 4157 solv->decisionmap[p2] = -solv->decisionmap[p2]; 4158 } 4159 } 4160 } 4161 4162 void 4163 pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what) 4164 { 4165 Id p, pp; 4166 how &= SOLVER_SELECTMASK; 4167 queue_empty(pkgs); 4168 if (how == SOLVER_SOLVABLE_ALL) 4169 { 4170 FOR_POOL_SOLVABLES(p) 4171 queue_push(pkgs, p); 4172 } 4173 else if (how == SOLVER_SOLVABLE_REPO) 4174 { 4175 Repo *repo = pool_id2repo(pool, what); 4176 Solvable *s; 4177 if (repo) 4178 FOR_REPO_SOLVABLES(repo, p, s) 4179 queue_push(pkgs, p); 4180 } 4181 else 4182 { 4183 FOR_JOB_SELECT(p, pp, how, what) 4184 queue_push(pkgs, p); 4185 } 4186 } 4187 4188 int 4189 pool_isemptyupdatejob(Pool *pool, Id how, Id what) 4190 { 4191 Id p, pp, pi, pip; 4192 Id select = how & SOLVER_SELECTMASK; 4193 if ((how & SOLVER_JOBMASK) != SOLVER_UPDATE) 4194 return 0; 4195 if (select == SOLVER_SOLVABLE_ALL || select == SOLVER_SOLVABLE_REPO) 4196 return 0; 4197 if (!pool->installed) 4198 return 1; 4199 FOR_JOB_SELECT(p, pp, select, what) 4200 if (pool->solvables[p].repo == pool->installed) 4201 return 0; 4202 /* hard work */ 4203 FOR_JOB_SELECT(p, pp, select, what) 4204 { 4205 Solvable *s = pool->solvables + p; 4206 FOR_PROVIDES(pi, pip, s->name) 4207 { 4208 Solvable *si = pool->solvables + pi; 4209 if (si->repo != pool->installed || si->name != s->name) 4210 continue; 4211 return 0; 4212 } 4213 if (s->obsoletes) 4214 { 4215 Id obs, *obsp = s->repo->idarraydata + s->obsoletes; 4216 while ((obs = *obsp++) != 0) 4217 { 4218 FOR_PROVIDES(pi, pip, obs) 4219 { 4220 Solvable *si = pool->solvables + pi; 4221 if (si->repo != pool->installed) 4222 continue; 4223 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs)) 4224 continue; 4225 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si)) 4226 continue; 4227 return 0; 4228 } 4229 } 4230 } 4231 } 4232 return 1; 4233 } 4234