From 4d76d60ac572237b27c14a7c4c1199eab2fae19d Mon Sep 17 00:00:00 2001
From: David Lehman <dlehman@redhat.com>
Date: Fri, 20 Jun 2014 15:17:21 -0500
Subject: [PATCH 09/12] Remove the TotalSizeSet, SameSizeSet clases and
 manageSizeSets.

---
 blivet/partitioning.py | 171 +++++++++++--------------------------------------
 1 file changed, 39 insertions(+), 132 deletions(-)

diff --git a/blivet/partitioning.py b/blivet/partitioning.py
index 671dbc8..515d889 100644
--- a/blivet/partitioning.py
+++ b/blivet/partitioning.py
@@ -1791,18 +1791,20 @@ def getDiskChunks(disk, partitions, free):
 
     return chunks
 
-class TotalSizeSet(object):
-    """ Set of device requests with a target combined size.
-
-        This will be handled by growing the requests until the desired combined
-        size has been achieved.
-    """
-    def __init__(self, devices, size):
+class SizeSet(object):
+    """ Manage the sizes of a set of related requests. """
+    def __init__(self, devices, total_size, uniform=False):
         """
-            :param devices: the set of devices
-            :type devices: list of :class:`~.devices.PartitionDevice`
-            :param size: the target combined size
-            :type size: :class:`~.size.Size`
+            :param devices: iterable containing the set members
+            :type devices: list of :class:`~.devices.StorageDevice`
+            :param :class:`~.size.Size` total_size: target sum of member sizes
+            :keyword bool uniform: whether member sizes should be the same
+
+            .. note::
+
+                A total_size of None means the set should grow as large as
+                possible.
+
         """
         self.devices = []
         for device in devices:
@@ -1813,137 +1815,42 @@ class TotalSizeSet(object):
 
             self.devices.append(partition)
 
-        self.size = size
+        self.total = total_size
+        self.allocated = 0
+        self.uniform = uniform
+        self.done = False
 
-        self.requests = []
+        self.reset()
 
-        self.allocated = sum([d.req_base_size for d in self.devices])
-        log.debug("set.allocated = %d", self.allocated)
+    def __str__(self):
+        values = { "classname": self.__class__.__name__,
+                   "devices": [d.name for d in self.devices],
+                   "total": self.total, "allocated": self.allocated,
+                   "needed": self.needed, "uniform": self.uniform }
+        fmt = "%(classname)s: devices=%(devices)s  total=%(total)s  "
+        fmt += "uniform=%(uniform)s  allocated=%(allocated)s  needed=%(needed)s"
+        return fmt % values
+
+    def reset(self):
+        log.debug("resetting %s", self)
+        self.allocated = sum(d.size for d in self.devices)
+        self.done = False
 
     def allocate(self, amount):
-        log.debug("allocating %d to TotalSizeSet with %d/%d (%d needed)",
-                    amount, self.allocated, self.size, self.needed)
+        log.debug("allocating %s to %s", amount, self)
         self.allocated += amount
 
-    @property
-    def needed(self):
-        return self.size - self.allocated
-
     def deallocate(self, amount):
-        log.debug("deallocating %d from TotalSizeSet with %d/%d (%d needed)",
-                    amount, self.allocated, self.size, self.needed)
+        log.debug("deallocating %d from %s", amount, self)
         self.allocated -= amount
 
