先说清楚这篇不是教程,也不是事故复盘,我就是想把这口气吐出来。
事情是这样的。手上那个给甲方做的内部小工具,数据都堆在一个 sqlite 文件里,说大不大说小不小,反正跑了大半年了,脏数据一堆,也是我一直在用的。今天下午想清理一下里面几张废表,就写了个脚本,drop table 前先备份,逻辑不复杂。
然后我就在那儿敲。mv data.db data.db.bak,然后跑脚本重建。手一挥回车。
报错。说不出来哪不对,反正脚本没跑完,退出了。我盯着屏幕看了两秒,心想没事,备份在。然后我 ls 了一下。
目录里只有一个 data.db。是空的,刚建的那个。
我当时脑子嗡一下。第一反应是有没有 data.db.bak——没有。我想了半天才反应过来,我 mv 那条命令根本没执行成功,因为我在前面加了个 &&,前半句条件不成立,后半句就没跑。也就是说,压根没有备份。那个 .bak 是我脑子里以为的。
说句实话,那一瞬间我手都在抖。半年的数据,甲方那边下个月还要用。我第一个念头是完了,第二个念头是别慌先看有没有 WAL 文件。
有。sqlite 那个 -wal 还在,还有 -shm。但主库被我建了个新的空文件覆盖了吗?没有——我用的是 open 新建,如果原文件还在的话应该是追加不是覆盖。但我刚才 ls 只看到一个 db 文件,说明原文件已经没了。
等等,我先捋一下我当时到底干了什么。
其实复盘到现在还是有点乱。我真正想说的不是技术细节,我想说的是那个心跳到嗓子眼的十分钟。我坐在那,一边告诉自己冷静一边手在打开各种目录找残留文件,翻到系统临时目录里去了,什么也没找着。
后来救回来是因为一件事:我在跑脚本之前,鬼使神差地 cp 了一份到 /tmp。
……对,就是前面我说没有备份的地方。我记岔了。mv 那条没走,但我前面确实顺手 cp 过一次到 /tmp,是准备拿来测试用的,我自己都给忘了。翻到 /tmp 里那个 data.db 的时候,我人瘫在椅子上。
数据是老了几分钟,但没丢。
所以现在回头看,整个过程特别荒诞:我以为我做了备份其实没做,又以为我没做其实做了。全凭一个我已经忘了的肌肉记忆。
写这篇之前犹豫了一下,这种事写出来显得很蠢。但说句实话,蠢归蠢,比翻车强。而且我确实想记一笔,就是因为我知道下次我可能还是会这么慌。
不吹不黑,这次运气占八成。剩下两成是那个 cp。以后这种活我打算先在测试库上跑一遍再动真的——这话说得像在总结方法论了,打住,就这样。
顺便提醒自己一句,那个 /tmp 里的文件别删。