mongodb驱动程序在迭代过程中有错误吗?文档包含无效的UTF-8


MongoDB shell version v4.4.6
Build Info: {
"version": "4.4.6",
"gitVersion": "72e66213c2c3eab37d9358d5e78ad7f5c1d0d0d7",
"openSSLVersion": "OpenSSL 1.1.1f  31 Mar 2020",
"modules": [],
"allocator": "tcmalloc",
"environment": {
"distmod": "ubuntu2004",
"distarch": "x86_64",
"target_arch": "x86_64"
}
}

我在索引期间mongodb崩溃:

{"t":{"$date":"2021-07-09T15:02:31.139+02:00"},"s":"I",  "c":"STORAGE",  "id":20649,   "ctx":"IndexBuildsCoordinatorMongod-0","msg":"Index build failed","attr":{"buildUUID":{"uuid":{"$uuid":"5ed4dd6b-420b-46e3-8611-3fba75d9739e"}},"namespace":"testdb.articles","uuid":{"uuid":{"$uuid":"cdf839b1-a9b4-4dfb-a500-c1f80f2dea2a"}},"error":{"code":28755,"codeName":"Location28755","errmsg":"text contains invalid UTF-8"}}}

我想知道如何才能真正找到此文档并将其删除?我正在使用pymongo

是否有任何与buildUUID相关的日志文件可以告诉我文档的id是什么?或者可能有一些mongo命令可以让我检测到无效的UTF-8?

奇怪的bson解码错误

我使用以下代码来尝试检测问题

def check_doc(skip: int):
it_cursor = col.find().skip(skip)
count = 0
while True:
try:
doc = it_cursor.next()
print(f"{count}, {doc['_id']}")
except Exception as e:
print(f"i={count}, last doc {doc}", file=sys.stderr)
raise e
count += 1

然后我在'_id':ObjectId('60e7a4e2a3a21f66d1895c46')之后检测到问题

File "/home/user/.local/lib/python3.8/site-packages/pymongo/message.py", line 1615, in unpack_response
return bson._decode_all_selective(
File "/home/user/.local/lib/python3.8/site-packages/bson/__init__.py", line 1089, in _decode_all_selective
return decode_all(data, codec_options)
bson.errors.InvalidBSON: 'utf-8' codec can't decode byte 0xc2 in position 0: unexpected end of data

然而,如果我使用以下代码,我实际上可以获得文档,并且我看不到任何异常:

col.find({"_id":bson.ObjectId('60e7a4e2a3a21f66d1895c47')}).next()

这是否意味着bug实际上在驱动程序中,而文档实际上是可以的?

我刚刚发现更改了跳过值,无效的utf8错误跳了很多。文档在某些运行中是正常的,但在其他运行中报告错误。例如,check_doc(23447800)check_doc(23447850)都在第101轮开始引发错误,这不可能是真的:如果文档23447901真的有问题,那么第二个check_doc将在第51轮引发错误。所以我想这是一个驱动程序错误。

我试图在mongo shell中复制这个,但我不能,以下命令不会引起任何问题:

db.articles.find().skip(23447800).forEach(function(doc){printjson(doc);})

另一个有趣的发现是,如果我强加一个限制((,那么错误就消失了。所以这个错误只发生在没有限制的pymongo迭代和文本索引中。check_doc(23447800, 205)不会引发任何错误。

def check_doc2(skip: int, limit: int):
it_cursor = col.find().skip(skip).limit(limit)
count = 0
while True:
try:
doc = it_cursor.next()
print(f"{count}, {doc['_id']}, {doc['pmid']}")
except StopIteration:
break
except Exception as e:
print(f"i={count}, last doc {doc}", file=sys.stderr)
raise e
count += 1

在深入研究代码之后。我发现pymongo在遍历光标时会以庞大的方式读取文档。因此,check_doc((不是定位有问题文档的好方法。当产生当前游标时,pymongo会继续读取后面的文档,如果下一次大容量读取出现问题,则会引发错误。更好的方法是使用以下具有精确匹配的函数从check_doc((开始发出错误的点开始检索文档。

def check_doc3(start_id, count: int):
ret = []
st = int(str(start_id), 16)
for i in range(st, st+count):
try:
_id = bson.ObjectId("%x"%i)
col.find({"_id": _id}).next()
except StopIteration:
break
except Exception as e:
ret.append(i)
print(e)
return ret

最新更新