跳转至

运行要求

CI 运行时会在命令行参数给出 -b 选项,给程序的输入为多行 SQL 语句,每一行一定是一个完整的 ; 结尾的 SQL 语句,输出格式见 0.3 前端约定 相关内容。

评测器在完成编译后、正式测试前会先用 --init 参数运行你的程序,这一阶段你或许会对你的数据文件做一些初始化来使它们成为一个合理的状态,如果此前已经有数据了应该全部删除,这主要是为了方便你本地测试不必在运行测例前手动删除已有的数据。理论上如果你觉得没必要有这么一个阶段,你可以在主函数里处理成看到该参数后直接退出程序。

命令行参数指定数据文件夹路径

一种可能的情况是你在本地跑测例,你的数据库中已经有了你花了一些时间建立导入的数据,你希望运行测例时不要干扰你已有的数据,那么在这种情况下你可以考虑为数据库新增一个参数来指定数据文件夹的路径。

例如你可能会添加参数 --data_dir ./test-data 来让运行测例时处理的数据都在 ./test-data 内,而平时你不加这一参数,默认的 data_dir./data

数据文件夹的位置我们没有统一要求,,但为了保证 CI 检查不出现问题,你需要保证数据文件夹应该在 ./ 之下,例如 ./data。错误的位置可能导致没有访问权限从而出错,或者因为挂载盘类型不同而性能大降。

评测器在运行期间可能会不定期地试图重启 DBMS 以验证持久性,但我们并不要求崩溃一致性,你只需要保证 DBMS 能够正常退出即可,为此我们约定在输入 SQL 时如果输入一个 "exit" (常用于交互场景)或者读到 EOF (常用于重定向场景)则应该主动释放资源、退出进程。

考虑到往年部分同学采用将数据全部导入内存的作弊方法,以及我们的数据库系统很多细节设计都是为了解决内存高性能低容量与磁盘低性能高容量之间的矛盾,我们对 CI 运行时的资源进行了限制,我们限制如下:

  • 时间:~3600s
  • 内存:256MB
  • 硬盘:10GB
  • CPU核数:1

注意这里的控制并非是精确控制,不像 DSA 的 OJ,在数据库这样的大项目里精确控制时间与空间是几乎不可能的,你需要合理地估算。

就时间而言,为了践行老师所说的“不卡时间”的准则,助教使用 Python 作为标程,确定 Python 版数据库能在规定时间内通过测试,而传统的数据库引擎通常用 C++ 编写,在复杂度、缓存等技术使用无误的情况下理应不会存在性能瓶颈。另一方面,实验推荐使用 C++ 完成,因此除非你对自己的 Python 性能优化很有把握,否则不建议使用 Python 完成实验。另外注意时间限制用了表示估计的 ~ 符号,这是因为计时会包含评测器向你的DBMS的输入时间、以及 DMBS 进程启动时间,但一般来说这些时间基本可以忽略,除非你的DBMS启动时需要消耗大量时间,而你的 DBMS 在评测过程中进程崩溃重启若干次。注意前述 --init 指令会被调用一次直到进程退出,且也会计入总时间。

内存上对你的 DBMS 进程使用了虚存限制,推荐你使用 128MB 空间用作页式文件系统的缓存页,严格限制其他部分的内存应该在某个约束之内。理想情况下其他部分应采用 O(1) 的额外内存,当然严格限制 O(1) 会为你编程带来不必要的困难,因此在此约定所有查询结果不超过 32MB(按整数、浮点数均8字节,字符串为实际长度+1字节进行封底估算)。如果你计划完成聚合查询的选做,那么你或许应该谨慎考虑是否要将所有数据读入内存后再进行聚合操作。

这里举一个内存估算的例子,附件提供的C++页式文件系统为缓存准备了 CAP=MOD=6k 个槽位,为了维护结构信息一次开了 CAP 若干倍个整数,但这部分是可以忽略的小量,即便开了 10 倍的整数,也不过是 $6000 * 40B / 1024 / 1024 = 0.23MB$,它的主要内存消耗在于后面动态分配的 CAP 个页,每页 8192 字节,因此它的主要内存消耗约为 $6000 * 8192B / 1024 / 1024 = 47MB$。

CPU 核数限制 1 则是提示不必使用并行加速等方法来卷性能,另外对于 Python 的 numpy 这种库,默认会用多线程加速,在 Linux 上会因为大量 pthread 导致极高内存占用,所以我们在评测器中预设了 OMP_THREAD_NUM=1 来限制。

硬盘空间的约束通常用不上,这只是为了防止你的程序出现死循环输出等BUG而给的限制,实际上我们的数据总量通常在1GB以内,即便你用了一些辅助空间也远不会用到10GB——除非你滥用 append-only 模式、留了大量 Log 并且从来不进行空间回收。由于 CI 检测用到了 Docker,而严格的空间限制在 Docker 上并不容易实现,我们实际上将 /builds 路径挂载到了一个位于 SSD 上的 10GB 文件创建的虚拟文件系统上(其他路径均为机械硬盘),而 GitLab 的 runner 会将你的项目 clone 到 /builds 的一个多级子目录下。因此只要你按上文所说将数据文件存在 ./data 下便是预料中的行为,值得一提的是对于 Python 的包管理软件 pip 而言它的包安装路径在机械硬盘上的家目录下,因此不会被计入 10GB 约束中,而像 Node.jsnpm 默认将包装在 ./node_modules 下则会计入上述 10GB约束。

超越空间限制实例

TODO:蹲一个真的把空间用超了的例子,在这里“公开处刑”。

Authors: Congyuan Rao