Ejemplo n.º 1
0
    def execute(self,
                shard_id,
                group_id,
                split_value=None,
                update_only=False,
                synchronous=True):
        """Split the shard represented by the shard_id into the destination
        group.

        :param shard_id: The shard_id of the shard that needs to be split.
        :param group_id: The ID of the group into which the split data needs
                         to be moved.
        :param split_value: The value at which the range needs to be split.
        :update_only: Only update the state store and skip provisioning.
        :param synchronous: Whether one should wait until the execution
                            finishes
        """
        mysqldump_binary = _services_utils.read_config_value(
            self.config, 'sharding', 'mysqldump_program')
        mysqlclient_binary = _services_utils.read_config_value(
            self.config, 'sharding', 'mysqlclient_program')
        prune_limit = _services_utils.read_config_value(
            self.config, 'sharding', 'prune_limit')
        config_file = self.config.config_file if self.config.config_file else ""

        procedures = _events.trigger(CHECK_SHARD_INFORMATION,
                                     self.get_lockable_objects(), shard_id,
                                     group_id, mysqldump_binary,
                                     mysqlclient_binary, split_value,
                                     config_file, prune_limit, "SPLIT",
                                     update_only)
        return self.wait_for_procedures(procedures, synchronous)
Ejemplo n.º 2
0
    def execute(self, shard_id, group_id, update_only=False,
                synchronous=True):
        """Move the shard represented by the shard_id to the destination group.

        :param shard_id: The ID of the shard that needs to be moved.
        :param group_id: The ID of the group to which the shard needs to
                         be moved.
        :update_only: Only update the state store and skip provisioning.
        :param synchronous: Whether one should wait until the execution finishes
                        or not.
        """
        mysqldump_binary = _services_utils.read_config_value(
                                self.config,
                                'sharding',
                                'mysqldump_program'
                            )
        mysqlclient_binary = _services_utils.read_config_value(
                                self.config,
                                'sharding',
                                'mysqlclient_program'
                            )
        config_file = self.config.config_file if self.config.config_file else ""

        procedures = _events.trigger(
            CHECK_SHARD_INFORMATION, self.get_lockable_objects(), shard_id,
            group_id, mysqldump_binary, mysqlclient_binary, None, config_file,
            "", "MOVE", update_only
        )
        return self.wait_for_procedures(procedures, synchronous)
Ejemplo n.º 3
0
def _restore_server(source_uuid, host, port, backup_image):
    """Restore the backup on the destination Server.

    :param source_uuid: The UUID of the source server.
    :param host: The hostname of the destination server.
    :param port: The port number of the destination server.
    :param backup_image: The backup image path.
    """
    restore_user = _services_utils.read_config_value(_config.global_config,
                                                     'servers', 'restore_user')
    restore_passwd = _services_utils.read_config_value(_config.global_config,
                                                       'servers',
                                                       'restore_password')

    mysqlclient_binary = _services_utils.read_config_value(
        _config.global_config, 'sharding', 'mysqlclient_program')

    source_server = _server.MySQLServer.fetch(source_uuid)
    if not source_server:
        raise _errors.ServerError(SERVER_NOT_FOUND % source_uuid)
    #Build a backup image that will be used for restoring
    bk_img = _backup.BackupImage(backup_image)
    _backup.MySQLDump.restore_server(host, port, restore_user, restore_passwd,
                                     bk_img, mysqlclient_binary)
    _LOGGER.debug("Done with restore of server with host = %s, port = %s",
                  host, port)
Ejemplo n.º 4
0
def _restore_shard_backup(shard_id, source_group_id, destn_group_id,
                          backup_image, split_value, prune_limit, cmd):
    """Restore the backup on the destination Group.

    :param shard_id: The shard ID of the shard that needs to be moved.
    :param source_group_id: The group_id of the source shard.
    :param destn_group_id: The ID of the group to which the shard needs to
                           be moved.
    :param backup_image: The destination file that contains the backup
                         of the source shard.
    :param split_value: Indicates the value at which the range for the
                        particular shard will be split. Will be set only
                        for shard split operations.
    :param prune_limit: The number of DELETEs that should be
                        done in one batch.
    :param cmd: Indicates the type of re-sharding operation
    """
    restore_user = _services_utils.read_config_value(
                            _config.global_config,
                            'servers',
                            'restore_user'
                        )
    restore_passwd = _services_utils.read_config_value(
                            _config.global_config,
                            'servers',
                            'restore_password'
                        )
    mysqlclient_binary = _services_utils.read_config_value(
                            _config.global_config,
                            'sharding',
                            'mysqlclient_program'
                        )

    destn_group = Group.fetch(destn_group_id)
    if destn_group is None:
        raise _errors.ShardingError(_services_sharding.SHARD_GROUP_NOT_FOUND %
                                    (destn_group_id, ))

    #Build a backup image that will be used for restoring
    bk_img = _backup.BackupImage(backup_image)

    for destn_group_server in destn_group.servers():
        destn_group_server.connect()
        _backup.MySQLDump.restore_fabric_server(
            destn_group_server,
            restore_user, restore_passwd,
            bk_img,
            mysqlclient_binary
        )

    #Setup sync between the source and the destination groups.
    _events.trigger_within_procedure(
                                     SETUP_REPLICATION,
                                     shard_id,
                                     source_group_id,
                                     destn_group_id,
                                     split_value,
                                     prune_limit,
                                     cmd
                                     )
