src/modules/client/pkg_solver.py
changeset 3317 81fca2c09539
parent 3294 6bc144461e5e
child 3328 9bfe1d86b9ce
equal deleted inserted replaced
3316:97e1801e1f2c 3317:81fca2c09539
  1551         def __comb_newer_fmris(self, fmri, dotrim=True, obsolete_ok=True):
  1551         def __comb_newer_fmris(self, fmri, dotrim=True, obsolete_ok=True):
  1552                 """Returns tuple of set of fmris that are matched within
  1552                 """Returns tuple of set of fmris that are matched within
  1553                 CONSTRAINT.NONE of specified version and set of remaining
  1553                 CONSTRAINT.NONE of specified version and set of remaining
  1554                 fmris."""
  1554                 fmris."""
  1555 
  1555 
  1556                 if dotrim or not obsolete_ok or not fmri.version or \
  1556                 return self.__comb_common(fmri, dotrim,
  1557                     not fmri.version.timestr:
  1557                     version.CONSTRAINT_NONE, obsolete_ok)
  1558                         return self.__comb_common(fmri, dotrim,
       
  1559                             version.CONSTRAINT_NONE, obsolete_ok)
       
  1560 
       
  1561                 # In the case that a precise version (down to timestamp) is
       
  1562                 # provided, no trimming is being done, and obsoletes are ok, the
       
  1563                 # set of matching FMRIs can be determined without using version
       
  1564                 # comparison because the solver caches catalog FMRIs in
       
  1565                 # ascending version order.
       
  1566 
       
  1567                 # determine if the data is cacheable or cached:
       
  1568                 tp = (fmri, dotrim, version.CONSTRAINT_NONE, obsolete_ok)
       
  1569                 try:
       
  1570                         return self.__cache[tp]
       
  1571                 except KeyError:
       
  1572                         pass
       
  1573 
       
  1574                 mver = fmri.version
       
  1575                 # Always use a copy in reverse order (so versions are in
       
  1576                 # descending order); return value may be cached.
       
  1577                 all_fmris = self.__get_catalog_fmris(fmri.pkg_name)[::-1]
       
  1578 
       
  1579                 # frozensets are used so callers don't inadvertently
       
  1580                 # update these sets (which may be cached).  Iteration is
       
  1581                 # performed in descending version order with the
       
  1582                 # assumption that systems are generally up-to-date so it
       
  1583                 # should be faster to start at the end and look for the
       
  1584                 # older version.
       
  1585                 last_ver = None
       
  1586                 for i, f in enumerate(all_fmris):
       
  1587                         if mver == f.version:
       
  1588                                 last_ver = i
       
  1589                         elif last_ver is not None:
       
  1590                                 break
       
  1591 
       
  1592                 if last_ver is not None:
       
  1593                         matching = frozenset(all_fmris[:last_ver + 1])
       
  1594                         remaining = frozenset(all_fmris[last_ver + 1:])
       
  1595                 else:
       
  1596                         matching = frozenset()
       
  1597                         remaining = frozenset(all_fmris)
       
  1598 
       
  1599                 # if we haven't finished trimming, don't cache this
       
  1600                 if not self.__trimdone:
       
  1601                         return matching, remaining
       
  1602 
       
  1603                 # cache the result
       
  1604                 self.__cache[tp] = (matching, remaining)
       
  1605                 return self.__cache[tp]
       
  1606 
       
  1607         def __comb_common_noversion(self, fmri, dotrim, obsolete_ok):
       
  1608                 """Implements versionless comb logic."""
       
  1609 
       
  1610                 all_fmris = self.__get_catalog_fmris(fmri.pkg_name)
       
  1611                 matching = frozenset((
       
  1612                     f
       
  1613                     for f in all_fmris
       
  1614                     if not dotrim or f not in self.__trim_dict
       
  1615                     if obsolete_ok or not self.__fmri_is_obsolete(f)
       
  1616                 ))
       
  1617                 remaining = frozenset(set(all_fmris) - matching)
       
  1618                 return matching, remaining
       
  1619 
       
  1620         def __comb_common_version(self, fmri, dotrim, constraint, obsolete_ok):
       
  1621                 """Implements versioned comb logic."""
       
  1622 
       
  1623                 # If using a version constraint that cares about branch (but not
       
  1624                 # timestr), the fmris will have to be resorted so that the
       
  1625                 # version chopping done here works as expected.  This is because
       
  1626                 # version sort order is release, branch, timestr which is
       
  1627                 # different than is_successor() order.  However, if the provided
       
  1628                 # FMRI has a timestamp, doesn't have a branch, or we're applying
       
  1629                 # a constraint that doesn't care about the branch, then we don't
       
  1630                 # need to resort.
       
  1631                 mver = fmri.version
       
  1632                 branch_sort = not mver.timestr and mver.branch and \
       
  1633                     constraint not in (version.CONSTRAINT_NONE,
       
  1634                         version.CONSTRAINT_RELEASE,
       
  1635                         version.CONSTRAINT_RELEASE_MAJOR,
       
  1636                         version.CONSTRAINT_RELEASE_MINOR)
       
  1637 
       
  1638                 all_fmris = self.__get_catalog_fmris(fmri.pkg_name)
       
  1639                 if branch_sort:
       
  1640                         # The first version of this attempted to perform
       
  1641                         # multiple passes to avoid the cost of sorting by
       
  1642                         # finding the last entry that matched CONSTRAINT_RELEASE
       
  1643                         # and then only resorting the slice of comb_fmris from
       
  1644                         # first_ver to last_ver, but that actually ended up
       
  1645                         # being slower because multiple passes with
       
  1646                         # is_successor() (even over a small portion of
       
  1647                         # comb_fmris) is more expensive than simply resorting
       
  1648                         # the entire list.  Ideally, we'd get the entries from
       
  1649                         # __get_catalog_fmris() in this order already which
       
  1650                         # would be faster since we'd avoid a second sort.
       
  1651                         skey = operator.attrgetter(
       
  1652                             'version.branch', 'version.release')
       
  1653                         # Always use a copy; return value may be cached.
       
  1654                         comb_fmris = sorted(all_fmris, key=skey,
       
  1655                             reverse=True)
       
  1656                 else:
       
  1657                         # Always use a copy; return value may be cached.
       
  1658                         comb_fmris = all_fmris[::-1]
       
  1659 
       
  1660                 # Iteration is performed in descending version order with the
       
  1661                 # assumption that systems are generally up-to-date so it should
       
  1662                 # be faster to start at the end and look for the oldest version
       
  1663                 # that matches.
       
  1664                 first_ver = None
       
  1665                 last_ver = None
       
  1666                 for i, f in enumerate(comb_fmris):
       
  1667                         fver = f.version
       
  1668                         if ((fver.is_successor(mver, constraint=constraint) or
       
  1669                             fver == mver)):
       
  1670                                 if first_ver is None:
       
  1671                                         first_ver = i
       
  1672                                 last_ver = i
       
  1673                         elif last_ver is not None:
       
  1674                                 break
       
  1675 
       
  1676                 if last_ver is not None:
       
  1677                         # Oddly enough, it's a little bit faster to iterate
       
  1678                         # through the slice of comb_fmris again and store
       
  1679                         # matches here instead of above.  Perhaps variable
       
  1680                         # scoping overhead is to blame?
       
  1681                         matching = []
       
  1682                         remaining = []
       
  1683                         for f in comb_fmris[first_ver:last_ver + 1]:
       
  1684                                 if ((not dotrim or
       
  1685                                     f not in self.__trim_dict) and
       
  1686                                     (obsolete_ok or not
       
  1687                                         self.__fmri_is_obsolete(f))):
       
  1688                                         matching.append(f)
       
  1689                                 else:
       
  1690                                         remaining.append(f)
       
  1691                         matching = frozenset(matching)
       
  1692                         remaining = frozenset(chain(
       
  1693                             comb_fmris[:first_ver],
       
  1694                             remaining,
       
  1695                             comb_fmris[last_ver + 1:]))
       
  1696                 else:
       
  1697                         matching = frozenset()
       
  1698                         remaining = frozenset(comb_fmris)
       
  1699 
       
  1700                 return matching, remaining
       
  1701 
  1558 
  1702         def __comb_common(self, fmri, dotrim, constraint, obsolete_ok):
  1559         def __comb_common(self, fmri, dotrim, constraint, obsolete_ok):
  1703                 """Underlying impl. of other comb routines"""
  1560                 """Underlying impl. of other comb routines"""
  1704 
  1561 
  1705                 self.__progress()
  1562                 self.__progress()
  1707                 tp = (fmri, dotrim, constraint, obsolete_ok) # cache index
  1564                 tp = (fmri, dotrim, constraint, obsolete_ok) # cache index
  1708                 # determine if the data is cacheable or cached:
  1565                 # determine if the data is cacheable or cached:
  1709                 if (not self.__trimdone and dotrim) or tp not in self.__cache:
  1566                 if (not self.__trimdone and dotrim) or tp not in self.__cache:
  1710                         # use frozensets so callers don't inadvertently update
  1567                         # use frozensets so callers don't inadvertently update
  1711                         # these sets (which may be cached).
  1568                         # these sets (which may be cached).
  1712                         if not fmri.version or not fmri.version.release:
  1569                         all_fmris = set(self.__get_catalog_fmris(fmri.pkg_name))
  1713                                 matching, remaining = \
  1570                         matching = frozenset([
  1714                                     self.__comb_common_noversion(fmri, dotrim,
  1571                             f
  1715                                         obsolete_ok)
  1572                             for f in all_fmris
  1716                         else:
  1573                             if f not in self.__trim_dict or not dotrim
  1717                                 matching, remaining = \
  1574                             if not fmri.version or
  1718                                     self.__comb_common_version(fmri, dotrim,
  1575                                 fmri.version == f.version or
  1719                                         constraint, obsolete_ok)
  1576                                 f.version.is_successor(fmri.version,
       
  1577                                     constraint=constraint)
       
  1578                             if obsolete_ok or not self.__fmri_is_obsolete(f)
       
  1579                         ])
       
  1580                         remaining = frozenset(all_fmris - matching)
  1720 
  1581 
  1721                         # if we haven't finished trimming, don't cache this
  1582                         # if we haven't finished trimming, don't cache this
  1722                         if not self.__trimdone:
  1583                         if not self.__trimdone:
  1723                                 return matching, remaining
  1584                                 return matching, remaining
  1724                         # cache the result
  1585                         # cache the result