Docs 菜单
Docs 主页
/ / /
C 驱动程序
/ /

游标

在此页面上

  • 处理游标故障
  • 销毁服务器端游标
  • 可追加游标

游标存在于 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_destroy 被调用。使用游标后未能调用此函数将导致客户端内存泄漏,并在服务器端消耗额外的内存。如果将游标配置为永不超时,则会导致服务器上的内存泄漏。

可追加游标是即使在返回最终结果后仍保持打开状态的游标。这样,如果将更多文档添加到集合中(即添加到游标的结果集),则可以继续调用 mongoc_cursor_next 以检索这些其他结果。

下面是一个完整的测试案例,演示了可追加游标的用法。

注意

可追加游标仅适用于固定大小集合。

从副本集中跟踪 oplog 的示例。

mongoc-tail.c
#include <bson/bson.h>
#include <mongoc/mongoc.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
#define sleep(_n) Sleep ((_n) * 1000)
#endif
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", &gt);
BSON_APPEND_TIMESTAMP (&gt, "$gt", last_time, 0);
bson_append_document_end (&query, &gt);
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({})的示例。

提示

另请参阅:

后退

数据压缩

来年

批量写入操作