Beispiel #1
0
    def __get_chunk_uuids_by_host_uuid(cls,
                                       chunk_uuids, acceptor_host_uuid, rdbw):
        """Get the actual distribution of chunks to the hosts which have them.

        @todo: the complexity of the function depends on the complexity
            of C{TrustedQueries.TrustedChunks.get_host_uuids_for_chunks()}.

        @param chunk_uuids: the UUIDs of the chunks whose location (on the
            peers) we want to know.
        @type chunk_uuids: col.Iterable

        @param acceptor_host_uuid: the UUID of the host for which the restore
            is executed.
        @type acceptor_host_uuid: PeerUUID
        @type rdbw: DatabaseWrapperSQLAlchemy

        @return: the mapping from the host UUID to the chunks (ones from
            C{chunk_uuids}) which are stored on that host.
            If the "p2p_storage" feature is supported,
            all hosts which have these chunks are returned;
            otherwise, only the Trusted Hosts and the acceptor host
            are returned.
        @rtype: col.Mapping
        """
        # Get the hosts which carry these chunks, but differently
        # depending upon the availability of the P2P storage.
        _chunk_uuids_by_host_uuid = \
            TrustedQueries.TrustedChunks.get_host_uuids_for_chunks(
                chunk_uuids, rdbw)

        # Now filter the result depending on the system capabilities.

        feature_set = settings.get_feature_set()
        if feature_set.p2p_storage:
            # With "p2p_storage" feature, each host may serve some chunks
            # separately.
            result = _chunk_uuids_by_host_uuid

        else:
            # Without "p2p_storage" feature, let's consider that only
            # Trusted Hosts serve the chunks.
            _trusted_storage_host_uuids = \
                {h.uuid
                     for h in TrustedQueries.HostAtNode.get_all_trusted_hosts(
                                  for_storage=True, rdbw=rdbw)}
            _wanted_host_uuids = \
                _trusted_storage_host_uuids | {acceptor_host_uuid}
            result = {h_uuid: c_uuids
                          for h_uuid, c_uuids
                              in _chunk_uuids_by_host_uuid.iteritems()
                          if h_uuid in _wanted_host_uuids}

        return result
Beispiel #2
0
    def __find_hosts(self):
        """
        @rtype: PBHResultData
        """
        cls = self.__class__

        result_code = ProvideBackupHostsMessage.ResultCodes.OK
        result = {}

        if __debug__:
            rng = random.Random(42)
        else:
            rng = None

        host = self.message.src
        feature_set = settings.get_feature_set()

        if feature_set.p2p_storage:
            _hosts = self.manager.app.known_hosts.alive_peers(
                filter_uuid=host.uuid)
        else:
            _hosts = self.manager.app.known_hosts.alive_trusted_hosts(
                for_storage=True)

        # Make sure _hosts is reiterable
        hosts = list(_hosts)
        logger.debug('For backup, will be using the following hosts: %r',
                     hosts)

        uuids_to_urls = {h.uuid: h.urls for h in hosts}

        # To be safe, let's distribute only the hosts which have urls defined
        # and non-empty
        host_uuids_to_distribute = frozenset(h.uuid for h in hosts if h.urls)

        hosts_free_space_map = \
            {host_uuid: stat.free_size
                 for host_uuid, stat
                     in TrustedQueries.SpaceStat.get_hosts_space_stat()
                                                .iteritems()
                 if host_uuid in host_uuids_to_distribute}

        data = self.message.chunks_by_size_code

        if not host_uuids_to_distribute:
            # Probably, we cannot complete a backup.
            # But if there is not chunk data to backup,... yes we can!
            if sum(data.itervalues()) == 0:
                result_code = ProvideBackupHostsMessage.ResultCodes.OK
                logger.debug(
                    '%r attempts a backup with no chunks, '
                    'when there are no hosts', host)
            else:
                result_code = \
                    ProvideBackupHostsMessage.ResultCodes.NO_SPACE_ON_CLOUD
                logger.warning('%r attempts a backup, but there is no hosts!',
                               host)

        else:
            # We should try to complete a backup.
            logger.debug('Distributing to: %r', host_uuids_to_distribute)

            try:
                _result = cls._calculate_distribution(
                    chunks_map=data,
                    hosts_free_space_map=hosts_free_space_map,
                    rng=rng)

            except NoSpaceError:
                result_code = ProvideBackupHostsMessage.ResultCodes \
                                                       .NO_SPACE_ON_CLOUD
                result = {}
                logger.debug(
                    'Could not allocate all the required chunks '
                    'due to error %i! %r, %r', result_code,
                    hosts_free_space_map, data)

            else:
                result_code = ProvideBackupHostsMessage.ResultCodes.OK
                result = {
                    host_uuid: PerHostChunksData(urls=uuids_to_urls[host_uuid],
                                                 chunks_by_size=per_host)
                    for host_uuid, per_host in _result.iteritems()
                }
                logger.debug('Allocated the chunks! %r, %r', data, _result)

            logger.debug('Final result %r', result)

        # By now, we have calculated "result_code" and "result" variables.

        return PBHResultData(result_code=result_code, result=result)
