分区一致性哈希环

环 IO

class swift.common.ring.io.IndexEntry(compressed_start: int, uncompressed_start: int, compressed_end: int, uncompressed_end: int, checksum_method: str, checksum_value: str)

基类: object

checksum_method: str
checksum_value: str
compressed_end: int
property compressed_length: int
compressed_start: int
property compression_ratio: float
uncompressed_end: int
property uncompressed_length: int
uncompressed_start: int
class swift.common.ring.io.RingReader(fileobj)

基类: _RingGzReader

用于读取环文件的辅助工具。

提供格式版本检测,并加载 v2 环的索引。

chunk_size = 65536
load_index()

如果这是 v2 环,则加载文件末尾存储的索引。

这将作为初始化的一部分完成;用户不需要自己执行此操作。

open_section(section)

打开一个部分,无需将整个部分缓冲到内存中

引发:
  • ValueError – 如果没有索引

  • KeyError – 如果 section 不在索引中

  • IOError – 如果索引中的部分大小与 blob 开头处的长度之间存在冲突

返回值:

一个 SectionReader 包装该部分

read_blob(fmt='!Q')

读取长度-值编码的 BLOB

请注意,RingReader 需要已经正确定位。

参数:

fmt – 用于写入 BLOB 长度的格式代码。所有 v2 BLOB 都使用 !Q,但 v1 可能需要 !I

返回值:

BLOB 值

read_section(section)

移动到某个部分并读取其所有数据

class swift.common.ring.io.RingWriter(*a, **kw)

基类: _RingGzWriter

用于稍后由 RingReader 读取的环文件写入的辅助工具

这在标准的 GzipFile 之上具有一些关键特性

  • 用于写入长度-值编码 BLOB 的辅助工具

  • 能够定义将在文件末尾作为索引写入的部分

  • 刷新始终使用 Z_FULL_FLUSH 以支持寻道。

请注意,只有定义了命名部分才会写入索引。

checksum_method = 'sha256'
close()
section(name)

定义一个命名部分。

返回一个上下文管理器;该部分包含在该上下文内写入的任何数据。

索引将在进入上下文时包含该部分及其起始位置进行更新;正常退出时,索引将再次使用结束位置和校验和信息进行更新。

write(data)
write_blob(data, fmt='!Q')

写入长度-值编码的 BLOB。

参数:
  • data – 要写入的字节

  • fmt – 用于写入长度的 struct 格式。所有 v2 BLOB 都应使用 !Q

write_index()

在文件末尾写入索引及其起始位置。

调用者不需要自己使用此功能;它将在使用写入器作为上下文管理器时自动完成。

write_json(data, fmt='!Q')

写入长度-值编码的 JSON BLOB。

参数:
  • data – 要写入的 JSON 可序列化数据

  • fmt – 用于写入长度的 struct 格式。所有 v2 BLOB 都应使用 !Q

write_magic(version)

写入用于标识 Swift 环的我们的文件魔术。

参数:

version – 环版本;应为 1 或 2

write_ring_table(table)

写入长度-值编码的 replica2part2dev 表,或类似内容。不应用于 v1 环,因为始终存在 !Q 大小前缀,并且值以网络顺序写入。 :param table: 数组列表

write_size(size, fmt='!Q')

写入大小(通常是 BLOB 长度,但有时是文件偏移量)。

参数:
  • data – 要写入的大小

  • fmt – 用于写入长度的 struct 格式。所有 v2 BLOB 都应使用 !Q

class swift.common.ring.io.SectionReader(fp, length, digest=None, checksum=None)

基类: object

限制可以读取的字节数的类文件包装器。

还验证数据完整性。

参数:
  • fp – 以“rb”模式打开的文件类对象

  • length – 应读取的最大字节数

  • digest – 预期字节的十六进制摘要

  • checksum – 校验和实例,将字节馈送给它,稍后与 digest 进行比较;例如,hashlib.sha256()

