联系支持

我们通过电子邮件回复,通常两天内。

为防止滥用,Google reCAPTCHA 会检查这次提交,其间会向 Google 传输数据。脚本只在你打开此表单时才加载。

← 全部文章

删除一个计数器到底动了哪些地方

在这里删除一个计数器会清空 33 张表。昨天它清空 25 张。

它漏掉的那八张,全都是前一天建的,时间在上午 11:10 到下午 15:10 之间。

33 张表知道计数器的某些事 其中 8 张没有被清空 — 全都是前一天建的 这八张里一共躺着 4,840 行 今天补上,放在字母顺序的位置,不是追加到末尾 在其他表里找到 25 行孤儿行,已清除

删除是怎么做的

站长可以删掉自己的计数器。需要一个 POST、站长令牌,还有手动敲一遍计数器编号,因为没有撤销。什么都不会另存一份:影子副本正好是所请求之事的反面,而导出链接就在按钮上方,给想留一份的人。

然后一份表清单在同一个事务里被清空,主表放在最后,一块墓碑进入归档,好让这个编号永远不会再发给别人。任何一步失败,整件事回滚。什么都没删,好过删了一半。

在那份清单上面,文件里写着:

「每一张知道这个计数器某些事的表。写成清单而不是散落在代码里:这里缺了什么,就会作为孤儿行留下来,而且没有人会注意到。」

它提前一天描述了自己的失败

昨天,为一个新功能新增了六张表 — 页面停留时间、滚动深度、退出页面 — 另外还有两张。时间在 11:10 到 15:10 之间。

删除清单就在那一天被改过,为的是加进另一张新表。这八张是在那之后来的,而清单再没有动过。所以从昨天下午起,删除一个计数器会留下 4,840 行行为数据,散在八张表里,属于那些请求被遗忘的人。

这不是一个关于疏忽的故事。有人写了这份清单,完全明白它为什么是一份清单,写下了它落后时会发生什么 — 并且就在那一天为一张表更新过它。而它还是落后了,因为靠记得来让两样东西保持同步,是人类可靠地做到的事,一直可靠到他们没做到的那个下午。

修复,以及另一个修复

八个名字现在在清单里了。它们被插进各自的字母顺序位置,而不是追加到末尾,因为排好序的清单会让空缺显形,而只往后追加的清单不会。

那是小的修复。真正要紧的那个,是一个脚本:它问数据库哪些表带着计数器编号,从源文件里读出清单而不是重复一遍,然后比对两者。谁新建了表,就跑它一次。它不会像清单那样被忘掉,因为它什么都不保存 — 它每一次都从表结构推出答案。

它第一次运行就又找到了别的:另外八张表里有 25 行,它们的计数器编号既不在活的表里,也不在归档里。不是被删除的计数器 — 那些会留下墓碑。是不属于任何东西的编号,多数是归档检查存在之前留下的、一望而知的测试编号。它们被写进网站根目录之外的一个文件,然后被清掉了。

这件事的一般化

任何需要跟别的东西保持同步的清单,早晚都会失去同步,而那个缺口会是看不见的,因为一份少了一条的清单,看起来和一份完整的清单一模一样。

防线不是自律。防线是从一边推出另一边,并检查两者是否一致 — 并且在有人添加东西的那一刻跑这个检查,而不是在有人起疑的那一刻。

清单上面那段注释在所有事情上都对,只有一个词不对。它说没有人会注意到。有人注意到了,晚了一天,因为他是拿脚本去看的,不是拿记性。

广告