我正在深入研究CouchDB 2,我发现了一些序列号的意外排序。在一个案例中,我发现_changes feed的早期更改具有序列号
99-g1AAAAI-eJyd0EsOgjAQBuAGiI-dN9C9LmrBwqzkJtrSNkgQV6z1JnoTvYneBEvbhA0aMU1mkj6-_NMSITTJfYFm2anOcsFT10mpTzyG-LxpmiL32eqoN8aEAcWE9dz_jPCFrnzrHGQchiFM4kSgaV0JqQ6VFF-AtAV2DggMgCEGxrNhQfatc3bOyDiKUalg2EBVoCu66KapazcUh41e69-GssjNIvcWWRokk2oNofwj0MNazy4QFURhGQ0J9LKI-SHPIBHEgiak51nxBhxnrRk
对于同一个数据库,我的_changes Feed中的最后一个序列号是
228-g1AAAAJFeJyd0EkOgjAUBuAGTJCdN9AjlIKFruQm2jFAEFes9SZ6E72J3gQ7JW7QCGnyXtLhy-vfAgCWVSjAip96XglW-o5afRJQwNbDMDRVSOuj3ogQJRgiOnL_O8I2urKdd4B1KCRpkRcCxH0npKo7KX4ApQH2HogsAElOKOPTBjkY5-yd2DqKYqnItA91C13BRTdNXY0VWouRrV7JDOvmrLuxlLW4VAlJ5Qzr4aznJ2wskIIy-y9sh7wcYoMKLJKRXOACjTxr3uHcsBE
在浏览器控制台中,以下内容为false
'228-g1AAAAJFeJyd0EkOgjAUBuAGTJCdN9AjlIKFruQm2jFAEFes9SZ6E72J3gQ7JW7QCGnyXtLhy-vfAgCWVSjAip96XglW-o5afRJQwNbDMDRVSOuj3ogQJRgiOnL_O8I2urKdd4B1KCRpkRcCxH0npKo7KX4ApQH2HogsAElOKOPTBjkY5-yd2DqKYqnItA91C13BRTdNXY0VWouRrV7JDOvmrLuxlLW4VAlJ5Qzr4aznJ2wskIIy-y9sh7wcYoMKLJKRXOACjTxr3uHcsBE' > '99-g1AAAAI-eJyd0EsOgjAQBuAGiI-dN9C9LmrBwqzkJtrSNkgQV6z1JnoTvYneBEvbhA0aMU1mkj6-_NMSITTJfYFm2anOcsFT10mpTzyG-LxpmiL32eqoN8aEAcWE9dz_jPCFrnzrHGQchiFM4kSgaV0JqQ6VFF-AtAV2DggMgCEGxrNhQfatc3bOyDiKUalg2EBVoCu66KapazcUh41e69-GssjNIvcWWRokk2oNofwj0MNazy4QFURhGQ0J9LKI-SHPIBHEgiak51nxBhxnrRk'
这是一个错误还是我需要使用其他方法来比较序列号?
在查看我的_changes Feed中的其他序列号时,看起来它们通常按照我的预期排序,但在这种情况下,看起来当第一个数字时,例如99,从2位跳到3位,排序中断。如果你把它归结为一个简单的字符串比较示例,你可以看到'228'> '99'=>假
答案 0 :(得分:3)
以下答案包含来自@rnewson的电子邮件主题的摘录。我希望能帮助其他人理解CouchDB 2中的序列号。谢谢,罗伯特!
背景:
在2.0中没有简单的方法来比较它们,也没有对它们的要求 要井然有序。简而言之,它们不是为了检查而设计的 在couchdb之外比较;不透明地对待它们。
前面的数字是各个更新序列的总和 在第二部分编码,只存在于旧版本的旧版本 couchdb复制器进入检查站。
序列字符串的后半部分是{node, range,seq}元组(其中seq是你知道的整数值 2.0之前的版本)。当一个序列字符串被传回时,作为 因为=参数,couchdb解码此字符串并传递 适当的整数seq值到单个分片。
总而言之,前面的数字应该会增加。满满的 字符串本身不具有可比性,因为没有定义的顺序 到编码列表(因此可以生成两个字符串 编码不同但解码到相同的元组列表,只是在一个 不同的顺序)。
另一个方面是改变饲料并非完全 订购。对于给定的分片, 完全有序(分片为。) 与具有整数序列的pre 2.0数据库相同),couchdb 不会改变那个输出(虽然复制的正确性会 保留,如果它确实)。集群数据库由几个组成 但是碎片('q'值,默认为4 iirc)。聚集的 更改Feed将这些单独的更改组合成一个, 但没有努力对此施加总命令。我们不这样做 因为它既昂贵又不必要。
解决方案,如果您需要侦听_changes Feed然后重新启动 从你以后离开的地方开始:
正确使用更改Feed的算法是:
- read / dbname / _changes
- 理所当然地处理每一行
- 定期(每X秒或每X行)存储您处理的最后一行的“seq”值
醇>如果你遇到崩溃,或者你没有使用continuous = true,你可以这样做 同样的程序,但在步骤1中进行了修改;
修订1.读/ dbname / _changes?since = X
其中X是您在步骤3中保存的值。如果您不使用 连续模式然后你可以只记录“last_seq”值 消耗不连续响应的结束。你冒的风险 但是,要重新处理更多的物品。
通过这个方案(复制者和所有索引者都遵循),你 不关心结果是否有问题,你不需要比较 任何两个seq值。
您做需要确保您可以正确处理相同的更改 多次。举个例子,考虑复制器,何时 它从更改提要中看到一行,它会询问目标数据库是否存在 包含该行的_id和_rev值。如果确实如此,那就是 复制器移动到下一行。如果没有,它会尝试写 该行中的文档到目标数据库。如果是 崩溃,因此使用之前的seq值调用_changes 处理该行时,它会询问目标数据库是否有 再次_id / _rev,只有这次目标会说是。