问题:
- 主要问题:并行这些工作的最佳策略是什么?
- 想法:如何使用其他机制(如第二个校验和(Adler32?)
塞纳里奥:
我正在用java编写一种同步工具。基本上,它从网络服务器下载一个存储库,该存储库代表本地机器上的文件/目录结构,并以压缩形式定义所需文件的源,并结合哈希值来验证文件。我猜是一个基本的东西。
要求:
- 多平台java桌面应用
- 最佳速度和并行化
示例结构:(最好使用游戏模组来描述)
示例存储库文件
{"name":"subset1", "mods":[
{
"modfolder":"mod1",
"modfiles":[
{
"url":"http://www.example.com/file2.7z",
"localpath":"mod1/file2",
"size":5,
"sizecompressed":3,
"checksum":"46aabad952db3e21e273ce"
},
{
"url":"http://www.example.com/file1.7z",
"localpath":"mod1/file1",
"size":9,
"sizecompressed":4,
"checksum":"862f90bafda118c4d3c5ee6477"
}
]
},
{
"modfolder":"mod2",
"modfiles":[
{
"url":"http://www.example.com/file3.7z",
"localpath":"mod2/file3",
"size":8,
"sizecompressed":4,
"checksum":"cb1e69de0f75a81bbeb465ee0cdd8232"
},
{
"url":"http://www.example.com/file1.7z",
"localpath":"mod2/file1",
"size":9,
"sizecompressed":4,
"checksum":"862f90bafda118c4d3c5ee6477"
}
]
}
]}
客户端文件结构,应该是在同步之后
mod1/
file2
file1
mod2/
file3
file1
// mod1/file2 == mod2/file2
关于存储库的一个特殊之处: 从服务器获取的存储库仅代表更大存储库的子集,因为用户只需要一个子树,它正在变化(也重叠)。有时存储库由 mod1 和 mod2 组成,有时由 mod1 和 mod3 等组成。
要做的工作:
- 下载存储库并解析它(Net I/O)
- 在进程结束时将不在存储库中的文件标记为删除(由于相同的校验和,文件可能被复制)(文件 I/O)
- 如果文件存在:检查现有文件的校验和(校验和缓存)(文件 I/O)
- 如果文件不存在:检查其他子树中相同文件的校验和缓存以复制文件而不是下载文件(轻文件 I/O)
- 以压缩形式下载单个文件 (Net I/O)
- 提取压缩文件(文件 I/O)
- 未压缩文件的校验和(文件 I/O)
- 缓存与文件关联的校验和。(轻文件 I/O)
我的解决方案:(许多不同的生产者/消费者)
- 校验和缓存正在使用 MapDBs 持久映射。
- ATM 仅使用 md5 校验和。
- 队列:每个 Workertype 都有一个阻塞队列(生产者/消费者)
- 线程池:每个 Workertype 都有一个固定的线程池,例如 3 个下载器,2 个校验和,...
- Worker 将当前作业分发到其他队列:Downloader -> Extract -> Checksum
工人类型:
- Localfile Worker:检查本地文件结构(使用校验和缓存),将工作重定向到 Download-Worker、Delete-Worker
- 复制:将具有相同校验和的文件复制到目标
- 下载:下载文件
- 校验和:校验和文件并插入校验和缓存
- 删除:删除文件
- 提取:提取压缩文件