Ejemplo n.º 5
0
    def execute(self, shard_id, group_id, split_value=None,
                update_only=False, synchronous=True):
        """Split the shard represented by the shard_id into the destination
        group.

        :param shard_id: The shard_id of the shard that needs to be split.
        :param group_id: The ID of the group into which the split data needs
                         to be moved.
        :param split_value: The value at which the range needs to be split.
        :update_only: Only update the state store and skip provisioning.
        :param synchronous: Whether one should wait until the execution
                            finishes
        """
        mysqldump_binary = _services_utils.read_config_value(
                                self.config,
                                'sharding',
                                'mysqldump_program'
                            )
        mysqlclient_binary = _services_utils.read_config_value(
                                self.config,
                                'sharding',
                                'mysqlclient_program'
                            )
        prune_limit =   _services_utils.read_config_value(
                                self.config,
                                'sharding',
                                'prune_limit'
                            )
        config_file = self.config.config_file if self.config.config_file else ""

        procedures = _events.trigger(
            CHECK_SHARD_INFORMATION, self.get_lockable_objects(),
            shard_id, group_id, mysqldump_binary, mysqlclient_binary,
            split_value, config_file, prune_limit, "SPLIT", update_only)
        return self.wait_for_procedures(procedures, synchronous)
Ejemplo n.º 6
0
def _restore_shard_backup(shard_id, source_group_id, destn_group_id,
                          backup_image, split_value, prune_limit, cmd):
    """Restore the backup on the destination Group.

    :param shard_id: The shard ID of the shard that needs to be moved.
    :param source_group_id: The group_id of the source shard.
    :param destn_group_id: The ID of the group to which the shard needs to
                           be moved.
    :param backup_image: The destination file that contains the backup
                         of the source shard.
    :param split_value: Indicates the value at which the range for the
                        particular shard will be split. Will be set only
                        for shard split operations.
    :param prune_limit: The number of DELETEs that should be
                        done in one batch.
    :param cmd: Indicates the type of re-sharding operation
    """
    restore_user = _services_utils.read_config_value(
                            _config.global_config,
                            'servers',
                            'restore_user'
                        )
    restore_passwd = _services_utils.read_config_value(
                            _config.global_config,
                            'servers',
                            'restore_password'
                        )
    mysqlclient_binary = _services_utils.read_config_value(
                            _config.global_config,
                            'sharding',
                            'mysqlclient_program'
                        )

    destn_group = Group.fetch(destn_group_id)
    if destn_group is None:
        raise _errors.ShardingError(_services_sharding.SHARD_GROUP_NOT_FOUND %
                                    (destn_group_id, ))

    #Build a backup image that will be used for restoring
    bk_img = _backup.BackupImage(backup_image)

    for destn_group_server in destn_group.servers():
        destn_group_server.connect()
        _backup.MySQLDump.restore_fabric_server(
            destn_group_server,
            restore_user, restore_passwd,
            bk_img,
            mysqlclient_binary
        )

    #Setup sync between the source and the destination groups.
    _events.trigger_within_procedure(
                                     SETUP_REPLICATION,
                                     shard_id,
                                     source_group_id,
                                     destn_group_id,
                                     split_value,
                                     prune_limit,
                                     cmd
                                     )
