クエリカーソルからBSONドキュメントを蓄積し、後で処理する次のコードフラグメントがあります。
// Accumulate
std::vector<BSONObj> results;
while (cursor->more()) {
BSONObj r = cursor->nextSafe();
results.push_back(r);
}
...
// Process it (example)
for (unsigned int ix = 0; ix < results.size(); ix++) {
BSONElement be = results[ix].getField("_id");
// Do somtething with 'be'
...
}
このコードはしばらくの間(数か月)はうまく機能していましたが、最近、DB内の大きなドキュメント(約results[ix].getField("_id")
1.1MB )で、ステートメントがsegfaultでクラッシュすることがわかりました。これはバックトレースのトップです:
(gdb) bt
#0 readNative<int> (offset=0, t=<synthetic pointer>, this=<optimized out>) at src/mongo/base/data_view.h:46
#1 readNative<int> (offset=0, this=<optimized out>) at src/mongo/base/data_view.h:53
#2 readLE<int> (offset=0, this=<optimized out>) at src/mongo/base/data_view.h:59
#3 objsize (this=0x7f74340022e0) at src/mongo/bson/bsonobj.h:309
#4 BSONObjIterator (jso=..., this=<synthetic pointer>) at src/mongo/bson/bsonobjiterator.h:42
#5 mongo::BSONObj::getField (this=0x7f74340022e0, name=...) at src/mongo/bson/bsonobj.cpp:635
...
のresults.push_back(r.copy())
代わりにを使用して問題を解決しましたresults.push_back(r)
。したがって、おそらくエラーは、r
オブジェクトがwhile
ブロックスコープの最後で破棄され、コピーが不安定な状態でベクターにプッシュバックされたときに発生しました。r
新しい変数としてブロックスコープにヒットせずにのコピーをプッシュバックすると、問題が解決するようです。
だから、私は次の質問があります:
クエリ結果から取得したBSONObjを格納する最良の方法は何std::vector
ですか?私は合理的な解決策を見つけたと思いますが、これが最良の解決策であるかどうかはわかりません。
使用するコードpush_back(r)
が小さなドキュメントで機能するのはなぜですか?ブロックスコープの最後でのr.copy()
破壊の問題を回避するために正しい方法を使用する場合、約1.1MBのオブジェクトの場合だけでなく、常に失敗するはずだと理解しています。r
while
私はMongoDBC ++ドライバーlegacy-1.0.7を使用しています(それが役立つ場合や、問題がMongoDB C ++ドライバーの特定のバージョンに関連している可能性がある場合)。
nextSafeによって返されるBSONObjオブジェクトはデータを所有しておらず、nextSafeへの後続の呼び出しによって無効になります。
したがって、ベクターには無効なBSONObjオブジェクトが入力されます。
代わりに、ベクトルをプッシュバックする前に、カーソル結果に対してBSONObj :: getOwned()を呼び出します。
AddressSanitizerまたはvalgrindでプログラムを実行すると、ほぼ確実に解放後使用タイプのエラーが表示されます。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加