分享

OpenStack Swift源码分析(4)----swift-ring-builder源代码解析之一

tntzbzc 发表于 2014-11-20 15:34:57 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 0 22730
本帖最后由 pig2 于 2014-11-21 15:12 编辑
问题导读

1.ring组件在swift中的作用是什么?
2.swift-ring-builder中包含了对ring的哪些操作方法?






    ring是swift中的核心组件,它描述和决定了数据如何在集群系统中分布。其中的一致性哈希算法更是核心内容之一。
    swift-ring-builder中包含了对ring的各种操作方法,包括create、default、search、list_parts、add、set_weight、set_info、remove、rebalance、validate、write_ring、pretend_min_part_hours_passed、set_min_part_hours和set_replicas等方法,我将会逐个解析这写方法的实现过程;
    首先来看swift-ring-builder中的main方法:

  1. if __name__ == '__main__':  
  2.     if len(argv) < 2:  
  3.         print "swift-ring-builder %(MAJOR_VERSION)s.%(MINOR_VERSION)s\n" % globals()  
  4.         print Commands.default.__doc__.strip()  
  5.         print  
  6.         cmds = [c for c, f in Commands.__dict__.iteritems()  
  7.                 if f.__doc__ and c[0] != '_' and c != 'default']  
  8.         cmds.sort()  
  9.         for cmd in cmds:  
  10.             print Commands.__dict__[cmd].__doc__.strip()  
  11.             print  
  12.         print RingBuilder.search_devs.__doc__.strip()  
  13.         print  
  14.         for line in wrap(' '.join(cmds), 79, initial_indent='Quick list: ',  
  15.                          subsequent_indent='            '):  
  16.             print line  
  17.         print ('Exit codes: 0 = operation successful\n'  
  18.                '            1 = operation completed with warnings\n'  
  19.                '            2 = error')  
  20.         exit(EXIT_SUCCESS)  
  21.   
  22.     # 验证argv[1]的路径是否存在;  
  23.     if exists(argv[1]):  
  24.         # builder从argv[1]指定文件获取初始化数据;  
  25.         # 再对RingBuilder类进行实例化;  
  26.         # 根据具体情况决定是否改变builder的初始化数据;  
  27.         builder = RingBuilder.load(argv[1])  
  28.     # 如果argv[1]不存在,而且调用的还不是'create'命令,则退出;  
  29.     elif len(argv) < 3 or argv[2] != 'create':  
  30.         print 'Ring Builder file does not exist: %s' % argv[1]  
  31.         exit(EXIT_ERROR)  
  32.   
  33.     # 获取文件夹'backups'的整体路径;  
  34.     backup_dir = pathjoin(dirname(argv[1]), 'backups')  
  35.     # 新建文件夹'backups';  
  36.     try:  
  37.         mkdir(backup_dir)  
  38.     except OSError, err:  
  39.         if err.errno != EEXIST:  
  40.             raise  
  41.   
  42.     # 获取argv[1],作为ring_file;  
  43.     ring_file = argv[1]  
  44.     if ring_file.endswith('.builder'):  
  45.         ring_file = ring_file[:-len('.builder')]  
  46.     ring_file += '.ring.gz'     
  47.   
  48.     if len(argv) == 2:  
  49.         command = "default"  
  50.     else:  
  51.         command = argv[2]  
  52.     if argv[0].endswith('-safe'):  
  53.         try:  
  54.             with lock_parent_directory(abspath(argv[1]), 15):  
  55.                 Commands.__dict__.get(command, Commands.unknown.im_func)()  
  56.         except exceptions.LockTimeout:  
  57.             print "Ring/builder dir currently locked."  
  58.             exit(2)  
  59.     else:  
  60.         Commands.__dict__.get(command, Commands.unknown.im_func)()  
复制代码




