数据表设计
1. SQLITE 特点
- 字符类型是 TEXT, 虽然支持 VARCHAR 但是长度约束无效,且本质上会转化为 TEXT
- sqlite 的 INTEGER, 会根据值的大小自动选择 1~8 字节存储
2. 详细数据库设计
- 时间戳使用 unix 时间戳 (即单位为秒)
根目录索引 info_root
归档的时候,需要把根目录写入索引表; 解档的时候,需要从索引表中选取需要解档的根目录。
字段 类型 约束 默认值 备注 id INTEGER PRIMARY KEY AUTOINCREMENT 目录唯一标识 root_name TEXT NOT NULL 目录名称 root_path TEXT NOT NULL 根目录 (不是唯一,不同系统可能会重复) status TEXT NOT NULL 'HEALTH' 状态:HEALTH/RECYCLED created_at INTEGER NOT NULL CURRENT_TIMESTAMP 创建时间戳 updated_at INTEGER NOT NULL CURRENT_TIMESTAMP 更新时间戳 目录索引表 info_directory
字段 类型 约束 默认值 备注 id INTEGER PRIMARY KEY AUTOINCREMENT 目录唯一标识 root_id INTEGER NOT NULL REFERENCES root_index(id) 目录根目录 directory_name TEXT NOT NULL '' 目录名 (TODO 是否需要) directory_mtime INTEGER NOT NULL 0 修改时间 (unix 时间戳) directory_path TEXT 相对路径 status TEXT NOT NULL 'HEALTH' 状态:HEALTH/RECYCLED created_at INTEGER NOT NULL CURRENT_TIMESTAMP 创建时间戳 updated_at INTEGER NOT NULL CURRENT_TIMESTAMP 更新时间戳 - unique(root_id, directory_path)
[Optional]目录树关系表 - 闭包表 (directory_tree)
字段 类型 约束 默认值 备注 ancestor_id INTEGER NOT NULL REFERENCES directory_index(id) 祖先目录 ID descendant_id INTEGER NOT NULL REFERENCES directory_index(id) 后代目录 ID depth INTEGER NOT NULL 目录层级深度(0 表示自身) status TEXT NOT NULL 'HEALTH' 状态:HEALTH/RECYCLED created_at INTEGER NOT NULL CURRENT_TIMESTAMP 创建时间戳 updated_at INTEGER NOT NULL CURRENT_TIMESTAMP 更新时间戳 文件索引表 info_file
- 硬链接所指的文件,和源文件仅路径和名称存在差异,hash,修改日期等都一致
- 文件索引表中仅文件信息相关内容,不要有归档相关信息,和归档解耦,归档相关数据表单向引用文件索引表的内容
字段 类型 约束 默认值 备注 id INTEGER PRIMARY KEY AUTOINCREMENT 文件唯一标识 directory_id INTEGER NOT NULL REFERENCES directory_index(id) file_name TEXT NOT NULL 文件名 (不含路径) file_size INTEGER NOT NULL 0 文件大小 (字节) file_mtime INTEGER NOT NULL 0 修改时间 (unix 时间戳) file_hash TEXT hash/SHA256哈希值(可重复, 当文件内容相同,文件名不同时) status TEXT NOT NULL 'HEALTH' 状态:HEALTH/RECYCLED created_at INTEGER NOT NULL CURRENT_TIMESTAMP 创建时间戳 updated_at INTEGER NOT NULL CURRENT_TIMESTAMP 更新时间戳 - UNIQUE (directory_id, file_name)
- UNIQUE (directory_id, file_name, file_hash)
归档元数据表 archive_metadata
字段 类型 约束 默认值 备注 id INTEGER PRIMARY KEY AUTOINCREMENT 归档 ID archive_uri TEXT NOT NULL 归档存储 URI,每个归档可以自定义存储目录 archive_name TEXT UNIQUE NOT NULL 归档名称,文件系统中的文件名 archive_limit_size INTEGER NOT NULL 归档限制大小(字节) archive_hash TEXT 归档文件的 hash 校验值 is_compressed INTEGER NOT NULL 0 0=未压缩,1=已压缩 compressed_algorithm TEXT 压缩算法(如 gzip/zstd) is_encrypted INTEGER NOT NULL 0 0=未加密,1=已加密 encryption_algorithm TEXT 加密算法(如 aes-256-cbc) status TEXT NOT NULL 'HEALTH' 状态(HEALTH/RECYCLED/HASH_OUTDATED) created_at INTEGER NOT NULL CURRENT_TIMESTAMP 创建时间戳 updated_at INTEGER NOT NULL CURRENT_TIMESTAMP 更新时间戳 - archive_uri: 支持移动到网络驱动,所以在解档,以及数据巡检的时候需要额外操作,例如下载到本地等
归档内容表 archive_chunk
- chunk_size 不包括 tar 格式文件头的信息,所以 chunk_size 的总和可能小于 archive_metadata.archive_limit_size 以及 archive_metadata 的实际尺寸
字段 类型 约束 默认值 备注 id INTEGER PRIMARY KEY AUTOINCREMENT 归档数据块唯一标识 archive_id INTEGER NOT NULL REFERENCES archive_metadata(id) 关联的归档 ID chunk_name TEXT NOT NULL UNIQUE 归档数据块名称,一般为 hash 值和文件名不一致 chunk_size INTEGER NOT NULL 0 逻辑数据块大小 (字节),非实际占用 (压缩,加密会影响实际大小) chunk_hash TEXT NOT NULL UNIQUE 归档数据块的 hash 必须计算,否则后续要计算得先解档 chunk_mtime INTEGER NOT NULL 0 修改时间 (unix 时间戳) chunk_relative_path TEXT NOT NULL './' 数据块在归档内的相对路径 status TEXT NOT NULL 'HEALTH' 状态:HEALTH/CLOSED/RECYCLED/DRAFT created_at INTEGER NOT NULL CURRENT_TIMESTAMP 创建时间戳 updated_at INTEGER NOT NULL CURRENT_TIMESTAMP 更新时间戳 - 由于文件添加到归档中一般不分层级,所以要求使用 id 或 hash 重命名文件,并存储到归档中,文件名要求唯一
文件与归档数据块表 map_file_chunk
- 当文件体积过大被拆分时,一份文件可能对应多个归档和分卷数据块。
- 当文件重复时,一份数据块可能对应多份文件。
- 分卷是针对文件 file, 归档并不会识别出这个数据块是分卷数据块还是普通数据块
字段名 类型 约束 默认值 说明 id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL file_id INTEGER NOT NULL REFERENCES file_index(id) chunk_id INTEGER NOT NULL REFERENCES archive_chunk(id) volume_order INTEGER NOT NULL 1 分卷顺序编号 status TEXT NOT NULL 'HEALTH' 状态:HEALTH/CLOSED/RECYCLED created_at INTEGER NOT NULL CURRENT_TIMESTAMP 创建时间戳 updated_at INTEGER NOT NULL CURRENT_TIMESTAMP 更新时间戳 灾备组 disaster_recovery_group
字段名 类型 约束 默认值 说明 id INTEGER PRIMARY KEY AUTOINCREMENT group_id TEXT NOT NULL UNIQUE 灾备组 UUID num_data_shards INTEGER NOT NULL 数据分片数量 num_parity_shards INTEGER NOT NULL 校验分片数量 shard_size INTEGER NOT NULL 分片大小 data_shards_stored INTEGER NOT NULL 0 是否存储数据分片 status TEXT NOT NULL 'HEALTH' 状态 last_verified INTEGER 最后校验时间戳 created_at INTEGER NOT NULL CURRENT_TIMESTAMP 创建时间戳 updated_at INTEGER NOT NULL CURRENT_TIMESTAMP 更新时间戳 数据分片 disaster_recovery_data_shard
字段名 类型 约束 默认值 说明 id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL group_id INTEGER NOT NULL REFERENCES disaster_recovery_group(id) 灾备组 ID shard_index INTEGER NOT NULL 分片索引 shard_path TEXT 分片路径(可为空) shard_hash TEXT NOT NULL 分片哈希值 status TEXT NOT NULL 'HEALTH' 状态:HEALTH/CORRUPTED/MISSING last_verified INTEGER 最后校验时间戳 created_at INTEGER NOT NULL CURRENT_TIMESTAMP 创建时间戳 updated_at INTEGER NOT NULL CURRENT_TIMESTAMP 更新时间戳 - unique: (group_id, shard_index)
- shard_index 用于标识分片顺序,reed-Solomon 对于分片有顺序要求
校验分片 disaster_recovery_parity_shard
字段名 类型 约束 默认值 说明 id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL group_id INTEGER NOT NULL REFERENCES disaster_recovery_group(id) 灾备组 ID shard_index INTEGER NOT NULL 分片索引 shard_path TEXT NOT NULL 分片路径(不能为空) shard_hash TEXT NOT NULL 分片哈希值 status TEXT NOT NULL 'HEALTH' 状态:HEALTH/CORRUPTED/MISSING last_verified INTEGER 最后校验时间戳 created_at INTEGER NOT NULL CURRENT_TIMESTAMP 创建时间戳 updated_at INTEGER NOT NULL CURRENT_TIMESTAMP 更新时间戳 - unique: (group_id, shard_index)
- shard_index 用于标识分片顺序,reed-Solomon 对于分片有顺序要求
归档文件与数据分片映射表 map_archive_data_shard
这是一个用于明确关联灾备组中每个数据分片与其对应原始归档文件的映射表,解决通过 shard_index 隐式关联的问题。
字段名 类型 约束 默认值 说明 id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL shard_id INTEGER NOT NULL REFERENCES disaster_recovery_data_shard(id) 数据分片 ID archive_id INTEGER NOT NULL REFERENCES archive_metadata(id) 原始归档文件 ID archive_order INTEGER NOT NULL 归档文件顺序 original_archive_hash TEXT NOT NULL 创建分片时, 归档文件哈希值 status TEXT NOT NULL 'HEALTH' 状态:HEALTH/CORRUPTED/MISSING created_at INTEGER NOT NULL CURRENT_TIMESTAMP 创建时间戳 updated_at INTEGER NOT NULL CURRENT_TIMESTAMP 更新时间戳 - UNIQUE (shard_id, archive_id)
- archive 可能有多个 data shard, 因为不同的 group 的最大文件大小不一样,所以即使相同的 archive 对齐后的 data shard 也不一定一样
- original_archive_hash 是创建灾备时,归档文件哈希值,避免 archive 改变 (增减内容,或者灾备恢复,破损等), archive metadata 中的 hash 值更新,导致数据不一致
- 关于 archive, data shard 的关系:
- [TODO] (目前还是一对一) archive 可能被拆分为多个 data shard; 但不会多个 archive 合并为同一个 data shard
- 关于 group 与 shard 的关系:
- 每个 data shard 仅属于单个灾备组,但不同或者同一灾备组中的 data shard 可能具有相同的内容和 hash 值
- 一个 group 会有多个 data shard
- TODO 目前每个 shard 都是独立存储,之后再考虑是否需要合并
- 关于 archive 与 group 的关系 (从数据库层面以及代码编码层面,两者没有直接关系,但是从用户层面,archive 和 group 存在关系)
- archive 可能属于多个 group; 且 group 中 archive 可能会重复
- TODO 需要考虑针对单个文件分块创建灾备组的情况
- TODO 如果需要增加对于 archive 分块,需要调整灾备恢复 reporter 的逻辑,需要调整计算分片可用性的相关逻辑
视图
文件列表视图 view_file
- file 是最小单位
字段名 类型 描述 root_id INTEGER 根目录 ID root_path TEXT 根目录路径 root_status TEXT 根目录状态 directory_id INTEGER 目录 ID directory_path TEXT 目录相对路径 directory_mtime INTEGER 目录修改时间 directory_status TEXT 目录状态 file_id INTEGER 文件 ID file_name TEXT 文件名 file_size INTEGER 文件大小 file_mtime INTEGER 文件修改时间 file_hash TEXT 文件哈希值 file_status TEXT 文件状态 数据块列表视图 view_chunk
- chunk 是最小单位
字段名 类型 描述 archive_id INTEGER 归档 ID archive_uri TEXT 归档目录 archive_name TEXT 归档名 archive_status TEXT 归档状态 chunk_id INTEGER 数据块 ID chunk_name TEXT 数据块名 chunk_size INTEGER 数据块大小 chunk_hash TEXT 数据块哈希值 chunk_mtime INTEGER 数据块修改时间 chunk_relative_path TEXT 数据块相对路径 chunk_status TEXT 数据块状态 file_id INTEGER 文件 ID volume_order INTEGER 分卷顺序编号