Swift源码解析之创建Ring文件

通过setup.cfg文件可以知道swift-ring-builder工具的源码入口位于/bin/swift-ring-builder脚本,这个脚本仅仅是对swift.cli.ringbuilder模块的封装,直接调用了swift.cli.ringbuilder中的main函数。
def main(arguments=None):
    if len(argv) == 2:
        command = "default"
    else:
        command = argv[2]
    if argv[0].endswith('-safe'):
        try:
            with lock_parent_directory(abspath(argv[1]), 15):
                Commands.__dict__.get(command, Commands.unknown.im_func)()
        except exceptions.LockTimeout:
            print "Ring/builder dir currently locked."
            exit(2)
    else:
        #调动Commands类的名为"command"函数,如果该函数不存在则调用
        #Commands类的unknown()函数,对于Ring的创建,"command"为create
        Commands.__dict__.get(command, Commands.unknown.im_func)()
完成一定的参数解析工作后,最终使用swift.cli.ringbuilder.Commands类的create()函数去完成Ring的创建。
class Commands(object):
    def create():
        """
        swift-ring-builder <builder_file> create <part_power> <replicas> <min_part_hours>
        Creates <builder_file> with 2^<part_power> partitions and <replicas>.
        <min_part_hours> is number of hours to restrict moving a partition more than once.
        """
        if len(argv) < 6:
            print Commands.create.__doc__.strip()
            exit(EXIT_ERROR)
        #创建RingBuilder对象实例
        builder = RingBuilder(int(argv[3]), float(argv[4]), int(argv[5]))
        #为builder文件创建一个备份目录,该目录下会备份builder文件
        backup_dir = pathjoin(dirname(argv[1]), 'backups')
        try:
            mkdir(backup_dir)
        except OSError as err:
            if err.errno != EEXIST:
                raise
        #将Ring的初始化信息保存到备份文件中去
        builder.save(pathjoin(backup_dir, '%d.' % time() + basename(argv[1])))
        #将Ring的初始化信息保存到builer文件中去
        builder.save(argv[1])
        exit(EXIT_SUCCESS)
这个函数的逻辑非常简单,主要就是创建一个swift.common.ring.builder.RingBuilder类的实例,然后将它的初始化信息保存到Ring的builder文件和备份文件里。
接下来看看这类的初始化过程
# swift/common/ring/builder.py
class RingBuilder(object):
    def __init__(self, part_power, replicas, min_part_hours):
        self.part_power = part_power
        self.replicas = replicas
        self.min_part_hours = min_part_hours
        self.parts = 2 ** self.part_power
        self.devs = []
        self.devs_changed = False
        self.version = 0
        # _replica2part2dev 是一个二维数组,第一维从replica映射到partition
        # 第二维从partition映射到device。所以对一个replica个数为3,
        # partition个数为 2^23 的ring来说,_replica2part2dev是一个3*2^23数组
        # 该数据的每一个元素都是device ID(数据类型unsigned short)。
        self._replica2part2dev = None
        # _last_part_moves是一个长度为2^23的数组,数组中每个元素为unsigned byte
        # 这个数组的每个元素表示该元素所对应的partition据上次移动所过去的时间
        # (以小时为单位)。这个数组存在的目的是为了保证同一个partition在一定的时间内(一般是24小时)
        # 不会被移动两次。不过删除或者把一个设备的weight设为0不受这个时间的限制。这是因为
        # 删除设备或者把wight设为0是因为该设备已经出现故障
        # _last_part_moves_epoch表示_last_part_moves的基准时间
        self._last_part_moves_epoch = None
        self._last_part_moves = None
        self._last_part_gather_start = 0
        self._remove_devs = []
        self._ring = None
RingBuild类实例初始化后,在保存了传递进来的part_power、replicas以及min_part_hours等参数之后,初始化了一个重要的二维数组_replica2part2dev。
_replica2part2dev数组就是设备查询表,它的第一维以replicas为索引,也就是说如果设定replicas等于3,那么该数组第一维就是3个成员,每一个成员都是一个数组(第二维数组)。第二维数组负责partition到device的映射,长度为partition的个数。
_replica2part2dev之外的一个重要数组即devs[]数组,该数组即为我们前面提到的设备列表。根据从_replica2part2dev中检索到的设备号,到该表中查询设备的具体位置信息。目前设备表的内容为空,因为此时还不知道设备的情况。
到此,构建Ring的第一个步骤创建Ring文件已经完成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值