这个main方法主要做了以下几件事:
    (1)检测命令行的正确性;
    (2)如果argv[1]文件存在,则调用类RingBuilder中的方法load加载argv[1]文件,并返回类RingBuilder的实例化对象;
    (3)建立backups文件夹;
    (4)初始化ring_file文件;
    (5)调用运行command中指定的处理ring的方法;
    在类Commands中有若干处理ring的方法,如create、default、search、list_parts、add、set_weight、set_info、remove、rebalance、validate、write_ring、pretend_min_part_hours_passed、set_min_part_hours和set_replicas等等。下面我们来逐一解析这些方法:
    1.来看方法create:
   
  1. def create():  
  2.     if len(argv) < 6:  
  3.         print Commands.create.__doc__.strip()  
  4.         exit(EXIT_ERROR)  
  5.          
  6.     builder = RingBuilder(int(argv[3]), float(argv[4]), int(argv[5]))  
  7.     backup_dir = pathjoin(dirname(argv[1]), 'backups')  
  8.     try:  
  9.         mkdir(backup_dir)  
  10.     except OSError, err:  
  11.         if err.errno != EEXIST:  
  12.             raise  
  13.   
  14.     # Python中可以使用 pickle 模块将对象转化为文件保存在磁盘上,在需要的时候再读取并还原。  
  15.     # 这里即是把转化为字典格式的builder写入到文件pathjoin(backup_dir,'%d.' % time() + basename(argv[1]))文件中;  
  16.     # builder.to_dict():以字典的形式返回初始化的RingBuilder类的对象;  
  17.     pickle.dump(builder.to_dict(), open(pathjoin(backup_dir,'%d.' % time() + basename(argv[1])), 'wb'), protocol=2)  
  18.   
  19.     # 再把转化为字典格式的builder写入到argv[1]指明的文件中;  
  20.     pickle.dump(builder.to_dict(), open(argv[1], 'wb'), protocol=2)  
  21.   
  22.     exit(EXIT_SUCCESS)  
复制代码





这个方法主要实现的功能是:
    (1)根据命令初始化类RingBuilder,获取类RingBuilder的实例化对象;
    (2)创建用于备份的文件夹'backups';
    (3)使用 pickle 模块将对象转化为文件保存在磁盘上,以便在需要的时候再读取还原;这里具体是把转化为字典格式的builder保存两份,一份写入到建立的文件夹'backups'中的指定文件中,一份写入到argv[1]指明的文件中;


    2.来看方法default:

  1. def default():  
  2.     print '%s, build version %d' % (argv[1], builder.version)  
  3.     regions = 0  
  4.     zones = 0  
  5.     balance = 0  
  6.     dev_count = 0  
  7.     if builder.devs:  
  8.         regions = len(set(d['region'] for d in builder.devs  
  9.                           if d is not None))  
  10.         zones = len(set((d['region'], d['zone']) for d in builder.devs  
  11.                         if d is not None))  
  12.         dev_count = len([d for d in builder.devs  
  13.                          if d is not None])  
  14.         balance = builder.get_balance()  
  15.     print '%d partitions, %.6f replicas, %d regions, %d zones, ' \  
  16.           '%d devices, %.02f balance' % (builder.parts, builder.replicas,  
  17.                                          regions, zones, dev_count,  
  18.                                          balance)  
  19.     print 'The minimum number of hours before a partition can be ' \  
  20.           'reassigned is %s' % builder.min_part_hours  
  21.     if builder.devs:  
  22.         print 'Devices:    id  region  zone      ip address  port' \  
  23.               '      name weight partitions balance meta'  
  24.         weighted_parts = builder.parts * builder.replicas / sum(d['weight'] for d in builder.devs if d is not None)  
  25.         for dev in builder.devs:  
  26.             if dev is None:  
  27.                 continue  
  28.             if not dev['weight']:  
  29.                 if dev['parts']:  
  30.                     balance = 999.99  
  31.                 else:  
  32.                     balance = 0  
  33.             else:  
  34.                 balance = 100.0 * dev['parts'] / (dev['weight'] * weighted_parts) - 100.0  
  35.             print('         %5d %5d %5d %15s %5d %9s %6.02f %10s'  
  36.                   '%7.02f %s' %  
  37.                   (dev['id'], dev['region'], dev['zone'], dev['ip'],  
  38.                    dev['port'], dev['device'], dev['weight'], dev['parts'],  
  39.                    balance, dev['meta']))  
  40.     exit(EXIT_SUCCESS)  
