#+TITLE: Deepin 仓库改进说明

* debian/ubuntu系列的问题

** 404 Not Found
404 出现的问题一般都是因为仓库处于同步的过程中．此时
dists目录已经同步成功了，但pools目录因为内容太多导致更新缓慢．

每次同步都导致用户处于一个不可用状态.　这种不稳定状态普遍在小时级别．

** 镜像源速度非常快，但是内容过期了
各个地区以及网络情况都不同，在目前大环境下，社区提供的镜像源还是必不可少的．
但部分镜像源的同步周期是不确定的．更有些国外镜像源因为同步官方源速度实在
太慢，导致长期处于不稳定以及过期状态．

** 如果镜像源服务器出现问题，官方源无法做有效的补救措施
如果镜像源被黑或者当机，那么官方源无法做任何处理．用户处于无法
安装软件的状态．另外还有一个潜在风险: 内容被恶意修改．挨个通知用户
修改镜像源的效率和效果都非常差．


* deepin在做什么？
在保留镜像源的优势下，100%保证用户看到的数据与官方源一致，完全规避了
镜像源的劣势．

** SmartMirrors
*** 核心思想
用户要下载的某个数据，如果其在镜像源中与官方源一致则采用镜像源的数据．
否则采用官方源的数据．

扩展来解释
- dists目录下的Release文件只会从官方源下载(10KB以内), 所有其他数据(包括lists文件)
  *优先* 从镜像源下载．

- 以下情况会导致数据从官方源下载
  1. 镜像源中某个deb版本与官方源不一致
  2. 镜像源中的Packages(lists)文件与官方源不一致
  3. 镜像源直接服务器挂了
  4. 镜像源下载的deb的hash检验失败 (当前版本0.9未处理此种情况,不会fallback到官方源)

- /etc/apt/sources.list永远不会变动，只会是packages.deepin.com/deepin

*** 实现方式
因为要支持这种动态选择只能通过修改apt的逻辑进行．但为了尽量减少对apt的影响所以采取
对apt进行最小patch配合外部程序进行实际逻辑处理的方式．

目前对apt的修改在 [[./smartmirror.patch]]

实际逻辑处理是由本项目的lastore-smartmirror提供的.

核心逻辑如下
1. 对apt的pkgAcquire::Worker::QueueItem中的Item.URI U0进行hook
2. 根据/etc/apt.conf.d/99lastore.conf的内容获得当前官方源地址U1以及用户期望的镜像源地址U2
3. 将U0 U1 U2 传递给lastore-smartmirror，同时向U1, U2发送一个HEAD/GET的请求．然后判断最终的URI
4. 将最终的URI返回给apt, 之后逻辑与正常情况相同

补充
1. 因为不是所有服务器都支持HEAD方法，所以只有官方源使用HEAD. 其他源使用GET并在获取Header后
   立刻断开connection
2. lastore-smartmirror会判断U0是否是支持镜像源的，比如U0是一个ppa里面的deb那么就不会进行后续判断了
3. pools中因为deb的名称里包含版本等信息，可以简单的通过uri即可判断镜像源是否和官方源的版本一致.
4. Packages文件因为名称上不包含版本等信息所以无法通过URI是否存在来判断内容是否与官方源一致，因此
   开启了apt中最新的by-hash特性．这样Packages文件也会出现在一个以hash值为名称的文件中.
5. 可以通过修改99lastore.conf以及99mirrors.conf文件调整行为．主要有3个参数
   - Debug 开启后可以看到实际使用的下载地址. 但可能导致某些依赖apt-get输出的程序失败.
   - Enable 若关闭，则和正常apt行为一致.
   - MirrorSource 用户期望的镜像源地址
   所有配置信息都可以通过apt-config dump Acquire::SmartMirrors查询到，
   通过-o key=value方式针对单个apt命令进行调整

** 原子更新 (处理中)
*** 核心思想
官方源在更新仓库的时候先将所有数据同步到一个独立的目录下，然后直接rename到
提供仓库数据的目录去．　从而让用户完全感受不到官方源的更新过程．

补充
1. 若用户正在下载，按目前的方式会导致下载中断．(但之前的方式也会)
2. 镜像源的内容虽然官方无法要求按照此方式进行，但因为SmartMirrors的缘故，所以
   当镜像源的某个deb失效时会直接fallback到官方源．

** 将来计划中的一些改善
- 配合仓库根目录下的特殊文件，快速判断是否需要自动执行apt-get update
- 针对不同镜像源，采用时间差的方式，缓解官方源更新时的压力．可以从两方面入手
  1. 客户端检测的时候打时间差，不是所有客户端看到更新就立刻提示有更新．
  2. 针对镜像源的地理位置等信息，将更新信息分批告知出去．(可以通过不同IP不同内容的形式)