close()

验证是否读取了所有字节。

如果提供了摘要,则还验证读取的字节是否与摘要匹配。不关闭底层文件类。

引发:

ValueError – 如果验证失败

read(amt=None)

读取 amt 字节,默认为“所有剩余可用字节”。

read_ring_table(itemsize, partition_count)

class swift.common.ring.ring.Ring(serialized_path, reload_time=None, ring_name=None, validation_hook=<function Ring.<lambda>>)

基类: object

分区一致性哈希环。

参数:
  • serialized_path – 序列化 RingData 实例的路径

  • reload_time – 检查环更改的时间间隔(秒)

  • ring_name – 环名称字符串(基本上由策略指定)

  • validation_hook – 在运行时验证环配置的挂钩点

引发:

RingLoadError – 如果加载的环数据违反其约束

property assigned_device_count

环中具有分配的设备数量。

property dev_id_bytes
property device_count

环中设备的数量。

property devs

环中的设备

get_more_nodes(part)

生成器,用于获取分区以进行提示性交接的更多节点。

交接节点将尝试位于主区域以外的区域,将考虑设备权重,并且通常即使在环更改时也会保持相同的交接序列。

参数:

part – 要获取交接节点的分区

返回值:

节点字典生成器

请参阅 get_nodes() 以获取节点字典的描述。

get_nodes(account, container=None, obj=None)

获取账户/容器/对象的划分和节点。如果一个节点负责多个副本,它在输出中只会出现一次。

参数:
  • account – 账户名称

  • container – 容器名称

  • obj – 对象名称

返回值:

一个 (划分, 节点字典列表) 元组

每个节点字典至少包含以下键

id

设备之间的唯一整数标识符

索引

该划分中主节点列表的偏移量

权重

一个浮点数,表示相对于其他设备的相对权重;这表明构建器将尝试将多少个划分分配给此设备

zone

一个整数,指示设备所在的区域;给定的划分不会被分配到同一区域内的多个设备

ip

设备的 IP 地址

端口

设备的 TCP 端口

设备

磁盘上的设备名称(例如 sdb1)

meta

通用“extra”字段;例如:在线日期、硬件描述

get_part(account, container=None, obj=None)

获取账户/容器/对象的划分。

参数:
  • account – 账户名称

  • container – 容器名称

  • obj – 对象名称

返回值:

划分编号

get_part_nodes(part)

获取负责该划分的节点。如果一个节点负责同一划分的多个副本,它在输出中只会出现一次。

参数:

part – 要获取节点的划分

返回值:

节点字典列表

请参阅 get_nodes() 以获取节点字典的描述。

has_changed()

检查磁盘上的环是否与内存中的当前环不同。

返回值:

如果磁盘上的环已更改,则为 True,否则为 False

property next_part_power
property part_power
property partition_count

环中的划分数。

property raw_size
property replica_count

环中使用的副本数(完整或部分)。

property size
property version
property weighted_device_count

环中具有权重的设备数。

class swift.common.ring.ring.RingData(replica2part2dev_id, devs, part_shift, next_part_power=None, version=None)

基类: object

分区一致性哈希环数据(用于序列化)。

classmethod deserialize_v1(reader, metadata_only=False)

将 v1 环文件反序列化为包含 devspart_shiftreplica2part2dev_id 键的字典。

如果可选关键字参数 metadata_only 为 True,则不加载 replica2part2dev_id,并且该键在返回的字典中仅具有值 []

参数:
  • reader (RingReader) – 位于文件开头的已打开的 RingReader

  • metadata_only (bool) – 如果为 True,则仅加载 devspart_shift

返回值:

包含 devspart_shiftreplica2part2dev_id 的字典

classmethod deserialize_v2(reader, metadata_only=False, include_devices=True)

将 v2 环文件反序列化为包含 devspart_shiftreplica2part2dev_id 键的字典。