复制代码


   

    这个方法主要实现的功能是显示ring和设备内部的信息;
    3.来看方法search:
  1. def search():  
  2.     if len(argv) < 4:  
  3.         print Commands.search.__doc__.strip()  
  4.         print  
  5.         print builder.search_devs.__doc__.strip()  
  6.         exit(EXIT_ERROR)  
  7.          
  8.     # search_devs:<search-value>可以通过<device_id>/<region>/<zone>-<ip>:<port>/<device_name>_<meta>几种格式来进行查询;  
  9.     devs = builder.search_devs(argv[3])  
  10.   
  11.     if not devs:  
  12.         print 'No matching devices found'  
  13.         exit(EXIT_ERROR)  
  14.     print 'Devices:    id  region  zone      ip address  port      name ' \  
  15.           'weight partitions balance meta'  
  16.   
  17.     weighted_parts = builder.parts * builder.replicas / sum(d['weight'] for d in builder.devs if d is not None)  
  18.   
  19.     for dev in devs:  
  20.         if not dev['weight']:  
  21.             if dev['parts']:  
  22.                 balance = 999.99  
  23.             else:  
  24.                 balance = 0  
  25.         else:  
  26.             balance = 100.0 * dev['parts'] / \  
  27.                 (dev['weight'] * weighted_parts) - 100.0  
  28.         print('         %5d %5d %5d %15s %5d %9s %6.02f %10s %7.02f %s' %  
  29.               (dev['id'], dev['region'], dev['zone'], dev['ip'],  
  30.                dev['port'], dev['device'], dev['weight'], dev['parts'],  
  31.                balance, dev['meta']))  
  32.     exit(EXIT_SUCCESS)  
复制代码



  这个方法主要实现了显示匹配的设备信息的功能;
    主要做了以下几件事:
    (1)验证命令行正确性;
    (2)调用方法search_devs实现对设备信息的搜索功能;
    (3)遍历得到的匹配设备信息,组成输出信息并进行打印输出;
    我们来看看方法search_devs:


  1.   def search_devs(self, search_value):
  2.         """        
  3.         可以通过//-:/_几种格式来进行查询;
  4.         
  5.         Examples::
  6.         d74              Matches the device id 74
  7.         r4               Matches devices in region 4
  8.         z1               Matches devices in zone 1
  9.         z1-1.2.3.4       Matches devices in zone 1 with the ip 1.2.3.4
  10.         1.2.3.4          Matches devices in any zone with the ip 1.2.3.4
  11.         z1:5678          Matches devices in zone 1 using port 5678
  12.         :5678            Matches devices that use port 5678
  13.         /sdb1            Matches devices with the device name sdb1
  14.         _shiny           Matches devices with shiny in the meta data
  15.         _"snet: 5.6.7.8" Matches devices with snet: 5.6.7.8 in the meta data
  16.         [::1]            Matches devices in any zone with the ip ::1
  17.         z1-[::1]:5678    Matches devices in zone 1 with ip ::1 and port 5678
  18.         Most specific example::
  19.         d74r4z1-1.2.3.4:5678/sdb1_"snet: 5.6.7.8"
  20.         """
  21.         orig_search_value = search_value
  22.         match = []
  23.         if search_value.startswith('d'):
  24.             ......
  25.         if search_value.startswith('r'):
  26.             ......
  27.         if search_value.startswith('z'):
  28.             ......
  29.         if search_value.startswith('-'):
  30.             ......
  31.         if len(search_value) and search_value[0].isdigit():
  32.             ......
  33.         elif len(search_value) and search_value[0] == '[':
  34.             ......
  35.         if search_value.startswith(':'):
  36.             ......
  37.         if search_value.startswith('/'):
  38.             ......
  39.         if search_value.startswith('_'):
  40.             ......
  41.         if search_value:
  42.             ......
  43.         matched_devs = []
  44.         for dev in self.devs:
  45.             if not dev:
  46.                 continue
  47.             matched = True
  48.             for key, value in match:
  49.                 if key == 'meta':
  50.                     if value not in dev.get(key):
  51.                         matched = False
  52.                 elif dev.get(key) != value:
  53.                     matched = False
  54.             if matched:
  55.                 matched_devs.append(dev)
  56.         return matched_devs