Ejemplo n.º 7
0
    def execute(self, group_id, destn_address, server_id=None, timeout=None,
                synchronous=True):
        """Clone the objects of a given server into a destination server.

        :param group_id: The ID of the source group.
        :param destn_address: The address of the destination MySQL Server.
        :param source_id: The address or UUID of the source MySQL Server.
        :param timeout: Time in seconds after which an error is reported
                        if the destination server is unreachable.
        :param synchronous: Whether one should wait until the execution
                            finishes or not.
        """
        # If the destination server is already part of a Fabric Group, raise
        # an error
        destn_server_uuid = _lookup_uuid(destn_address, timeout)
        _check_server_not_in_any_group(destn_server_uuid)
        host, port = split_host_port(
            destn_address, _backup.MySQLDump.MYSQL_DEFAULT_PORT
        )

        # Fetch information on backup and restore programs.
        config_file = self.config.config_file if self.config.config_file else ""

        mysqldump_binary = _utils.read_config_value(
                                self.config,
                                'sharding',
                                'mysqldump_program'
                            )
        mysqlclient_binary = _utils.read_config_value(
                                self.config,
                                'sharding',
                                'mysqlclient_program'
                            )

        if not _utils.is_valid_binary(mysqldump_binary):
            raise _errors.ServerError(MYSQLDUMP_NOT_FOUND % mysqldump_binary)

        if not _utils.is_valid_binary(mysqlclient_binary):
            raise _errors.ServerError(MYSQLCLIENT_NOT_FOUND % mysqlclient_binary)

        # Fetch a reference to source server.
        if server_id:
            server = _retrieve_server(server_id, group_id)
        else:
            group = _retrieve_group(group_id)
            server = _utils.fetch_backup_server(group)

        # Schedule the clone operation through the executor.
        procedures = _events.trigger(
            BACKUP_SERVER,
            self.get_lockable_objects(),
            str(server.uuid),
            host,
            port,
            mysqldump_binary,
            mysqlclient_binary,
            config_file
        )
        return self.wait_for_procedures(procedures, synchronous)
Ejemplo n.º 8
0
def _backup_source_shard(shard_id, source_group_id, destn_group_id,
                         split_value, prune_limit, cmd, update_only):
    """Backup the source shard.

    :param shard_id: The shard ID of the shard that needs to be moved.
    :param source_group_id: The group_id of the source shard.
    :param destn_group_id: The ID of the group to which the shard needs to
                           be moved.
    :param split_value: Indicates the value at which the range for the
                        particular shard will be split. Will be set only
                        for shard split operations.
    :param prune_limit: The number of DELETEs that should be
                        done in one batch.
    :param cmd: Indicates the type of re-sharding operation (move, split)
    :update_only: Only update the state store and skip provisioning.
    """
    backup_user = _services_utils.read_config_value(
                            _config.global_config,
                            'servers',
                            'backup_user'
                        )
    backup_passwd = _services_utils.read_config_value(
                            _config.global_config,
                            'servers',
                            'backup_password'
                        )
    mysqldump_binary = _services_utils.read_config_value(
                            _config.global_config,
                            'sharding',
                            'mysqldump_program'
                        )

    source_group = Group.fetch(source_group_id)
    move_source_server = _services_utils.fetch_backup_server(source_group)

    #Do the backup of the group hosting the source shard.
    backup_image = _backup.MySQLDump.backup(
                        move_source_server,
                        backup_user, backup_passwd,
                        mysqldump_binary
                    )

    #Change the master for the server that is master of the group which hosts
    #the destination shard.
    _events.trigger_within_procedure(
                                     RESTORE_SHARD_BACKUP,
                                     shard_id,
                                     source_group_id,
                                     destn_group_id,
                                     backup_image.path,
                                     split_value,
                                     prune_limit,
                                     cmd
                                     )
Ejemplo n.º 9
0
def _backup_source_shard(shard_id, source_group_id, destn_group_id,
                         split_value, prune_limit, cmd, update_only):
    """Backup the source shard.

    :param shard_id: The shard ID of the shard that needs to be moved.
    :param source_group_id: The group_id of the source shard.
    :param destn_group_id: The ID of the group to which the shard needs to
                           be moved.
    :param split_value: Indicates the value at which the range for the
                        particular shard will be split. Will be set only
                        for shard split operations.
    :param prune_limit: The number of DELETEs that should be
                        done in one batch.
    :param cmd: Indicates the type of re-sharding operation (move, split)
    :update_only: Only update the state store and skip provisioning.
    """
    backup_user = _services_utils.read_config_value(
                            _config.global_config,
                            'servers',
                            'backup_user'
                        )
    backup_passwd = _services_utils.read_config_value(
                            _config.global_config,
                            'servers',
                            'backup_password'
                        )
    mysqldump_binary = _services_utils.read_config_value(
                            _config.global_config,
                            'sharding',
                            'mysqldump_program'
                        )

    source_group = Group.fetch(source_group_id)
    move_source_server = _services_utils.fetch_backup_server(source_group)

    #Do the backup of the group hosting the source shard.
    backup_image = _backup.MySQLDump.backup(
                        move_source_server,
                        backup_user, backup_passwd,
                        mysqldump_binary
                    )

    #Change the master for the server that is master of the group which hosts
    #the destination shard.
    _events.trigger_within_procedure(
                                     RESTORE_SHARD_BACKUP,
                                     shard_id,
                                     source_group_id,
                                     destn_group_id,
                                     backup_image.path,
                                     split_value,
                                     prune_limit,
                                     cmd
                                     )