-class SameSizeSet(object):
-    """ Set of device requests with a common target size. """
-    def __init__(self, devices, size, grow=False, max_size=None):
-        """
-            :param devices: the set of devices
-            :type devices: list of :class:`~.devices.PartitionDevice`
-            :param size: target size for each device/request
-            :type size: :class:`~.size.Size`
-            :keyword grow: whether the devices can be grown
-            :type grow: bool
-            :keyword max_size: the maximum size for growable devices
-            :type max_size: :class:`~.size.Size`
-        """
-        self.devices = []
-        for device in devices:
-            if isinstance(device, LUKSDevice):
-                partition = device.slave
-            else:
-                partition = device
-
-            self.devices.append(partition)
-
-        self.size = int(size / len(devices))
-        self.grow = grow
-        self.max_size = max_size
-
-        self.requests = []
-
-def manageSizeSets(size_sets, chunks):
-    growth_by_request = {}
-    requests_by_device = {}
-    chunks_by_request = {}
-    for chunk in chunks:
-        for request in chunk.requests:
-            requests_by_device[request.device] = request
-            chunks_by_request[request] = chunk
-            growth_by_request[request] = 0
-
-    for i in range(2):
-        reclaimed = dict([(chunk, 0) for chunk in chunks])
-        for ss in size_sets:
-            if isinstance(ss, TotalSizeSet):
-                # TotalSizeSet members are trimmed to achieve the requested
-                # total size
-                log.debug("set: %s %d/%d", [d.name for d in ss.devices],
-                                           ss.allocated, ss.size)
-
-                for device in ss.devices:
-                    request = requests_by_device[device]
-                    chunk = chunks_by_request[request]
-                    new_growth = request.growth - growth_by_request[request]
-                    ss.allocate(chunk.lengthToSize(new_growth))
-
-                # decide how much to take back from each request
-                # We may assume that all requests have the same base size.
-                # We're shooting for a roughly equal distribution by trimming
-                # growth from the requests that have grown the most first.
-                requests = sorted([requests_by_device[d] for d in ss.devices],
-                                  key=lambda r: r.growth, reverse=True)
-                needed = ss.needed
-                for request in requests:
-                    chunk = chunks_by_request[request]
-                    log.debug("%s", request)
-                    log.debug("needed: %d", ss.needed)
-
-                    if ss.needed < 0:
-                        # it would be good to take back some from each device
-                        # instead of taking all from the last one(s)
-                        extra = -chunk.sizeToLength(needed) / len(ss.devices)
-                        if extra > request.growth and i == 0:
-                            log.debug("not reclaiming from this request")
-                            continue
-                        else:
-                            extra = min(extra, request.growth)
-
-                        reclaimed[chunk] += extra
-                        chunk.reclaim(request, extra)
-                        ss.deallocate(chunk.lengthToSize(extra))
-
-                    if ss.needed <= 0:
-                        request.done = True
-
-            elif isinstance(ss, SameSizeSet):
-                # SameSizeSet members all have the same size as the smallest
-                # member
-                requests = [requests_by_device[d] for d in ss.devices]
-                _min_growth = min([r.growth for r in requests])
-                log.debug("set: %s %d", [d.name for d in ss.devices], ss.size)
-                log.debug("min growth is %d", _min_growth)
-                for request in requests:
-                    chunk = chunks_by_request[request]
-                    _max_growth = chunk.sizeToLength(ss.size) - request.base
-                    log.debug("max growth for %s is %d", request, _max_growth)
-                    min_growth = max(min(_min_growth, _max_growth), 0)
-                    if request.growth > min_growth:
-                        extra = request.growth - min_growth
-                        reclaimed[chunk] += extra
-                        chunk.reclaim(request, extra)
-                        request.done = True
-                    elif request.growth == min_growth:
-                        request.done = True
-
-        # store previous growth amounts so we know how much was allocated in
-        # the latest growRequests call
-        for request in growth_by_request.keys():
-            growth_by_request[request] = request.growth
+    @property
+    def needed(self):
+        """ Needed space as :class:`~.size.Size` or None if unbounded """
+        if self.total is None:
+            return None
 
-        for chunk in chunks:
-            if reclaimed[chunk] and not chunk.done:
-                chunk.growRequests()
+        return self.total - self.allocated
 
 def growPartitions(disks, partitions, free, size_sets=None):
     """ Grow all growable partition requests.
-- 
1.9.3