如果可选关键字参数 metadata_only 为 True,则不加载 replica2part2dev_id,并且该键在返回的字典中仅具有值 []

如果可选关键字参数 include_devices 为 False,则不加载 devs 列表,并且该键在返回的字典中仅具有值 []

参数:
  • reader (RingReader) – 已加载文件末尾索引的已打开的 RingReader。

  • metadata_only (bool) – 如果为 True,则跳过加载 replica2part2dev_id

  • include_devices (bool) – 如果为 False,则跳过加载 devs

返回值:

包含 devspart_shiftdev_id_bytesreplica2part2dev_id 的字典

property dev_id_bytes
classmethod from_dict(ring_data)
classmethod load(filename, metadata_only=False, include_devices=True)

从文件加载环数据。

参数:
  • filename – 要序列化的文件的路径。

  • metadata_only (bool) – 如果为 True,则仅加载 devspart_shift

返回值:

包含加载数据的 RingData 实例。

property part_power
property replica_count

环中使用的副本数(完整或部分)。

save(filename, mtime=1300507380.0, format_version=1)

将此 RingData 实例序列化到磁盘。

参数:
  • filename – 要序列化的文件。

  • mtime – 用于覆盖 gzip 的 mtime 的时间,默认值或 None(如果调用者希望包含时间)

  • format_version – 0、1 或 2 中的一个。保留旧版本是为了与使用旧版本的集群兼容

serialize_v1(writer)
serialize_v2(writer)
to_dict()
swift.common.ring.ring.calc_replica_count(replica2part2dev_id)
swift.common.ring.ring.normalize_devices(devs)

环构建器

class swift.common.ring.builder.RingBuilder(part_power, replicas, min_part_hours)

基类: object

用于构建 swift.common.ring.RingData 实例以写入磁盘并与 swift.common.ring.Ring 实例一起使用。请参阅 bin/swift-ring-builder 以获取示例用法。

实例变量 devs_changed 指示设备信息自上次平衡以来是否已更改。这可用于工具来了解重新平衡请求是孤立请求还是由于添加、更改或删除的设备引起的。

参数:
  • part_power – 划分数 = 2**part_power。

  • replicas – 每个划分的副本数

  • min_part_hours – 划分更改之间的最小小时数

add_dev(dev)

将设备添加到环中。此设备字典应至少包含以下键

id

设备之间的唯一整数标识符。如果字典中未提供“id”键,则默认为下一个 id

权重

一个浮点数,表示相对于其他设备的相对权重;这表明构建器将尝试将多少个划分分配给此设备

region

设备所在的区域的整数

zone

设备所在的区域;如果存在任何替代方案,则给定的划分不会被分配到同一 (区域, 区域) 对内的多个设备

ip

设备的 IP 地址

端口

设备的 TCP 端口

设备

磁盘上的设备名称(例如 sdb1)

meta

通用“extra”字段;例如:在线日期、硬件描述

注意

这不会立即重新平衡环,因为您可能希望为单个重新平衡进行多次更改。

参数:

dev – 设备字典

返回值:

设备 ID(不再在树中使用,但未知用户可能依赖它)

cancel_increase_partition_power()

取消环划分幂增加。

这将 next_part_power 设置为当前 part_power。对象复制器仍将跳过复制,并且仍需要进行清理。最后,需要运行 finish_increase_partition_power。

返回值:

如果 next_part_power 未设置或等于当前 part_power,则为 False,否则为 True。

change_min_part_hours(min_part_hours)

更改用于确定给定划分是否可以再次移动的值。此限制是为了让整个系统有足够的时间将划分稳定到其新位置,然后再将其移动到另一个位置。虽然快速移动划分几次不会导致数据丢失,但可能会使该数据在短时间内无法访问。

应将其设置为至少平均的完全划分复制时间。从 24 小时开始,然后将其降低到复制器报告的最长划分周期为佳。

参数:

min_part_hours – min_part_hours 的新值

copy_from(builder)

从给定的构建器数据重新初始化此 RingBuilder 实例。代码示例

b = RingBuilder(1, 1, 1)  # Dummy values
b.copy_from(builder)

这是为了恢复先前已保存 b.to_dict() 的 RingBuilder。

debug()

临时启用调试日志记录,在测试中很有用,例如:

with rb.debug():
    rb.rebalance()
property dev_id_bytes
property dev_id_type_code
property ever_rebalanced
finish_increase_partition_power()

完成分区幂的增加。

旧对象位置的硬链接应该已经删除。

classmethod from_dict(builder_data)
get_balance()

获取环的平衡度。平衡值是给定设备期望的分区数量相对于期望数量的最高百分比。例如,如果“最差”设备(基于其相对于所有设备权重之和的权重)想要 123 个分区,并且它有 124 个分区,则平衡值将为 0.83(1 额外 / 123 想要 * 100 以获得百分比)。

返回值:

环的平衡度

get_part_devices(part)

获取负责该分区的设备,并过滤掉重复项。

参数:

part – 获取设备的partition

返回值:

设备字典列表

get_required_overload(weighted=None, wanted=None)

返回使环最大程度分散所需的最小超载值。

所需的超载是任何单个设备从其加权副本到其所需副本的最大的百分比变化(注意:加权设备具有负百分比变化)以实现分散 - 也就是说,必须超载 5% 的单个设备比单个层中超载 1% 的 5 个设备更糟糕。

get_ring()

获取环,或者更具体地说,swift.common.ring.RingData。此环数据是使用环的最低要求。环构建器本身保留其他数据,例如上次移动分区的时间。

property id
increase_partition_power()

增加环分区幂一次。

设备将被分配到分区,如下所示

OLD: 0, 3, 7, 5, 2, 1, … NEW: 0, 0, 3, 3, 7, 7, 5, 5, 2, 2, 1, 1, …

返回值:

如果未设置 next_part_power 或等于 current part_power,则为 False,如果出现问题,则为 None,否则为 True。

classmethod load(builder_file, open=<built-in function open>, **kwargs)

获取提供的构建器文件的 RingBuilder 实例

参数:

builder_file – 要加载的构建器文件的路径

返回值:

RingBuilder 实例

property max_dev_id
property min_part_seconds_left

获取可以执行重新平衡的总秒数

property none_dev_id
property part_shift
prepare_increase_partition_power()

准备环以增加分区幂。

这使得能够基于下一个分区幂计算任何对象的未来位置。

在此阶段,对象服务器应在完成写入新位置时创建硬链接。在重新启动对象服务器后,将运行一个重链接器,为它们未来的位置创建指向所有现有对象的硬链接。

返回值:

如果未设置 next_part_power,则为 False,否则为 True。

pretend_min_part_hours_passed()

通过将所有分区标记为已移动 255 小时前并将上次移动纪元设置为“时间开始”来覆盖 min_part_hours。这可用于在下一次调用 rebalance 时强制执行完全重新平衡。

rebalance(seed=None)

重新平衡环。

这是构建器的主要工作函数,它将根据权重、不同的区域、最近的重新分配等在环中分配和重新分配设备到分区。

该过程并不总是完美地分配分区(这需要更多的分析和因此更多的时间 - 我之前有代码可以做到这一点)。因此,它会一直重新平衡,直到设备偏差(设备想要的分区数量与它拥有的分区数量)降至 1% 以下,或者变化不超过 1%(仅发生在无法平衡的环中)。

参数:

seed – 随机种子值(可选)

返回值:

(已更改的分区数量,生成的平衡度,已删除的设备数量)

remove_dev(dev_id)

从环中删除设备。

注意

这不会立即重新平衡环,因为您可能希望为单个重新平衡进行多次更改。

参数:

dev_id – 设备 ID

save(builder_file)

