00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <map>
00023
00024 #include "zypp/base/String.h"
00025 #include "zypp/solver/detail/ResolverQueue.h"
00026 #include "zypp/solver/detail/QueueItemBranch.h"
00027 #include "zypp/solver/detail/QueueItemConflict.h"
00028 #include "zypp/solver/detail/QueueItemEstablish.h"
00029 #include "zypp/solver/detail/QueueItemGroup.h"
00030 #include "zypp/solver/detail/QueueItemInstall.h"
00031 #include "zypp/solver/detail/QueueItemRequire.h"
00032 #include "zypp/solver/detail/QueueItemUninstall.h"
00033 #include "zypp/solver/detail/ResolverContext.h"
00034 #include "zypp/CapSet.h"
00035 #include "zypp/base/Logger.h"
00036
00038 namespace zypp
00039 {
00040
00041 namespace solver
00042 {
00043
00044 namespace detail
00045 {
00046
00047 using namespace std;
00048
00049 IMPL_PTR_TYPE(ResolverQueue);
00050
00051
00052
00053
00054
00055
00056 ostream&
00057 operator<<( ostream& os, const ResolverQueue & resolverqueue)
00058 {
00059 os << str::form ("Context [%p]", (const void *)resolverqueue._context.get());
00060 os << ", " << resolverqueue._qitems.size() << " Items:" << endl << "\t";
00061 os << resolverqueue._qitems;
00062 return os;
00063 }
00064
00065
00066
00067 ResolverQueue::ResolverQueue (const ResPool & pool, const Arch & arch, ResolverContext_Ptr context)
00068 : _context (context)
00069 {
00070 _XDEBUG("ResolverQueue::ResolverQueue(pool, " << context << ")");
00071 if (context == NULL)
00072 _context = new ResolverContext(pool, arch);
00073 }
00074
00075
00076 ResolverQueue::~ResolverQueue()
00077 {
00078 }
00079
00080
00081
00082 void
00083 ResolverQueue::addPoolItemToInstall (PoolItem_Ref poolItem)
00084 {
00085 QueueItemInstall_Ptr qitem;
00086
00087 if (_context->isPresent (poolItem)
00088 && poolItem.status().staysInstalled()) {
00089 WAR << poolItem << " is already installed" << endl;
00090 return;
00091 }
00092
00093 qitem = new QueueItemInstall (_context->pool(), poolItem, poolItem.status().isSoftInstall());
00094 poolItem.status().setSoftInstall(false);
00095 qitem->setExplicitlyRequested ();
00096
00097 addItem (qitem);
00098 }
00099
00100
00101 void
00102 ResolverQueue::addPoolItemToEstablish (PoolItem_Ref poolItem)
00103 {
00104 QueueItemEstablish_Ptr qitem;
00105
00106 qitem = new QueueItemEstablish (_context->pool(), poolItem);
00107 qitem->setExplicitlyRequested ();
00108
00109 addItem (qitem);
00110 }
00111
00112
00113 void
00114 ResolverQueue::addPoolItemToRemove (PoolItem_Ref poolItem, bool remove_only_mode)
00115 {
00116 QueueItemUninstall_Ptr qitem;
00117
00118 if (_context->isAbsent (poolItem))
00119 return;
00120
00121 qitem = new QueueItemUninstall (_context->pool(), poolItem, QueueItemUninstall::EXPLICIT, poolItem.status().isSoftUninstall());
00122 poolItem.status().setSoftUninstall(false);
00123 if (remove_only_mode)
00124 qitem->setRemoveOnly ();
00125
00126 qitem->setExplicitlyRequested ();
00127
00128 addItem (qitem);
00129 }
00130
00131
00132 void
00133 ResolverQueue::addPoolItemToVerify (PoolItem_Ref poolItem)
00134 {
00135 if (poolItem.status().staysInstalled()
00136 || poolItem.status().isToBeInstalled()) {
00137
00138 CapSet requires = poolItem->dep (Dep::REQUIRES);
00139 for (CapSet::const_iterator iter = requires.begin(); iter != requires.end(); ++iter) {
00140 QueueItemRequire_Ptr qitem = new QueueItemRequire (_context->pool(), *iter);
00141 qitem->addPoolItem (poolItem);
00142 addItem (qitem);
00143 }
00144
00145 CapSet conflicts = poolItem->dep (Dep::CONFLICTS);
00146 for (CapSet::const_iterator iter = conflicts.begin(); iter != conflicts.end(); ++iter) {
00147 QueueItemConflict_Ptr qitem = new QueueItemConflict (_context->pool(), *iter, poolItem);
00148 addItem (qitem);
00149 }
00150 }
00151 }
00152
00153
00154 void
00155 ResolverQueue::addExtraCapability (const Capability & dep)
00156 {
00157 QueueItemRequire_Ptr qitem = new QueueItemRequire (_context->pool(), dep);
00158 addItem (qitem);
00159 }
00160
00161
00162 void
00163 ResolverQueue::addExtraConflict (const Capability & dep)
00164 {
00165 QueueItemConflict_Ptr qitem = new QueueItemConflict (_context->pool(), dep, PoolItem_Ref());
00166 addItem (qitem);
00167 }
00168
00169
00170 void
00171 ResolverQueue::addItem (QueueItem_Ptr qitem)
00172 {
00173 _qitems.push_back(qitem);
00174 }
00175
00176
00177 bool
00178 ResolverQueue::isInvalid ()
00179 {
00180 return _context->isInvalid() || _context->askUser();
00181 }
00182
00183
00184 bool
00185 ResolverQueue::containsOnlyBranches ()
00186 {
00187 for (QueueItemList::const_iterator iter = _qitems.begin(); iter != _qitems.end(); ++iter) {
00188 if (!(*iter)->isBranch())
00189 return false;
00190 }
00191
00192 return true;
00193 }
00194
00195
00196
00197 static int
00198 qitemlist_max_priority (const QueueItemList & qil)
00199 {
00200 int max_priority = -1;
00201 for (QueueItemList::const_iterator iter = qil.begin(); iter != qil.end(); ++iter) {
00202 if ((*iter)->priority() > max_priority) {
00203 max_priority = (*iter)->priority();
00204 }
00205 }
00206
00207 return max_priority;
00208 }
00209
00210
00211
00212 bool
00213 ResolverQueue::processOnce ()
00214 {
00215 QueueItemList new_qitems;
00216 int max_priority;
00217 bool did_something = false;
00218
00219 _XDEBUG("ResolverQueue::processOnce()" << (int) _qitems.size() << " items");
00220 while ( (max_priority = qitemlist_max_priority (_qitems)) >= 0
00221 && _context->isValid () ) {
00222
00223 bool did_something_recently = false;
00224
00225 for (QueueItemList::iterator iter = _qitems.begin(); iter != _qitems.end() && _context->isValid();) {
00226 QueueItem_Ptr qitem = *iter;
00227 _XDEBUG( "=====> 1st pass: [" << *qitem << "]");
00228 QueueItemList::iterator next = iter; ++next;
00229 if (qitem && qitem->priority() == max_priority) {
00230 if (qitem->process (_context, new_qitems)) {
00231 did_something_recently = true;
00232 }
00233 _qitems.erase (iter);
00234 }
00235 iter = next;
00236 }
00237
00238 if (did_something_recently) {
00239 did_something = true;
00240 }
00241 }
00242
00243 _qitems = new_qitems;
00244 _XDEBUG(_qitems.size() << " qitems after first pass");
00245
00246
00247
00248
00249
00250
00251
00252 for (QueueItemList::iterator iter = _qitems.begin(); iter != _qitems.end();) {
00253 QueueItemList::iterator next = iter; ++next;
00254 QueueItem_Ptr qitem = *iter;
00255
00256 _XDEBUG( "=====> 2nd pass: [" << *qitem << "]");
00257 if (qitem->isBranch()) {
00258 _XDEBUG("ResolverQueue::processOnce() is branch");
00259 QueueItemBranch_Ptr branch = dynamic_pointer_cast<QueueItemBranch>(qitem);
00260 for (QueueItemList::const_iterator iter2 = _qitems.begin(); iter2 != _qitems.end(); ++iter2) {
00261 _XDEBUG("Compare branch with [" << *(*iter2) << "]");
00262 if (iter != iter2
00263 && branch->contains (*iter2)) {
00264 _XDEBUG("Contained within, removing");
00265 _qitems.erase (iter);
00266 break;
00267 }
00268 }
00269 }
00270 iter = next;
00271 }
00272 if (did_something) {
00273 _XDEBUG( "did something: " << _qitems.size() << " qitems");
00274 }
00275 else {
00276 _XDEBUG( "did nothing: " << _qitems.size() << " qitems");
00277 }
00278
00279 return did_something;
00280 }
00281
00282
00283 void
00284 ResolverQueue::process ()
00285 {
00286 _XDEBUG("----- Processing -----");
00287 spew ();
00288
00289 while (_context->isValid ()
00290 && ! isEmpty ()
00291 && processOnce ()) {
00292
00293 spew ();
00294 }
00295 }
00296
00297
00298
00299
00300 ResolverQueue_Ptr
00301 ResolverQueue::copy_queue_except_for_branch (QueueItem_Ptr branch_qitem, QueueItem_Ptr subqitem) const
00302 {
00303 ResolverContext_Ptr new_context;
00304 ResolverQueue_Ptr new_queue;
00305 _XDEBUG("copy_queue_except_for_branch");
00306 new_context = new ResolverContext (_context->pool(), _context->architecture(), _context);
00307
00308 new_queue = new ResolverQueue (new_context->pool(), new_context->architecture(), new_context);
00309
00310 QueueItemList qil = _qitems;
00311 for (QueueItemList::const_iterator iter = qil.begin(); iter != qil.end(); ++iter) {
00312 QueueItem_Ptr qitem = *iter;
00313 QueueItem_Ptr new_qitem;
00314
00315 if (qitem == branch_qitem) {
00316 new_qitem = subqitem->copy ();
00317
00318 if (new_qitem->isInstall()) {
00319 QueueItemInstall_Ptr install_qitem = dynamic_pointer_cast<QueueItemInstall>(new_qitem);
00320
00321
00322 int penalty;
00323 Source_Ref src = install_qitem->item()->source();
00324 penalty = - src.priority();
00325
00326 install_qitem->setOtherPenalty (penalty);
00327 }
00328
00329 } else {
00330
00331 new_qitem = qitem->copy ();
00332
00333 }
00334
00335 new_queue->addItem (new_qitem);
00336 }
00337
00338 return new_queue;
00339 }
00340
00341
00342 void
00343 ResolverQueue::splitFirstBranch (ResolverQueueList & new_queues, ResolverQueueList & deferred_queues)
00344 {
00345 QueueItemBranch_Ptr first_branch = NULL;
00346 typedef std::map <QueueItem_Ptr, QueueItem_Ptr> DeferTable;
00347 DeferTable to_defer;
00348
00349 for (QueueItemList::const_iterator iter = _qitems.begin(); iter != _qitems.end() && first_branch == NULL; ++iter) {
00350 QueueItem_Ptr qitem = *iter;
00351 if (qitem->isBranch()) {
00352 first_branch = dynamic_pointer_cast<QueueItemBranch>(qitem);
00353 }
00354 }
00355
00356 if (first_branch == NULL)
00357 return;
00358
00359 QueueItemList possible_qitems = first_branch->possibleQItems();
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369 for (QueueItemList::const_iterator iter = possible_qitems.begin(); iter != possible_qitems.end(); ++iter) {
00370 QueueItemList::const_iterator iter2 = iter;
00371 for (iter2++; iter2 != possible_qitems.end(); iter2++) {
00372 QueueItem_Ptr qitem = *iter;
00373 QueueItem_Ptr qitem2 = *iter2;
00374
00375 if (qitem->isInstall() && qitem2->isInstall()) {
00376 PoolItem_Ref r = (dynamic_pointer_cast<QueueItemInstall>(qitem))->item();
00377 PoolItem_Ref r2 = (dynamic_pointer_cast<QueueItemInstall>(qitem2))->item();
00378 Source_Ref source = r->source();
00379 Source_Ref source2 = r2->source();
00380 int priority, priority2;
00381
00382 priority = _context->getSourcePriority( source );
00383 priority2 = _context->getSourcePriority( source2 );
00384
00385 if (priority != priority2 && r->name() == r2->name()) {
00386 if (r->edition().compare(r2->edition()) == 0
00387 || (priority < priority2 && r->edition().compare(r2->edition()) < 0)
00388 || (priority > priority2 && r->edition().compare(r2->edition()) > 0))
00389 {
00390 if (priority < priority2)
00391 to_defer[qitem] = qitem;
00392 else
00393 to_defer[qitem2] = qitem2;
00394 }
00395 }
00396 }
00397 }
00398 }
00399
00400 for (QueueItemList::const_iterator iter = possible_qitems.begin(); iter != possible_qitems.end(); ++iter) {
00401 ResolverQueue_Ptr new_queue;
00402 QueueItem_Ptr new_qitem = *iter;
00403
00404 new_queue = copy_queue_except_for_branch ((QueueItem_Ptr) first_branch, new_qitem);
00405
00406 DeferTable::const_iterator pos = to_defer.find (new_qitem);
00407 if (pos != to_defer.end()) {
00408 deferred_queues.push_back(new_queue);
00409 } else {
00410 new_queues.push_back(new_queue);
00411 }
00412 }
00413
00414 }
00415
00416
00417 void
00418 ResolverQueue::spew ()
00419 {
00420 _XDEBUG( "Resolver Queue: " << (_context->isInvalid() ? "INVALID" : "") );
00421
00422 if (_qitems.empty()) {
00423
00424 _XDEBUG( " (empty)" );
00425
00426 } else {
00427 for (QueueItemList::const_iterator iter = _qitems.begin(); iter != _qitems.end(); ++iter) {
00428 _XDEBUG( " " << *(*iter) );
00429 }
00430
00431 }
00432 }
00433
00435 };
00438 };
00441 };
00443