ResolverQueue.cc

Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
00002 /* ResolverQueue.cc
00003  *
00004  * Copyright (C) 2000-2002 Ximian, Inc.
00005  * Copyright (C) 2005 SUSE Linux Products GmbH
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License,
00009  * version 2, as published by the Free Software Foundation.
00010  *
00011  * This program is distributed in the hope that it will be useful, but
00012  * WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019  * 02111-1307, USA.
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         // regarding only items which will on the system after commit
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 (_qitems, _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        Now make a second pass over the queue, removing any super-branches.
00248        (If one branch contains all of the possible items of another branch,
00249        the larger branch can be dropped.
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               /* all of the work is in the conditional! */
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                 /* Penalties are negative priorities */
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        Check for deferrable qitems: if we have two install qitems where the to-be-installed
00363        poolItems have the same name, then we will defer the lower-priority install if
00364        one of the following is true:
00365        (1) Both poolItems have the same version
00366        (2) The lower-priority channel is a previous version.
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 /* if (priority > priority2) */
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     };// namespace detail
00438   };// namespace solver
00441 };// namespace zypp
00443 

Generated on Thu Apr 24 02:24:54 2008 for zypp by  doxygen 1.4.6