Ejemplo n.º 10
0
    def execute(self,
                group_id,
                destn_address,
                server_id=None,
                timeout=None,
                synchronous=True):
        """Clone the objects of a given server into a destination server.

        :param group_id: The ID of the source group.
        :param destn_address: The address of the destination MySQL Server.
        :param source_id: The address or UUID of the source MySQL Server.
        :param timeout: Time in seconds after which an error is reported
                        if the destination server is unreachable.
        :param synchronous: Whether one should wait until the execution
                            finishes or not.
        """
        # If the destination server is already part of a Fabric Group, raise
        # an error
        destn_server_uuid = _lookup_uuid(destn_address, timeout)
        _check_server_not_in_any_group(destn_server_uuid)
        host, port = split_host_port(destn_address,
                                     _backup.MySQLDump.MYSQL_DEFAULT_PORT)

        # Fetch information on backup and restore programs.
        config_file = self.config.config_file if self.config.config_file else ""

        mysqldump_binary = _utils.read_config_value(self.config, 'sharding',
                                                    'mysqldump_program')
        mysqlclient_binary = _utils.read_config_value(self.config, 'sharding',
                                                      'mysqlclient_program')

        if not _utils.is_valid_binary(mysqldump_binary):
            raise _errors.ServerError(MYSQLDUMP_NOT_FOUND % mysqldump_binary)

        if not _utils.is_valid_binary(mysqlclient_binary):
            raise _errors.ServerError(MYSQLCLIENT_NOT_FOUND %
                                      mysqlclient_binary)

        # Fetch a reference to source server.
        if server_id:
            server = _retrieve_server(server_id, group_id)
        else:
            group = _retrieve_group(group_id)
            server = _utils.fetch_backup_server(group)

        # Schedule the clone operation through the executor.
        procedures = _events.trigger(BACKUP_SERVER,
                                     self.get_lockable_objects(),
                                     str(server.uuid), host, port,
                                     mysqldump_binary, mysqlclient_binary,
                                     config_file)
        return self.wait_for_procedures(procedures, synchronous)
Ejemplo n.º 11
0
    def execute(self, shard_id, group_id, update_only=False, synchronous=True):
        """Move the shard represented by the shard_id to the destination group.

        :param shard_id: The ID of the shard that needs to be moved.
        :param group_id: The ID of the group to which the shard needs to
                         be moved.
        :update_only: Only update the state store and skip provisioning.
        :param synchronous: Whether one should wait until the execution finishes
                        or not.
        """
        mysqldump_binary = _services_utils.read_config_value(
            self.config, 'sharding', 'mysqldump_program')
        mysqlclient_binary = _services_utils.read_config_value(
            self.config, 'sharding', 'mysqlclient_program')
        config_file = self.config.config_file if self.config.config_file else ""

        procedures = _events.trigger(CHECK_SHARD_INFORMATION,
                                     self.get_lockable_objects(), shard_id,
                                     group_id, mysqldump_binary,
                                     mysqlclient_binary, None, config_file, "",
                                     "MOVE", update_only)
        return self.wait_for_procedures(procedures, synchronous)
