'Sets the parts_wanted key for each of the devices to the number of
partitions the device wants based on its relative weight. This key is
used to sort the devices according to "most wanted" during rebalancing
to best distribute partitions. A negative parts_wanted indicates the
device is "overweight" and wishes to give partitions away if possible.
:param replica_plan: a dict of dicts, as returned from
_build_replica_plan, that that maps
each tier to it\'s target replicanths.'

def _set_parts_wanted(self, replica_plan):

    tier2children = self._build_tier2children()
    parts_by_tier = defaultdict(int)
    def place_parts(tier, parts):
        parts_by_tier[tier] = parts
        sub_tiers = sorted(tier2children[tier])
        if (not sub_tiers):
            return
        to_place = defaultdict(int)
        for t in sub_tiers:
            to_place[t] = min(parts, int(math.floor((replica_plan[t]['target'] * self.parts))))
            parts -= to_place[t]
        sub_tier_gen = itertools.cycle(sorted(sub_tiers, key=(lambda t: replica_plan[t]['target'])))
        while (parts > 0):
            t = next(sub_tier_gen)
            to_place[t] += 1
            parts -= 1
        for (t, p) in to_place.items():
            place_parts(t, p)
    total_parts = int((self.replicas * self.parts))
    place_parts((), total_parts)
    tiers = ['cluster', 'regions', 'zones', 'servers', 'devices']
    for (i, tier_name) in enumerate(tiers):
        parts_at_tier = sum((parts_by_tier[t] for t in parts_by_tier if (len(t) == i)))
        if (parts_at_tier != total_parts):
            raise exceptions.RingValidationError(('%s    !=    %s    at    tier    %s' % (parts_at_tier, total_parts, tier_name)))
    for dev in self._iter_devs():
        if (not dev['weight']):
            dev['parts_wanted'] = ((- self.parts) * self.replicas)
        else:
            tier = (dev['region'], dev['zone'], dev['ip'], dev['id'])
            dev['parts_wanted'] = (parts_by_tier[tier] - dev['parts'])