将此 RingBuilder 实例序列化到磁盘。

参数:

builder_file – 要保存的构建器文件的路径

search_devs(search_values)

按参数搜索设备。

参数:

search_values – 包含用于过滤设备的搜索值的字典,支持的参数为 id、region、zone、ip、port、replication_ip、replication_port、device、weight、meta

返回值:

设备字典列表

set_dev_id_bytes(new_dev_id_bytes)
set_dev_region(dev_id, region)

设置设备的区域。应调用此方法,而不是直接更改设备字典中的区域键,因为构建器需要重建一些内部状态以反映更改。

注意

这不会立即重新平衡环,因为您可能希望为单个重新平衡进行多次更改。

参数:
  • dev_id – 设备 ID

  • region – 设备的新的区域

set_dev_weight(dev_id, weight)

设置设备的权重。应调用此方法,而不是直接更改设备字典中的权重键,因为构建器需要重建一些内部状态以反映更改。

注意

这不会立即重新平衡环,因为您可能希望为单个重新平衡进行多次更改。

参数:
  • dev_id – 设备 ID

  • weight – 设备的新的权重

set_dev_zone(dev_id, zone)

设置设备的区域。应调用此方法,而不是直接更改设备字典中的区域键,因为构建器需要重建一些内部状态以反映更改。

注意

这不会立即重新平衡环,因为您可能希望为单个重新平衡进行多次更改。

参数:
  • dev_id – 设备 ID

  • zone – 设备的新的区域

set_overload(overload)
set_replicas(new_replica_count)

更改此环中的副本数。

如果新的副本数与 self._replica2part2dev 的大小变化足够大,则设置 self.devs_changed。这样,像 bin/swift-ring-builder 这样的工具就可以知道要将新的环写入,而不是因为平衡度没有变化而退出。

to_dict()

返回一个字典,稍后可以使用 copy_from 恢复 RingBuilder。swift-ring-builder 使用此方法将字典 pickle.dump 到文件,然后加载该字典到 copy_from 中。

validate(stats=False)

验证环。

这是一个安全函数,用于尝试捕获构建过程中的任何错误。它确保分区已分配给实际设备,未双重分配等。它还可以选择性地检查设备之间分区分布的均匀性。

参数:

stats – 如果为 True,则检查设备之间分区分布

返回值:

如果 stats 为 True,则为 (device_usage, worst_stat) 元组,否则为 (None, None)。device_usage[dev_id] 等于分配给该设备的partition数量。worst_stat 等于最坏设备偏离其应有partition数量的数量。

引发:

RingValidationError – 发现环存在问题。

weight_of_one_part()

返回根据所有设备的总权重计算的每个分区的权重。

exception swift.common.ring.builder.RingValidationWarning

Bases: Warning

复合环构建器

使用 ring-builder 构建的标准环将尝试在故障域中随机分散副本或纠删编码片段,但不能保证将每个分区的至少一个副本放置在每个区域中。复合环旨在为运营商提供对集群中对象副本或片段分散的更大控制,尤其是在希望确保某些副本或片段放置在某些故障域中时。这对于具有重复纠删编码片段的策略尤其重要。

复合环由两个或多个组件环组成,这些环组合成一个副本数等于组件环副本数之和的单个环。组件环独立构建,使用不同区域中的不同设备,这意味着组件之间的副本分散可以得到保证。composite_builder 工具可用于将组件组合成复合环。

例如,考虑一个具有 4 个副本和两个区域 r1r2 的普通环 ring0。尽管环构建器尽了最大的努力,但有可能某个分区的三个副本放置在一个区域,而只有一个副本放置在另一个区域。例如

part_n -> r1z1h110/sdb r1z2h12/sdb r1z3h13/sdb r2z1h21/sdb

现在考虑两个正常的环,每个环的副本数为 2:ring1 仅在 r1 中有设备;ring2 仅在 r2 中有设备。当这些环组合成一个复合环时,每个分区保证映射到 r1r2 中的两个设备,例如

