MongoDB 更新插入在锁定时不会更新
mongodb upsert doesn't update if locked
我有一个用C++编写的应用程序,有16个线程,从wireshark/tshark的输出中读取。Wireshark/tshark剖析pcap文件,这些文件gsm_map信令捕获。
Mongodb 是 2.6.7
我的文档所需的结构是这样的:
注意"数据包"是一个数组,稍后会很明显为什么。
对于所有不了解TCAP的人来说,TCAP层是面向事务的,这意味着所有数据包都包括:
- 事务状态:开始/继续/结束
- 源交易 ID (otid)
- 目标交易 ID (dtid)
例如,您可能会看到一个包含 3 个数据包的事务,查看 TCAP 层大致是这样的
两个数据包,一个"开始",一个"结束"。
{
"_id" : ObjectId("54ccd186b8ea19c89ee8f231"),
"deleted" : "0",
"packet" : {
"datetime" : ISODate("2015-01-31T12:58:11.939Z"),
"signallingType" : "M2PA",
"opc" : "326",
"dpc" : "6406",
"transState" : "begin",
"otid" : "M2PA0400435B",
"dtid" : "",
"sccpCalling" : "523332075100",
"sccpCalled" : "523331466304",
"operation" : "mo-forwardSM (46)",
...
}
}
/* 1 */
{
"_id" : ObjectId("54ccd1a1b8ea19c89ee8f7c5"),
"deleted" : "0",
"packet" : {
"datetime" : ISODate("2015-01-31T12:58:16.788Z"),
"signallingType" : "M2PA",
"opc" : "6407",
"dpc" : "326",
"transState" : "end",
"otid" : "",
"dtid" : "M2PA0400435B",
"sccpCalling" : "523331466304",
"sccpCalled" : "523332075100",
"operation" : "Not Found",
...
}
}
由于网络体系结构,我们在两 (2) 个点中进行跟踪,并且流量在这两个点之间平衡。这意味着有时我们在"开始"之前看到"继续"或"结束"。相反,我们可能会在"开始"或"结束"之前看到"继续"。简而言之,交易不是有序的。
此外,多个端点之间在"交谈",事务 ID 可能会重复,2 个端点可能同时使用相同的 tid,其他 2 个端点,尽管这不会一直发生,但它确实会发生。
由于后面的原因,我还需要使用 SCCP 层的"呼叫"和"呼叫"全局标题(如电话号码)。
请记住,我不知道给定数据包的去向,所以这就是我正在做的事情:
- 每当我收到一个新数据包时,我都必须找到该事务是否已存在于 mongodb 中,我正在使用 upsert 来执行此操作。
- 我通过在现有数据包的 otid 或 dtid 中搜索当前数据包的数据包 otid 或 dtid 来做到这一点
- 如果是:将新数据包推送到现有文档中。
- 如果没有:使用数据包创建一个新文档。
例如,这是一个"结束"的更新插入,应该找到一个"开始":
db.runCommand(
{
update: "packets",
updates:
[
{ q:
{ $and:
[
{
$or: [
{ "packet.otid":
{ $in: [ "M2PA042e3918" ] }
},
{ "packet.dtid":
{ $in: [ "M2PA042e3918" ] }
}
]
},
{
$or: [
{ "packet.sccpCalling":
{ $in: [ "523332075151", "523331466305" ] }
},
{ "packet.sccpCalled":
{ $in: [ "523332075151", "523331466305" ] }
}
]
}
]
},
{
$setOnInsert: {
"unique-id": "422984b6-6688-4782-9ba1-852a9fc6db3b", deleted: "0"
},
$push: {
packet: {
datetime: new Date(1422371239182),
opc: "327", dpc: "6407",
transState: "end",
otid: "", dtid: "M2PA042e3918", sccpCalling: "523332075151", ... }
}
},
upsert: true
}
],
writeConcern: { j: "1" }
}
)
现在,所有这些都有效,直到我将其投入生产。
似乎数据包正在快速发展,我看到很多:
"客户端光标::静态收益无法解锁递归锁的 B/c"警告我读到我们可以忽略此警告,但我发现我的更新插入不会更新文档!看起来有一个锁,mongodb忘记了更新。如果我将更新插入更改为简单的插入,则不会丢失任何数据包
我也读到这与没有使用索引有关,我有以下索引:
"3" : {
"v" : 1,
"key" : {
"packet.otid" : 1,
"packet.dtid" : 1,
"packet.sccpCalling" : 1,
"packet.sccpCalled" : 1
},
"name" : "packet.otid_1_packet.dtid_1_packet.sccpCalling_1_packet.sccpCalled_1",
"ns" : "tracer.packets"
所以总结一下:
1.- 如果此索引不正确,有人可以帮我创建正确的索引吗?2.- 如果 mongo 找到锁,它不会更新文档是正常的吗?
谢谢和问候!
大卫
为什么要将所有数据包存储在一个数组中?通常在这种情况下,最好将每个数据包单独制作为文档;如果没有有关您的用例的更多信息(或者,也许,对您正在使用的所有这些首字母缩略词有更多的了解:D),就很难说更多。您的更新将成为插入项,您无需执行更新查询。相反,数据包上的其他一些元数据会将相关数据包连接在一起,以便您可以重建事务或需要执行的任何操作。
更直接地解决您的问题,我会使用数组字段tids
来存储[otid, dtid]
,并使用数组字段sccps
来存储[sccpCalling, sccpCalled]
,这将使您的更新查询看起来像
{ "tids" : { "$in" : ["M2PA042e3918"] }, "sccps" : { "$in" : [ "523332075151", "523331466305" ] } }
并适合索引{ "tids" : 1, "sccps" : 1 }
。
- 从C++本机插件更新Vector3数组
- QGraphicsPolygonItem在拖动时未更新QPolygonF坐标
- Ardunio UNO解决了多个重叠的定时器循环
- cmake更新缓存的变量
- 更新到莫哈韦后出现cmath错误
- OpenMP:并行更新数组总是需要减少数组吗
- 为什么我的变量没有更新,我的 LED 没有亮起?
- 指针没有更新它在void函数内部指向的值
- 如何在c++中获取要更新的值
- 已修改的LinkedList未在文本文件本身中更新
- Qt:当QListView获得新条目时,如何更新QStringList
- 更新的矢量元素不打印
- 如何使用按钮更新GTK3图像以使用C++从相机捕获图片
- 如何在ECS框架中更新组件数据和通知系统
- 从VS 2015更新3更新到VS2015更新3 d后浮点计算行为不同的原因
- 如果我想在没有更新编译器的情况下使用新功能,该怎么办?
- 如何在 C++11 中查找和更新向量中的一个嵌套结构
- (SFML)按下键时,播放器构造函数未使用正确的动画进行更新
- 在 emscripten 网页汇编正在运行期间更新进度条?
- 在运行时使用范围更新结果