Ejemplo n.º 12
0
def _restore_server(source_uuid, host, port, backup_image):
    """Restore the backup on the destination Server.

    :param source_uuid: The UUID of the source server.
    :param host: The hostname of the destination server.
    :param port: The port number of the destination server.
    :param backup_image: The backup image path.
    """
    restore_user = _services_utils.read_config_value(
                            _config.global_config,
                            'servers',
                            'restore_user'
                        )
    restore_passwd = _services_utils.read_config_value(
                            _config.global_config,
                            'servers',
                            'restore_password'
                        )

    mysqlclient_binary = _services_utils.read_config_value(
                            _config.global_config,
                            'sharding',
                            'mysqlclient_program'
                        )

    source_server = _server.MySQLServer.fetch(source_uuid)
    if not source_server:
        raise _errors.ServerError(SERVER_NOT_FOUND % source_uuid)
    #Build a backup image that will be used for restoring
    bk_img = _backup.BackupImage(backup_image)
    _backup.MySQLDump.restore_server(
        host,
        port,
        restore_user, restore_passwd,
        bk_img,
        mysqlclient_binary
    )
    _LOGGER.debug("Done with restore of server with host = %s, port = %s",
                  host, port)
Ejemplo n.º 13
0
def _backup_server(source_uuid, host, port):
    """Backup the source server, given by the source_uuid.

    :param source_uuid: The UUID of the source server.
    :param host: The hostname of the destination server.
    :param port: The port number of the destination server.
    """
    backup_user = _services_utils.read_config_value(_config.global_config,
                                                    'servers', 'backup_user')
    backup_passwd = _services_utils.read_config_value(_config.global_config,
                                                      'servers',
                                                      'backup_password')
    mysqldump_binary = _services_utils.read_config_value(
        _config.global_config, 'sharding', 'mysqldump_program')

    source_server = _server.MySQLServer.fetch(source_uuid)
    #Do the backup of the group hosting the source shard.
    backup_image = _backup.MySQLDump.backup(source_server, backup_user,
                                            backup_passwd, mysqldump_binary)
    _LOGGER.debug("Done with backup of server with uuid = %s.", source_uuid)
    _events.trigger_within_procedure(RESTORE_SERVER, source_uuid, host, port,
                                     backup_image.path)
Ejemplo n.º 14
0
def _backup_server(source_uuid, host, port):
    """Backup the source server, given by the source_uuid.

    :param source_uuid: The UUID of the source server.
    :param host: The hostname of the destination server.
    :param port: The port number of the destination server.
    """
    backup_user = _services_utils.read_config_value(
                            _config.global_config,
                            'servers',
                            'backup_user'
                        )
    backup_passwd = _services_utils.read_config_value(
                            _config.global_config,
                            'servers',
                            'backup_password'
                        )
    mysqldump_binary = _services_utils.read_config_value(
                            _config.global_config,
                            'sharding',
                            'mysqldump_program'
                        )

    source_server = _server.MySQLServer.fetch(source_uuid)
    #Do the backup of the group hosting the source shard.
    backup_image = _backup.MySQLDump.backup(
                        source_server,
                        backup_user, backup_passwd,
                        mysqldump_binary
                    )
    _LOGGER.debug("Done with backup of server with uuid = %s.", source_uuid)
    _events.trigger_within_procedure(
        RESTORE_SERVER,
        source_uuid,
        host,
        port,
        backup_image.path
    )
Ejemplo n.º 15
0
    def execute(self, table_name, synchronous=True):
        """Given the table name prune the tables according to the defined
        sharding specification for the table. The command prunes all the
        tables that are part of this shard. There might be multiple tables that
        are part of the same shard, these tables will be related together by
        the same sharding key.

        :param table_name: The table that needs to be sharded.
        :param synchronous: Whether one should wait until the execution finishes
                            or not.
        """
        prune_limit = _services_utils.read_config_value(
            self.config, 'sharding', 'prune_limit')
        procedures = _events.trigger(PRUNE_SHARD_TABLES,
                                     self.get_lockable_objects(), table_name,
                                     prune_limit)
        return self.wait_for_procedures(procedures, synchronous)
Ejemplo n.º 16
0
    def execute(self, table_name, synchronous=True):
        """Given the table name prune the tables according to the defined
        sharding specification for the table. The command prunes all the
        tables that are part of this shard. There might be multiple tables that
        are part of the same shard, these tables will be related together by
        the same sharding key.

        :param table_name: The table that needs to be sharded.
        :param synchronous: Whether one should wait until the execution finishes
                            or not.
        """
        prune_limit =   _services_utils.read_config_value(
                                self.config,
                                'sharding',
                                'prune_limit'
                            )
        procedures = _events.trigger(
            PRUNE_SHARD_TABLES,
            self.get_lockable_objects(),
            table_name,
            prune_limit
        )
        return self.wait_for_procedures(procedures, synchronous)