复制代码


    在这个方法中我们要注意的地方就是搜索指令的格式;
    4.来看方法add:
  1. def add():  
  2.     """
  3.     swift-ring-builder <builder_file> add
  4.     [r<region>]z<zone>-<ip>:<port>/<device_name>_<meta> <weight>
  5.     [[r<region>]z<zone>-<ip>:<port>/<device_name>_<meta> <weight>] ...
  6.     使用给定的信息添加新的设备到ring上;
  7.     add操作不会分配partitions到新的设备上,只有运行了'rebalance'命令后,才会进行分区的分配;
  8.     因此,这种机制可以允许我们一次添加多个设备,并只执行一次'rebalance'实现对这些设备的分区分配;
  9.      
  10.     使用 pickle 模块将对象转化为文件保存在磁盘上,以便在需要的时候再读取还原;
  11.     这里具体是把转化为字典格式的builder写入到argv[1]指定文件中;
  12.     """  
  13.     if len(argv) < 5 or len(argv) % 2 != 1:  
  14.         print Commands.add.__doc__.strip()  
  15.         exit(EXIT_ERROR)  
  16.   
  17.     # itertools.islice(iterable, start, stop[, step])  
  18.     # islice('ABCDEFG', 2) --> A B  
  19.     # islice('ABCDEFG', 2, 4) --> C D  
  20.     # islice('ABCDEFG', 2, None) --> C D E F G  
  21.     # islice('ABCDEFG', 0, None, 2) --> A C E G  
  22.             
  23.     # 从命令行获取匹配的devstr和weightstr集合;  
  24.     devs_and_weights = izip(islice(argv, 3, len(argv), 2),islice(argv, 4, len(argv), 2))  
  25.     for devstr, weightstr in devs_and_weights:  
  26.         region = 1  
  27.         rest = devstr  
  28.          
  29.         if devstr.startswith('r'):  
  30.             i = 1  
  31.             while i < len(devstr) and devstr[i].isdigit():  
  32.                 i += 1  
  33.             region = int(devstr[1:i])  
  34.             rest = devstr[i:]  
  35.         else:  
  36.             stderr.write("WARNING: No region specified for %s. "  
  37.                          "Defaulting to region 1.\n" % devstr)  
  38.   
  39.         if not rest.startswith('z'):  
  40.             print 'Invalid add value: %s' % devstr  
  41.             exit(EXIT_ERROR)  
  42.               
  43.         i = 1  
  44.         while i < len(rest) and rest[i].isdigit():  
  45.             i += 1  
  46.         zone = int(rest[1:i])  
  47.         rest = rest[i:]  
  48.   
  49.         if not rest.startswith('-'):  
  50.             print 'Invalid add value: %s' % devstr  
  51.             print "The on-disk ring builder is unchanged.\n"  
  52.             exit(EXIT_ERROR)  
  53.               
  54.         i = 1  
  55.         if rest[i] == '[':  
  56.             i += 1  
  57.             while i < len(rest) and rest[i] != ']':  
  58.                 i += 1  
  59.             i += 1  
  60.             ip = rest[1:i].lstrip('[').rstrip(']')  
  61.             rest = rest[i:]  
  62.         else:  
  63.             while i < len(rest) and rest[i] in '0123456789.':  
  64.                 i += 1  
  65.             ip = rest[1:i]  
  66.             rest = rest[i:]  
  67.   
  68.         if not rest.startswith(':'):  
  69.             print 'Invalid add value: %s' % devstr  
  70.             print "The on-disk ring builder is unchanged.\n"  
  71.             exit(EXIT_ERROR)  
  72.               
  73.         i = 1  
  74.         while i < len(rest) and rest[i].isdigit():  
  75.             i += 1  
  76.         port = int(rest[1:i])  
  77.         rest = rest[i:]  
  78.   
  79.         if not rest.startswith('/'):  
  80.             print 'Invalid add value: %s' % devstr  
  81.             print "The on-disk ring builder is unchanged.\n"  
  82.             exit(EXIT_ERROR)  
  83.               
  84.         i = 1  
  85.         while i < len(rest) and rest[i] != '_':  
  86.             i += 1  
  87.         device_name = rest[1:i]  
  88.         rest = rest[i:]  
  89.   
  90.         meta = ''  
  91.         if rest.startswith('_'):  
  92.             meta = rest[1:]  
  93.   
  94.         try:  
  95.             weight = float(weightstr)  
  96.         except ValueError:  
  97.             print 'Invalid weight value: %s' % weightstr  
  98.             print "The on-disk ring builder is unchanged.\n"  
  99.             exit(EXIT_ERROR)  
  100.   
  101.         if weight < 0:  
  102.             print 'Invalid weight value (must be positive): %s' % weightstr  
  103.             print "The on-disk ring builder is unchanged.\n"  
  104.             exit(EXIT_ERROR)  
  105.   
  106.         for dev in builder.devs:  
  107.             if dev is None:  
  108.                 continue  
  109.             if dev['ip'] == ip and dev['port'] == port and \  
  110.                     dev['device'] == device_name:  
  111.                 print 'Device %d already uses %s:%d/%s.' % \  
  112.                       (dev['id'], dev['ip'], dev['port'], dev['device'])  
  113.                 print "The on-disk ring builder is unchanged.\n"  
  114.                 exit(EXIT_ERROR)  
  115.   
  116.         # 增加一个device到ring;  
  117.         # 这个方法不会马上执行ring的重新平衡操作,因为我们可能需要在重新平衡操作之前进行多次改变;  
  118.         # 这样做也是为了提高效率的;  
  119.         builder.add_dev({'region': region, 'zone': zone, 'ip': ip,  
  120.                          'port': port, 'device': device_name,  
  121.                          'weight': weight, 'meta': meta})  
  122.         new_dev = builder.search_devs('r%dz%d-%s:%s/%s' % (region, zone, ip, port, device_name))[0]['id']  
  123.          
  124.         if ':' in ip:  
  125.             print(  
  126.                 'Device r%dz%d-[%s]:%s/%s_"%s" with %s weight got id %s' %  
  127.                 (region, zone, ip, port,  
  128.                  device_name, meta, weight, new_dev))  
  129.         else:  
  130.             print('Device r%dz%d-%s:%s/%s_"%s" with %s weight got id %s' %  
  131.                   (region, zone, ip, port,  
  132.                    device_name, meta, weight, new_dev))  
  133.       
  134.     # 使用 pickle 模块将对象转化为文件保存在磁盘上,以便在需要的时候再读取还原;  
  135.     # 这里具体是把转化为字典格式的builder写入到argv[1]指定文件中;  
  136.     pickle.dump(builder.to_dict(), open(argv[1], 'wb'), protocol=2)  
  137.   
  138.     exit(EXIT_SUCCESS)  