Beispiel #3
0
    def __find_hosts(self):
        """
        @rtype: PBHResultData
        """
        cls = self.__class__

        result_code = ProvideBackupHostsMessage.ResultCodes.OK
        result = {}

        if __debug__:
            rng = random.Random(42)
        else:
            rng = None

        host = self.message.src
        feature_set = settings.get_feature_set()

        if feature_set.p2p_storage:
            _hosts = self.manager.app.known_hosts.alive_peers(
                         filter_uuid=host.uuid)
        else:
            _hosts = self.manager.app.known_hosts.alive_trusted_hosts(
                         for_storage=True)

        # Make sure _hosts is reiterable
        hosts = list(_hosts)
        logger.debug('For backup, will be using the following hosts: %r',
                     hosts)

        uuids_to_urls = {h.uuid: h.urls for h in hosts}

        # To be safe, let's distribute only the hosts which have urls defined
        # and non-empty
        host_uuids_to_distribute = frozenset(h.uuid for h in hosts
                                                    if h.urls)

        hosts_free_space_map = \
            {host_uuid: stat.free_size
                 for host_uuid, stat
                     in TrustedQueries.SpaceStat.get_hosts_space_stat()
                                                .iteritems()
                 if host_uuid in host_uuids_to_distribute}

        data = self.message.chunks_by_size_code

        if not host_uuids_to_distribute:
            # Probably, we cannot complete a backup.
            # But if there is not chunk data to backup,... yes we can!
            if sum(data.itervalues()) == 0:
                result_code = ProvideBackupHostsMessage.ResultCodes.OK
                logger.debug('%r attempts a backup with no chunks, '
                                 'when there are no hosts',
                             host)
            else:
                result_code = \
                    ProvideBackupHostsMessage.ResultCodes.NO_SPACE_ON_CLOUD
                logger.warning('%r attempts a backup, but there is no hosts!',
                               host)

        else:
            # We should try to complete a backup.
            logger.debug('Distributing to: %r', host_uuids_to_distribute)

            try:
                _result = cls._calculate_distribution(
                              chunks_map=data,
                              hosts_free_space_map=hosts_free_space_map,
                              rng=rng)

            except NoSpaceError:
                result_code = ProvideBackupHostsMessage.ResultCodes \
                                                       .NO_SPACE_ON_CLOUD
                result = {}
                logger.debug('Could not allocate all the required chunks '
                                 'due to error %i! %r, %r',
                             result_code, hosts_free_space_map, data)

            else:
                result_code = ProvideBackupHostsMessage.ResultCodes.OK
                result = {host_uuid: PerHostChunksData(
                                         urls=uuids_to_urls[host_uuid],
                                         chunks_by_size=per_host)
                              for host_uuid, per_host in _result.iteritems()}
                logger.debug('Allocated the chunks! %r, %r',
                             data, _result)

            logger.debug('Final result %r', result)

        # By now, we have calculated "result_code" and "result" variables.

        return PBHResultData(result_code=result_code,
                             result=result)