Ejemplo n.º 17
0
def _check_shard_information(shard_id, destn_group_id,
                             split_value, prune_limit, cmd, update_only):
    """Verify the sharding information before starting a re-sharding operation.

    :param shard_id: The destination shard ID.
    :param destn_group_id: The Destination group ID.
    :param split_value: The point at which the sharding definition
                        should be split.
    :param prune_limit: The number of DELETEs that should be
                        done in one batch.
    :param cmd: Indicates if it is a split or a move being executed.
    :param update_only: If the operation is a update only operation.
    """
    backup_user = _services_utils.read_config_value(
                            _config.global_config,
                            'servers',
                            'backup_user'
                        )
    backup_passwd = _services_utils.read_config_value(
                            _config.global_config,
                            'servers',
                            'backup_password'
                        )
    restore_user = _services_utils.read_config_value(
                            _config.global_config,
                            'servers',
                            'restore_user'
                        )
    restore_passwd = _services_utils.read_config_value(
                            _config.global_config,
                            'servers',
                            'restore_password'
                        )
    mysqldump_binary = _services_utils.read_config_value(
                            _config.global_config,
                            'sharding',
                            'mysqldump_program'
                        )
    mysqlclient_binary = _services_utils.read_config_value(
                            _config.global_config,
                            'sharding',
                            'mysqlclient_program'
                        )

    if not _services_utils.is_valid_binary(mysqldump_binary):
        raise _errors.ShardingError(
                _services_sharding.MYSQLDUMP_NOT_FOUND % mysqldump_binary)

    if not _services_utils.is_valid_binary(mysqlclient_binary):
        raise _errors.ShardingError(
                _services_sharding.MYSQLCLIENT_NOT_FOUND % mysqlclient_binary)

    if cmd == "SPLIT":
        range_sharding_spec, _, shard_mappings, _ = \
            _services_sharding.verify_and_fetch_shard(shard_id)
        upper_bound = \
            SHARDING_SPECIFICATION_HANDLER[shard_mappings[0].type_name].\
                        get_upper_bound(
                            range_sharding_spec.lower_bound,
                            range_sharding_spec.shard_mapping_id,
                            shard_mappings[0].type_name
                          )
        #If the underlying sharding scheme is a HASH. When a shard is split,
        #all the tables that are part of the shard, have the same sharding
        #scheme. All the shard mappings associated with this shard_id will be
        #of the same sharding type. Hence it is safe to use one of the shard
        #mappings.
        if shard_mappings[0].type_name == "HASH":
            if split_value is not None:
                raise _errors.ShardingError(
                    _services_sharding.NO_LOWER_BOUND_FOR_HASH_SHARDING
                )
            if  upper_bound is None:
                #While splitting a range, retrieve the next upper bound and
                #find the mid-point, in the case where the next upper_bound
                #is unavailable pick the maximum value in the set of values in
                #the shard.
                upper_bound = HashShardingSpecification.fetch_max_key(shard_id)

            #Calculate the split value.
            split_value = \
                SHARDING_DATATYPE_HANDLER[shard_mappings[0].type_name].\
                split_value(
                    range_sharding_spec.lower_bound,
                    upper_bound
                )
        elif split_value is not None:
            if not (SHARDING_DATATYPE_HANDLER[shard_mappings[0].type_name].\
                    is_valid_split_value(
                        split_value, range_sharding_spec.lower_bound,
                        upper_bound
                    )
                ):
                raise _errors.ShardingError(
                    _services_sharding.INVALID_LOWER_BOUND_VALUE %
                    (split_value, )
                )
        elif split_value is None:
            raise _errors.ShardingError(
                _services_sharding.SPLIT_VALUE_NOT_DEFINED
            )

    #Ensure that the group does not already contain a shard.
    if Shards.lookup_shard_id(destn_group_id) is not None:
        raise _errors.ShardingError(
            _services_sharding.SHARD_MOVE_DESTINATION_NOT_EMPTY %
            (destn_group_id, )
        )

    #Fetch the group information for the source shard that
    #needs to be moved.
    source_shard = Shards.fetch(shard_id)
    if source_shard is None:
        raise _errors.ShardingError(
            _services_sharding.SHARD_NOT_FOUND % (shard_id, ))

    #Fetch the group_id and the group that hosts the source shard.
    source_group_id = source_shard.group_id

    destn_group = Group.fetch(destn_group_id)
    if destn_group is None:
        raise _errors.ShardingError(
            _services_sharding.SHARD_GROUP_NOT_FOUND %
            (destn_group_id, ))

    if not update_only:
        # Check if the source server has backup privileges.
        source_group = Group.fetch(source_group_id)
        server = _services_utils.fetch_backup_server(source_group)
        server.user = backup_user
        server.passwd = backup_passwd
        _backup.MySQLDump.check_backup_privileges(server)

        # Check if the destination server has restore privileges.
        destination_group = Group.fetch(destn_group_id)
        server = MySQLServer.fetch(destination_group.master)
        server.user = restore_user
        server.passwd = restore_passwd
        _backup.MySQLDump.check_restore_privileges(server)

        _events.trigger_within_procedure(
            BACKUP_SOURCE_SHARD, shard_id, source_group_id, destn_group_id,
            split_value, prune_limit, cmd, update_only
        )
    else:
        _events.trigger_within_procedure(
            SETUP_RESHARDING_SWITCH, shard_id, source_group_id, destn_group_id,
            split_value, prune_limit, cmd, update_only
        )