part_n -> r1z1h10/sdb r1z2h20/sdb  r2z1h21/sdb r2z2h22/sdb
          |_____________________|  |_____________________|
                     |                        |
                   ring1                    ring2

分区副本在两个组件环中的故障域内的分布可能会随着修改和重新平衡而改变,但通过使用复合环,可以保证两个区域之间的副本分布。

为了将环形成复合环,它们必须满足以下要求

  • 所有组件环必须具有相同的分区幂(因此分区数相同)

  • 所有组件环必须具有整数副本数

  • 每个区域只能用于一个组件环

  • 每个设备只能用于一个组件环

在底层,复合环有一个 _replica2part2dev_id 表,它是组件环表中所有表的联合。每当组件环重新平衡时,必须重建复合环。复合环不会动态重建。

注意

组件环组合成复合环的顺序非常重要,因为它决定了 Ring.get_part_nodes() 方法将为复合环提供主节点的方式,从而决定分配给主节点的节点索引。对于使用擦除编码策略的情况,主节点索引的意外更改可能导致大量数据移动,因为碎片被移动到它们的新正确主节点。

因此,每个组件 RingBuilder 的 id 存储在复合环的元数据中,并在重新组合相同的复合环时用于检查组件顺序。RingBuilder id 通常在首次保存 RingBuilder 实例时分配。从文件中加载的较旧的 RingBuilder 实例可能没有分配 id,并且在用作复合环的组件之前需要保存。这可以通过以下方式实现,例如

swift-ring-builder <builder-file> rebalance --force
class swift.common.ring.composite_builder.CompositeRingBuilder(builder_files=None)

基类: object

提供创建、持久化、加载、重新平衡和更新复合环的设施,例如

# create a CompositeRingBuilder instance with a list of
# component builder files
crb = CompositeRingBuilder(["region1.builder", "region2.builder"])

# perform a cooperative rebalance of the component builders
crb.rebalance()

# call compose which will make a new RingData instance
ring_data = crb.compose()

# save the composite ring file
ring_data.save("composite_ring.gz")

# save the composite metadata file
crb.save("composite_builder.composite")

# load the persisted composite metadata file
crb = CompositeRingBuilder.load("composite_builder.composite")

# compose (optionally update the paths to the component builder files)
crb.compose(["/path/to/region1.builder", "/path/to/region2.builder"])

复合环元数据以 JSON 格式保存到文件中。元数据的结构如下所示(使用示例值)

{
  "version": 4,
  "components": [
    {
      "version": 3,
      "id": "8e56f3b692d43d9a666440a3d945a03a",
      "replicas": 1
    },
    {
      "version": 5,
      "id": "96085923c2b644999dbfd74664f4301b",
      "replicas": 1
    }
  ]
  "component_builder_files": {
      "8e56f3b692d43d9a666440a3d945a03a": "/etc/swift/region1.builder",
      "96085923c2b644999dbfd74664f4301b": "/etc/swift/region2.builder",
  }
  "serialization_version": 1,
  "saved_path": "/etc/swift/multi-ring-1.composite",
}

version 是一个整数,表示复合环的当前版本,每次成功(重新)组合环时都会递增。

components 是一个字典列表,每个字典描述了组件环的相关属性

component_builder_files 是一个字典,将组件环构建器 ID 映射到加载该组件环构建器文件。

serialization_version 是一个整数常量。

saved_path 是写入元数据的路径。

参数 builder_files:

将用作复合环组件的构建器文件的路径列表。

can_part_move(part)

检查所有组件构建器是否可以移动分区。

参数:

part – 要检查的分区。

返回值:

如果所有组件构建器都同意可以移动分区,则返回 True,否则返回 False。

compose(builder_files=None, force=False, require_modified=False)

使用从构建器文件列表加载的组件环构建器构建复合环,并更新复合环元数据。

