Cursors
カーソルの障害の処理
カーソルは MongoDB サーバー上に存在します。 ただし、 mongoc_cursor_t
構造はローカル プロセスにカーソルへの処理を提供します。 クライアントでカーソルを反復処理している間に、サーバーでエラーが発生する可能性があります。 ネットワーク パーティションも発生する可能性があります。 つまり、アプリケーションはカーソルの障害を処理する際に堅牢である必要があります。
カーソルを反復処理する間に、エラーが発生したかどうかを確認する必要があります。 エラーを確実にチェックする方法については、次の例を参照してください。
static void print_all_documents (mongoc_collection_t *collection) { mongoc_cursor_t *cursor; const bson_t *doc; bson_error_t error; bson_t query = BSON_INITIALIZER; char *str; cursor = mongoc_collection_find_with_opts (collection, query, NULL, NULL); while (mongoc_cursor_next (cursor, &doc)) { str = bson_as_canonical_extended_json (doc, NULL); printf ("%s\n", str); bson_free (str); } if (mongoc_cursor_error (cursor, &error)) { fprintf (stderr, "Failed to iterate all documents: %s\n", error.message); } mongoc_cursor_destroy (cursor); }
サーバーサイド カーソルの破棄
MongoDB C ドライバーは、 mongoc_cursor_destructor の場合にサーバー側カーソルを自動的に破棄します は呼び出されます。カーソルを使用して実行するときにこの関数を呼び出されない場合、クライアント側でメモリがリークされるだけでなく、サーバー側で余計なメモリが消費されます。 カーソルがタイムアウトしないように設定されている場合、サーバー上のメモリリークになります。
テール可能カーソル
追尾可能 (tailable) カーソルは、最終結果を返した後も開いたままであるカーソルです。 この方法では、コレクション(カーソルの結果セット)にさらにドキュメントが追加された場合でも、引き続き mongoc_cursor_next を呼び出すことができます。 これらの追加の結果を検索するには、を参照してください。
以下は、追尾可能 (tailable) カーソルの使用を示す完全なテストケースです。
注意
追尾可能(tailable)なカーソルは、Cappedコレクションのみに適用されます。
レプリカセットから oplog を追跡する例。
static void print_bson (const bson_t *b) { char *str; str = bson_as_canonical_extended_json (b, NULL); fprintf (stdout, "%s\n", str); bson_free (str); } static mongoc_cursor_t * query_collection (mongoc_collection_t *collection, uint32_t last_time) { mongoc_cursor_t *cursor; bson_t query; bson_t gt; bson_t opts; BSON_ASSERT (collection); bson_init (&query); BSON_APPEND_DOCUMENT_BEGIN (&query, "ts", >); BSON_APPEND_TIMESTAMP (>, "$gt", last_time, 0); bson_append_document_end (&query, >); bson_init (&opts); BSON_APPEND_BOOL (&opts, "tailable", true); BSON_APPEND_BOOL (&opts, "awaitData", true); cursor = mongoc_collection_find_with_opts (collection, &query, &opts, NULL); bson_destroy (&query); bson_destroy (&opts); return cursor; } static void tail_collection (mongoc_collection_t *collection) { mongoc_cursor_t *cursor; uint32_t last_time; const bson_t *doc; bson_error_t error; bson_iter_t iter; BSON_ASSERT (collection); last_time = (uint32_t) time (NULL); while (true) { cursor = query_collection (collection, last_time); while (!mongoc_cursor_error (cursor, &error) && mongoc_cursor_more (cursor)) { if (mongoc_cursor_next (cursor, &doc)) { if (bson_iter_init_find (&iter, doc, "ts") && BSON_ITER_HOLDS_TIMESTAMP (&iter)) { bson_iter_timestamp (&iter, &last_time, NULL); } print_bson (doc); } } if (mongoc_cursor_error (cursor, &error)) { if (error.domain == MONGOC_ERROR_SERVER) { fprintf (stderr, "%s\n", error.message); exit (1); } } mongoc_cursor_destroy (cursor); sleep (1); } } int main (int argc, char *argv[]) { mongoc_collection_t *collection; mongoc_client_t *client; mongoc_uri_t *uri; bson_error_t error; if (argc != 2) { fprintf (stderr, "usage: %s MONGO_URI\n", argv[0]); return EXIT_FAILURE; } mongoc_init (); uri = mongoc_uri_new_with_error (argv[1], &error); if (!uri) { fprintf (stderr, "failed to parse URI: %s\n" "error message: %s\n", argv[1], error.message); return EXIT_FAILURE; } client = mongoc_client_new_from_uri (uri); if (!client) { return EXIT_FAILURE; } mongoc_client_set_error_api (client, 2); collection = mongoc_client_get_collection (client, "local", "oplog.rs"); tail_collection (collection); mongoc_collection_destroy (collection); mongoc_uri_destroy (uri); mongoc_client_destroy (client); return EXIT_SUCCESS; }
この例をコンパイルしてレプリカセットに対して実行し、アップデートが行われる際に確認しましょう。
$ gcc -Wall -o mongoc-tail mongoc-tail.c $(pkg-config --cflags --libs libmongoc-1.0) $ ./mongoc-tail mongodb://example.com/?replicaSet=myReplSet { "h" : -8458503739429355503, "ns" : "test.test", "o" : { "_id" : { "$oid" : "5372ab0a25164be923d10d50" } }, "op" : "i", "ts" : { "$timestamp" : { "i" : 1, "t" : 1400023818 } }, "v" : 2 }
出力の行は、レプリカセットで mongo shell からdb.test.insert({})
を実行する場合のサンプルです。