Ejemplo n.º 18
0
def _check_shard_information(shard_id, destn_group_id,
                             split_value, prune_limit, cmd, update_only):
    """Verify the sharding information before starting a re-sharding operation.

    :param shard_id: The destination shard ID.
    :param destn_group_id: The Destination group ID.
    :param split_value: The point at which the sharding definition
                        should be split.
    :param prune_limit: The number of DELETEs that should be
                        done in one batch.
    :param cmd: Indicates if it is a split or a move being executed.
    :param update_only: If the operation is a update only operation.
    """
    backup_user = _services_utils.read_config_value(
                            _config.global_config,
                            'servers',
                            'backup_user'
                        )
    backup_passwd = _services_utils.read_config_value(
                            _config.global_config,
                            'servers',
                            'backup_password'
                        )
    restore_user = _services_utils.read_config_value(
                            _config.global_config,
                            'servers',
                            'restore_user'
                        )
    restore_passwd = _services_utils.read_config_value(
                            _config.global_config,
                            'servers',
                            'restore_password'
                        )
    mysqldump_binary = _services_utils.read_config_value(
                            _config.global_config,
                            'sharding',
                            'mysqldump_program'
                        )
    mysqlclient_binary = _services_utils.read_config_value(
                            _config.global_config,
                            'sharding',
                            'mysqlclient_program'
                        )

    if not _services_utils.is_valid_binary(mysqldump_binary):
        raise _errors.ShardingError(
                _services_sharding.MYSQLDUMP_NOT_FOUND % mysqldump_binary)

    if not _services_utils.is_valid_binary(mysqlclient_binary):
        raise _errors.ShardingError(
                _services_sharding.MYSQLCLIENT_NOT_FOUND % mysqlclient_binary)

    if cmd == "SPLIT":
        range_sharding_spec, _, shard_mappings, _ = \
            _services_sharding.verify_and_fetch_shard(shard_id)
        upper_bound = \
            SHARDING_SPECIFICATION_HANDLER[shard_mappings[0].type_name].\
                        get_upper_bound(
                            range_sharding_spec.lower_bound,
                            range_sharding_spec.shard_mapping_id,
                            shard_mappings[0].type_name
                          )
        #If the underlying sharding scheme is a HASH. When a shard is split,
        #all the tables that are part of the shard, have the same sharding
        #scheme. All the shard mappings associated with this shard_id will be
        #of the same sharding type. Hence it is safe to use one of the shard
        #mappings.
        if shard_mappings[0].type_name == "HASH":
            if split_value is not None:
                raise _errors.ShardingError(
                    _services_sharding.NO_LOWER_BOUND_FOR_HASH_SHARDING
                )
            if  upper_bound is None:
                #While splitting a range, retrieve the next upper bound and
                #find the mid-point, in the case where the next upper_bound
                #is unavailable pick the maximum value in the set of values in
                #the shard.
                upper_bound = HashShardingSpecification.fetch_max_key(shard_id)

            #Calculate the split value.
            split_value = \
                SHARDING_DATATYPE_HANDLER[shard_mappings[0].type_name].\
                split_value(
                    range_sharding_spec.lower_bound,
                    upper_bound
                )
        elif split_value is not None:
            if not (SHARDING_DATATYPE_HANDLER[shard_mappings[0].type_name].\
                    is_valid_split_value(
                        split_value, range_sharding_spec.lower_bound,
                        upper_bound
                    )
                ):
                raise _errors.ShardingError(
                    _services_sharding.INVALID_LOWER_BOUND_VALUE %
                    (split_value, )
                )
        elif split_value is None:
            raise _errors.ShardingError(
                _services_sharding.SPLIT_VALUE_NOT_DEFINED
            )

    #Ensure that the group does not already contain a shard.
    if Shards.lookup_shard_id(destn_group_id) is not None:
        raise _errors.ShardingError(
            _services_sharding.SHARD_MOVE_DESTINATION_NOT_EMPTY %
            (destn_group_id, )
        )

    #Fetch the group information for the source shard that
    #needs to be moved.
    source_shard = Shards.fetch(shard_id)
    if source_shard is None:
        raise _errors.ShardingError(
            _services_sharding.SHARD_NOT_FOUND % (shard_id, ))

    #Fetch the group_id and the group that hosts the source shard.
    source_group_id = source_shard.group_id

    destn_group = Group.fetch(destn_group_id)
    if destn_group is None:
        raise _errors.ShardingError(
            _services_sharding.SHARD_GROUP_NOT_FOUND %
            (destn_group_id, ))

    if not update_only:
        # Check if the source server has backup privileges.
        source_group = Group.fetch(source_group_id)
        server = _services_utils.fetch_backup_server(source_group)
        server.user = backup_user
        server.passwd = backup_passwd
        _backup.MySQLDump.check_backup_privileges(server)

        # Check if the destination server has restore privileges.
        destination_group = Group.fetch(destn_group_id)
        server = MySQLServer.fetch(destination_group.master)
        server.user = restore_user
        server.passwd = restore_passwd
        _backup.MySQLDump.check_restore_privileges(server)

        _events.trigger_within_procedure(
            BACKUP_SOURCE_SHARD, shard_id, source_group_id, destn_group_id,
            split_value, prune_limit, cmd, update_only
        )
    else:
        _events.trigger_within_procedure(
            SETUP_RESHARDING_SWITCH, shard_id, source_group_id, destn_group_id,
            split_value, prune_limit, cmd, update_only
        )