如果提供了组件环构建器文件的列表,则将使用该列表加载组件环构建器。否则,将使用实例构造时设置的构建器文件列表加载组件环构建器。

在任何一种情况下,如果已加载现有复合环的元数据,则除非设置了可选的 force 标志为 True,否则将验证组件环构建器与现有构建器的组成是否一致。

参数:
  • builder_files – 可选的环构建器文件路径列表,将用于加载组件环构建器。通常,组件构建器文件列表将在实例构造时设置,例如在使用 load() 类方法时。但是,如果组件构建器文件路径已移动,或者与 force 参数结合使用,如果要使用新的构建器列表,则可以使用此参数。

  • force – 如果为 True,则不要验证给定的构建器与任何现有的复合环一致(默认值为 False)。

  • require_modified – 如果为 True 且 force 为 False,则验证自上次构建复合环以来,至少有一个给定的构建器已修改(默认值为 False)。

返回值:

一个 swift.common.ring.ring.RingData 实例

引发:

ValueError 如果组件环构建器不适合相互组合,或者与任何现有的复合环不一致,或者如果 require_modified 为 True 且相对于现有环没有更改。

classmethod load(path_to_file)

加载复合环元数据。

参数:

path_to_file – 复合环 JSON 文件的绝对路径。

返回值:

一个 CompositeRingBuilder 实例

引发:
  • IOError – 如果打开文件时出现问题

  • ValueError – 如果文件不包含有效的复合环元数据

load_components(builder_files=None, force=False, require_modified=False)

从构建器文件加载组件环构建器。先前加载的组件环构建器将被丢弃并重新加载。

如果提供了组件环构建器文件的列表,则将使用该列表加载组件环构建器。否则,将使用实例构造时设置的构建器文件列表加载组件环构建器。

在任何一种情况下,如果已加载现有复合环的元数据,则除非设置了可选的 force 标志为 True,否则将验证组件环构建器与现有构建器的组成是否一致。

参数:
  • builder_files – 可选的环构建器文件路径列表,将用于加载组件环构建器。通常,组件构建器文件列表将在实例构造时设置,例如在使用 load() 类方法时。但是,如果组件构建器文件路径已移动,或者与 force 参数结合使用,如果要使用新的构建器列表,则可以使用此参数。

  • force – 如果为 True,则不要验证给定的构建器与任何现有的复合环一致(默认值为 False)。

  • require_modified – 如果为 True 且 force 为 False,则验证自上次构建复合环以来,至少有一个给定的构建器已修改(默认值为 False)。

返回值:

一个元组 (构建器文件,加载的构建器)

引发:

ValueError 如果组件环构建器不适合相互组合,或者与任何现有的复合环不一致,或者如果 require_modified 为 True 且相对于现有环没有更改。

rebalance()

协同重新平衡所有组件环构建器。

此方法不会更改复合环的状态;需要后续调用 compose() 以生成更新的复合 RingData

返回值:

一个字典列表,每个字典对应一个组件构建器,包含以下键

  • ’builder_file’ 映射到组件构建器文件;

  • ’builder’ 映射到相应的 swift.common.ring.builder.RingBuilder 实例;

  • ’result’ 映射到该组件重新平衡的结果,即一个元组:(已更改的分区数,结果平衡,已删除的设备数)

该列表的顺序与复合环中组件的顺序相同。

引发:

RingBuilderError – 如果在重新平衡任何组件构建器时发生错误。

save(path_to_file)

将复合环元数据保存到给定的文件。有关持久化元数据的详细信息,请参阅 CompositeRingBuilder

参数:

path_to_file – 复合环文件的绝对路径

引发:

ValueError – 如果该实例尚未构建任何复合环

to_dict()

将复合环属性转换为字典。有关持久化元数据的详细信息,请参阅 CompositeRingBuilder

返回值:

一个复合环元数据字典

update_last_part_moves()

