如果锁定,mongodb upsert不会更新

时间:2015-01-31 16:14:16

标签: c++ mongodb upsert

我有一个用C ++编写的应用程序,有16个线程,可以从wireshark / tshark的输出中读取。 Wireshark / tshark分析了作为gsm_map信令捕获的pcap文件。

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)个点进行跟踪,并且这两个点之间的流量是平衡的。这意味着有时我们会在“开始”之前看到“继续”或“结束”。相反,我们可能会在“开始”或“结束”之前看到“继续”。简而言之,交易订购。

此外,多个端点之间正在“交谈”,并且transactionID可能会重复,2个端点可能同时使用相同的tid和其他2个端点,尽管这不会一直发生,它发生

由于后者,我还需要使用SCCP层的“呼叫”和“呼叫”全局标题(如电话号码)。

请记住,我不知道给定数据包的走向,所以这就是我正在做的事情:

  • 每当我收到一个新数据包时,我必须找到mongodb中是否已存在该事务,我正在使用upsert来执行此操作。
    • 我是通过在现有数据包的otid或dtid中搜索当前的数据包otid或dtid来实现此目的
    • 如果是:将新数据包推入现有文档。
    • 如果没有:使用数据包创建新文档。

作为一个例子,这是一个“结束”的upsert,它应该找到一个“开始”:

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" }
  }
)

现在,所有这些都有效,直到我投入生产。

似乎数据包正在快速发展,我看到很多:

“ClientCursor :: staticYield无法解锁B / c递归锁定”警告 我读到我们可以忽略这个警告,但我发现我的upserts不会更新文件!看起来有一个锁和mongodb会忘记更新。如果我将upsert更改为简单插入,则不会丢失数据包

我还读到这与没有使用索引有关,我有以下索引:

"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不会更新文件是否正常?

谢谢和问候!

大卫

1 个答案:

答案 0 :(得分:0)

为什么要将所有数据包存储在数组中?通常在这种情况下,最好将每个数据包单独作为文档;如果没有关于你的用例的更多信息(或者更多地了解你正在使用的所有这些首字母缩略词,很难说更多):D)。您的更新将成为插入,您不需要执行更新查询。相反,数据包上的一些其他元数据会将相关数据包连接在一起,因此您可以重建事务或任何您需要做的事情。

更直接地解决您的问题,我会使用数组字段tids来存储[otid, dtid],使用数组字段sccps来存储[sccpCalling, sccpCalled],这将使您的更新查询看起来像

{ "tids" : { "$in" : ["M2PA042e3918"] }, "sccps" : { "$in" : [ "523332075151", "523331466305" ] } }

并且可以使用索引{ "tids" : 1, "sccps" : 1 }