Ejemplo n.º 19
0
    def execute(self, group_id, destn_address, server_uuid=None,
                synchronous=True):
        """Clone the objects of a given server into a destination server.

        :param group_id: The ID of the source group.
        :param destn_address: The address of the MySQL Server to which
            the clone needs to happen.
        :param server_uuid: The UUID of the source MySQL Server.
        :param synchronous: Whether one should wait until the execution
                            finishes or not.
        """
        #If the destination server is already part of a Fabric Group, raise
        #an error
        if destn_address:
            destn_server_uuid = _server.MySQLServer.\
                discover_uuid(destn_address)
            destn_server = _server.MySQLServer.fetch(destn_server_uuid)
            #we should check for both the presence of the server object
            #and its associated group ID. Checking its association with
            #a group ID would verify that a server that is part of Fabric
            #but is not part of a group can also be cloned into.
            if destn_server and destn_server.group_id:
                raise _errors.ServerError("The Destination server is already "\
                    "part of Group (%s)" % (destn_server.group_id,))

        config_file = self.config.config_file if self.config.config_file else ""

        mysqldump_binary = _utils.read_config_value(
                                self.config,
                                'sharding',
                                'mysqldump_program'
                            )
        mysqlclient_binary = _utils.read_config_value(
                                self.config,
                                'sharding',
                                'mysqlclient_program'
                            )

        if not _utils.is_valid_binary(mysqldump_binary):
            raise _errors.ServerError(MYSQLDUMP_NOT_FOUND % mysqldump_binary)

        if not _utils.is_valid_binary(mysqlclient_binary):
            raise _errors.ServerError(MYSQLCLIENT_NOT_FOUND % mysqlclient_binary)

        if server_uuid:
            server = _server.MySQLServer.fetch(server_uuid)
            if group_id != server.group_id:
                raise _errors.ServerError("The server %s was not found in "\
                                          "group %s" % (server_uuid, group_id, ))
        elif not server_uuid:
            group = _server.Group.fetch(group_id)
            server = _utils.fetch_backup_server(group)
            server_uuid = str(server.uuid)

        host, port = _server_utils.split_host_port(
                                destn_address,
                                _backup.MySQLDump.MYSQL_DEFAULT_PORT
                            )

        procedures = _events.trigger(
            BACKUP_SERVER,
            self.get_lockable_objects(),
            server_uuid,
            host,
            port,
            mysqldump_binary,
            mysqlclient_binary,
            config_file
        )
        return self.wait_for_procedures(procedures, synchronous)