更新所有组件构建器中每个分区移动了多少小时的记录。

class swift.common.ring.composite_builder.CooperativeRingBuilder(part_power, replicas, min_part_hours, parent_builder)

基类: RingBuilder

一个继承自 RingBuilder 的子类,参与协同重新平衡。

在重新平衡期间,此子类将与它的 parent_builder 协商,然后再移动分区。 parent_builder 反过来可能会检查与协作者(包括此实例)以验证没有一个在过去 min_part_hours 内移动过该分区。

参数:
  • part_power – 划分数 = 2**part_power。

  • replicas – 每个分区的副本数。

  • min_part_hours – 分区更改之间的最小小时数。

  • parent_builder – 一个 CompositeRingBuilder 实例。

can_part_move(part)

检查仅在此构建器中,是否可以移动分区。

参数:

part – 要检查的分区。

返回值:

如果可以移动分区,则返回 True,否则返回 False。

update_last_part_moves()

更新此构建器中每个分区移动了多少小时的记录。

swift.common.ring.composite_builder.check_against_existing(old_composite_meta, new_composite_meta)

检查给定的构建器及其顺序是否与用于构建现有复合环的构建器相同。如果任何给定的构建器相对于创建给定 component_meta 时的状态已修改,则返回 True。

参数:
  • old_composite_meta – 形式为 _make_composite_meta() 返回的字典

  • new_composite_meta – 形式为 _make_composite_meta() 返回的字典

返回值:

如果任何组件已修改,则返回 True,否则返回 False。

引发:

Value Error – 如果提出的新组件与任何现有组件不匹配。

swift.common.ring.composite_builder.check_builder_ids(builders)

检查给定列表中所有 builder 是否都分配了 id,并且列表中没有 id 重复。

参数:

builders – 一个 swift.common.ring.builder.RingBuilder 实例的列表

引发:

ValueError 如果任何 builder id 缺失或重复

swift.common.ring.composite_builder.check_for_dev_uniqueness(builders)

检查在给定 builder 列表中,没有设备出现在多个 builder 中。

参数:

builders – 一个 swift.common.ring.builder.RingBuilder 实例的列表

引发:

ValueError – 如果在多个 builder 中发现相同的设备

swift.common.ring.composite_builder.check_same_builder(old_component, new_component)

检查给定的 new_component 元数据是否描述与给定的 old_component 元数据相同的 builder。为了满足此检查,new_component builder 不一定需要处于与创建 old_component 元数据时相同的状态,例如,它可能已经更改了设备并重新平衡。

参数:
  • old_component – 一个描述 component builder 元数据的字典

  • new_component – 一个描述 component builder 元数据的字典

引发:

ValueError – 如果 new_component 与 old_component 描述的不相同

swift.common.ring.composite_builder.compose_rings(builders)

给定一个 component ring builder 列表,对 builder 列表进行验证,并返回一个 composite RingData 实例。

参数:

builders – 一个 swift.common.ring.builder.RingBuilder 实例的列表

返回值:

一个新的从 component builders 构建的 RingData 实例

引发:

ValueError – 如果 builders 相互之间无效

swift.common.ring.composite_builder.is_builder_newer(old_component, new_component)

如果给定的 builder 相对于创建给定 component_meta 时的状态已被修改,则返回 True。

参数:
  • old_component – 一个描述 component ring 的元数据的字典

  • new_component – 一个描述 component ring 的元数据的字典

返回值:

如果 builder 已修改,则返回 True,否则返回 False。

引发:

ValueError – 如果 new_component 的版本早于现有 component 的版本。

swift.common.ring.composite_builder.pre_validate_all_builders(builders)

对所有要包含在 composite ring 中的 component ring builder 进行预验证。检查所有 component ring 是否相互有效。

参数:

builders – 一个 swift.common.ring.builder.RingBuilder 实例的列表

引发:

ValueError – 如果 builders 相互之间无效