复制代码

可以知道命令行格式:
    swift-ring-builder <builder_file> add
    [r<region>]z<zone>-<ip>:<port>/<device_name>_<meta> <weight>
    [[r<region>]z<zone>-<ip>:<port>/<device_name>_<meta> <weight>]
    这个方法主要做了以下几件事:
    (1)验证命令行的正确性;
    (2)从命令行获取匹配的devstr和weightstr集合;
    调试示例:
    argv = ['/usr/bin/swift-ring-builder', 'account.builder', 'add', 'z1-127.0.0.1:6012/sda3', '1']
    izip(islice(argv, 3, len(argv), 2),islice(argv, 4, len(argv), 2))) = ('z1-127.0.0.1:6012/sda3', '1')
    (3)遍历每一对匹配的devstr和weightstr,从devstr和weightstr中获取region、zone、ip、port、device_name、weight和meta的值。调用add_dev方法实现增加这个device信息到ring,这个方法不会马上执行ring的重新平衡操作,因为可能需要在重新平衡操作之前进行多次改变(正如这里是个遍历循环操作,如果命令行中一次增加多个设备信息,就需要执行多次add_dev方法)。这样做也是为了提高效率的。
    (4)最后使用 pickle 模块将对象转化为文件保存在磁盘上,以便在需要的时候再读取还原。这里具体是把转化为字典格式的builder写入到argv[1]指定文件中。

    5.来看方法set_weight:

  1. def set_weight():  
  2.     """
  3.     swift-ring-builder <builder_file> set_weight <search-value> <weight>
  4.     [<search-value> <weight] ...
  5.     """  
  6.     if len(argv) < 5 or len(argv) % 2 != 1:  
  7.         print Commands.set_weight.__doc__.strip()  
  8.         print  
  9.         print builder.search_devs.__doc__.strip()  
  10.         exit(EXIT_ERROR)  
  11.   
  12.     devs_and_weights = izip(islice(argv, 3, len(argv), 2),  
  13.                             islice(argv, 4, len(argv), 2))  
  14.     for devstr, weightstr in devs_and_weights:  
  15.         devs = builder.search_devs(devstr)  
  16.         weight = float(weightstr)  
  17.         if not devs:  
  18.             print("Search value "%s" matched 0 devices.\n"  
  19.                   "The on-disk ring builder is unchanged.\n"  
  20.                   % devstr)  
  21.             exit(EXIT_ERROR)  
  22.         if len(devs) > 1:  
  23.             print 'Matched more than one device:'  
  24.             for dev in devs:  
  25.                 print '    d%(id)sz%(zone)s-%(ip)s:%(port)s/%(device)s_' \  
  26.                       '"%(meta)s"' % dev  
  27.             if raw_input('Are you sure you want to update the weight for '  
  28.                          'these %s devices? (y/N) ' % len(devs)) != 'y':  
  29.                 print 'Aborting device modifications'  
  30.                 exit(EXIT_ERROR)  
  31.         for dev in devs:  
  32.             # 设置device的weight值;  
  33.             # 这个方法不是仅仅直接在device字典中变更weight值;  
  34.             # 还有builder将会需要重新设置一些内部状态来反应weight值的改变;  
  35.             builder.set_dev_weight(dev['id'], weight)  
  36.             print 'd%(id)sz%(zone)s-%(ip)s:%(port)s/%(device)s_' \  
  37.                   '"%(meta)s" weight set to %(weight)s' % dev  
  38.     pickle.dump(builder.to_dict(), open(argv[1], 'wb'), protocol=2)  
  39.     exit(EXIT_SUCCESS)  
复制代码

这个方法实现了重新设置设备的weight。set_weight操作后,设备上的partition不会重新分配,只有运行了'rebalance'命令后才会进行分区的分配。因此,这种机制可以允许你一次添加多个设备,并只执行一次'rebalance'实现对这些设备的分区分配。
    这个方法做了以下几件事:
    (1)验证命令行正确性;
    (2)从命令行获取匹配的devstr和weightstr集合;
    (3)遍历每一对匹配的devstr和weightstr。调用search_devs方法根据devstr查询得到对应的devs,也就是要修改weight值的devs。遍历得到的devs,调用set_dev_weight方法为每一个dev重新设置weight值为float(weightstr)。所以每一组devs的weight的值都是相同的。
    (4)最后使用 pickle 模块将对象转化为文件保存在磁盘上,以便在需要的时候再读取还原。这里具体是把转化为字典格式的builder写入到argv[1]指定文件中。
    这里再来看看方法set_dev_weight,方法比较容易理解,具体解析如注释所示;

  1. def set_dev_weight(self, dev_id, weight):  
  2.     """
  3.     设置device的weight值;
  4.     这个方法不是仅仅直接在device字典中变更weight值;
  5.     还有builder将会需要重新设置一些内部状态来反应weight值的改变;
  6.     """  
  7.     self.devs[dev_id]['weight'] = weight  
  8.     # _set_parts_wanted:方法根据dev的weight计算dev除了目前已经分配的partition数目而外,还要分配的partition数目;  
  9.     self._set_parts_wanted()  
  10.     # 设置devs_changed为TRUE,说明已经改变;  
  11.     self.devs_changed = True  
  12.     self.version += 1
复制代码




    这里再来看看方法_set_parts_wanted,这个方法会在很多地方被调用,这里先来解析一下,具体解析如注释所示:

  1. def _set_parts_wanted(self):  
  2.     """        
  3.     方法根据dev的weight计算dev除了目前已经分配的partition数目而外,还要分配的partition数目;
  4.     计算方法是:
  5.     1.首先计算每个partition的weight,即将partition数目乘以副本数得到总的partition数目;
  6.       然后除以现有dev的weight总和,得到每个partition的权重;
  7.       实际上得到的是单位权重对应的partition数目;
  8.     2.dev根据上述结构计算自己应该获取的partition数目;
  9.       计算方法:dev weight * weigh_of_one_part – 已经分配的partition数目;
  10.       具体解释就是单位权重对应的partition数目乘以权重值,得到权重dev['weight']对应的总的partition数目,
  11.       然后减去已经分配的partition数目,就得到了还要分配的partition数目;
  12.      
  13.     由此可见,每次add设备操作都会引起partition分配的变化,但是真正的partition搬迁操作在rebalance执行时;
  14.     """  
  15.       
  16.     # weight_of_one_part:从所有设备的总权重(weight)中,返回计算出来的每一个分区的权重(weight);  
  17.     # 计算方法就是将partition数目乘以副本数得到总的partition数目,然后除以现有dev的weight总和,得到每个partition的权重;  
  18.     # 也就是说具有同样副本数的分区具有同样的权重值(weight);  
  19.     weight_of_one_part = self.weight_of_one_part()  
  20.   
  21.     for dev in self._iter_devs():  
  22.         if not dev['weight']:  
  23.             dev['parts_wanted'] = -self.parts * self.replicas  
  24.         else:  
  25.             dev['parts_wanted'] = int(weight_of_one_part * dev['weight']) - dev['parts']  
复制代码


此篇博文解析到这里吧,下一篇博文将会继续解析swift-ring-builder文件。
    博文中不免有不正确的地方,欢迎朋友们不吝批评指正,谢谢大家了!

下一篇
OpenStack Swift源码分析(5)----swift-ring-builder源代码解析之二


没找到任何评论,期待你打破沉寂

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条