Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
315 KB
Referenced Files
None
Subscribers
None
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/debian/patches/0001-Try-linking-with-public-libmongoc-1.0-library-and-sl.patch b/debian/patches/0001-Try-linking-with-public-libmongoc-1.0-library-and-sl.patch
index 4ae7cdf8..b44b0620 100644
--- a/debian/patches/0001-Try-linking-with-public-libmongoc-1.0-library-and-sl.patch
+++ b/debian/patches/0001-Try-linking-with-public-libmongoc-1.0-library-and-sl.patch
@@ -1,9281 +1,9353 @@
From: =?utf-8?q?Ond=C5=99ej_Sur=C3=BD?= <ondrej@sury.org>
Date: Mon, 18 Jan 2016 11:52:58 +0100
Subject: Try linking with public libmongoc-1.0 library and slowly resolve the
internal dependencies
---
- mongodb-1.1.2/config.m4 | 25 +-
+ mongodb-1.1.4/config.m4 | 25 +-
.../src/mongoc/mongoc-array-private.h | 60 +
.../src/mongoc/mongoc-async-cmd-private.h | 103 ++
.../src/mongoc/mongoc-async-private.h | 83 ++
.../src/mongoc/mongoc-buffer-private.h | 85 ++
.../src/mongoc/mongoc-bulk-operation-private.h | 55 +
.../src/mongoc/mongoc-client-private.h | 137 ++
- .../src/mongoc/mongoc-cluster-private.h | 150 ++
+ .../src/mongoc/mongoc-cluster-private.h | 152 ++
.../src/mongoc/mongoc-cursor-cursorid-private.h | 51 +
.../src/mongoc/mongoc-cursor-cursorid.c | 300 ++++
.../src/mongoc/mongoc-cursor-private.h | 132 ++
.../src/mongoc/mongoc-host-list-private.h | 41 +
.../src/mongoc/mongoc-list-private.h | 55 +
.../libmongoc-priv/src/mongoc/mongoc-log-private.h | 50 +
.../src/libmongoc-priv/src/mongoc/mongoc-log.c | 327 ++++
.../src/mongoc/mongoc-read-concern-private.h | 44 +
.../src/mongoc/mongoc-read-prefs-private.h | 61 +
.../libmongoc-priv/src/mongoc/mongoc-rpc-private.h | 117 ++
- .../src/mongoc/mongoc-server-description-private.h | 114 ++
+ .../src/mongoc/mongoc-server-description-private.h | 124 ++
.../src/mongoc/mongoc-server-stream-private.h | 62 +
.../libmongoc-priv/src/mongoc/mongoc-set-private.h | 101 ++
.../src/libmongoc-priv/src/mongoc/mongoc-set.c | 217 +++
.../src/mongoc/mongoc-thread-private.h | 126 ++
- .../mongoc/mongoc-topology-description-private.h | 97 ++
- .../src/mongoc/mongoc-topology-description.c | 1351 +++++++++++++++++
+ .../mongoc/mongoc-topology-description-private.h | 98 ++
+ .../src/mongoc/mongoc-topology-description.c | 1402 ++++++++++++++++++
.../src/mongoc/mongoc-topology-private.h | 102 ++
.../src/mongoc/mongoc-topology-scanner-private.h | 152 ++
.../libmongoc-priv/src/mongoc/mongoc-topology.c | 915 ++++++++++++
.../libmongoc-priv/src/mongoc/mongoc-uri-private.h | 87 ++
.../src/libmongoc-priv/src/mongoc/mongoc-uri.c | 1559 ++++++++++++++++++++
.../src/mongoc/mongoc-util-private.h | 56 +
.../src/mongoc/mongoc-write-command-private.h | 147 ++
- .../src/mongoc/mongoc-write-command.c | 1519 +++++++++++++++++++
+ .../src/mongoc/mongoc-write-command.c | 1527 +++++++++++++++++++
.../src/mongoc/mongoc-write-concern-private.h | 55 +
.../src/mongoc/mongoc-write-concern.c | 436 ++++++
- 35 files changed, 8967 insertions(+), 5 deletions(-)
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-array-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-async-cmd-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-async-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-buffer-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-bulk-operation-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-client-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-cluster-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-cursor-cursorid-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-cursor-cursorid.c
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-cursor-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-host-list-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-list-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-log-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-log.c
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-read-concern-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-read-prefs-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-rpc-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-server-description-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-server-stream-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-set-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-set.c
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-thread-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology-description-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology-description.c
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology-scanner-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology.c
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-uri-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-uri.c
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-util-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-write-command-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-write-command.c
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-write-concern-private.h
- create mode 100644 mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-write-concern.c
+ 35 files changed, 9039 insertions(+), 5 deletions(-)
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-array-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-async-cmd-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-async-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-buffer-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-bulk-operation-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-client-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-cluster-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-cursor-cursorid-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-cursor-cursorid.c
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-cursor-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-host-list-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-list-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-log-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-log.c
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-read-concern-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-read-prefs-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-rpc-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-server-description-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-server-stream-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-set-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-set.c
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-thread-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-topology-description-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-topology-description.c
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-topology-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-topology-scanner-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-topology.c
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-uri-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-uri.c
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-util-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-write-command-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-write-command.c
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-write-concern-private.h
+ create mode 100644 mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-write-concern.c
-diff --git a/mongodb-1.1.2/config.m4 b/mongodb-1.1.2/config.m4
-index 4d03388..b99fbdd 100644
---- a/mongodb-1.1.2/config.m4
-+++ b/mongodb-1.1.2/config.m4
+diff --git a/mongodb-1.1.4/config.m4 b/mongodb-1.1.4/config.m4
+index 52e84c0..ac1d664 100644
+--- a/mongodb-1.1.4/config.m4
++++ b/mongodb-1.1.4/config.m4
@@ -287,6 +287,17 @@ MONGOC_SOURCES_SSL="\
MONGOC_SOURCES_SASL=mongoc-sasl.c
+MONGOC_PRIV_SOURCES="\
+ mongoc-topology.c \
+ mongoc-topology-description.c \
+ mongoc-set.c \
+ mongoc-write-concern.c \
+ mongoc-write-command.c \
+ mongoc-cursor-cursorid.c \
+ mongoc-uri.c \
+ mongoc-log.c \
+ ";
+
if test "$ext_shared" = "no"; then
PHP_ADD_SOURCES(PHP_EXT_DIR(mongodb), $MONGODB_BSON)
PHP_ADD_SOURCES(PHP_EXT_DIR(mongodb), $MONGODB_BSON_CLASSES)
@@ -339,14 +350,15 @@ PHP_ARG_WITH(libmongoc, whether to use system libmongoc,
if test "$PHP_LIBMONGOC" != "no"; then
AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
AC_MSG_CHECKING(for libmongoc)
- if test -x "$PKG_CONFIG" && $PKG_CONFIG --exists libmongoc-1.0 && $PKG_CONFIG --exists libmongoc-priv; then
+ if test -x "$PKG_CONFIG" && $PKG_CONFIG --exists libmongoc-1.0; then
- if $PKG_CONFIG libmongoc-1.0 --atleast-version 1.3.0; then
+ if $PKG_CONFIG libmongoc-1.0 --atleast-version 1.3.3; then
- LIBMONGOC_INC=`$PKG_CONFIG libmongoc-priv --cflags`
- LIBMONGOC_LIB=`$PKG_CONFIG libmongoc-priv --libs`
- LIBMONGOC_VER=`$PKG_CONFIG libmongoc-priv --modversion`
+ LIBMONGOC_INC=`$PKG_CONFIG libmongoc-1.0 --cflags`
+ LIBMONGOC_LIB=`$PKG_CONFIG libmongoc-1.0 --libs`
+ LIBMONGOC_VER=`$PKG_CONFIG libmongoc-1.0 --modversion`
AC_MSG_RESULT(version $LIBMONGOC_VER found)
CFLAGS="$CFLAGS -DMONGOC_I_AM_A_DRIVER"
-
+ PHP_ADD_SOURCES_X(PHP_EXT_DIR(mongodb)[src/libmongoc-priv/src/mongoc], $MONGOC_PRIV_SOURCES, [$STD_CFLAGS], shared_objects_mongodb, yes)
+ CPPFLAGS="$CPPFLAGS -DMONGOC_COMPILATION -DMONGOC_TRACE"
else
- AC_MSG_ERROR(system libmongoc must be upgraded to version >= 1.3.0)
+ AC_MSG_ERROR(system libmongoc must be upgraded to version >= 1.3.3)
fi
@@ -472,6 +484,9 @@ dnl }}}
if test "$PHP_LIBMONGOC" == "no"; then
PHP_ADD_INCLUDE([$ext_srcdir/src/libmongoc/src/mongoc/])
PHP_ADD_BUILD_DIR([$ext_builddir/src/libmongoc/src/mongoc/])
+ else
+ PHP_ADD_INCLUDE([$ext_srcdir/src/libmongoc-priv/src/mongoc/])
+ PHP_ADD_BUILD_DIR([$ext_builddir/src/libmongoc-priv/src/mongoc/])
fi
if test "$PHP_LIBBSON" == "no"; then
m4_include(src/libbson/build/autotools/CheckAtomics.m4)
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-array-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-array-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-array-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-array-private.h
new file mode 100644
index 0000000..5674a0b
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-array-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-array-private.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2013 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_ARRAY_PRIVATE_H
+#define MONGOC_ARRAY_PRIVATE_H
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include <bson.h>
+
+
+BSON_BEGIN_DECLS
+
+
+typedef struct _mongoc_array_t mongoc_array_t;
+
+
+struct _mongoc_array_t
+{
+ size_t len;
+ size_t element_size;
+ size_t allocated;
+ void *data;
+};
+
+
+#define _mongoc_array_append_val(a, v) _mongoc_array_append_vals(a, &v, 1)
+#define _mongoc_array_index(a, t, i) (((t*)(a)->data)[i])
+#define _mongoc_array_clear(a) (a)->len = 0
+
+
+void _mongoc_array_init (mongoc_array_t *array,
+ size_t element_size);
+void _mongoc_array_copy (mongoc_array_t *dst,
+ const mongoc_array_t *src);
+void _mongoc_array_append_vals (mongoc_array_t *array,
+ const void *data,
+ uint32_t n_elements);
+void _mongoc_array_destroy (mongoc_array_t *array);
+
+
+BSON_END_DECLS
+
+
+#endif /* MONGOC_ARRAY_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-async-cmd-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-async-cmd-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-async-cmd-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-async-cmd-private.h
new file mode 100644
index 0000000..30a82f2
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-async-cmd-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-async-cmd-private.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2014 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_ASYNC_CMD_PRIVATE_H
+#define MONGOC_ASYNC_CMD_PRIVATE_H
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include <bson.h>
+
+#include "mongoc-client.h"
+#include "mongoc-async-private.h"
+#include "mongoc-array-private.h"
+#include "mongoc-buffer-private.h"
+#include "mongoc-rpc-private.h"
+#include "mongoc-stream.h"
+
+BSON_BEGIN_DECLS
+
+typedef enum
+{
+ MONGOC_ASYNC_CMD_SETUP,
+ MONGOC_ASYNC_CMD_SEND,
+ MONGOC_ASYNC_CMD_RECV_LEN,
+ MONGOC_ASYNC_CMD_RECV_RPC,
+ MONGOC_ASYNC_CMD_ERROR_STATE,
+ MONGOC_ASYNC_CMD_CANCELED_STATE,
+} mongoc_async_cmd_state_t;
+
+typedef struct _mongoc_async_cmd
+{
+ mongoc_stream_t *stream;
+
+ mongoc_async_t *async;
+ mongoc_async_cmd_state_t state;
+ int events;
+ mongoc_async_cmd_setup_t setup;
+ void *setup_ctx;
+ mongoc_async_cmd_cb_t cb;
+ void *data;
+ bson_error_t error;
+ int64_t start_time;
+ int64_t expire_at;
+ bson_t cmd;
+ mongoc_buffer_t buffer;
+ mongoc_array_t array;
+ mongoc_iovec_t *iovec;
+ size_t niovec;
+ size_t bytes_to_read;
+ mongoc_rpc_t rpc;
+ bson_t reply;
+ bool reply_needs_cleanup;
+ char ns[MONGOC_NAMESPACE_MAX];
+
+ struct _mongoc_async_cmd *next;
+ struct _mongoc_async_cmd *prev;
+} mongoc_async_cmd_t;
+
+mongoc_async_cmd_t *
+mongoc_async_cmd_new (mongoc_async_t *async,
+ mongoc_stream_t *stream,
+ mongoc_async_cmd_setup_t setup,
+ void *setup_ctx,
+ const char *dbname,
+ const bson_t *cmd,
+ mongoc_async_cmd_cb_t cb,
+ void *cb_data,
+ int32_t timeout_msec);
+
+void
+mongoc_async_cmd_destroy (mongoc_async_cmd_t *acmd);
+
+bool
+mongoc_async_cmd_run (mongoc_async_cmd_t *acmd);
+
+#ifdef MONGOC_ENABLE_SSL
+int
+mongoc_async_cmd_tls_setup (mongoc_stream_t *stream,
+ int *events,
+ void *ctx,
+ int32_t timeout_msec,
+ bson_error_t *error);
+#endif
+
+BSON_END_DECLS
+
+
+#endif /* MONGOC_ASYNC_CMD_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-async-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-async-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-async-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-async-private.h
new file mode 100644
index 0000000..663f819
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-async-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-async-private.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2014 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_ASYNC_PRIVATE_H
+#define MONGOC_ASYNC_PRIVATE_H
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include <bson.h>
+#include "mongoc-stream.h"
+
+BSON_BEGIN_DECLS
+
+struct _mongoc_async_cmd;
+
+typedef struct _mongoc_async
+{
+ struct _mongoc_async_cmd *cmds;
+ size_t ncmds;
+ uint32_t request_id;
+} mongoc_async_t;
+
+typedef enum
+{
+ MONGOC_ASYNC_CMD_IN_PROGRESS,
+ MONGOC_ASYNC_CMD_SUCCESS,
+ MONGOC_ASYNC_CMD_ERROR,
+ MONGOC_ASYNC_CMD_TIMEOUT,
+} mongoc_async_cmd_result_t;
+
+typedef void (*mongoc_async_cmd_cb_t)(mongoc_async_cmd_result_t result,
+ const bson_t *bson,
+ int64_t rtt_msec,
+ void *data,
+ bson_error_t *error);
+
+typedef int
+(*mongoc_async_cmd_setup_t)(mongoc_stream_t *stream,
+ int *events,
+ void *ctx,
+ int32_t timeout_msec,
+ bson_error_t *error);
+
+
+mongoc_async_t *
+mongoc_async_new ();
+
+void
+mongoc_async_destroy (mongoc_async_t *async);
+
+bool
+mongoc_async_run (mongoc_async_t *async,
+ int32_t timeout_msec);
+
+struct _mongoc_async_cmd *
+mongoc_async_cmd (mongoc_async_t *async,
+ mongoc_stream_t *stream,
+ mongoc_async_cmd_setup_t setup,
+ void *setup_ctx,
+ const char *dbname,
+ const bson_t *cmd,
+ mongoc_async_cmd_cb_t cb,
+ void *cb_data,
+ int32_t timeout_msec);
+
+BSON_END_DECLS
+
+#endif /* MONGOC_ASYNC_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-buffer-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-buffer-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-buffer-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-buffer-private.h
new file mode 100644
index 0000000..b42eb7d
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-buffer-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-buffer-private.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2013 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_BUFFER_PRIVATE_H
+#define MONGOC_BUFFER_PRIVATE_H
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include <bson.h>
+
+#include "mongoc-stream.h"
+
+
+BSON_BEGIN_DECLS
+
+
+typedef struct _mongoc_buffer_t mongoc_buffer_t;
+
+
+struct _mongoc_buffer_t
+{
+ uint8_t *data;
+ size_t datalen;
+ off_t off;
+ size_t len;
+ bson_realloc_func realloc_func;
+ void *realloc_data;
+};
+
+
+void
+_mongoc_buffer_init (mongoc_buffer_t *buffer,
+ uint8_t *buf,
+ size_t buflen,
+ bson_realloc_func realloc_func,
+ void *realloc_data);
+
+bool
+_mongoc_buffer_append_from_stream (mongoc_buffer_t *buffer,
+ mongoc_stream_t *stream,
+ size_t size,
+ int32_t timeout_msec,
+ bson_error_t *error);
+
+ssize_t
+_mongoc_buffer_try_append_from_stream (mongoc_buffer_t *buffer,
+ mongoc_stream_t *stream,
+ size_t size,
+ int32_t timeout_msec,
+ bson_error_t *error);
+
+ssize_t
+_mongoc_buffer_fill (mongoc_buffer_t *buffer,
+ mongoc_stream_t *stream,
+ size_t min_bytes,
+ int32_t timeout_msec,
+ bson_error_t *error);
+
+void
+_mongoc_buffer_destroy (mongoc_buffer_t *buffer);
+
+void
+_mongoc_buffer_clear (mongoc_buffer_t *buffer,
+ bool zero);
+
+
+BSON_END_DECLS
+
+
+#endif /* MONGOC_BUFFER_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-bulk-operation-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-bulk-operation-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-bulk-operation-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-bulk-operation-private.h
new file mode 100644
index 0000000..0b9b890
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-bulk-operation-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-bulk-operation-private.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2014 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_BULK_OPERATION_PRIVATE_H
+#define MONGOC_BULK_OPERATION_PRIVATE_H
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include "mongoc-array-private.h"
+#include "mongoc-client.h"
+#include "mongoc-write-command-private.h"
+
+
+BSON_BEGIN_DECLS
+
+struct _mongoc_bulk_operation_t
+{
+ char *database;
+ char *collection;
+ mongoc_client_t *client;
+ mongoc_write_concern_t *write_concern;
+ mongoc_bulk_write_flags_t flags;
+ uint32_t hint;
+ mongoc_array_t commands;
+ mongoc_write_result_t result;
+ bool executed;
+};
+
+
+mongoc_bulk_operation_t *_mongoc_bulk_operation_new (mongoc_client_t *client,
+ const char *database,
+ const char *collection,
+ mongoc_bulk_write_flags_t flags,
+ const mongoc_write_concern_t *write_concern);
+
+
+BSON_END_DECLS
+
+
+#endif /* MONGOC_BULK_OPERATION_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-client-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-client-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-client-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-client-private.h
new file mode 100644
index 0000000..88e8b68
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-client-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-client-private.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2013 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_CLIENT_PRIVATE_H
+#define MONGOC_CLIENT_PRIVATE_H
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include <bson.h>
+
+#include "mongoc-buffer-private.h"
+#include "mongoc-client.h"
+#include "mongoc-cluster-private.h"
+#include "mongoc-config.h"
+#include "mongoc-host-list.h"
+#include "mongoc-read-prefs.h"
+#include "mongoc-rpc-private.h"
+#include "mongoc-opcode.h"
+#ifdef MONGOC_ENABLE_SSL
+#include "mongoc-ssl.h"
+#endif
+#include "mongoc-stream.h"
+#include "mongoc-topology-private.h"
+#include "mongoc-write-concern.h"
+
+
+BSON_BEGIN_DECLS
+
+/* protocol versions this driver can speak */
+#define WIRE_VERSION_MIN 0
+#define WIRE_VERSION_MAX 4
+
+/* first version that supported aggregation cursors */
+#define WIRE_VERSION_AGG_CURSOR 1
+/* first version that supported "insert", "update", "delete" commands */
+#define WIRE_VERSION_WRITE_CMD 2
+/* first version when SCRAM-SHA-1 replaced MONGODB-CR as default auth mech */
+#define WIRE_VERSION_SCRAM_DEFAULT 3
+/* first version that supported "find" and "getMore" commands */
+#define WIRE_VERSION_FIND_CMD 4
+/* first version with "killCursors" command */
+#define WIRE_VERSION_KILLCURSORS_CMD 4
+/* first version when findAndModify accepts writeConcern */
+#define WIRE_VERSION_FAM_WRITE_CONCERN 4
+/* first version to support readConcern */
+#define WIRE_VERSION_READ_CONCERN 4
+
+
+struct _mongoc_client_t
+{
+ uint32_t request_id;
+ mongoc_list_t *conns;
+ mongoc_uri_t *uri;
+ mongoc_cluster_t cluster;
+ bool in_exhaust;
+
+ mongoc_stream_initiator_t initiator;
+ void *initiator_data;
+
+#ifdef MONGOC_ENABLE_SSL
+ bool use_ssl;
+ mongoc_ssl_opt_t ssl_opts;
+ char *pem_subject;
+#endif
+
+ mongoc_topology_t *topology;
+
+ mongoc_read_prefs_t *read_prefs;
+ mongoc_read_concern_t *read_concern;
+ mongoc_write_concern_t *write_concern;
+};
+
+
+mongoc_client_t *
+_mongoc_client_new_from_uri (const mongoc_uri_t *uri,
+ mongoc_topology_t *topology);
+
+mongoc_stream_t *
+mongoc_client_default_stream_initiator (const mongoc_uri_t *uri,
+ const mongoc_host_list_t *host,
+ void *user_data,
+ bson_error_t *error);
+
+mongoc_stream_t *
+_mongoc_client_create_stream (mongoc_client_t *client,
+ const mongoc_host_list_t *host,
+ bson_error_t *error);
+
+bool
+_mongoc_client_recv (mongoc_client_t *client,
+ mongoc_rpc_t *rpc,
+ mongoc_buffer_t *buffer,
+ mongoc_server_stream_t *server_stream,
+ bson_error_t *error);
+
+bool
+_mongoc_client_recv_gle (mongoc_client_t *client,
+ mongoc_server_stream_t *server_stream,
+ bson_t **gle_doc,
+ bson_error_t *error);
+
+void
+_mongoc_topology_background_thread_start (mongoc_topology_t *topology);
+
+void
+_mongoc_topology_background_thread_stop (mongoc_topology_t *topology);
+
+mongoc_server_description_t *
+_mongoc_client_get_server_description (mongoc_client_t *client,
+ uint32_t server_id);
+
+void
+_mongoc_client_kill_cursor (mongoc_client_t *client,
+ uint32_t server_id,
+ int64_t cursor_id,
+ const char *db,
+ const char *collection);
+
+BSON_END_DECLS
+
+
+#endif /* MONGOC_CLIENT_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-cluster-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-cluster-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-cluster-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-cluster-private.h
new file mode 100644
-index 0000000..72c625e
+index 0000000..b9ae36b
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-cluster-private.h
-@@ -0,0 +1,150 @@
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-cluster-private.h
+@@ -0,0 +1,152 @@
+/*
+ * Copyright 2013 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_CLUSTER_PRIVATE_H
+#define MONGOC_CLUSTER_PRIVATE_H
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include <bson.h>
+
+#include "mongoc-array-private.h"
+#include "mongoc-buffer-private.h"
+#include "mongoc-config.h"
+#include "mongoc-client.h"
+#include "mongoc-list-private.h"
+#include "mongoc-opcode.h"
+#include "mongoc-read-prefs.h"
+#include "mongoc-rpc-private.h"
+#include "mongoc-server-stream-private.h"
+#include "mongoc-set-private.h"
+#include "mongoc-stream.h"
+#include "mongoc-topology-description-private.h"
+#include "mongoc-uri.h"
+#include "mongoc-write-concern.h"
+
+
+BSON_BEGIN_DECLS
+
+
+typedef struct _mongoc_cluster_node_t
+{
+ mongoc_stream_t *stream;
+
+ int32_t max_wire_version;
+ int32_t min_wire_version;
+ int32_t max_write_batch_size;
+ int32_t max_bson_obj_size;
+ int32_t max_msg_size;
+
+ int64_t timestamp;
+} mongoc_cluster_node_t;
+
+typedef struct _mongoc_cluster_t
+{
+ uint32_t request_id;
+ uint32_t sockettimeoutms;
+ uint32_t socketcheckintervalms;
+ mongoc_uri_t *uri;
+ unsigned requires_auth : 1;
+
+ mongoc_client_t *client;
+
+ mongoc_set_t *nodes;
+ mongoc_array_t iov;
+} mongoc_cluster_t;
+
+void
+mongoc_cluster_init (mongoc_cluster_t *cluster,
+ const mongoc_uri_t *uri,
+ void *client);
+
+void
+mongoc_cluster_destroy (mongoc_cluster_t *cluster);
+
+void
+mongoc_cluster_disconnect_node (mongoc_cluster_t *cluster,
+ uint32_t id);
+
+int32_t
+mongoc_cluster_get_max_bson_obj_size (mongoc_cluster_t *cluster);
+
+int32_t
+mongoc_cluster_get_max_msg_size (mongoc_cluster_t *cluster);
+
+int32_t
+mongoc_cluster_node_max_wire_version (mongoc_cluster_t *cluster,
+ uint32_t server_id);
+
+int32_t
+mongoc_cluster_node_min_wire_version (mongoc_cluster_t *cluster,
+ uint32_t server_id);
+
+bool
+mongoc_cluster_sendv_to_server (mongoc_cluster_t *cluster,
+ mongoc_rpc_t *rpcs,
+ size_t rpcs_len,
+ mongoc_server_stream_t *server_stream,
+ const mongoc_write_concern_t *write_concern,
+ bson_error_t *error);
+
+bool
+mongoc_cluster_try_recv (mongoc_cluster_t *cluster,
+ mongoc_rpc_t *rpc,
+ mongoc_buffer_t *buffer,
+ mongoc_server_stream_t *server_stream,
+ bson_error_t *error);
+
+mongoc_server_stream_t *
+mongoc_cluster_stream_for_reads (mongoc_cluster_t *cluster,
+ const mongoc_read_prefs_t *read_prefs,
+ bson_error_t *error);
+
+mongoc_server_stream_t *
+mongoc_cluster_stream_for_writes (mongoc_cluster_t *cluster,
+ bson_error_t *error);
+
+mongoc_server_stream_t *
+mongoc_cluster_stream_for_server (mongoc_cluster_t *cluster,
+ uint32_t server_id,
+ bool reconnect_ok,
+ bson_error_t *error);
+
+bool
+mongoc_cluster_run_command_rpc (mongoc_cluster_t *cluster,
+ mongoc_stream_t *stream,
++ uint32_t server_id,
+ const char *command_name,
+ mongoc_rpc_t *rpc,
+ mongoc_rpc_t *reply_rpc,
+ mongoc_buffer_t *buffer,
+ bson_error_t *error);
+
+bool
+mongoc_cluster_run_command (mongoc_cluster_t *cluster,
+ mongoc_stream_t *stream,
++ uint32_t server_id,
+ mongoc_query_flags_t flags,
+ const char *db_name,
+ const bson_t *command,
+ bson_t *reply,
+ bson_error_t *error);
+
+
+BSON_END_DECLS
+
+
+#endif /* MONGOC_CLUSTER_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-cursor-cursorid-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-cursor-cursorid-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-cursor-cursorid-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-cursor-cursorid-private.h
new file mode 100644
index 0000000..9147822
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-cursor-cursorid-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-cursor-cursorid-private.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2013 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_CURSOR_CURSORID_PRIVATE_H
+#define MONGOC_CURSOR_CURSORID_PRIVATE_H
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include <bson.h>
+
+#include "mongoc-cursor-private.h"
+
+
+BSON_BEGIN_DECLS
+
+
+typedef struct
+{
+ bool in_batch;
+ bool in_reader;
+ bson_iter_t batch_iter;
+ bson_t current_doc;
+} mongoc_cursor_cursorid_t;
+
+
+bool _mongoc_cursor_cursorid_prime (mongoc_cursor_t *cursor);
+bool _mongoc_cursor_cursorid_next (mongoc_cursor_t *cursor,
+ const bson_t **bson);
+void _mongoc_cursor_cursorid_init (mongoc_cursor_t *cursor,
+ const bson_t *command);
+
+
+BSON_END_DECLS
+
+
+#endif /* MONGOC_CURSOR_CURSORID_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-cursor-cursorid.c b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-cursor-cursorid.c
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-cursor-cursorid.c b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-cursor-cursorid.c
new file mode 100644
index 0000000..4d93164
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-cursor-cursorid.c
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-cursor-cursorid.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2013 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "mongoc-cursor.h"
+#include "mongoc-cursor-private.h"
+#include "mongoc-cursor-cursorid-private.h"
+#include "mongoc-log.h"
+#include "mongoc-trace.h"
+#include "mongoc-error.h"
+#include "mongoc-util-private.h"
+
+
+#undef MONGOC_LOG_DOMAIN
+#define MONGOC_LOG_DOMAIN "cursor-cursorid"
+
+
+static void *
+_mongoc_cursor_cursorid_new (void)
+{
+ mongoc_cursor_cursorid_t *cid;
+
+ ENTRY;
+
+ cid = (mongoc_cursor_cursorid_t *)bson_malloc0 (sizeof *cid);
+
+ RETURN (cid);
+}
+
+
+static void
+_mongoc_cursor_cursorid_destroy (mongoc_cursor_t *cursor)
+{
+ ENTRY;
+
+ bson_free (cursor->iface_data);
+ _mongoc_cursor_destroy (cursor);
+
+ EXIT;
+}
+
+
+static bool
+_mongoc_cursor_cursorid_refresh_from_command (mongoc_cursor_t *cursor,
+ const bson_t *command)
+{
+ mongoc_cursor_cursorid_t *cid;
+ const bson_t *bson;
+ bson_iter_t iter, child;
+ const char *ns;
+
+ ENTRY;
+
+ cid = (mongoc_cursor_cursorid_t *)cursor->iface_data;
+ BSON_ASSERT (cid);
+
+ /* server replies to find / aggregate with {cursor: {id: N, firstBatch: []}},
+ * to getMore command with {cursor: {id: N, nextBatch: []}}. */
+ if (_mongoc_cursor_run_command (cursor, command) &&
+ _mongoc_read_from_buffer (cursor, &bson) &&
+ bson_iter_init_find (&iter, bson, "cursor") &&
+ BSON_ITER_HOLDS_DOCUMENT (&iter) &&
+ bson_iter_recurse (&iter, &child)) {
+
+ while (bson_iter_next (&child)) {
+ if (BSON_ITER_IS_KEY (&child, "id")) {
+ cursor->rpc.reply.cursor_id = bson_iter_as_int64 (&child);
+ } else if (BSON_ITER_IS_KEY (&child, "ns")) {
+ ns = bson_iter_utf8 (&child, &cursor->nslen);
+ bson_strncpy (cursor->ns, ns, sizeof cursor->ns);
+ } else if (BSON_ITER_IS_KEY (&child, "firstBatch") ||
+ BSON_ITER_IS_KEY (&child, "nextBatch")) {
+ if (BSON_ITER_HOLDS_ARRAY (&child) &&
+ bson_iter_recurse (&child, &cid->batch_iter)) {
+ cid->in_batch = true;
+ }
+ }
+ }
+
+ RETURN (true);
+ } else {
+ if (!cursor->error.domain) {
+ bson_set_error (&cursor->error,
+ MONGOC_ERROR_PROTOCOL,
+ MONGOC_ERROR_PROTOCOL_INVALID_REPLY,
+ "Invalid reply to %s command.",
+ _mongoc_get_command_name (command));
+ }
+
+ RETURN (false);
+ }
+}
+
+
+static void
+_mongoc_cursor_cursorid_read_from_batch (mongoc_cursor_t *cursor,
+ const bson_t **bson)
+{
+ mongoc_cursor_cursorid_t *cid;
+ const uint8_t *data = NULL;
+ uint32_t data_len = 0;
+
+ ENTRY;
+
+ cid = (mongoc_cursor_cursorid_t *)cursor->iface_data;
+ BSON_ASSERT (cid);
+
+ if (bson_iter_next (&cid->batch_iter) &&
+ BSON_ITER_HOLDS_DOCUMENT (&cid->batch_iter)) {
+ bson_iter_document (&cid->batch_iter, &data_len, &data);
+
+ if (bson_init_static (&cid->current_doc, data, data_len)) {
+ *bson = &cid->current_doc;
+ }
+ }
+}
+
+
+bool
+_mongoc_cursor_cursorid_prime (mongoc_cursor_t *cursor)
+{
+ cursor->sent = true;
+ return _mongoc_cursor_cursorid_refresh_from_command (cursor, &cursor->query);
+}
+
+
+static void
+_mongoc_cursor_prepare_getmore_command (mongoc_cursor_t *cursor,
+ bson_t *command)
+{
+ const char *collection;
+ int collection_len;
+ mongoc_cursor_cursorid_t *cid;
+
+ cid = (mongoc_cursor_cursorid_t *)cursor->iface_data;
+ BSON_ASSERT (cid);
+
+ _mongoc_cursor_collection (cursor, &collection, &collection_len);
+
+ bson_init (command);
+ bson_append_int64 (command, "getMore", 7, mongoc_cursor_get_id (cursor));
+ bson_append_utf8 (command, "collection", 10, collection, collection_len);
+
+ if (cursor->batch_size) {
+ bson_append_int32 (command, "batchSize", 9, cursor->batch_size);
+ }
+
+ /* Find, getMore And killCursors Commands Spec: "In the case of a tailable
+ cursor with awaitData == true the driver MUST provide a Cursor level
+ option named maxAwaitTimeMS (See CRUD specification for details). The
+ maxTimeMS option on the getMore command MUST be set to the value of the
+ option maxAwaitTimeMS. If no maxAwaitTimeMS is specified, the driver
+ SHOULD not set maxTimeMS on the getMore command."
+ */
+ if (cursor->flags & MONGOC_QUERY_TAILABLE_CURSOR &&
+ cursor->flags & MONGOC_QUERY_AWAIT_DATA &&
+ cursor->max_await_time_ms) {
+ bson_append_int32 (command, "maxTimeMS", 9, cursor->max_await_time_ms);
+ }
+}
+
+
+static bool
+_mongoc_cursor_cursorid_get_more (mongoc_cursor_t *cursor)
+{
+ mongoc_cursor_cursorid_t *cid;
+ mongoc_server_stream_t *server_stream;
+ bson_t command;
+ bool ret;
+
+ ENTRY;
+
+ cid = (mongoc_cursor_cursorid_t *)cursor->iface_data;
+ BSON_ASSERT (cid);
+
+ server_stream = _mongoc_cursor_fetch_stream (cursor);
+
+ if (!server_stream) {
+ RETURN (false);
+ }
+
+ if (_use_find_command (cursor, server_stream)) {
+ _mongoc_cursor_prepare_getmore_command (cursor, &command);
+ ret = _mongoc_cursor_cursorid_refresh_from_command (cursor, &command);
+ bson_destroy (&command);
+ } else {
+ ret = _mongoc_cursor_op_getmore (cursor, server_stream);
+ cid->in_reader = ret;
+ }
+
+ mongoc_server_stream_cleanup (server_stream);
+ RETURN (ret);
+}
+
+
+bool
+_mongoc_cursor_cursorid_next (mongoc_cursor_t *cursor,
+ const bson_t **bson)
+{
+ mongoc_cursor_cursorid_t *cid;
+ bool refreshed = false;
+
+ ENTRY;
+
+ *bson = NULL;
+
+ cid = (mongoc_cursor_cursorid_t *)cursor->iface_data;
+ BSON_ASSERT (cid);
+
+ if (!cursor->sent) {
+ if (!_mongoc_cursor_cursorid_prime (cursor)) {
+ GOTO (done);
+ }
+ }
+
+again:
+
+ if (cid->in_batch) {
+ _mongoc_cursor_cursorid_read_from_batch (cursor, bson);
+
+ if (*bson) {
+ GOTO (done);
+ }
+
+ cid->in_batch = false;
+ } else if (cid->in_reader) {
+ _mongoc_read_from_buffer (cursor, bson);
+
+ if (*bson) {
+ GOTO (done);
+ }
+
+ cid->in_reader = false;
+ }
+
+ if (!refreshed && mongoc_cursor_get_id (cursor)) {
+ if (!_mongoc_cursor_cursorid_get_more (cursor)) {
+ GOTO (done);
+ }
+
+ refreshed = true;
+ GOTO (again);
+ }
+
+done:
+ RETURN (*bson ? true : false);
+}
+
+
+static mongoc_cursor_t *
+_mongoc_cursor_cursorid_clone (const mongoc_cursor_t *cursor)
+{
+ mongoc_cursor_t *clone_;
+
+ ENTRY;
+
+ clone_ = _mongoc_cursor_clone (cursor);
+ _mongoc_cursor_cursorid_init (clone_, &cursor->query);
+
+ RETURN (clone_);
+}
+
+
+static mongoc_cursor_interface_t gMongocCursorCursorid = {
+ _mongoc_cursor_cursorid_clone,
+ _mongoc_cursor_cursorid_destroy,
+ NULL,
+ _mongoc_cursor_cursorid_next,
+};
+
+
+void
+_mongoc_cursor_cursorid_init (mongoc_cursor_t *cursor,
+ const bson_t *command)
+{
+ ENTRY;
+
+ bson_destroy (&cursor->query);
+ bson_copy_to (command, &cursor->query);
+
+ cursor->iface_data = _mongoc_cursor_cursorid_new ();
+
+ memcpy (&cursor->iface, &gMongocCursorCursorid,
+ sizeof (mongoc_cursor_interface_t));
+
+ EXIT;
+}
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-cursor-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-cursor-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-cursor-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-cursor-private.h
new file mode 100644
-index 0000000..d789780
+index 0000000..8c7e38c
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-cursor-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-cursor-private.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2013 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_CURSOR_PRIVATE_H
+#define MONGOC_CURSOR_PRIVATE_H
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include <bson.h>
+
+#include "mongoc-client.h"
+#include "mongoc-buffer-private.h"
+#include "mongoc-rpc-private.h"
+#include "mongoc-server-stream-private.h"
+
+
+BSON_BEGIN_DECLS
+
+typedef struct _mongoc_cursor_interface_t mongoc_cursor_interface_t;
+
+
+struct _mongoc_cursor_interface_t
+{
+ mongoc_cursor_t *(*clone) (const mongoc_cursor_t *cursor);
+ void (*destroy) (mongoc_cursor_t *cursor);
+ bool (*more) (mongoc_cursor_t *cursor);
+ bool (*next) (mongoc_cursor_t *cursor,
+ const bson_t **bson);
+ bool (*error) (mongoc_cursor_t *cursor,
+ bson_error_t *error);
+ void (*get_host) (mongoc_cursor_t *cursor,
+ mongoc_host_list_t *host);
+};
+
+
+struct _mongoc_cursor_t
+{
+ mongoc_client_t *client;
+
+ uint32_t hint;
+ uint32_t stamp;
+
+ unsigned is_command : 1;
+ unsigned sent : 1;
+ unsigned done : 1;
+ unsigned end_of_event : 1;
+ unsigned has_fields : 1;
+ unsigned in_exhaust : 1;
+
+ bson_t query;
+ bson_t fields;
+
+ mongoc_read_concern_t *read_concern;
+ mongoc_read_prefs_t *read_prefs;
+
+ mongoc_query_flags_t flags;
+ uint32_t skip;
-+ uint32_t limit;
++ int32_t limit;
+ uint32_t count;
+ uint32_t batch_size;
+ uint32_t max_await_time_ms;
+
+ char ns [140];
+ uint32_t nslen;
+ uint32_t dblen;
+
+ bson_error_t error;
+
+ mongoc_rpc_t rpc;
+ mongoc_buffer_t buffer;
+ bson_reader_t *reader;
+
+ const bson_t *current;
+
+ mongoc_cursor_interface_t iface;
+ void *iface_data;
+};
+
+
+mongoc_cursor_t * _mongoc_cursor_new (mongoc_client_t *client,
+ const char *db_and_collection,
+ mongoc_query_flags_t flags,
+ uint32_t skip,
-+ uint32_t limit,
++ int32_t limit,
+ uint32_t batch_size,
+ bool is_command,
+ const bson_t *query,
+ const bson_t *fields,
+ const mongoc_read_prefs_t *read_prefs,
+ const mongoc_read_concern_t *read_concern);
+mongoc_cursor_t *_mongoc_cursor_clone (const mongoc_cursor_t *cursor);
+void _mongoc_cursor_destroy (mongoc_cursor_t *cursor);
+bool _mongoc_read_from_buffer (mongoc_cursor_t *cursor,
+ const bson_t **bson);
+bool _use_find_command (const mongoc_cursor_t *cursor,
+ const mongoc_server_stream_t *server_stream);
+mongoc_server_stream_t * _mongoc_cursor_fetch_stream (mongoc_cursor_t *cursor);
+void _mongoc_cursor_collection (const mongoc_cursor_t *cursor,
+ const char **collection,
+ int *collection_len);
+bool _mongoc_cursor_op_getmore (mongoc_cursor_t *cursor,
+ mongoc_server_stream_t *server_stream);
+bool _mongoc_cursor_run_command (mongoc_cursor_t *cursor,
+ const bson_t *command);
+bool _mongoc_cursor_more (mongoc_cursor_t *cursor);
+bool _mongoc_cursor_next (mongoc_cursor_t *cursor,
+ const bson_t **bson);
+bool _mongoc_cursor_error (mongoc_cursor_t *cursor,
+ bson_error_t *error);
+void _mongoc_cursor_get_host (mongoc_cursor_t *cursor,
+ mongoc_host_list_t *host);
+
+
+BSON_END_DECLS
+
+
+#endif /* MONGOC_CURSOR_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-host-list-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-host-list-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-host-list-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-host-list-private.h
new file mode 100644
index 0000000..9cf93fd
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-host-list-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-host-list-private.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2013 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_HOST_LIST_PRIVATE_H
+#define MONGOC_HOST_LIST_PRIVATE_H
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include "mongoc-host-list.h"
+
+
+BSON_BEGIN_DECLS
+
+
+bool _mongoc_host_list_from_string (mongoc_host_list_t *host_list,
+ const char *host_and_port);
+
+bool _mongoc_host_list_equal (const mongoc_host_list_t *host_a,
+ const mongoc_host_list_t *host_b);
+
+void _mongoc_host_list_destroy_all (mongoc_host_list_t *host);
+
+BSON_END_DECLS
+
+
+#endif /* MONGOC_HOST_LIST_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-list-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-list-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-list-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-list-private.h
new file mode 100644
index 0000000..5a6c431
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-list-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-list-private.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_LIST_H
+#define MONGOC_LIST_H
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include <bson.h>
+
+
+BSON_BEGIN_DECLS
+
+
+typedef struct _mongoc_list_t mongoc_list_t;
+
+
+struct _mongoc_list_t
+{
+ mongoc_list_t *next;
+ void *data;
+};
+
+
+mongoc_list_t *_mongoc_list_append (mongoc_list_t *list,
+ void *data);
+mongoc_list_t *_mongoc_list_prepend (mongoc_list_t *list,
+ void *data);
+mongoc_list_t *_mongoc_list_remove (mongoc_list_t *list,
+ void *data);
+void _mongoc_list_foreach (mongoc_list_t *list,
+ void (*func) (void *data, void *user_data),
+ void * user_data);
+void _mongoc_list_destroy (mongoc_list_t *list);
+
+
+BSON_END_DECLS
+
+
+#endif /* MONGOC_LIST_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-log-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-log-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-log-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-log-private.h
new file mode 100644
index 0000000..49bf1cc
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-log-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-log-private.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2015 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_LOG_PRIVATE_H
+#define MONGOC_LOG_PRIVATE_H
+
+#if !defined (MONGOC_INSIDE) && !defined (MONGOC_COMPILATION) && !defined (MONGOC_I_AM_A_DRIVER)
+# error "Only <mongoc.h> can be included directly."
+#endif
+
+#include "mongoc-iovec.h"
+
+/* just for testing */
+void _mongoc_log_get_handler (mongoc_log_func_t *log_func,
+ void **user_data);
+
+bool _mongoc_log_trace_is_enabled (void);
+
+void
+mongoc_log_trace_bytes (const char *domain,
+ const uint8_t *_b,
+ size_t _l);
+
+void
+mongoc_log_trace_iovec (const char *domain,
+ const mongoc_iovec_t *_iov,
+ size_t _iovcnt);
+
+void
+mongoc_log_trace_enable (void);
+
+void
+mongoc_log_trace_disable (void);
+
+
+
+#endif /* MONGOC_LOG_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-log.c b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-log.c
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-log.c b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-log.c
new file mode 100644
index 0000000..47e13f3
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-log.c
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-log.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2013 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#if defined(__linux__)
+# include <sys/syscall.h>
+#elif defined(_WIN32)
+# include <process.h>
+#else
+# include <unistd.h>
+#endif
+#include <stdarg.h>
+#include <time.h>
+
+#include "mongoc-log.h"
+#include "mongoc-log-private.h"
+#include "mongoc-thread-private.h"
+
+
+static mongoc_mutex_t gLogMutex;
+static mongoc_log_func_t gLogFunc = mongoc_log_default_handler;
+#ifdef MONGOC_TRACE
+static bool gLogTrace = true;
+#endif
+static void *gLogData;
+
+static MONGOC_ONCE_FUN( _mongoc_ensure_mutex_once)
+{
+ mongoc_mutex_init(&gLogMutex);
+
+ MONGOC_ONCE_RETURN;
+}
+
+void
+mongoc_log_set_handler (mongoc_log_func_t log_func,
+ void *user_data)
+{
+ static mongoc_once_t once = MONGOC_ONCE_INIT;
+ mongoc_once(&once, &_mongoc_ensure_mutex_once);
+
+ mongoc_mutex_lock(&gLogMutex);
+ gLogFunc = log_func;
+ gLogData = user_data;
+ mongoc_mutex_unlock(&gLogMutex);
+}
+
+
+/* just for testing */
+void
+_mongoc_log_get_handler (mongoc_log_func_t *log_func,
+ void **user_data)
+{
+ *log_func = gLogFunc;
+ *user_data = gLogData;
+}
+
+
+void
+mongoc_log (mongoc_log_level_t log_level,
+ const char *log_domain,
+ const char *format,
+ ...)
+{
+ va_list args;
+ char *message;
+ static mongoc_once_t once = MONGOC_ONCE_INIT;
+ int stop_logging;
+
+ mongoc_once(&once, &_mongoc_ensure_mutex_once);
+
+ stop_logging = !gLogFunc;
+#ifdef MONGOC_TRACE
+ stop_logging = stop_logging || (log_level == MONGOC_LOG_LEVEL_TRACE && !gLogTrace);
+#endif
+ if (stop_logging) {
+ return;
+ }
+
+ BSON_ASSERT (format);
+
+ va_start(args, format);
+ message = bson_strdupv_printf(format, args);
+ va_end(args);
+
+ mongoc_mutex_lock(&gLogMutex);
+ gLogFunc(log_level, log_domain, message, gLogData);
+ mongoc_mutex_unlock(&gLogMutex);
+
+ bson_free(message);
+}
+
+
+const char *
+mongoc_log_level_str (mongoc_log_level_t log_level)
+{
+ switch (log_level) {
+ case MONGOC_LOG_LEVEL_ERROR:
+ return "ERROR";
+ case MONGOC_LOG_LEVEL_CRITICAL:
+ return "CRITICAL";
+ case MONGOC_LOG_LEVEL_WARNING:
+ return "WARNING";
+ case MONGOC_LOG_LEVEL_MESSAGE:
+ return "MESSAGE";
+ case MONGOC_LOG_LEVEL_INFO:
+ return "INFO";
+ case MONGOC_LOG_LEVEL_DEBUG:
+ return "DEBUG";
+ case MONGOC_LOG_LEVEL_TRACE:
+ return "TRACE";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+
+void
+mongoc_log_default_handler (mongoc_log_level_t log_level,
+ const char *log_domain,
+ const char *message,
+ void *user_data)
+{
+ struct timeval tv;
+ struct tm tt;
+ time_t t;
+ FILE *stream;
+ char nowstr[32];
+ int pid;
+
+ bson_gettimeofday(&tv);
+ t = tv.tv_sec;
+
+#ifdef _WIN32
+# ifdef _MSC_VER
+ localtime_s(&tt, &t);
+# else
+ tt = *(localtime(&t));
+# endif
+#else
+ localtime_r(&t, &tt);
+#endif
+
+ strftime (nowstr, sizeof nowstr, "%Y/%m/%d %H:%M:%S", &tt);
+
+ switch (log_level) {
+ case MONGOC_LOG_LEVEL_ERROR:
+ case MONGOC_LOG_LEVEL_CRITICAL:
+ case MONGOC_LOG_LEVEL_WARNING:
+ stream = stderr;
+ break;
+ case MONGOC_LOG_LEVEL_MESSAGE:
+ case MONGOC_LOG_LEVEL_INFO:
+ case MONGOC_LOG_LEVEL_DEBUG:
+ case MONGOC_LOG_LEVEL_TRACE:
+ default:
+ stream = stdout;
+ }
+
+#ifdef __linux__
+ pid = syscall (SYS_gettid);
+#elif defined(_WIN32)
+ pid = (int)_getpid ();
+#else
+ pid = (int)getpid ();
+#endif
+
+ fprintf (stream,
+ "%s.%04ld: [%5d]: %8s: %12s: %s\n",
+ nowstr,
+ tv.tv_usec / 1000L,
+ pid,
+ mongoc_log_level_str(log_level),
+ log_domain,
+ message);
+}
+
+bool
+_mongoc_log_trace_is_enabled (void)
+{
+#ifdef MONGOC_TRACE
+ return gLogTrace;
+#else
+ return false;
+#endif
+}
+
+void
+mongoc_log_trace_enable (void)
+{
+#ifdef MONGOC_TRACE
+ gLogTrace = true;
+#endif
+}
+
+void
+mongoc_log_trace_disable (void)
+{
+#ifdef MONGOC_TRACE
+ gLogTrace = false;
+#endif
+}
+
+void
+mongoc_log_trace_bytes (const char *domain, const uint8_t *_b, size_t _l)
+{
+ bson_string_t *str, *astr;
+ int32_t _i;
+ uint8_t _v;
+
+#ifdef MONGOC_TRACE
+ if (!gLogTrace) {
+ return;
+ }
+#endif
+
+ str = bson_string_new(NULL);
+ astr = bson_string_new(NULL);
+ for (_i = 0; _i < _l; _i++) {
+ _v = *(_b + _i);
+
+ if ((_i % 16) == 0) {
+ bson_string_append_printf(str, "%05x: ", _i);
+ }
+
+ bson_string_append_printf(str, " %02x", _v);
+ if (isprint(_v)) {
+ bson_string_append_printf(astr, " %c", _v);
+ } else {
+ bson_string_append(astr, " .");
+ }
+
+ if ((_i % 16) == 15) {
+ mongoc_log(MONGOC_LOG_LEVEL_TRACE, domain,
+ "%s %s", str->str, astr->str);
+ bson_string_truncate(str, 0);
+ bson_string_truncate(astr, 0);
+ } else if ((_i % 16) == 7) {
+ bson_string_append(str, " ");
+ bson_string_append(astr, " ");
+ }
+ }
+
+ if (_i != 16) {
+ mongoc_log(MONGOC_LOG_LEVEL_TRACE, domain,
+ "%-56s %s", str->str, astr->str);
+ }
+
+ bson_string_free(str, true);
+ bson_string_free(astr, true);
+}
+
+void
+mongoc_log_trace_iovec (const char *domain, const mongoc_iovec_t *_iov, size_t _iovcnt)
+{
+ bson_string_t *str, *astr;
+ const char *_b;
+ unsigned _i = 0;
+ unsigned _j = 0;
+ unsigned _k = 0;
+ size_t _l = 0;
+ uint8_t _v;
+
+#ifdef MONGOC_TRACE
+ if (!gLogTrace) {
+ return;
+ }
+#endif
+
+ for (_i = 0; _i < _iovcnt; _i++) {
+ _l += _iov[_i].iov_len;
+ }
+
+ _i = 0;
+ str = bson_string_new(NULL);
+ astr = bson_string_new(NULL);
+
+ for (_j = 0; _j < _iovcnt; _j++) {
+ _b = (char *)_iov[_j].iov_base;
+ _l = _iov[_j].iov_len;
+
+ for (_k = 0; _k < _l; _k++, _i++) {
+ _v = *(_b + _k);
+ if ((_i % 16) == 0) {
+ bson_string_append_printf(str, "%05x: ", _i);
+ }
+
+ bson_string_append_printf(str, " %02x", _v);
+ if (isprint(_v)) {
+ bson_string_append_printf(astr, " %c", _v);
+ } else {
+ bson_string_append(astr, " .");
+ }
+
+ if ((_i % 16) == 15) {
+ mongoc_log(MONGOC_LOG_LEVEL_TRACE, domain,
+ "%s %s", str->str, astr->str);
+ bson_string_truncate(str, 0);
+ bson_string_truncate(astr, 0);
+ } else if ((_i % 16) == 7) {
+ bson_string_append(str, " ");
+ bson_string_append(astr, " ");
+ }
+ }
+ }
+
+ if (_i != 16) {
+ mongoc_log(MONGOC_LOG_LEVEL_TRACE, domain,
+ "%-56s %s", str->str, astr->str);
+ }
+
+ bson_string_free(str, true);
+ bson_string_free(astr, true);
+}
+
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-read-concern-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-read-concern-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-read-concern-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-read-concern-private.h
new file mode 100644
index 0000000..3de75a1
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-read-concern-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-read-concern-private.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2015 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_READ_CONCERN_PRIVATE_H
+#define MONGOC_READ_CONCERN_PRIVATE_H
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include <bson.h>
+#include "mongoc-read-concern.h"
+
+
+BSON_BEGIN_DECLS
+
+
+struct _mongoc_read_concern_t
+{
+ char *level;
+ bool frozen;
+ bson_t compiled;
+};
+
+
+const bson_t *_mongoc_read_concern_get_bson (mongoc_read_concern_t *read_concern);
+
+BSON_END_DECLS
+
+
+#endif /* MONGOC_READ_CONCERN_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-read-prefs-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-read-prefs-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-read-prefs-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-read-prefs-private.h
new file mode 100644
index 0000000..4983500
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-read-prefs-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-read-prefs-private.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2013 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_READ_PREFS_PRIVATE_H
+#define MONGOC_READ_PREFS_PRIVATE_H
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include <bson.h>
+
+#include "mongoc-cluster-private.h"
+#include "mongoc-read-prefs.h"
+
+
+BSON_BEGIN_DECLS
+
+struct _mongoc_read_prefs_t
+{
+ mongoc_read_mode_t mode;
+ bson_t tags;
+};
+
+
+typedef struct _mongoc_apply_read_prefs_result_t {
+ bson_t *query_with_read_prefs;
+ bool query_owned;
+ mongoc_query_flags_t flags;
+} mongoc_apply_read_prefs_result_t;
+
+
+#define READ_PREFS_RESULT_INIT { NULL, false, MONGOC_QUERY_NONE }
+
+void
+apply_read_preferences (const mongoc_read_prefs_t *read_prefs,
+ const mongoc_server_stream_t *server_stream,
+ const bson_t *query_bson,
+ mongoc_query_flags_t initial_flags,
+ mongoc_apply_read_prefs_result_t *result);
+
+void
+apply_read_prefs_result_cleanup (mongoc_apply_read_prefs_result_t *result);
+
+BSON_END_DECLS
+
+
+#endif /* MONGOC_READ_PREFS_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-rpc-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-rpc-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-rpc-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-rpc-private.h
new file mode 100644
index 0000000..f742db3
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-rpc-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-rpc-private.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2013 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_RPC_PRIVATE_H
+#define MONGOC_RPC_PRIVATE_H
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include <bson.h>
+#include <stddef.h>
+
+#include "mongoc-array-private.h"
+#include "mongoc-iovec.h"
+#include "mongoc-write-concern.h"
+#include "mongoc-flags.h"
+
+
+BSON_BEGIN_DECLS
+
+
+#define RPC(_name, _code) typedef struct { _code } mongoc_rpc_##_name##_t;
+#define ENUM_FIELD(_name) uint32_t _name;
+#define INT32_FIELD(_name) int32_t _name;
+#define INT64_FIELD(_name) int64_t _name;
+#define INT64_ARRAY_FIELD(_len, _name) int32_t _len; int64_t *_name;
+#define CSTRING_FIELD(_name) const char *_name;
+#define BSON_FIELD(_name) const uint8_t *_name;
+#define BSON_ARRAY_FIELD(_name) const uint8_t *_name; int32_t _name##_len;
+#define IOVEC_ARRAY_FIELD(_name) const mongoc_iovec_t *_name; int32_t n_##_name; mongoc_iovec_t _name##_recv;
+#define RAW_BUFFER_FIELD(_name) const uint8_t *_name; int32_t _name##_len;
+#define BSON_OPTIONAL(_check, _code) _code
+
+
+#include "op-delete.def"
+#include "op-get-more.def"
+#include "op-header.def"
+#include "op-insert.def"
+#include "op-kill-cursors.def"
+#include "op-msg.def"
+#include "op-query.def"
+#include "op-reply.def"
+#include "op-update.def"
+
+
+typedef union
+{
+ mongoc_rpc_delete_t delete_;
+ mongoc_rpc_get_more_t get_more;
+ mongoc_rpc_header_t header;
+ mongoc_rpc_insert_t insert;
+ mongoc_rpc_kill_cursors_t kill_cursors;
+ mongoc_rpc_msg_t msg;
+ mongoc_rpc_query_t query;
+ mongoc_rpc_reply_t reply;
+ mongoc_rpc_update_t update;
+} mongoc_rpc_t;
+
+
+BSON_STATIC_ASSERT (sizeof (mongoc_rpc_header_t) == 16);
+BSON_STATIC_ASSERT (offsetof (mongoc_rpc_header_t, opcode) ==
+ offsetof (mongoc_rpc_reply_t, opcode));
+
+
+#undef RPC
+#undef ENUM_FIELD
+#undef INT32_FIELD
+#undef INT64_FIELD
+#undef INT64_ARRAY_FIELD
+#undef CSTRING_FIELD
+#undef BSON_FIELD
+#undef BSON_ARRAY_FIELD
+#undef IOVEC_ARRAY_FIELD
+#undef BSON_OPTIONAL
+#undef RAW_BUFFER_FIELD
+
+
+void _mongoc_rpc_gather (mongoc_rpc_t *rpc,
+ mongoc_array_t *array);
+bool _mongoc_rpc_needs_gle (mongoc_rpc_t *rpc,
+ const mongoc_write_concern_t *write_concern);
+void _mongoc_rpc_swab_to_le (mongoc_rpc_t *rpc);
+void _mongoc_rpc_swab_from_le (mongoc_rpc_t *rpc);
+void _mongoc_rpc_printf (mongoc_rpc_t *rpc);
+bool _mongoc_rpc_scatter (mongoc_rpc_t *rpc,
+ const uint8_t *buf,
+ size_t buflen);
+bool _mongoc_rpc_reply_get_first (mongoc_rpc_reply_t *reply,
+ bson_t *bson);
+void _mongoc_rpc_prep_command (mongoc_rpc_t *rpc,
+ const char *cmd_ns,
+ const bson_t *command,
+ mongoc_query_flags_t flags);
+bool _mongoc_rpc_parse_command_error(mongoc_rpc_t *rpc,
+ bson_error_t *error);
+bool _mongoc_rpc_parse_query_error (mongoc_rpc_t *rpc,
+ bson_error_t *error);
+
+
+BSON_END_DECLS
+
+
+#endif /* MONGOC_RPC_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-server-description-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-server-description-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-server-description-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-server-description-private.h
new file mode 100644
-index 0000000..621003e
+index 0000000..b8b5962
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-server-description-private.h
-@@ -0,0 +1,114 @@
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-server-description-private.h
+@@ -0,0 +1,124 @@
+/*
+ * Copyright 2014 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_SERVER_DESCRIPTION_PRIVATE_H
+#define MONGOC_SERVER_DESCRIPTION_PRIVATE_H
+
+#include "mongoc-server-description.h"
+
+
+#define MONGOC_DEFAULT_WIRE_VERSION 0
+#define MONGOC_DEFAULT_WRITE_BATCH_SIZE 1000
+#define MONGOC_DEFAULT_BSON_OBJ_SIZE 16 * 1024 * 1024
+#define MONGOC_DEFAULT_MAX_MSG_SIZE 48000000
+
++/* represent a server or topology with no replica set config version */
++#define MONGOC_NO_SET_VERSION -1
+
+typedef enum
+ {
+ MONGOC_SERVER_UNKNOWN,
+ MONGOC_SERVER_STANDALONE,
+ MONGOC_SERVER_MONGOS,
+ MONGOC_SERVER_POSSIBLE_PRIMARY,
+ MONGOC_SERVER_RS_PRIMARY,
+ MONGOC_SERVER_RS_SECONDARY,
+ MONGOC_SERVER_RS_ARBITER,
+ MONGOC_SERVER_RS_OTHER,
+ MONGOC_SERVER_RS_GHOST,
+ MONGOC_SERVER_DESCRIPTION_TYPES,
+ } mongoc_server_description_type_t;
+
+struct _mongoc_server_description_t
+{
+ uint32_t id;
+ mongoc_host_list_t host;
+ int64_t round_trip_time;
+ bson_t last_is_master;
+ bool has_is_master;
+ const char *connection_address;
+ const char *me;
+
+ /* The following fields are filled from the last_is_master and are zeroed on
+ * parse. So order matters here. DON'T move set_name */
+ const char *set_name;
+ bson_error_t error;
+ mongoc_server_description_type_t type;
+
+ int32_t min_wire_version;
+ int32_t max_wire_version;
+ int32_t max_msg_size;
+ int32_t max_bson_obj_size;
+ int32_t max_write_batch_size;
+
+ bson_t hosts;
+ bson_t passives;
+ bson_t arbiters;
+
+ bson_t tags;
+ const char *current_primary;
++ int64_t set_version;
+ bson_oid_t election_id;
+};
+
+void
+mongoc_server_description_init (mongoc_server_description_t *sd,
+ const char *address,
+ uint32_t id);
+bool
+mongoc_server_description_has_rs_member (mongoc_server_description_t *description,
+ const char *address);
+
++
++bool
++mongoc_server_description_has_set_version (mongoc_server_description_t *description);
++
+bool
+mongoc_server_description_has_election_id (mongoc_server_description_t *description);
+
+void
+mongoc_server_description_cleanup (mongoc_server_description_t *sd);
+
+void
+mongoc_server_description_reset (mongoc_server_description_t *sd);
+
+void
+mongoc_server_description_set_state (mongoc_server_description_t *description,
+ mongoc_server_description_type_t type);
+void
++mongoc_server_description_set_set_version (mongoc_server_description_t *description,
++ int64_t set_version);
++void
+mongoc_server_description_set_election_id (mongoc_server_description_t *description,
+ const bson_oid_t *election_id);
+void
+mongoc_server_description_update_rtt (mongoc_server_description_t *server,
+ int64_t new_time);
+
+void
+mongoc_server_description_handle_ismaster (
+ mongoc_server_description_t *sd,
+ const bson_t *reply,
+ int64_t rtt_msec,
+ bson_error_t *error);
+
+size_t
+mongoc_server_description_filter_eligible (
+ mongoc_server_description_t **descriptions,
+ size_t description_len,
+ const mongoc_read_prefs_t *read_prefs);
+
+#endif
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-server-stream-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-server-stream-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-server-stream-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-server-stream-private.h
new file mode 100644
index 0000000..0a2cde3
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-server-stream-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-server-stream-private.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2015 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_SERVER_STREAM_H
+#define MONGOC_SERVER_STREAM_H
+
+#include "mongoc-config.h"
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include <bson.h>
+
+#include "mongoc-topology-description-private.h"
+#include "mongoc-server-description-private.h"
+#include "mongoc-stream.h"
+
+BSON_BEGIN_DECLS
+
+typedef struct _mongoc_server_stream_t
+{
+ mongoc_topology_description_type_t topology_type;
+ mongoc_server_description_t *sd; /* owned */
+ mongoc_stream_t *stream; /* borrowed */
+} mongoc_server_stream_t;
+
+
+mongoc_server_stream_t *
+mongoc_server_stream_new (mongoc_topology_description_type_t topology_type,
+ mongoc_server_description_t *sd,
+ mongoc_stream_t *stream);
+
+int32_t
+mongoc_server_stream_max_bson_obj_size (mongoc_server_stream_t *server_stream);
+
+int32_t
+mongoc_server_stream_max_msg_size (mongoc_server_stream_t *server_stream);
+
+int32_t
+mongoc_server_stream_max_write_batch_size (mongoc_server_stream_t *server_stream);
+
+void
+mongoc_server_stream_cleanup (mongoc_server_stream_t *server_stream);
+
+BSON_END_DECLS
+
+
+#endif /* MONGOC_SERVER_STREAM_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-set-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-set-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-set-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-set-private.h
new file mode 100644
index 0000000..896dfe3
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-set-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-set-private.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2014 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_SET_PRIVATE_H
+#define MONGOC_SET_PRIVATE_H
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include <bson.h>
+
+BSON_BEGIN_DECLS
+
+typedef void (*mongoc_set_item_dtor)(void *item,
+ void *ctx);
+
+/* return true to continue iteration, false to stop */
+typedef bool (*mongoc_set_for_each_cb_t)(void *item,
+ void *ctx);
+
+typedef struct
+{
+ uint32_t id;
+ void *item;
+} mongoc_set_item_t;
+
+typedef struct
+{
+ mongoc_set_item_t *items;
+ size_t items_len;
+ size_t items_allocated;
+ mongoc_set_item_dtor dtor;
+ void *dtor_ctx;
+} mongoc_set_t;
+
+mongoc_set_t *
+mongoc_set_new (size_t nitems,
+ mongoc_set_item_dtor dtor,
+ void *dtor_ctx);
+
+void
+mongoc_set_add (mongoc_set_t *set,
+ uint32_t id,
+ void *item);
+
+void
+mongoc_set_rm (mongoc_set_t *set,
+ uint32_t id);
+
+void *
+mongoc_set_get (mongoc_set_t *set,
+ uint32_t id);
+
+void *
+mongoc_set_get_item (mongoc_set_t *set,
+ int idx);
+
+void
+mongoc_set_destroy (mongoc_set_t *set);
+
+/* loops over the set safe-ish.
+ *
+ * Caveats:
+ * - you can add items at any iteration
+ * - if you remove elements other than the one you're currently looking at,
+ * you may see it later in the iteration
+ */
+void
+mongoc_set_for_each (mongoc_set_t *set,
+ mongoc_set_for_each_cb_t cb,
+ void *ctx);
+
+/* first item in set for which "cb" returns true */
+void *
+mongoc_set_find_item (mongoc_set_t *set,
+ mongoc_set_for_each_cb_t cb,
+ void *ctx);
+
+/* id of first item in set for which "cb" returns true, or 0. */
+uint32_t
+mongoc_set_find_id (mongoc_set_t *set,
+ mongoc_set_for_each_cb_t cb,
+ void *ctx);
+
+BSON_END_DECLS
+
+#endif /* MONGOC_SET_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-set.c b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-set.c
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-set.c b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-set.c
new file mode 100644
index 0000000..1c42d93
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-set.c
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-set.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2014 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <bson.h>
+
+#include "mongoc-set-private.h"
+
+#undef MONGOC_LOG_DOMAIN
+#define MONGOC_LOG_DOMAIN "set"
+
+mongoc_set_t *
+mongoc_set_new (size_t nitems,
+ mongoc_set_item_dtor dtor,
+ void *dtor_ctx)
+{
+ mongoc_set_t *set = (mongoc_set_t *)bson_malloc (sizeof (*set));
+
+ set->items_allocated = nitems;
+ set->items = (mongoc_set_item_t *)bson_malloc (sizeof (*set->items) * set->items_allocated);
+ set->items_len = 0;
+
+ set->dtor = dtor;
+ set->dtor_ctx = dtor_ctx;
+
+ return set;
+}
+
+static int
+mongoc_set_id_cmp (const void *a_,
+ const void *b_)
+{
+ mongoc_set_item_t *a = (mongoc_set_item_t *)a_;
+ mongoc_set_item_t *b = (mongoc_set_item_t *)b_;
+
+ if (a->id == b->id) {
+ return 0;
+ }
+
+ return a->id < b->id ? -1 : 1;
+}
+
+void
+mongoc_set_add (mongoc_set_t *set,
+ uint32_t id,
+ void *item)
+{
+ if (set->items_len >= set->items_allocated) {
+ set->items_allocated *= 2;
+ set->items = (mongoc_set_item_t *)bson_realloc (set->items,
+ sizeof (*set->items) * set->items_allocated);
+ }
+
+ set->items[set->items_len].id = id;
+ set->items[set->items_len].item = item;
+
+ set->items_len++;
+
+ if (set->items_len > 1 && set->items[set->items_len - 2].id > id) {
+ qsort (set->items, set->items_len, sizeof (*set->items),
+ mongoc_set_id_cmp);
+ }
+}
+
+void
+mongoc_set_rm (mongoc_set_t *set,
+ uint32_t id)
+{
+ mongoc_set_item_t *ptr;
+ mongoc_set_item_t key;
+ int i;
+
+ key.id = id;
+
+ ptr = (mongoc_set_item_t *)bsearch (&key, set->items, set->items_len, sizeof (key),
+ mongoc_set_id_cmp);
+
+ if (ptr) {
+ set->dtor(ptr->item, set->dtor_ctx);
+
+ i = ptr - set->items;
+
+ if (i != set->items_len - 1) {
+ memmove (set->items + i, set->items + i + 1,
+ (set->items_len - (i + 1)) * sizeof (key));
+ }
+
+ set->items_len--;
+ }
+}
+
+void *
+mongoc_set_get (mongoc_set_t *set,
+ uint32_t id)
+{
+ mongoc_set_item_t *ptr;
+ mongoc_set_item_t key;
+
+ key.id = id;
+
+ ptr = (mongoc_set_item_t *)bsearch (&key, set->items, set->items_len, sizeof (key),
+ mongoc_set_id_cmp);
+
+ return ptr ? ptr->item : NULL;
+}
+
+void *
+mongoc_set_get_item (mongoc_set_t *set,
+ int idx)
+{
+ BSON_ASSERT (set);
+ BSON_ASSERT (idx < set->items_len);
+
+ return set->items[idx].item;
+}
+
+
+void
+mongoc_set_destroy (mongoc_set_t *set)
+{
+ int i;
+
+ for (i = 0; i < set->items_len; i++) {
+ set->dtor(set->items[i].item, set->dtor_ctx);
+ }
+
+ bson_free (set->items);
+ bson_free (set);
+}
+
+void
+mongoc_set_for_each (mongoc_set_t *set,
+ mongoc_set_for_each_cb_t cb,
+ void *ctx)
+{
+ size_t i;
+ mongoc_set_item_t *old_set;
+ size_t items_len;
+
+ items_len = set->items_len;
+
+ old_set = (mongoc_set_item_t *)bson_malloc (sizeof (*old_set) * items_len);
+ memcpy (old_set, set->items, sizeof (*old_set) * items_len);
+
+ for (i = 0; i < items_len; i++) {
+ if (!cb (old_set[i].item, ctx)) {
+ break;
+ }
+ }
+
+ bson_free (old_set);
+}
+
+
+static mongoc_set_item_t *
+_mongoc_set_find (mongoc_set_t *set,
+ mongoc_set_for_each_cb_t cb,
+ void *ctx)
+{
+ size_t i;
+ size_t items_len;
+ mongoc_set_item_t *item;
+
+ items_len = set->items_len;
+
+ for (i = 0; i < items_len; i++) {
+ item = &set->items[i];
+ if (cb (item->item, ctx)) {
+ return item;
+ }
+ }
+
+ return NULL;
+}
+
+
+void *
+mongoc_set_find_item (mongoc_set_t *set,
+ mongoc_set_for_each_cb_t cb,
+ void *ctx)
+{
+ mongoc_set_item_t *item;
+
+ if ((item = _mongoc_set_find (set, cb, ctx))) {
+ return item->item;
+ }
+
+ return NULL;
+}
+
+
+uint32_t
+mongoc_set_find_id (mongoc_set_t *set,
+ mongoc_set_for_each_cb_t cb,
+ void *ctx)
+{
+ mongoc_set_item_t *item;
+
+ if ((item = _mongoc_set_find (set, cb, ctx))) {
+ return item->id;
+ }
+
+ return 0;
+}
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-thread-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-thread-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-thread-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-thread-private.h
new file mode 100644
index 0000000..b71d139
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-thread-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-thread-private.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2013 MongoDB Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_THREAD_PRIVATE_H
+#define MONGOC_THREAD_PRIVATE_H
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include <bson.h>
+
+#include "mongoc-config.h"
+
+
+#if !defined(_WIN32)
+# include <pthread.h>
+# define MONGOC_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+# define mongoc_cond_t pthread_cond_t
+# define mongoc_cond_broadcast pthread_cond_broadcast
+# define mongoc_cond_init(_n) pthread_cond_init((_n), NULL)
+# define mongoc_cond_wait pthread_cond_wait
+# define mongoc_cond_signal pthread_cond_signal
+static BSON_INLINE int
+mongoc_cond_timedwait (pthread_cond_t *cond,
+ pthread_mutex_t *mutex,
+ int64_t timeout_msec)
+{
+ struct timespec to;
+ struct timeval tv;
+ int64_t msec;
+
+ bson_gettimeofday (&tv);
+
+ msec = ((int64_t)tv.tv_sec * 1000) + (tv.tv_usec / 1000) + timeout_msec;
+
+ to.tv_sec = msec / 1000;
+ to.tv_nsec = (msec % 1000) * 1000 * 1000;
+
+ return pthread_cond_timedwait (cond, mutex, &to);
+}
+# define mongoc_cond_destroy pthread_cond_destroy
+# define mongoc_mutex_t pthread_mutex_t
+# define mongoc_mutex_init(_n) pthread_mutex_init((_n), NULL)
+# define mongoc_mutex_lock pthread_mutex_lock
+# define mongoc_mutex_unlock pthread_mutex_unlock
+# define mongoc_mutex_destroy pthread_mutex_destroy
+# define mongoc_thread_t pthread_t
+# define mongoc_thread_create(_t,_f,_d) pthread_create((_t), NULL, (_f), (_d))
+# define mongoc_thread_join(_n) pthread_join((_n), NULL)
+# define mongoc_once_t pthread_once_t
+# define mongoc_once pthread_once
+# define MONGOC_ONCE_FUN(n) void n(void)
+# define MONGOC_ONCE_RETURN return
+# ifdef _PTHREAD_ONCE_INIT_NEEDS_BRACES
+# define MONGOC_ONCE_INIT {PTHREAD_ONCE_INIT}
+# else
+# define MONGOC_ONCE_INIT PTHREAD_ONCE_INIT
+# endif
+#else
+# define mongoc_thread_t HANDLE
+static BSON_INLINE int
+mongoc_thread_create (mongoc_thread_t *thread,
+ void *(*cb)(void *),
+ void *arg)
+{
+ *thread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) cb, arg, 0, NULL);
+ return 0;
+}
+# define mongoc_thread_join(_n) WaitForSingleObject((_n), INFINITE)
+# define mongoc_mutex_t CRITICAL_SECTION
+# define mongoc_mutex_init InitializeCriticalSection
+# define mongoc_mutex_lock EnterCriticalSection
+# define mongoc_mutex_unlock LeaveCriticalSection
+# define mongoc_mutex_destroy DeleteCriticalSection
+# define mongoc_cond_t CONDITION_VARIABLE
+# define mongoc_cond_init InitializeConditionVariable
+# define mongoc_cond_wait(_c, _m) mongoc_cond_timedwait((_c), (_m), INFINITE)
+static BSON_INLINE int
+mongoc_cond_timedwait (mongoc_cond_t *cond,
+ mongoc_mutex_t *mutex,
+ int64_t timeout_msec)
+{
+ int r;
+
+ if (SleepConditionVariableCS(cond, mutex, timeout_msec)) {
+ return 0;
+ } else {
+ r = GetLastError();
+
+ if (r == WAIT_TIMEOUT || r == ERROR_TIMEOUT) {
+ return WSAETIMEDOUT;
+ } else {
+ return EINVAL;
+ }
+ }
+}
+# define mongoc_cond_signal WakeConditionVariable
+# define mongoc_cond_broadcast WakeAllConditionVariable
+static BSON_INLINE int
+mongoc_cond_destroy (mongoc_cond_t *_ignored)
+{
+ return 0;
+}
+# define mongoc_once_t INIT_ONCE
+# define MONGOC_ONCE_INIT INIT_ONCE_STATIC_INIT
+# define mongoc_once(o, c) InitOnceExecuteOnce(o, c, NULL, NULL)
+# define MONGOC_ONCE_FUN(n) BOOL CALLBACK n(PINIT_ONCE _ignored_a, PVOID _ignored_b, PVOID *_ignored_c)
+# define MONGOC_ONCE_RETURN return true
+#endif
+
+
+#endif /* MONGOC_THREAD_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology-description-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology-description-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-topology-description-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-topology-description-private.h
new file mode 100644
-index 0000000..fd428c2
+index 0000000..e6c72fb
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology-description-private.h
-@@ -0,0 +1,97 @@
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-topology-description-private.h
+@@ -0,0 +1,98 @@
+/*
+ * Copyright 2014 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_TOPOLOGY_DESCRIPTION_PRIVATE_H
+#define MONGOC_TOPOLOGY_DESCRIPTION_PRIVATE_H
+
+#include "mongoc-set-private.h"
+#include "mongoc-server-description.h"
+
+#define MONGOC_SS_DEFAULT_TIMEOUT_MS 30000
+#define MONGOC_SS_DEFAULT_LOCAL_THRESHOLD_MS 15
+
+typedef enum
+ {
+ MONGOC_TOPOLOGY_UNKNOWN,
+ MONGOC_TOPOLOGY_SHARDED,
+ MONGOC_TOPOLOGY_RS_NO_PRIMARY,
+ MONGOC_TOPOLOGY_RS_WITH_PRIMARY,
+ MONGOC_TOPOLOGY_SINGLE,
+ MONGOC_TOPOLOGY_DESCRIPTION_TYPES
+ } mongoc_topology_description_type_t;
+
+typedef struct _mongoc_topology_description_t
+{
+ mongoc_topology_description_type_t type;
+ mongoc_set_t *servers;
+ char *set_name;
++ int64_t max_set_version;
+ bson_oid_t max_election_id;
+ bool compatible;
+ char *compatibility_error;
+ uint32_t max_server_id;
+ bool stale;
+} mongoc_topology_description_t;
+
+typedef enum
+ {
+ MONGOC_SS_READ,
+ MONGOC_SS_WRITE
+ } mongoc_ss_optype_t;
+
+void
+mongoc_topology_description_init (mongoc_topology_description_t *description,
+ mongoc_topology_description_type_t type);
+
+void
+mongoc_topology_description_destroy (mongoc_topology_description_t *description);
+
+void
+mongoc_topology_description_handle_ismaster (
+ mongoc_topology_description_t *topology,
+ mongoc_server_description_t *sd,
+ const bson_t *reply,
+ int64_t rtt_msec,
+ bson_error_t *error);
+
+mongoc_server_description_t *
+mongoc_topology_description_select (mongoc_topology_description_t *description,
+ mongoc_ss_optype_t optype,
+ const mongoc_read_prefs_t *read_pref,
+ int64_t local_threshold_ms);
+
+mongoc_server_description_t *
+mongoc_topology_description_server_by_id (mongoc_topology_description_t *description,
+ uint32_t id,
+ bson_error_t *error);
+
+void
+mongoc_topology_description_suitable_servers (
+ mongoc_array_t *set, /* OUT */
+ mongoc_ss_optype_t optype,
+ mongoc_topology_description_t *topology,
+ const mongoc_read_prefs_t *read_pref,
+ size_t local_threshold_ms);
+
+void
+mongoc_topology_description_invalidate_server (mongoc_topology_description_t *topology,
+ uint32_t id);
+
+bool
+mongoc_topology_description_add_server (mongoc_topology_description_t *topology,
+ const char *server,
+ uint32_t *id /* OUT */);
+
+#endif /* MONGOC_TOPOLOGY_DESCRIPTION_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology-description.c b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology-description.c
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-topology-description.c b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-topology-description.c
new file mode 100644
-index 0000000..678b5fb
+index 0000000..38e21db
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology-description.c
-@@ -0,0 +1,1351 @@
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-topology-description.c
+@@ -0,0 +1,1402 @@
+/*
+ * Copyright 2014 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mongoc-array-private.h"
+#include "mongoc-error.h"
+#include "mongoc-server-description-private.h"
+#include "mongoc-topology-description-private.h"
+#include "mongoc-trace.h"
+#include "mongoc-util-private.h"
+
+
+static void
+_mongoc_topology_server_dtor (void *server_,
+ void *ctx_)
+{
+ mongoc_server_description_destroy ((mongoc_server_description_t *)server_);
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * mongoc_topology_description_init --
+ *
+ * Initialize the given topology description
+ *
+ * Returns:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------------------
+ */
+void
+mongoc_topology_description_init (mongoc_topology_description_t *description,
+ mongoc_topology_description_type_t type)
+{
+ ENTRY;
+
+ BSON_ASSERT (description);
+ BSON_ASSERT (type == MONGOC_TOPOLOGY_UNKNOWN ||
+ type == MONGOC_TOPOLOGY_SINGLE ||
+ type == MONGOC_TOPOLOGY_RS_NO_PRIMARY);
+
+ memset (description, 0, sizeof (*description));
+
+ description->type = type;
+ description->servers = mongoc_set_new(8, _mongoc_topology_server_dtor, NULL);
+ description->set_name = NULL;
++ description->max_set_version = MONGOC_NO_SET_VERSION;
+ description->compatible = true;
+ description->compatibility_error = NULL;
+ description->stale = true;
+
+ EXIT;
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * mongoc_topology_description_destroy --
+ *
+ * Destroy allocated resources within @description
+ *
+ * Returns:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------------------
+ */
+void
+mongoc_topology_description_destroy (mongoc_topology_description_t *description)
+{
+ ENTRY;
+
+ BSON_ASSERT(description);
+
+ mongoc_set_destroy(description->servers);
+
+ if (description->set_name) {
+ bson_free (description->set_name);
+ }
+
+ if (description->compatibility_error) {
+ bson_free (description->compatibility_error);
+ }
+
+ EXIT;
+}
+
+/* find the primary, then stop iterating */
+static bool
+_mongoc_topology_description_has_primary_cb (void *item,
+ void *ctx /* OUT */)
+{
+ mongoc_server_description_t *server = (mongoc_server_description_t *)item;
+ mongoc_server_description_t **primary = (mongoc_server_description_t **)ctx;
+
+ /* TODO should this include MONGOS? */
+ if (server->type == MONGOC_SERVER_RS_PRIMARY || server->type == MONGOC_SERVER_STANDALONE) {
+ *primary = (mongoc_server_description_t *)item;
+ return false;
+ }
+ return true;
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * _mongoc_topology_description_has_primary --
+ *
+ * If topology has a primary, return it.
+ *
+ * Returns:
+ * A pointer to the primary, or NULL.
+ *
+ * Side effects:
+ * None
+ *
+ *--------------------------------------------------------------------------
+ */
+static mongoc_server_description_t *
+_mongoc_topology_description_has_primary (mongoc_topology_description_t *description)
+{
+ mongoc_server_description_t *primary = NULL;
+
+ mongoc_set_for_each(description->servers, _mongoc_topology_description_has_primary_cb, &primary);
+
+ return primary;
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * _mongoc_topology_description_later_election --
+ *
+ * Check if we've seen a more recent election in the replica set
+ * than this server has.
+ *
+ * Returns:
-+ * True if the topology description's max election id is greater
-+ * than the server description's election_id.
++ * True if the topology description's max replica set version plus
++ * election id is later than the server description's.
+ *
+ * Side effects:
+ * None
+ *
+ *--------------------------------------------------------------------------
+ */
+static bool
+_mongoc_topology_description_later_election (mongoc_topology_description_t *td,
+ mongoc_server_description_t *sd)
+{
-+ return bson_oid_compare (&td->max_election_id, &sd->election_id) > 0;
++ /* initially max_set_version is -1 and max_election_id is zeroed */
++ return td->max_set_version > sd->set_version ||
++ (td->max_set_version == sd->set_version &&
++ bson_oid_compare (&td->max_election_id, &sd->election_id) > 0);
++}
++
++/*
++ *--------------------------------------------------------------------------
++ *
++ * _mongoc_topology_description_set_max_set_version --
++ *
++ * Remember that we've seen a new replica set version. Unconditionally
++ * sets td->set_version to sd->set_version.
++ *
++ *--------------------------------------------------------------------------
++ */
++static void
++_mongoc_topology_description_set_max_set_version (
++ mongoc_topology_description_t *td,
++ mongoc_server_description_t *sd)
++{
++ td->max_set_version = sd->set_version;
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * _mongoc_topology_description_set_max_election_id --
+ *
+ * Remember that we've seen a new election id. Unconditionally sets
+ * td->max_election_id to sd->election_id.
+ *
+ *--------------------------------------------------------------------------
+ */
+static void
+_mongoc_topology_description_set_max_election_id (
+ mongoc_topology_description_t *td,
+ mongoc_server_description_t *sd)
+{
+ bson_oid_copy (&sd->election_id, &td->max_election_id);
+}
+
+static bool
+_mongoc_topology_description_server_is_candidate (
+ mongoc_server_description_type_t desc_type,
+ mongoc_read_mode_t read_mode,
+ mongoc_topology_description_type_t topology_type)
+{
+ switch ((int)topology_type) {
+ case MONGOC_TOPOLOGY_SINGLE:
+ switch ((int)desc_type) {
+ case MONGOC_SERVER_STANDALONE:
+ return true;
+ default:
+ return false;
+ }
+
+ case MONGOC_TOPOLOGY_RS_NO_PRIMARY:
+ case MONGOC_TOPOLOGY_RS_WITH_PRIMARY:
+ switch ((int)read_mode) {
+ case MONGOC_READ_PRIMARY:
+ switch ((int)desc_type) {
+ case MONGOC_SERVER_POSSIBLE_PRIMARY:
+ case MONGOC_SERVER_RS_PRIMARY:
+ return true;
+ default:
+ return false;
+ }
+ case MONGOC_READ_SECONDARY:
+ switch ((int)desc_type) {
+ case MONGOC_SERVER_RS_SECONDARY:
+ return true;
+ default:
+ return false;
+ }
+ default:
+ switch ((int)desc_type) {
+ case MONGOC_SERVER_POSSIBLE_PRIMARY:
+ case MONGOC_SERVER_RS_PRIMARY:
+ case MONGOC_SERVER_RS_SECONDARY:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ case MONGOC_TOPOLOGY_SHARDED:
+ switch ((int)desc_type) {
+ case MONGOC_SERVER_MONGOS:
+ return true;
+ default:
+ return false;
+ }
+ default:
+ return false;
+ }
+}
+
+typedef struct _mongoc_suitable_data_t
+{
+ mongoc_read_mode_t read_mode;
+ mongoc_topology_description_type_t topology_type;
+ mongoc_server_description_t *primary; /* OUT */
+ mongoc_server_description_t **candidates; /* OUT */
+ size_t candidates_len; /* OUT */
+ bool has_secondary; /* OUT */
+} mongoc_suitable_data_t;
+
+static bool
+_mongoc_replica_set_read_suitable_cb (void *item,
+ void *ctx)
+{
+ mongoc_server_description_t *server = (mongoc_server_description_t *)item;
+ mongoc_suitable_data_t *data = (mongoc_suitable_data_t *)ctx;
+
+ if (_mongoc_topology_description_server_is_candidate (server->type,
+ data->read_mode,
+ data->topology_type)) {
+
+ if (server->type == MONGOC_SERVER_RS_PRIMARY) {
+ data->primary = server;
+
+ if (data->read_mode == MONGOC_READ_PRIMARY ||
+ data->read_mode == MONGOC_READ_PRIMARY_PREFERRED) {
+ /* we want a primary and we have one, done! */
+ return false;
+ }
+ }
+
+ if (server->type == MONGOC_SERVER_RS_SECONDARY) {
+ data->has_secondary = true;
+ }
+
+ /* add to our candidates */
+ data->candidates[data->candidates_len++] = server;
+ }
+ return true;
+}
+
+/* if any mongos are candidates, add them to the candidates array */
+static bool
+_mongoc_find_suitable_mongos_cb (void *item,
+ void *ctx)
+{
+ mongoc_server_description_t *server = (mongoc_server_description_t *)item;
+ mongoc_suitable_data_t *data = (mongoc_suitable_data_t *)ctx;
+
+ if (_mongoc_topology_description_server_is_candidate (server->type,
+ data->read_mode,
+ data->topology_type)) {
+ data->candidates[data->candidates_len++] = server;
+ }
+ return true;
+}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * mongoc_topology_description_suitable_servers --
+ *
+ * Return an array of suitable server descriptions for this
+ * operation and read preference.
+ *
+ * NOTE: this method should only be called while holding the mutex on
+ * the owning topology object.
+ *
+ * Returns:
+ * Array of server descriptions, or NULL upon failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+void
+mongoc_topology_description_suitable_servers (
+ mongoc_array_t *set, /* OUT */
+ mongoc_ss_optype_t optype,
+ mongoc_topology_description_t *topology,
+ const mongoc_read_prefs_t *read_pref,
+ size_t local_threshold_ms)
+{
+ mongoc_suitable_data_t data;
+ mongoc_server_description_t **candidates;
+ mongoc_server_description_t *server;
+ int64_t nearest = -1;
+ int i;
+ mongoc_read_mode_t read_mode = mongoc_read_prefs_get_mode(read_pref);
+
+ candidates = (mongoc_server_description_t **)bson_malloc0(sizeof(*candidates) * topology->servers->items_len);
+
+ data.read_mode = read_mode;
+ data.topology_type = topology->type;
+ data.primary = NULL;
+ data.candidates = candidates;
+ data.candidates_len = 0;
+ data.has_secondary = false;
+
+ /* Single server --
+ * Either it is suitable or it isn't */
+ if (topology->type == MONGOC_TOPOLOGY_SINGLE) {
+ server = (mongoc_server_description_t *)mongoc_set_get_item (topology->servers, 0);
+ if (_mongoc_topology_description_server_is_candidate (server->type, read_mode, topology->type)) {
+ _mongoc_array_append_val (set, server);
+ }
+ goto DONE;
+ }
+
+ /* Replica sets --
+ * Find suitable servers based on read mode */
+ if (topology->type == MONGOC_TOPOLOGY_RS_NO_PRIMARY ||
+ topology->type == MONGOC_TOPOLOGY_RS_WITH_PRIMARY) {
+
+ if (optype == MONGOC_SS_READ) {
+
+ mongoc_set_for_each(topology->servers, _mongoc_replica_set_read_suitable_cb, &data);
+
+ /* if we have a primary, it's a candidate, for some read modes we are done */
+ if (read_mode == MONGOC_READ_PRIMARY || read_mode == MONGOC_READ_PRIMARY_PREFERRED) {
+ if (data.primary) {
+ _mongoc_array_append_val (set, data.primary);
+ goto DONE;
+ }
+ }
+
+ if (! mongoc_server_description_filter_eligible (data.candidates, data.candidates_len, read_pref)) {
+ if (read_mode == MONGOC_READ_NEAREST) {
+ goto DONE;
+ } else {
+ data.has_secondary = false;
+ }
+ }
+
+ if (data.has_secondary &&
+ (read_mode == MONGOC_READ_SECONDARY || read_mode == MONGOC_READ_SECONDARY_PREFERRED)) {
+ /* secondary or secondary preferred and we have one. */
+
+ for (i = 0; i < data.candidates_len; i++) {
+ if (candidates[i] && candidates[i]->type == MONGOC_SERVER_RS_PRIMARY) {
+ candidates[i] = NULL;
+ }
+ }
+ } else if (read_mode == MONGOC_READ_SECONDARY_PREFERRED && data.primary) {
+ /* secondary preferred, but only the one primary is a candidate */
+ _mongoc_array_append_val (set, data.primary);
+ goto DONE;
+ }
+
+ } else if (topology->type == MONGOC_TOPOLOGY_RS_WITH_PRIMARY) {
+ /* includes optype == MONGOC_SS_WRITE as the exclusion of the above if */
+ mongoc_set_for_each(topology->servers, _mongoc_topology_description_has_primary_cb,
+ &data.primary);
+ if (data.primary) {
+ _mongoc_array_append_val (set, data.primary);
+ goto DONE;
+ }
+ }
+ }
+
+ /* Sharded clusters --
+ * All candidates in the latency window are suitable */
+ if (topology->type == MONGOC_TOPOLOGY_SHARDED) {
+ mongoc_set_for_each (topology->servers, _mongoc_find_suitable_mongos_cb, &data);
+ }
+
+ /* Ways to get here:
+ * - secondary read
+ * - secondary preferred read
+ * - primary_preferred and no primary read
+ * - sharded anything
+ * Find the nearest, then select within the window */
+
+ for (i = 0; i < data.candidates_len; i++) {
+ if (candidates[i] && (nearest == -1 || nearest > candidates[i]->round_trip_time)) {
+ nearest = candidates[i]->round_trip_time;
+ }
+ }
+
+ for (i = 0; i < data.candidates_len; i++) {
+ if (candidates[i] && (candidates[i]->round_trip_time <= nearest + local_threshold_ms)) {
+ _mongoc_array_append_val (set, candidates[i]);
+ }
+ }
+
+DONE:
+
+ bson_free (candidates);
+
+ return;
+}
+
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * mongoc_topology_description_select --
+ *
+ * Return a server description of a node that is appropriate for
+ * the given read preference and operation type.
+ *
+ * NOTE: this method simply attempts to select a server from the
+ * current topology, it does not retry or trigger topology checks.
+ *
+ * NOTE: this method should only be called while holding the mutex on
+ * the owning topology object.
+ *
+ * Returns:
+ * Selected server description, or NULL upon failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+mongoc_server_description_t *
+mongoc_topology_description_select (mongoc_topology_description_t *topology,
+ mongoc_ss_optype_t optype,
+ const mongoc_read_prefs_t *read_pref,
+ int64_t local_threshold_ms)
+{
+ mongoc_array_t suitable_servers;
+ mongoc_server_description_t *sd = NULL;
+
+ ENTRY;
+
+ if (!topology->compatible) {
+ /* TODO, should we return an error object here,
+ or just treat as a case where there are no suitable servers? */
+ RETURN(NULL);
+ }
+
+ if (topology->type == MONGOC_TOPOLOGY_SINGLE) {
+ sd = (mongoc_server_description_t *)mongoc_set_get_item (topology->servers, 0);
+
+ if (sd->has_is_master) {
+ RETURN(sd);
+ } else {
+ RETURN(NULL);
+ }
+ }
+
+ _mongoc_array_init(&suitable_servers, sizeof(mongoc_server_description_t *));
+
+ mongoc_topology_description_suitable_servers(&suitable_servers, optype,
+ topology, read_pref, local_threshold_ms);
+ if (suitable_servers.len != 0) {
+ sd = _mongoc_array_index(&suitable_servers, mongoc_server_description_t*,
+ rand() % suitable_servers.len);
+ }
+
+ _mongoc_array_destroy (&suitable_servers);
+
+ RETURN(sd);
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * mongoc_topology_description_server_by_id --
+ *
+ * Get the server description for @id, if that server is present
+ * in @description. Otherwise, return NULL and fill out optional
+ * @error.
+ *
+ * NOTE: In most cases, caller should create a duplicate of the
+ * returned server description. Caller should hold the mutex on the
+ * owning topology object while calling this method and while using
+ * the returned reference.
+ *
+ * Returns:
+ * A mongoc_server_description_t *, or NULL.
+ *
+ * Side effects:
+ * Fills out optional @error if server not found.
+ *
+ *--------------------------------------------------------------------------
+ */
+
+mongoc_server_description_t *
+mongoc_topology_description_server_by_id (mongoc_topology_description_t *description,
+ uint32_t id,
+ bson_error_t *error)
+{
+ mongoc_server_description_t *sd;
+
+ BSON_ASSERT (description);
+
+ sd = (mongoc_server_description_t *)mongoc_set_get(description->servers, id);
+ if (!sd) {
+ bson_set_error (error,
+ MONGOC_ERROR_STREAM,
+ MONGOC_ERROR_STREAM_NOT_ESTABLISHED,
+ "Could not find description for node %u", id);
+ }
+
+ return sd;
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * _mongoc_topology_description_remove_server --
+ *
+ * If present, remove this server from this topology description.
+ *
+ * Returns:
+ * None.
+ *
+ * Side effects:
+ * Removes the server description from topology and destroys it.
+ *
+ *--------------------------------------------------------------------------
+ */
+static void
+_mongoc_topology_description_remove_server (mongoc_topology_description_t *description,
+ mongoc_server_description_t *server)
+{
+ BSON_ASSERT (description);
+ BSON_ASSERT (server);
+
+ mongoc_set_rm(description->servers, server->id);
+}
+
+typedef struct _mongoc_address_and_id_t {
+ const char *address; /* IN */
+ bool found; /* OUT */
+ uint32_t id; /* OUT */
+} mongoc_address_and_id_t;
+
+/* find the given server and stop iterating */
+static bool
+_mongoc_topology_description_has_server_cb (void *item,
+ void *ctx /* IN - OUT */)
+{
+ mongoc_server_description_t *server = (mongoc_server_description_t *)item;
+ mongoc_address_and_id_t *data = (mongoc_address_and_id_t *)ctx;
+
+ if (strcasecmp (data->address, server->connection_address) == 0) {
+ data->found = true;
+ data->id = server->id;
+ return false;
+ }
+ return true;
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
++ * _mongoc_topology_description_has_set_version --
++ *
++ * Whether @topology's max replica set version has been set.
++ *
++ * Returns:
++ * True if the max setVersion was ever set.
++ *
++ * Side effects:
++ * None.
++ *
++ *--------------------------------------------------------------------------
++ */
++static bool
++_mongoc_topology_description_has_set_version (mongoc_topology_description_t *td)
++{
++ return td->max_set_version != MONGOC_NO_SET_VERSION;
++}
++
++/*
++ *--------------------------------------------------------------------------
++ *
+ * _mongoc_topology_description_topology_has_server --
+ *
+ * Return true if @server is in @topology. If so, place its id in
+ * @id if given.
+ *
+ * Returns:
+ * True if server is in topology, false otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------------------
+ */
+static bool
+_mongoc_topology_description_has_server (mongoc_topology_description_t *description,
+ const char *address,
+ uint32_t *id /* OUT */)
+{
+ mongoc_address_and_id_t data;
+
+ BSON_ASSERT (description);
+ BSON_ASSERT (address);
+
+ data.address = address;
+ data.found = false;
+ mongoc_set_for_each (description->servers, _mongoc_topology_description_has_server_cb, &data);
+
+ if (data.found && id) {
+ *id = data.id;
+ }
+
+ return data.found;
+}
+
+typedef struct _mongoc_address_and_type_t
+{
+ const char *address;
+ mongoc_server_description_type_t type;
+} mongoc_address_and_type_t;
+
+static bool
+_mongoc_label_unknown_member_cb (void *item,
+ void *ctx)
+{
+ mongoc_server_description_t *server = (mongoc_server_description_t *)item;
+ mongoc_address_and_type_t *data = (mongoc_address_and_type_t *)ctx;
+
+ if (strcasecmp (server->connection_address, data->address) == 0 &&
+ server->type == MONGOC_SERVER_UNKNOWN) {
+ mongoc_server_description_set_state(server, data->type);
+ return false;
+ }
+ return true;
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * _mongoc_topology_description_label_unknown_member --
+ *
+ * Find the server description with the given @address and if its
+ * type is UNKNOWN, set its type to @type.
+ *
+ * Returns:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------------------
+ */
+static void
+_mongoc_topology_description_label_unknown_member (mongoc_topology_description_t *description,
+ const char *address,
+ mongoc_server_description_type_t type)
+{
+ mongoc_address_and_type_t data;
+
+ BSON_ASSERT (description);
+ BSON_ASSERT (address);
+
+ data.type = type;
+ data.address = address;
+
+ mongoc_set_for_each(description->servers, _mongoc_label_unknown_member_cb, &data);
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * _mongoc_topology_description_set_state --
+ *
+ * Change the state of this cluster and unblock things waiting
+ * on a change of topology type.
+ *
+ * Returns:
+ * None.
+ *
+ * Side effects:
+ * Unblocks anything waiting on this description to change states.
+ *
+ *--------------------------------------------------------------------------
+ */
+static void
+_mongoc_topology_description_set_state (mongoc_topology_description_t *description,
+ mongoc_topology_description_type_t type)
+{
+ description->type = type;
+}
+
+
+static void
+_update_rs_type (mongoc_topology_description_t *topology)
+{
+ if (_mongoc_topology_description_has_primary(topology)) {
+ _mongoc_topology_description_set_state(topology, MONGOC_TOPOLOGY_RS_WITH_PRIMARY);
+ }
+ else {
+ _mongoc_topology_description_set_state(topology, MONGOC_TOPOLOGY_RS_NO_PRIMARY);
+ }
+}
+
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * _mongoc_topology_description_check_if_has_primary --
+ *
+ * If there is a primary in topology, set topology
+ * type to RS_WITH_PRIMARY, otherwise set it to
+ * RS_NO_PRIMARY.
+ *
+ * Returns:
+ * None.
+ *
+ * Side effects:
+ * Changes the topology type.
+ *
+ *--------------------------------------------------------------------------
+ */
+static void
+_mongoc_topology_description_check_if_has_primary (mongoc_topology_description_t *topology,
+ mongoc_server_description_t *server)
+{
+ _update_rs_type (topology);
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * mongoc_topology_description_invalidate_server --
+ *
+ * Invalidate a server if a network error occurred while using it in
+ * another part of the client. Server description is set to type
+ * UNKNOWN and other parameters are reset to defaults.
+ *
+ * NOTE: this method should only be called while holding the mutex on
+ * the owning topology object.
+ *
+ *--------------------------------------------------------------------------
+ */
+void
+mongoc_topology_description_invalidate_server (mongoc_topology_description_t *topology,
+ uint32_t id)
+{
+ mongoc_server_description_t *sd;
+ bson_error_t error;
+
+ sd = mongoc_topology_description_server_by_id (topology, id, NULL);
+ mongoc_topology_description_handle_ismaster (topology, sd, NULL, 0, &error);
+
+ return;
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * mongoc_topology_description_add_server --
+ *
+ * Add the specified server to the cluster topology if it is not
+ * already a member. If @id, place its id in @id.
+ *
+ * NOTE: this method should only be called while holding the mutex on
+ * the owning topology object.
+ *
+ * Return:
+ * True if the server was added or already existed in the topology,
+ * false if an error occurred.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------------------
+ */
+bool
+mongoc_topology_description_add_server (mongoc_topology_description_t *topology,
+ const char *server,
+ uint32_t *id /* OUT */)
+{
+ uint32_t server_id;
+ mongoc_server_description_t *description;
+
+ BSON_ASSERT (topology);
+ BSON_ASSERT (server);
+
+ if (!_mongoc_topology_description_has_server(topology, server, &server_id)){
+
+ /* TODO this might not be an accurate count in all cases */
+ server_id = ++topology->max_server_id;
+
+ description = (mongoc_server_description_t *)bson_malloc0(sizeof *description);
+ mongoc_server_description_init(description, server, server_id);
+
+ mongoc_set_add(topology->servers, server_id, description);
+ }
+
+ if (id) {
+ *id = server_id;
+ }
+
+ return true;
+}
+
+
+static void
+_mongoc_topology_description_add_new_servers (
+ mongoc_topology_description_t *topology,
+ mongoc_server_description_t *server)
+{
+ bson_iter_t member_iter;
+ const bson_t *rs_members[3];
+ int i;
+
+ rs_members[0] = &server->hosts;
+ rs_members[1] = &server->arbiters;
+ rs_members[2] = &server->passives;
+
+ for (i = 0; i < 3; i++) {
+ bson_iter_init (&member_iter, rs_members[i]);
+
+ while (bson_iter_next (&member_iter)) {
+ mongoc_topology_description_add_server(topology, bson_iter_utf8(&member_iter, NULL), NULL);
+ }
+ }
+}
+
+typedef struct _mongoc_primary_and_topology_t {
+ mongoc_topology_description_t *topology;
+ mongoc_server_description_t *primary;
+} mongoc_primary_and_topology_t;
+
+/* invalidate old primaries */
+static bool
+_mongoc_topology_description_invalidate_primaries_cb (void *item,
+ void *ctx)
+{
+ mongoc_server_description_t *server = (mongoc_server_description_t *)item;
+ mongoc_primary_and_topology_t *data = (mongoc_primary_and_topology_t *)ctx;
+
+ if (server->id != data->primary->id &&
+ server->type == MONGOC_SERVER_RS_PRIMARY) {
+ mongoc_server_description_set_state (server, MONGOC_SERVER_UNKNOWN);
++ mongoc_server_description_set_set_version (server, MONGOC_NO_SET_VERSION);
+ mongoc_server_description_set_election_id (server, NULL);
+ }
+ return true;
+}
+
+
+/* Remove and destroy all replica set members not in primary's hosts lists */
+static void
+_mongoc_topology_description_remove_unreported_servers (
+ mongoc_topology_description_t *topology,
+ mongoc_server_description_t *primary)
+{
+ mongoc_array_t to_remove;
+ int i;
+ mongoc_server_description_t *member;
+ const char *address;
+
+ _mongoc_array_init (&to_remove,
+ sizeof (mongoc_server_description_t *));
+
+ /* Accumulate servers to be removed - do this before calling
+ * _mongoc_topology_description_remove_server, which could call
+ * mongoc_server_description_cleanup on the primary itself if it
+ * doesn't report its own connection_address in its hosts list.
+ * See hosts_differ_from_seeds.json */
+ for (i = 0; i < topology->servers->items_len; i++) {
+ member = (mongoc_server_description_t *)mongoc_set_get_item (topology->servers, i);
+ address = member->connection_address;
+ if (!mongoc_server_description_has_rs_member(primary, address)) {
+ _mongoc_array_append_val (&to_remove, member);
+ }
+ }
+
+ /* now it's safe to call _mongoc_topology_description_remove_server,
+ * even on the primary */
+ for (i = 0; i < to_remove.len; i++) {
+ member = _mongoc_array_index (
+ &to_remove, mongoc_server_description_t *, i);
+
+ _mongoc_topology_description_remove_server (topology, member);
+ }
+
+ _mongoc_array_destroy (&to_remove);
+}
+
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * _mongoc_topology_description_matches_me --
+ *
+ * Server Discovery And Monitoring Spec: "Removal from the topology of
+ * seed list members where the "me" property does not match the address
+ * used to connect prevents clients from being able to select a server,
+ * only to fail to re-select that server once the primary has responded.
+ *
+ * Returns:
+ * True if "me" matches "connection_address".
+ *
+ * Side Effects:
+ * None.
+ *
+ *--------------------------------------------------------------------------
+ */
+static bool
+_mongoc_topology_description_matches_me (mongoc_server_description_t *server)
+{
+ BSON_ASSERT (server->connection_address);
+
+ if (!server->me) {
+ /* "me" is unknown: consider it a match */
+ return true;
+ }
+
+ return strcasecmp (server->connection_address, server->me) == 0;
+}
+
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * _mongoc_update_rs_from_primary --
+ *
+ * First, determine that this is really the primary:
+ * -If this node isn't in the cluster, do nothing.
+ * -If the cluster's set name is null, set it to node's set name.
+ * Otherwise if the cluster's set name is different from node's,
+ * we found a rogue primary, so remove it from the cluster and
+ * check the cluster for a primary, then return.
+ * -If any of the members of cluster reports an address different
+ * from node's, node cannot be the primary.
+ * Now that we know this is the primary:
+ * -If any hosts, passives, or arbiters in node's description aren't
+ * in the cluster, add them as UNKNOWN servers.
+ * -If the cluster has any servers that aren't in node's description,
+ * remove and destroy them.
+ * Finally, check the cluster for the new primary.
+ *
+ * Returns:
+ * None.
+ *
+ * Side effects:
+ * Changes to the cluster, possible removal of cluster nodes.
+ *
+ *--------------------------------------------------------------------------
+ */
+static void
+_mongoc_topology_description_update_rs_from_primary (mongoc_topology_description_t *topology,
+ mongoc_server_description_t *server)
+{
+ mongoc_primary_and_topology_t data;
+
+ BSON_ASSERT (topology);
+ BSON_ASSERT (server);
+
+ if (!_mongoc_topology_description_has_server(topology, server->connection_address, NULL)) return;
+
+ /* If server->set_name was null this function wouldn't be called from
+ * mongoc_server_description_handle_ismaster(). static code analyzers however
+ * don't know that so we check for it explicitly. */
+ if (server->set_name) {
+ /* 'Server' can only be the primary if it has the right rs name */
+
+ if (!topology->set_name) {
+ topology->set_name = bson_strdup (server->set_name);
+ }
+ else if (strcmp(topology->set_name, server->set_name) != 0) {
+ _mongoc_topology_description_remove_server(topology, server);
+ _update_rs_type (topology);
+ return;
+ }
+ }
+
-+ if (mongoc_server_description_has_election_id (server)) {
++ if (mongoc_server_description_has_set_version (server) &&
++ mongoc_server_description_has_election_id (server)) {
+ /* Server Discovery And Monitoring Spec: "The client remembers the
+ * greatest electionId reported by a primary, and distrusts primaries
+ * with lesser electionIds. This prevents the client from oscillating
+ * between the old and new primary during a split-brain period."
+ */
+ if (_mongoc_topology_description_later_election (topology, server)) {
+ /* stale primary */
+ mongoc_topology_description_invalidate_server (topology, server->id);
+ _update_rs_type (topology);
+ return;
+ }
+
+ /* server's electionId >= topology's max electionId */
+ _mongoc_topology_description_set_max_election_id (topology, server);
+ }
+
++ if (mongoc_server_description_has_set_version (server) &&
++ (! _mongoc_topology_description_has_set_version (topology) ||
++ server->set_version > topology->max_set_version)) {
++ _mongoc_topology_description_set_max_set_version (topology, server);
++ }
++
+ /* 'Server' is the primary! Invalidate other primaries if found */
+ data.primary = server;
+ data.topology = topology;
+ mongoc_set_for_each(topology->servers, _mongoc_topology_description_invalidate_primaries_cb, &data);
+
+ /* Add to topology description any new servers primary knows about */
+ _mongoc_topology_description_add_new_servers (topology, server);
+
+ /* Remove from topology description any servers primary doesn't know about */
+ _mongoc_topology_description_remove_unreported_servers (topology, server);
+
+ /* Finally, set topology type */
+ _update_rs_type (topology);
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * _mongoc_topology_description_update_rs_without_primary --
+ *
+ * Update cluster's information when there is no primary.
+ *
+ * Returns:
+ * None.
+ *
+ * Side Effects:
+ * Alters cluster state, may remove node from cluster.
+ *
+ *--------------------------------------------------------------------------
+ */
+static void
+_mongoc_topology_description_update_rs_without_primary (mongoc_topology_description_t *topology,
+ mongoc_server_description_t *server)
+{
+ BSON_ASSERT (topology);
+ BSON_ASSERT (server);
+
+ if (!_mongoc_topology_description_has_server(topology, server->connection_address, NULL)) {
+ return;
+ }
+
+ /* make sure we're talking about the same replica set */
+ if (server->set_name) {
+ if (!topology->set_name) {
+ topology->set_name = bson_strdup(server->set_name);
+ }
+ else if (strcmp(topology->set_name, server->set_name)!= 0) {
+ _mongoc_topology_description_remove_server(topology, server);
+ return;
+ }
+ }
+
+ /* Add new servers that this replica set member knows about */
+ _mongoc_topology_description_add_new_servers (topology, server);
+
+ if (!_mongoc_topology_description_matches_me (server)) {
+ _mongoc_topology_description_remove_server(topology, server);
+ return;
+ }
+
+ /* If this server thinks there is a primary, label it POSSIBLE_PRIMARY */
+ if (server->current_primary) {
+ _mongoc_topology_description_label_unknown_member(topology,
+ server->current_primary,
+ MONGOC_SERVER_POSSIBLE_PRIMARY);
+ }
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * _mongoc_topology_description_update_rs_with_primary_from_member --
+ *
+ * Update cluster's information when there is a primary, but the
+ * update is coming from another replica set member.
+ *
+ * Returns:
+ * None.
+ *
+ * Side Effects:
+ * Alters cluster state.
+ *
+ *--------------------------------------------------------------------------
+ */
+static void
+_mongoc_topology_description_update_rs_with_primary_from_member (mongoc_topology_description_t *topology,
+ mongoc_server_description_t *server)
+{
+ BSON_ASSERT (topology);
+ BSON_ASSERT (server);
+
+ if (!_mongoc_topology_description_has_server(topology, server->connection_address, NULL)) {
+ return;
+ }
+
+ /* set_name should never be null here */
+ if (strcmp(topology->set_name, server->set_name) != 0) {
+ _mongoc_topology_description_remove_server(topology, server);
+ _update_rs_type (topology);
+ return;
+ }
+
+ if (!_mongoc_topology_description_matches_me (server)) {
+ _mongoc_topology_description_remove_server(topology, server);
+ return;
+ }
+
+ /* If there is no primary, label server's current_primary as the POSSIBLE_PRIMARY */
+ if (!_mongoc_topology_description_has_primary(topology) && server->current_primary) {
+ _mongoc_topology_description_set_state(topology, MONGOC_TOPOLOGY_RS_NO_PRIMARY);
+ _mongoc_topology_description_label_unknown_member(topology,
+ server->current_primary,
+ MONGOC_SERVER_POSSIBLE_PRIMARY);
+ }
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * _mongoc_topology_description_set_topology_type_to_sharded --
+ *
+ * Sets topology's type to SHARDED.
+ *
+ * Returns:
+ * None
+ *
+ * Side effects:
+ * Alter's topology's type
+ *
+ *--------------------------------------------------------------------------
+ */
+static void
+_mongoc_topology_description_set_topology_type_to_sharded (mongoc_topology_description_t *topology,
+ mongoc_server_description_t *server)
+{
+ _mongoc_topology_description_set_state(topology, MONGOC_TOPOLOGY_SHARDED);
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * _mongoc_topology_description_transition_unknown_to_rs_no_primary --
+ *
+ * Encapsulates transition from cluster state UNKNOWN to
+ * RS_NO_PRIMARY. Sets the type to RS_NO_PRIMARY,
+ * then updates the replica set accordingly.
+ *
+ * Returns:
+ * None.
+ *
+ * Side effects:
+ * Changes topology state.
+ *
+ *--------------------------------------------------------------------------
+ */
+static void
+_mongoc_topology_description_transition_unknown_to_rs_no_primary (mongoc_topology_description_t *topology,
+ mongoc_server_description_t *server)
+{
+ _mongoc_topology_description_set_state(topology, MONGOC_TOPOLOGY_RS_NO_PRIMARY);
+ _mongoc_topology_description_update_rs_without_primary(topology, server);
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * _mongoc_topology_description_remove_and_check_primary --
+ *
+ * Remove the server and check if the topology still has a primary.
+ *
+ * Returns:
+ * None.
+ *
+ * Side effects:
+ * Removes server from topology and destroys it.
+ *
+ *--------------------------------------------------------------------------
+ */
+static void
+_mongoc_topology_description_remove_and_check_primary (mongoc_topology_description_t *topology,
+ mongoc_server_description_t *server)
+{
+ _mongoc_topology_description_remove_server(topology, server);
+ _update_rs_type (topology);
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * _mongoc_topology_description_update_unknown_with_standalone --
+ *
+ * If the cluster doesn't contain this server, do nothing.
+ * Otherwise, if the topology only has one seed, change its
+ * type to SINGLE. If the topology has multiple seeds, it does not
+ * include us, so remove this server and destroy it.
+ *
+ * Returns:
+ * None.
+ *
+ * Side effects:
+ * Changes the topology type, might remove server from topology.
+ *
+ *--------------------------------------------------------------------------
+ */
+static void
+_mongoc_topology_description_update_unknown_with_standalone (mongoc_topology_description_t *topology,
+ mongoc_server_description_t *server)
+{
+ BSON_ASSERT (topology);
+ BSON_ASSERT (server);
+
+ if (!_mongoc_topology_description_has_server(topology, server->connection_address, NULL)) return;
+
+ if (topology->servers->items_len > 1) {
+ /* This cluster contains other servers, it cannot be a standalone. */
+ _mongoc_topology_description_remove_server(topology, server);
+ } else {
+ _mongoc_topology_description_set_state(topology, MONGOC_TOPOLOGY_SINGLE);
+ }
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * This table implements the 'ToplogyType' table outlined in the Server
+ * Discovery and Monitoring spec. Each row represents a server type,
+ * and each column represents the topology type. Given a current topology
+ * type T and a newly-observed server type S, use the function at
+ * state_transions[S][T] to transition to a new state.
+ *
+ * Rows should be read like so:
+ * { server type for this row
+ * UNKNOWN,
+ * SHARDED,
+ * RS_NO_PRIMARY,
+ * RS_WITH_PRIMARY
+ * }
+ *
+ *--------------------------------------------------------------------------
+ */
+
+typedef void (*transition_t)(mongoc_topology_description_t *topology,
+ mongoc_server_description_t *server);
+
+transition_t
+gSDAMTransitionTable[MONGOC_SERVER_DESCRIPTION_TYPES][MONGOC_TOPOLOGY_DESCRIPTION_TYPES] = {
+ { /* UNKNOWN */
+ NULL, /* MONGOC_TOPOLOGY_UNKNOWN */
+ NULL, /* MONGOC_TOPOLOGY_SHARDED */
+ NULL, /* MONGOC_TOPOLOGY_RS_NO_PRIMARY */
+ _mongoc_topology_description_check_if_has_primary /* MONGOC_TOPOLOGY_RS_WITH_PRIMARY */
+ },
+ { /* STANDALONE */
+ _mongoc_topology_description_update_unknown_with_standalone,
+ _mongoc_topology_description_remove_server,
+ _mongoc_topology_description_remove_server,
+ _mongoc_topology_description_remove_and_check_primary
+ },
+ { /* MONGOS */
+ _mongoc_topology_description_set_topology_type_to_sharded,
+ NULL,
+ _mongoc_topology_description_remove_server,
+ _mongoc_topology_description_remove_and_check_primary
+ },
+ { /* POSSIBLE_PRIMARY */
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ },
+ { /* PRIMARY */
+ _mongoc_topology_description_update_rs_from_primary,
+ _mongoc_topology_description_remove_server,
+ _mongoc_topology_description_update_rs_from_primary,
+ _mongoc_topology_description_update_rs_from_primary
+ },
+ { /* SECONDARY */
+ _mongoc_topology_description_transition_unknown_to_rs_no_primary,
+ _mongoc_topology_description_remove_server,
+ _mongoc_topology_description_update_rs_without_primary,
+ _mongoc_topology_description_update_rs_with_primary_from_member
+ },
+ { /* ARBITER */
+ _mongoc_topology_description_transition_unknown_to_rs_no_primary,
+ _mongoc_topology_description_remove_server,
+ _mongoc_topology_description_update_rs_without_primary,
+ _mongoc_topology_description_update_rs_with_primary_from_member
+ },
+ { /* RS_OTHER */
+ _mongoc_topology_description_transition_unknown_to_rs_no_primary,
+ _mongoc_topology_description_remove_server,
+ _mongoc_topology_description_update_rs_without_primary,
+ _mongoc_topology_description_update_rs_with_primary_from_member
+ },
+ { /* RS_GHOST */
+ NULL,
+ _mongoc_topology_description_remove_server,
+ NULL,
+ _mongoc_topology_description_check_if_has_primary
+ }
+};
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * mongoc_topology_description_handle_ismaster --
+ *
+ * Handle an ismaster. This is called by the background SDAM process,
+ * and by client when invalidating servers.
+ *
+ * NOTE: this method should only be called while holding the mutex on
+ * the owning topology object.
+ *
+ *--------------------------------------------------------------------------
+ */
+
+void
+mongoc_topology_description_handle_ismaster (
+ mongoc_topology_description_t *topology,
+ mongoc_server_description_t *sd,
+ const bson_t *ismaster_response,
+ int64_t rtt_msec,
+ bson_error_t *error)
+{
+ BSON_ASSERT (topology);
+ BSON_ASSERT (sd);
+
+ if (!_mongoc_topology_description_has_server (topology,
+ sd->connection_address,
+ NULL)) {
+ MONGOC_DEBUG("Couldn't find %s in Topology Description", sd->connection_address);
+ return;
+ }
+
+ mongoc_server_description_handle_ismaster (sd, ismaster_response, rtt_msec,
+ error);
+
+ if (gSDAMTransitionTable[sd->type][topology->type]) {
+ TRACE("Transitioning to %d for %d", topology->type, sd->type);
+ gSDAMTransitionTable[sd->type][topology->type] (topology, sd);
+ } else {
+ TRACE("No transition entry to %d for %d", topology->type, sd->type);
+ }
+}
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-topology-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-topology-private.h
new file mode 100644
index 0000000..fc7f982
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-topology-private.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2014 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_TOPOLOGY_PRIVATE_H
+#define MONGOC_TOPOLOGY_PRIVATE_H
+
+#include "mongoc-read-prefs-private.h"
+#include "mongoc-topology-scanner-private.h"
+#include "mongoc-server-description-private.h"
+#include "mongoc-topology-description-private.h"
+#include "mongoc-thread-private.h"
+#include "mongoc-uri.h"
+
+#define MONGOC_TOPOLOGY_MIN_HEARTBEAT_FREQUENCY_MS 500
+#define MONGOC_TOPOLOGY_SOCKET_CHECK_INTERVAL_MS 5000
+#define MONGOC_TOPOLOGY_COOLDOWN_MS 5000
+#define MONGOC_TOPOLOGY_SERVER_SELECTION_TIMEOUT_MS 30000
+#define MONGOC_TOPOLOGY_HEARTBEAT_FREQUENCY_MS_MULTI_THREADED 10000
+#define MONGOC_TOPOLOGY_HEARTBEAT_FREQUENCY_MS_SINGLE_THREADED 60000
+
+typedef enum {
+ MONGOC_TOPOLOGY_BG_OFF,
+ MONGOC_TOPOLOGY_BG_RUNNING,
+ MONGOC_TOPOLOGY_BG_SHUTTING_DOWN,
+} mongoc_topology_bg_state_t;
+
+typedef struct _mongoc_topology_t
+{
+ mongoc_topology_description_t description;
+ mongoc_uri_t *uri;
+ mongoc_topology_scanner_t *scanner;
+ bool server_selection_try_once;
+
+ int64_t last_scan;
+ int64_t connect_timeout_msec;
+ int64_t server_selection_timeout_msec;
+ int64_t heartbeat_msec;
+
+ mongoc_mutex_t mutex;
+ mongoc_cond_t cond_client;
+ mongoc_cond_t cond_server;
+ mongoc_thread_t thread;
+
+ mongoc_topology_bg_state_t bg_thread_state;
+ bool scan_requested;
+ bool scanning;
+ bool got_ismaster;
+ bool shutdown_requested;
+ bool single_threaded;
+ bool stale;
+} mongoc_topology_t;
+
+mongoc_topology_t *
+mongoc_topology_new (const mongoc_uri_t *uri,
+ bool single_threaded);
+
+void
+mongoc_topology_destroy (mongoc_topology_t *topology);
+
+mongoc_server_description_t *
+mongoc_topology_select (mongoc_topology_t *topology,
+ mongoc_ss_optype_t optype,
+ const mongoc_read_prefs_t *read_prefs,
+ int64_t local_threshold_msec,
+ bson_error_t *error);
+
+mongoc_server_description_t *
+mongoc_topology_server_by_id (mongoc_topology_t *topology,
+ uint32_t id,
+ bson_error_t *error);
+
+bool mongoc_topology_get_server_type (mongoc_topology_t *topology,
+ uint32_t id,
+ mongoc_topology_description_type_t *topology_type,
+ mongoc_server_description_type_t *server_type,
+ bson_error_t *error);
+
+void
+mongoc_topology_request_scan (mongoc_topology_t *topology);
+
+void
+mongoc_topology_invalidate_server (mongoc_topology_t *topology,
+ uint32_t id);
+
+int64_t
+mongoc_topology_server_timestamp (mongoc_topology_t *topology,
+ uint32_t id);
+
+#endif
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology-scanner-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology-scanner-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-topology-scanner-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-topology-scanner-private.h
new file mode 100644
index 0000000..c8517ac
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology-scanner-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-topology-scanner-private.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2014 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_TOPOLOGY_SCANNER_PRIVATE_H
+#define MONGOC_TOPOLOGY_SCANNER_PRIVATE_H
+
+/* TODO: rename to TOPOLOGY scanner */
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include <bson.h>
+#include "mongoc-async-private.h"
+#include "mongoc-async-cmd-private.h"
+#include "mongoc-host-list.h"
+
+BSON_BEGIN_DECLS
+
+typedef void (*mongoc_topology_scanner_cb_t)(uint32_t id,
+ const bson_t *bson,
+ int64_t rtt,
+ void *data,
+ bson_error_t *error);
+
+struct mongoc_topology_scanner;
+
+typedef struct mongoc_topology_scanner_node
+{
+ uint32_t id;
+ mongoc_async_cmd_t *cmd;
+ mongoc_stream_t *stream;
+ int64_t timestamp;
+ int64_t last_used;
+ int64_t last_failed;
+ bool has_auth;
+ mongoc_host_list_t host;
+ struct addrinfo *dns_results;
+ struct addrinfo *current_dns_result;
+ struct mongoc_topology_scanner *ts;
+
+ struct mongoc_topology_scanner_node *next;
+ struct mongoc_topology_scanner_node *prev;
+
+ bool retired;
+ bson_error_t last_error;
+} mongoc_topology_scanner_node_t;
+
+typedef struct mongoc_topology_scanner
+{
+ mongoc_async_t *async;
+ mongoc_topology_scanner_node_t *nodes;
+ uint32_t seq;
+ bson_t ismaster_cmd;
+ mongoc_topology_scanner_cb_t cb;
+ void *cb_data;
+ bool in_progress;
+ const mongoc_uri_t *uri;
+ mongoc_async_cmd_setup_t setup;
+ mongoc_stream_initiator_t initiator;
+ void *initiator_context;
+
+#ifdef MONGOC_ENABLE_SSL
+ mongoc_ssl_opt_t *ssl_opts;
+#endif
+} mongoc_topology_scanner_t;
+
+mongoc_topology_scanner_t *
+mongoc_topology_scanner_new (const mongoc_uri_t *uri,
+ mongoc_topology_scanner_cb_t cb,
+ void *data);
+
+void
+mongoc_topology_scanner_destroy (mongoc_topology_scanner_t *ts);
+
+mongoc_topology_scanner_node_t *
+mongoc_topology_scanner_add (mongoc_topology_scanner_t *ts,
+ const mongoc_host_list_t *host,
+ uint32_t id);
+
+void
+mongoc_topology_scanner_add_and_scan (mongoc_topology_scanner_t *ts,
+ const mongoc_host_list_t *host,
+ uint32_t id,
+ int64_t timeout_msec);
+
+void
+mongoc_topology_scanner_node_retire (mongoc_topology_scanner_node_t *node);
+
+void
+mongoc_topology_scanner_node_disconnect (mongoc_topology_scanner_node_t *node,
+ bool failed);
+
+void
+mongoc_topology_scanner_node_destroy (mongoc_topology_scanner_node_t *node,
+ bool failed);
+
+void
+mongoc_topology_scanner_start (mongoc_topology_scanner_t *ts,
+ int32_t timeout_msec,
+ bool obey_cooldown);
+
+bool
+mongoc_topology_scanner_work (mongoc_topology_scanner_t *ts,
+ int32_t timeout_msec);
+
+void
+mongoc_topology_scanner_sum_errors (mongoc_topology_scanner_t *ts,
+ bson_error_t *error);
+
+void
+mongoc_topology_scanner_reset (mongoc_topology_scanner_t *ts);
+
+bool
+mongoc_topology_scanner_node_setup (mongoc_topology_scanner_node_t *node,
+ bson_error_t *error);
+
+mongoc_topology_scanner_node_t *
+mongoc_topology_scanner_get_node (mongoc_topology_scanner_t *ts,
+ uint32_t id);
+
+bool
+mongoc_topology_scanner_has_node_for_host (mongoc_topology_scanner_t *ts,
+ mongoc_host_list_t *host);
+
+void
+mongoc_topology_scanner_set_stream_initiator (mongoc_topology_scanner_t *ts,
+ mongoc_stream_initiator_t si,
+ void *ctx);
+
+#ifdef MONGOC_ENABLE_SSL
+void
+mongoc_topology_scanner_set_ssl_opts (mongoc_topology_scanner_t *ts,
+ mongoc_ssl_opt_t *opts);
+#endif
+
+BSON_END_DECLS
+
+#endif /* MONGOC_TOPOLOGY_SCANNER_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology.c b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology.c
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-topology.c b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-topology.c
new file mode 100644
index 0000000..be7eb9a
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology.c
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-topology.c
@@ -0,0 +1,915 @@
+/*
+ * Copyright 2014 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mongoc-error.h"
+#include "mongoc-topology-private.h"
+#include "mongoc-uri-private.h"
+#include "mongoc-util-private.h"
+
+#include "utlist.h"
+
+static void
+_mongoc_topology_background_thread_stop (mongoc_topology_t *topology);
+
+static void
+_mongoc_topology_background_thread_start (mongoc_topology_t *topology);
+
+static void
+_mongoc_topology_request_scan (mongoc_topology_t *topology);
+
+static bool
+_mongoc_topology_reconcile_add_nodes (void *item,
+ void *ctx)
+{
+ mongoc_server_description_t *sd = item;
+ mongoc_topology_t *topology = (mongoc_topology_t *)ctx;
+ mongoc_topology_scanner_t *scanner = topology->scanner;
+
+ /* quickly search by id, then check if a node for this host was retired in
+ * this scan. */
+ if (! mongoc_topology_scanner_get_node (scanner, sd->id) &&
+ ! mongoc_topology_scanner_has_node_for_host (scanner, &sd->host)) {
+ mongoc_topology_scanner_add_and_scan (scanner, &sd->host, sd->id,
+ topology->connect_timeout_msec);
+ }
+
+ return true;
+}
+
+void
+mongoc_topology_reconcile (mongoc_topology_t *topology) {
+ mongoc_topology_scanner_node_t *ele, *tmp;
+ mongoc_topology_description_t *description;
+ mongoc_topology_scanner_t *scanner;
+
+ description = &topology->description;
+ scanner = topology->scanner;
+
+ /* Add newly discovered nodes */
+ mongoc_set_for_each(description->servers,
+ _mongoc_topology_reconcile_add_nodes,
+ topology);
+
+ /* Remove removed nodes */
+ DL_FOREACH_SAFE (scanner->nodes, ele, tmp) {
+ if (!mongoc_topology_description_server_by_id (description, ele->id, NULL)) {
+ mongoc_topology_scanner_node_retire (ele);
+ }
+ }
+}
+/*
+ *-------------------------------------------------------------------------
+ *
+ * _mongoc_topology_scanner_cb --
+ *
+ * Callback method to handle ismaster responses received by async
+ * command objects.
+ *
+ * NOTE: This method locks the given topology's mutex.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+void
+_mongoc_topology_scanner_cb (uint32_t id,
+ const bson_t *ismaster_response,
+ int64_t rtt_msec,
+ void *data,
+ bson_error_t *error)
+{
+ mongoc_topology_t *topology;
+ mongoc_server_description_t *sd;
+
+ BSON_ASSERT (data);
+
+ topology = (mongoc_topology_t *)data;
+
+ if (rtt_msec >= 0) {
+ /* If the scanner failed to create a socket for this server, that means
+ * we're in scanner_start, which means we're under the mutex. So don't
+ * take the mutex for rtt < 0 */
+
+ mongoc_mutex_lock (&topology->mutex);
+ }
+
+ sd = mongoc_topology_description_server_by_id (&topology->description, id,
+ NULL);
+
+ if (sd) {
+ mongoc_topology_description_handle_ismaster (&topology->description, sd,
+ ismaster_response, rtt_msec,
+ error);
+
+ /* The processing of the ismaster results above may have added/removed
+ * server descriptions. We need to reconcile that with our monitoring agents
+ */
+
+ mongoc_topology_reconcile(topology);
+
+ /* TODO only wake up all clients if we found any topology changes */
+ mongoc_cond_broadcast (&topology->cond_client);
+ }
+
+ if (rtt_msec >= 0) {
+ mongoc_mutex_unlock (&topology->mutex);
+ }
+}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * mongoc_topology_new --
+ *
+ * Creates and returns a new topology object.
+ *
+ * Returns:
+ * A new topology object.
+ *
+ * Side effects:
+ * None.
+ *
+ *-------------------------------------------------------------------------
+ */
+mongoc_topology_t *
+mongoc_topology_new (const mongoc_uri_t *uri,
+ bool single_threaded)
+{
+ mongoc_topology_t *topology;
+ mongoc_topology_description_type_t init_type;
+ uint32_t id;
+ const mongoc_host_list_t *hl;
+
+ BSON_ASSERT (uri);
+
+ topology = (mongoc_topology_t *)bson_malloc0(sizeof *topology);
+
+ /*
+ * Not ideal, but there's no great way to do this.
+ * Base on the URI, we assume:
+ * - if we've got a replicaSet name, initialize to RS_NO_PRIMARY
+ * - otherwise, if the seed list has a single host, initialize to SINGLE
+ * - everything else gets initialized to UNKNOWN
+ */
+ if (mongoc_uri_get_replica_set(uri)) {
+ init_type = MONGOC_TOPOLOGY_RS_NO_PRIMARY;
+ } else {
+ hl = mongoc_uri_get_hosts(uri);
+ if (hl->next) {
+ init_type = MONGOC_TOPOLOGY_UNKNOWN;
+ } else {
+ init_type = MONGOC_TOPOLOGY_SINGLE;
+ }
+ }
+
+ mongoc_topology_description_init(&topology->description, init_type);
+ topology->description.set_name = bson_strdup(mongoc_uri_get_replica_set(uri));
+
+ topology->uri = mongoc_uri_copy (uri);
+ topology->scanner = mongoc_topology_scanner_new (topology->uri,
+ _mongoc_topology_scanner_cb,
+ topology);
+ topology->single_threaded = single_threaded;
+ if (single_threaded) {
+ /* Server Selection Spec:
+ *
+ * "Single-threaded drivers MUST provide a "serverSelectionTryOnce"
+ * mode, in which the driver scans the topology exactly once after
+ * server selection fails, then either selects a server or raises an
+ * error.
+ *
+ * "The serverSelectionTryOnce option MUST be true by default."
+ */
+ topology->server_selection_try_once = mongoc_uri_get_option_as_bool (
+ uri,
+ "serverselectiontryonce",
+ true);
+ } else {
+ topology->server_selection_try_once = false;
+ }
+
+ topology->server_selection_timeout_msec = mongoc_uri_get_option_as_int32(
+ topology->uri, "serverselectiontimeoutms",
+ MONGOC_TOPOLOGY_SERVER_SELECTION_TIMEOUT_MS);
+
+ /* Total time allowed to check a server is connectTimeoutMS.
+ * Server Discovery And Monitoring Spec:
+ *
+ * "The socket used to check a server MUST use the same connectTimeoutMS as
+ * regular sockets. Multi-threaded clients SHOULD set monitoring sockets'
+ * socketTimeoutMS to the connectTimeoutMS."
+ */
+ topology->connect_timeout_msec = mongoc_uri_get_option_as_int32(
+ topology->uri, "connecttimeoutms",
+ MONGOC_DEFAULT_CONNECTTIMEOUTMS);
+
+ topology->heartbeat_msec = mongoc_uri_get_option_as_int32(
+ topology->uri, "heartbeatfrequencyms",
+ (single_threaded ? MONGOC_TOPOLOGY_HEARTBEAT_FREQUENCY_MS_SINGLE_THREADED :
+ MONGOC_TOPOLOGY_HEARTBEAT_FREQUENCY_MS_MULTI_THREADED)
+ );
+
+ mongoc_mutex_init (&topology->mutex);
+ mongoc_cond_init (&topology->cond_client);
+ mongoc_cond_init (&topology->cond_server);
+
+ for ( hl = mongoc_uri_get_hosts (uri); hl; hl = hl->next) {
+ mongoc_topology_description_add_server (&topology->description,
+ hl->host_and_port,
+ &id);
+ mongoc_topology_scanner_add (topology->scanner, hl, id);
+ }
+
+ if (! topology->single_threaded) {
+ _mongoc_topology_background_thread_start (topology);
+ }
+
+ return topology;
+}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * mongoc_topology_destroy --
+ *
+ * Free the memory associated with this topology object.
+ *
+ * Returns:
+ * None.
+ *
+ * Side effects:
+ * @topology will be cleaned up.
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+mongoc_topology_destroy (mongoc_topology_t *topology)
+{
+ if (!topology) {
+ return;
+ }
+
+ _mongoc_topology_background_thread_stop (topology);
+
+ mongoc_uri_destroy (topology->uri);
+ mongoc_topology_description_destroy(&topology->description);
+ mongoc_topology_scanner_destroy (topology->scanner);
+ mongoc_cond_destroy (&topology->cond_client);
+ mongoc_cond_destroy (&topology->cond_server);
+ mongoc_mutex_destroy (&topology->mutex);
+
+ bson_free(topology);
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * _mongoc_topology_run_scanner --
+ *
+ * Not threadsafe, the expectation is that we're either single
+ * threaded or only the background thread runs scans.
+ *
+ * Crank the underlying scanner until we've timed out or finished.
+ *
+ * Returns:
+ * true if there is more work to do, false otherwise
+ *
+ *--------------------------------------------------------------------------
+ */
+static bool
+_mongoc_topology_run_scanner (mongoc_topology_t *topology,
+ int64_t work_msec)
+{
+ int64_t now;
+ int64_t expire_at;
+ bool keep_going = true;
+
+ now = bson_get_monotonic_time ();
+ expire_at = now + (work_msec * 1000);
+
+ /* while there is more work to do and we haven't timed out */
+ while (keep_going && now <= expire_at) {
+ keep_going = mongoc_topology_scanner_work (topology->scanner, (expire_at - now) / 1000);
+
+ if (keep_going) {
+ now = bson_get_monotonic_time ();
+ }
+ }
+
+ return keep_going;
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * _mongoc_topology_do_blocking_scan --
+ *
+ * Monitoring entry for single-threaded use case. Assumes the caller
+ * has checked that it's the right time to scan.
+ *
+ *--------------------------------------------------------------------------
+ */
+static void
+_mongoc_topology_do_blocking_scan (mongoc_topology_t *topology, bson_error_t *error) {
+ mongoc_topology_scanner_start (topology->scanner,
+ topology->connect_timeout_msec,
+ true);
+
+ while (_mongoc_topology_run_scanner (topology,
+ topology->connect_timeout_msec)) {}
+
+ /* Aggregate all scanner errors, if any */
+ mongoc_topology_scanner_sum_errors (topology->scanner, error);
+ /* "retired" nodes can be checked again in the next scan */
+ mongoc_topology_scanner_reset (topology->scanner);
+ topology->last_scan = bson_get_monotonic_time ();
+ topology->stale = false;
+}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * mongoc_topology_select --
+ *
+ * Selects a server description for an operation based on @optype
+ * and @read_prefs.
+ *
+ * NOTE: this method returns a copy of the original server
+ * description. Callers must own and clean up this copy.
+ *
+ * NOTE: this method locks and unlocks @topology's mutex.
+ *
+ * Parameters:
+ * @topology: The topology.
+ * @optype: Whether we are selecting for a read or write operation.
+ * @read_prefs: Required, the read preferences for the command.
+ * @local_threshold_ms: Maximum latency *beyond* the nearest server
+ * among which to randomly select servers. See Server Selection
+ * Spec.
+ * @error: Required, out pointer for error info.
+ *
+ * Returns:
+ * A mongoc_server_description_t, or NULL on failure, in which case
+ * @error will be set.
+ *
+ * Side effects:
+ * @error may be set.
+ *
+ *-------------------------------------------------------------------------
+ */
+mongoc_server_description_t *
+mongoc_topology_select (mongoc_topology_t *topology,
+ mongoc_ss_optype_t optype,
+ const mongoc_read_prefs_t *read_prefs,
+ int64_t local_threshold_ms,
+ bson_error_t *error)
+{
+ int r;
+ mongoc_server_description_t *selected_server = NULL;
+ bool try_once;
+ int64_t sleep_usec;
+ bool tried_once;
+ bson_error_t scanner_error = { 0 };
+
+ /* These names come from the Server Selection Spec pseudocode */
+ int64_t loop_start; /* when we entered this function */
+ int64_t loop_end; /* when we last completed a loop (single-threaded) */
+ int64_t scan_ready; /* the soonest we can do a blocking scan */
+ int64_t next_update; /* the latest we must do a blocking scan */
+ int64_t expire_at; /* when server selection timeout expires */
+
+ BSON_ASSERT (topology);
+
+ try_once = topology->server_selection_try_once;
+ loop_start = loop_end = bson_get_monotonic_time ();
+ expire_at = loop_start
+ + ((int64_t) topology->server_selection_timeout_msec * 1000);
+
+ if (topology->single_threaded) {
+ tried_once = false;
+ next_update = topology->last_scan + topology->heartbeat_msec * 1000;
+ if (next_update < loop_start) {
+ /* we must scan now */
+ topology->stale = true;
+ }
+
+ /* until we find a server or time out */
+ for (;;) {
+ if (topology->stale) {
+ /* how soon are we allowed to scan? */
+ scan_ready = topology->last_scan
+ + MONGOC_TOPOLOGY_MIN_HEARTBEAT_FREQUENCY_MS * 1000;
+
+ if (scan_ready > expire_at && !try_once) {
+ /* selection timeout will expire before min heartbeat passes */
+ bson_set_error(error,
+ MONGOC_ERROR_SERVER_SELECTION,
+ MONGOC_ERROR_SERVER_SELECTION_FAILURE,
+ "No suitable servers found: "
+ "`minheartbeatfrequencyms` not reached yet");
+ goto FAIL;
+ }
+
+ sleep_usec = scan_ready - loop_end;
+ if (sleep_usec > 0) {
+ _mongoc_usleep (sleep_usec);
+ }
+
+ /* takes up to connectTimeoutMS. sets "last_scan", clears "stale" */
+ _mongoc_topology_do_blocking_scan (topology, &scanner_error);
+ tried_once = true;
+ }
+
+ selected_server = mongoc_topology_description_select(&topology->description,
+ optype,
+ read_prefs,
+ local_threshold_ms);
+
+ if (selected_server) {
+ return mongoc_server_description_new_copy(selected_server);
+ }
+
+ topology->stale = true;
+
+ if (try_once) {
+ if (tried_once) {
+ if (scanner_error.code) {
+ bson_set_error(error,
+ MONGOC_ERROR_SERVER_SELECTION,
+ MONGOC_ERROR_SERVER_SELECTION_FAILURE,
+ "No suitable servers found "
+ "(`serverselectiontryonce` set): %s", scanner_error.message);
+ } else {
+ bson_set_error(error,
+ MONGOC_ERROR_SERVER_SELECTION,
+ MONGOC_ERROR_SERVER_SELECTION_FAILURE,
+ "No suitable servers found "
+ "(`serverselectiontryonce` set)");
+ }
+ goto FAIL;
+ }
+ } else {
+ loop_end = bson_get_monotonic_time ();
+
+ if (loop_end > expire_at) {
+ /* no time left in server_selection_timeout_msec */
+ bson_set_error(error,
+ MONGOC_ERROR_SERVER_SELECTION,
+ MONGOC_ERROR_SERVER_SELECTION_FAILURE,
+ "No suitable servers found: "
+ "`serverselectiontimeoutms` timed out");
+ goto FAIL;
+ }
+ }
+ }
+ }
+
+ /* With background thread */
+ /* we break out when we've found a server or timed out */
+ for (;;) {
+ mongoc_mutex_lock (&topology->mutex);
+ selected_server = mongoc_topology_description_select(&topology->description,
+ optype,
+ read_prefs,
+ local_threshold_ms);
+
+ if (! selected_server) {
+ _mongoc_topology_request_scan (topology);
+
+ r = mongoc_cond_timedwait (&topology->cond_client, &topology->mutex,
+ (expire_at - loop_start) / 1000);
+
+ mongoc_mutex_unlock (&topology->mutex);
+
+#ifdef _WIN32
+ if (r == WSAETIMEDOUT) {
+#else
+ if (r == ETIMEDOUT) {
+#endif
+ /* handle timeouts */
+ bson_set_error(error,
+ MONGOC_ERROR_SERVER_SELECTION,
+ MONGOC_ERROR_SERVER_SELECTION_FAILURE,
+ "Timed out trying to select a server");
+ goto FAIL;
+ } else if (r) {
+ bson_set_error(error,
+ MONGOC_ERROR_SERVER_SELECTION,
+ MONGOC_ERROR_SERVER_SELECTION_FAILURE,
+ "Unknown error '%d' received while waiting on thread condition",
+ r);
+ goto FAIL;
+ }
+
+ loop_start = bson_get_monotonic_time ();
+
+ if (loop_start > expire_at) {
+ bson_set_error(error,
+ MONGOC_ERROR_SERVER_SELECTION,
+ MONGOC_ERROR_SERVER_SELECTION_FAILURE,
+ "Timed out trying to select a server");
+ goto FAIL;
+ }
+ } else {
+ selected_server = mongoc_server_description_new_copy(selected_server);
+ mongoc_mutex_unlock (&topology->mutex);
+ return selected_server;
+ }
+ }
+
+FAIL:
+ topology->stale = true;
+
+ return NULL;
+}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * mongoc_topology_server_by_id --
+ *
+ * Get the server description for @id, if that server is present
+ * in @description. Otherwise, return NULL and fill out the optional
+ * @error.
+ *
+ * NOTE: this method returns a copy of the original server
+ * description. Callers must own and clean up this copy.
+ *
+ * NOTE: this method locks and unlocks @topology's mutex.
+ *
+ * Returns:
+ * A mongoc_server_description_t, or NULL.
+ *
+ * Side effects:
+ * Fills out optional @error if server not found.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+mongoc_server_description_t *
+mongoc_topology_server_by_id (mongoc_topology_t *topology,
+ uint32_t id,
+ bson_error_t *error)
+{
+ mongoc_server_description_t *sd;
+
+ mongoc_mutex_lock (&topology->mutex);
+
+ sd = mongoc_server_description_new_copy (
+ mongoc_topology_description_server_by_id (&topology->description,
+ id,
+ error));
+
+ mongoc_mutex_unlock (&topology->mutex);
+
+ return sd;
+}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * mongoc_topology_get_server_type --
+ *
+ * Get the topology type, and the server type for @id, if that server
+ * is present in @description. Otherwise, return false and fill out
+ * the optional @error.
+ *
+ * NOTE: this method locks and unlocks @topology's mutex.
+ *
+ * Returns:
+ * True on success.
+ *
+ * Side effects:
+ * Fills out optional @error if server not found.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+bool
+mongoc_topology_get_server_type (
+ mongoc_topology_t *topology,
+ uint32_t id,
+ mongoc_topology_description_type_t *topology_type /* OUT */,
+ mongoc_server_description_type_t *server_type /* OUT */,
+ bson_error_t *error)
+{
+ mongoc_server_description_t *sd;
+ bool ret = false;
+
+ BSON_ASSERT (topology);
+ BSON_ASSERT (topology_type);
+ BSON_ASSERT (server_type);
+
+ mongoc_mutex_lock (&topology->mutex);
+
+ sd = mongoc_topology_description_server_by_id (&topology->description,
+ id,
+ error);
+
+ if (sd) {
+ *topology_type = topology->description.type;
+ *server_type = sd->type;
+ ret = true;
+ }
+
+ mongoc_mutex_unlock (&topology->mutex);
+
+ return ret;
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * _mongoc_topology_request_scan --
+ *
+ * Non-locking variant
+ *
+ *--------------------------------------------------------------------------
+ */
+
+static void
+_mongoc_topology_request_scan (mongoc_topology_t *topology)
+{
+ topology->scan_requested = true;
+
+ mongoc_cond_signal (&topology->cond_server);
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * mongoc_topology_request_scan --
+ *
+ * Used from within the driver to request an immediate topology check.
+ *
+ * NOTE: this method locks and unlocks @topology's mutex.
+ *
+ *--------------------------------------------------------------------------
+ */
+
+void
+mongoc_topology_request_scan (mongoc_topology_t *topology)
+{
+ mongoc_mutex_lock (&topology->mutex);
+
+ _mongoc_topology_request_scan (topology);
+
+ mongoc_mutex_unlock (&topology->mutex);
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * mongoc_topology_invalidate_server --
+ *
+ * Invalidate the given server after receiving a network error in
+ * another part of the client.
+ *
+ * NOTE: this method uses @topology's mutex.
+ *
+ *--------------------------------------------------------------------------
+ */
+void
+mongoc_topology_invalidate_server (mongoc_topology_t *topology,
+ uint32_t id)
+{
+ mongoc_mutex_lock (&topology->mutex);
+ mongoc_topology_description_invalidate_server (&topology->description, id);
+ mongoc_mutex_unlock (&topology->mutex);
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * mongoc_topology_server_timestamp --
+ *
+ * Return the topology's scanner's timestamp for the given server,
+ * or -1 if there is no scanner node for the given server.
+ *
+ * NOTE: this method uses @topology's mutex.
+ *
+ * Returns:
+ * Timestamp, or -1
+ *
+ *--------------------------------------------------------------------------
+ */
+int64_t
+mongoc_topology_server_timestamp (mongoc_topology_t *topology,
+ uint32_t id)
+{
+ mongoc_topology_scanner_node_t *node;
+ int64_t timestamp = -1;
+
+ mongoc_mutex_lock (&topology->mutex);
+
+ node = mongoc_topology_scanner_get_node (topology->scanner, id);
+ if (node) {
+ timestamp = node->timestamp;
+ }
+
+ mongoc_mutex_unlock (&topology->mutex);
+
+ return timestamp;
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * _mongoc_topology_run_background --
+ *
+ * The background topology monitoring thread runs in this loop.
+ *
+ * NOTE: this method uses @topology's mutex.
+ *
+ *--------------------------------------------------------------------------
+ */
+static
+void * _mongoc_topology_run_background (void *data)
+{
+ mongoc_topology_t *topology;
+ int64_t now;
+ int64_t last_scan;
+ int64_t timeout;
+ int64_t force_timeout;
+ int r;
+
+ BSON_ASSERT (data);
+
+ last_scan = 0;
+ topology = (mongoc_topology_t *)data;
+ /* we exit this loop when shutdown_requested, or on error */
+ for (;;) {
+ /* unlocked after starting a scan or after breaking out of the loop */
+ mongoc_mutex_lock (&topology->mutex);
+
+ /* we exit this loop on error, or when we should scan immediately */
+ for (;;) {
+ if (topology->shutdown_requested) goto DONE;
+
+ now = bson_get_monotonic_time ();
+
+ if (last_scan == 0) {
+ /* set up the "last scan" as exactly long enough to force an
+ * immediate scan on the first pass */
+ last_scan = now - (topology->heartbeat_msec * 1000);
+ }
+
+ timeout = topology->heartbeat_msec - ((now - last_scan) / 1000);
+
+ /* if someone's specifically asked for a scan, use a shorter interval */
+ if (topology->scan_requested) {
+ force_timeout = MONGOC_TOPOLOGY_MIN_HEARTBEAT_FREQUENCY_MS - ((now - last_scan) / 1000);
+
+ timeout = BSON_MIN (timeout, force_timeout);
+ }
+
+ /* if we can start scanning, do so immediately */
+ if (timeout <= 0) {
+ mongoc_topology_scanner_start (topology->scanner,
+ topology->connect_timeout_msec,
+ false);
+ break;
+ } else {
+ /* otherwise wait until someone:
+ * o requests a scan
+ * o we time out
+ * o requests a shutdown
+ */
+ r = mongoc_cond_timedwait (&topology->cond_server, &topology->mutex, timeout);
+
+#ifdef _WIN32
+ if (! (r == 0 || r == WSAETIMEDOUT)) {
+#else
+ if (! (r == 0 || r == ETIMEDOUT)) {
+#endif
+ /* handle errors */
+ goto DONE;
+ }
+
+ /* if we timed out, or were woken up, check if it's time to scan
+ * again, or bail out */
+ }
+ }
+
+ topology->scan_requested = false;
+ topology->scanning = true;
+
+ /* scanning locks and unlocks the mutex itself until the scan is done */
+ mongoc_mutex_unlock (&topology->mutex);
+
+ while (_mongoc_topology_run_scanner (topology,
+ topology->connect_timeout_msec)) {}
+
+ mongoc_mutex_lock (&topology->mutex);
+
+ /* "retired" nodes can be checked again in the next scan */
+ mongoc_topology_scanner_reset (topology->scanner);
+
+ topology->last_scan = bson_get_monotonic_time ();
+ topology->scanning = false;
+ mongoc_mutex_unlock (&topology->mutex);
+
+ last_scan = bson_get_monotonic_time();
+ }
+
+DONE:
+ mongoc_mutex_unlock (&topology->mutex);
+
+ return NULL;
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * mongoc_topology_background_thread_start --
+ *
+ * Start the topology background thread running. This should only be
+ * called once per pool. If clients are created separately (not
+ * through a pool) the SDAM logic will not be run in a background
+ * thread.
+ *
+ * NOTE: this method uses @topology's mutex.
+ *
+ *--------------------------------------------------------------------------
+ */
+
+static void
+_mongoc_topology_background_thread_start (mongoc_topology_t *topology)
+{
+ bool launch_thread = true;
+
+ if (topology->single_threaded) {
+ return;
+ }
+
+ mongoc_mutex_lock (&topology->mutex);
+ if (topology->bg_thread_state != MONGOC_TOPOLOGY_BG_OFF) launch_thread = false;
+ topology->bg_thread_state = MONGOC_TOPOLOGY_BG_RUNNING;
+ mongoc_mutex_unlock (&topology->mutex);
+
+ if (launch_thread) {
+ mongoc_thread_create (&topology->thread, _mongoc_topology_run_background,
+ topology);
+ }
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * mongoc_topology_background_thread_stop --
+ *
+ * Stop the topology background thread. Called by the owning pool at
+ * its destruction.
+ *
+ * NOTE: this method uses @topology's mutex.
+ *
+ *--------------------------------------------------------------------------
+ */
+
+static void
+_mongoc_topology_background_thread_stop (mongoc_topology_t *topology)
+{
+ bool join_thread = false;
+
+ if (topology->single_threaded) {
+ return;
+ }
+
+ mongoc_mutex_lock (&topology->mutex);
+ if (topology->bg_thread_state == MONGOC_TOPOLOGY_BG_RUNNING) {
+ /* if the background thread is running, request a shutdown and signal the
+ * thread */
+ topology->shutdown_requested = true;
+ mongoc_cond_signal (&topology->cond_server);
+ topology->bg_thread_state = MONGOC_TOPOLOGY_BG_SHUTTING_DOWN;
+ join_thread = true;
+ } else if (topology->bg_thread_state == MONGOC_TOPOLOGY_BG_SHUTTING_DOWN) {
+ /* if we're mid shutdown, wait until it shuts down */
+ while (topology->bg_thread_state != MONGOC_TOPOLOGY_BG_OFF) {
+ mongoc_cond_wait (&topology->cond_client, &topology->mutex);
+ }
+ } else {
+ /* nothing to do if it's already off */
+ }
+
+ mongoc_mutex_unlock (&topology->mutex);
+
+ if (join_thread) {
+ /* if we're joining the thread, wait for it to come back and broadcast
+ * all listeners */
+ mongoc_thread_join (topology->thread);
+ mongoc_cond_broadcast (&topology->cond_client);
+ }
+}
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-uri-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-uri-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-uri-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-uri-private.h
new file mode 100644
index 0000000..df33181
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-uri-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-uri-private.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2015 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_URI_PRIVATE_H
+#define MONGOC_URI_PRIVATE_H
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include "mongoc-uri.h"
+
+
+BSON_BEGIN_DECLS
+
+
+void
+mongoc_uri_lowercase_hostname ( const char *src,
+ char *buf /* OUT */,
+ int len);
+void
+mongoc_uri_append_host ( mongoc_uri_t *uri,
+ const char *host,
+ uint16_t port);
+bool
+mongoc_uri_parse_host ( mongoc_uri_t *uri,
+ const char *str);
+bool
+mongoc_uri_set_username ( mongoc_uri_t *uri,
+ const char *username);
+bool
+mongoc_uri_set_password ( mongoc_uri_t *uri,
+ const char *password);
+bool
+mongoc_uri_set_database ( mongoc_uri_t *uri,
+ const char *database);
+bool
+mongoc_uri_set_auth_source ( mongoc_uri_t *uri,
+ const char *value);
+bool
+mongoc_uri_option_is_int32 (const char *key);
+bool
+mongoc_uri_option_is_bool (const char *key);
+bool
+mongoc_uri_option_is_utf8 (const char *key);
+int32_t
+mongoc_uri_get_option_as_int32 (const mongoc_uri_t *uri,
+ const char *option,
+ int32_t fallback);
+bool
+mongoc_uri_get_option_as_bool (const mongoc_uri_t *uri,
+ const char *option,
+ bool fallback);
+const char*
+mongoc_uri_get_option_as_utf8 (const mongoc_uri_t *uri,
+ const char *option,
+ const char *fallback);
+bool
+mongoc_uri_set_option_as_int32 ( mongoc_uri_t *uri,
+ const char *option,
+ int32_t value);
+bool
+mongoc_uri_set_option_as_bool ( mongoc_uri_t *uri,
+ const char *option,
+ bool value);
+bool
+mongoc_uri_set_option_as_utf8 ( mongoc_uri_t *uri,
+ const char *option,
+ const char *value);
+
+BSON_END_DECLS
+
+
+#endif /* MONGOC_URI_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-uri.c b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-uri.c
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-uri.c b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-uri.c
new file mode 100644
index 0000000..c58ae5d
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-uri.c
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-uri.c
@@ -0,0 +1,1559 @@
+/*
+ * Copyright 2013 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <math.h>
+
+/* strcasecmp on windows */
+#include "mongoc-util-private.h"
+
+#include "mongoc-host-list.h"
+#include "mongoc-host-list-private.h"
+#include "mongoc-log.h"
+#include "mongoc-socket.h"
+#include "mongoc-uri-private.h"
+#include "mongoc-read-concern-private.h"
+#include "mongoc-write-concern-private.h"
+
+
+struct _mongoc_uri_t
+{
+ char *str;
+ mongoc_host_list_t *hosts;
+ char *username;
+ char *password;
+ char *database;
+ bson_t options;
+ bson_t credentials;
+ mongoc_read_prefs_t *read_prefs;
+ mongoc_read_concern_t *read_concern;
+ mongoc_write_concern_t *write_concern;
+};
+
+static void
+mongoc_uri_do_unescape (char **str)
+{
+ char *tmp;
+
+ if ((tmp = *str)) {
+ *str = mongoc_uri_unescape(tmp);
+ bson_free(tmp);
+ }
+}
+
+void
+mongoc_uri_lowercase_hostname (const char *src,
+ char *buf /* OUT */,
+ int len)
+{
+ bson_unichar_t c;
+ const char *iter;
+ char *buf_iter;
+
+ /* TODO: this code only accepts ascii, and assumes that lowercased
+ chars are the same width as originals */
+ for (iter = src, buf_iter = buf;
+ iter && *iter && (c = bson_utf8_get_char(iter)) && buf_iter - buf < len;
+ iter = bson_utf8_next_char(iter), buf_iter++) {
+ assert(c < 128);
+ *buf_iter = tolower(c);
+ }
+}
+
+void
+mongoc_uri_append_host (mongoc_uri_t *uri,
+ const char *host,
+ uint16_t port)
+{
+ mongoc_host_list_t *iter;
+ mongoc_host_list_t *link_;
+
+ link_ = (mongoc_host_list_t *)bson_malloc0(sizeof *link_);
+ mongoc_uri_lowercase_hostname(host, link_->host, sizeof link_->host);
+ if (strchr (host, ':')) {
+ bson_snprintf (link_->host_and_port, sizeof link_->host_and_port,
+ "[%s]:%hu", host, port);
+ link_->family = AF_INET6;
+ } else {
+ bson_snprintf (link_->host_and_port, sizeof link_->host_and_port,
+ "%s:%hu", host, port);
+ link_->family = strstr (host, ".sock") ? AF_UNIX : AF_INET;
+ }
+ link_->host_and_port[sizeof link_->host_and_port - 1] = '\0';
+ link_->port = port;
+
+ if ((iter = uri->hosts)) {
+ for (; iter && iter->next; iter = iter->next) {}
+ iter->next = link_;
+ } else {
+ uri->hosts = link_;
+ }
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * scan_to_unichar --
+ *
+ * Scans 'str' until either a character matching 'match' is found,
+ * until one of the characters in 'terminators' is encountered, or
+ * until we reach the end of 'str'.
+ *
+ * NOTE: 'terminators' may not include multibyte UTF-8 characters.
+ *
+ * Returns:
+ * If 'match' is found, returns a copy of the section of 'str' before
+ * that character. Otherwise, returns NULL.
+ *
+ * Side Effects:
+ * If 'match' is found, sets 'end' to begin at the matching character
+ * in 'str'.
+ *
+ *--------------------------------------------------------------------------
+ */
+
+static char *
+scan_to_unichar (const char *str,
+ bson_unichar_t match,
+ const char *terminators,
+ const char **end)
+{
+ bson_unichar_t c;
+ const char *iter;
+
+ for (iter = str;
+ iter && *iter && (c = bson_utf8_get_char(iter));
+ iter = bson_utf8_next_char(iter)) {
+ if (c == match) {
+ *end = iter;
+ return bson_strndup(str, iter - str);
+ } else if (c == '\\') {
+ iter = bson_utf8_next_char(iter);
+ if (!bson_utf8_get_char(iter)) {
+ break;
+ }
+ } else {
+ const char *term_iter;
+ for (term_iter = terminators; *term_iter; term_iter++) {
+ if (c == *term_iter) {
+ return NULL;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+static bool
+mongoc_uri_parse_scheme (const char *str,
+ const char **end)
+{
+ if (!!strncmp(str, "mongodb://", 10)) {
+ return false;
+ }
+
+ *end = str + 10;
+
+ return true;
+}
+
+
+static bool
+mongoc_uri_parse_userpass (mongoc_uri_t *uri,
+ const char *str,
+ const char **end)
+{
+ bool ret = false;
+ const char *end_userpass;
+ const char *end_user;
+ char *s;
+
+ if ((s = scan_to_unichar(str, '@', "", &end_userpass))) {
+ if ((uri->username = scan_to_unichar(s, ':', "", &end_user))) {
+ uri->password = bson_strdup(end_user + 1);
+ } else {
+ uri->username = bson_strndup(str, end_userpass - str);
+ uri->password = NULL;
+ }
+ mongoc_uri_do_unescape(&uri->username);
+ mongoc_uri_do_unescape(&uri->password);
+ *end = end_userpass + 1;
+ bson_free(s);
+ ret = true;
+ } else {
+ ret = true;
+ }
+
+ return ret;
+}
+
+static bool
+mongoc_uri_parse_port (uint16_t *port,
+ const char *str)
+{
+ unsigned long ul_port;
+
+ ul_port = strtoul (str, NULL, 10);
+
+ if (ul_port == 0 || ul_port > UINT16_MAX) {
+ /* Parse error or port number out of range. mongod prohibits port 0. */
+ return false;
+ }
+
+ *port = (uint16_t)ul_port;
+ return true;
+}
+
+
+static bool
+mongoc_uri_parse_host6 (mongoc_uri_t *uri,
+ const char *str)
+{
+ uint16_t port = MONGOC_DEFAULT_PORT;
+ const char *portstr;
+ const char *end_host;
+ char *hostname;
+
+ if ((portstr = strrchr (str, ':')) && !strstr (portstr, "]")) {
+ if (!mongoc_uri_parse_port(&port, portstr + 1)) {
+ return false;
+ }
+ }
+
+ hostname = scan_to_unichar (str + 1, ']', "", &end_host);
+
+ mongoc_uri_do_unescape (&hostname);
+ if (!hostname) {
+ return false;
+ }
+
+ mongoc_uri_append_host (uri, hostname, port);
+ bson_free (hostname);
+
+ return true;
+}
+
+
+bool
+mongoc_uri_parse_host (mongoc_uri_t *uri,
+ const char *str)
+{
+ uint16_t port;
+ const char *end_host;
+ char *hostname;
+
+ if (*str == '[' && strchr (str, ']')) {
+ return mongoc_uri_parse_host6 (uri, str);
+ }
+
+ if ((hostname = scan_to_unichar(str, ':', "?/,", &end_host))) {
+ end_host++;
+ if (!mongoc_uri_parse_port(&port, end_host)) {
+ bson_free (hostname);
+ return false;
+ }
+ } else {
+ hostname = bson_strdup(str);
+ port = MONGOC_DEFAULT_PORT;
+ }
+
+ mongoc_uri_do_unescape(&hostname);
+ if (!hostname) {
+ /* invalid */
+ bson_free (hostname);
+ return false;
+ }
+
+ mongoc_uri_append_host(uri, hostname, port);
+ bson_free(hostname);
+
+ return true;
+}
+
+
+bool
+_mongoc_host_list_from_string (mongoc_host_list_t *host_list,
+ const char *host_and_port)
+{
+ bool rval = false;
+ char *uri_str = NULL;
+ mongoc_uri_t *uri = NULL;
+ const mongoc_host_list_t *uri_hl;
+
+ BSON_ASSERT (host_list);
+ BSON_ASSERT (host_and_port);
+
+ uri_str = bson_strdup_printf("mongodb://%s/", host_and_port);
+ if (! uri_str) goto CLEANUP;
+
+ uri = mongoc_uri_new(uri_str);
+ if (! uri) goto CLEANUP;
+
+ uri_hl = mongoc_uri_get_hosts(uri);
+ if (uri_hl->next) goto CLEANUP;
+
+ memcpy(host_list, uri_hl, sizeof(*uri_hl));
+
+ rval = true;
+
+CLEANUP:
+
+ bson_free(uri_str);
+ if (uri) mongoc_uri_destroy(uri);
+
+ return rval;
+}
+
+
+static bool
+mongoc_uri_parse_hosts (mongoc_uri_t *uri,
+ const char *str,
+ const char **end)
+{
+ bool ret = false;
+ const char *end_hostport;
+ const char *sock;
+ const char *tmp;
+ char *s;
+
+ /*
+ * Parsing the series of hosts is a lot more complicated than you might
+ * imagine. This is due to some characters being both separators as well as
+ * valid characters within the "hostname". In particularly, we can have file
+ * paths to specify paths to UNIX domain sockets. We impose the restriction
+ * that they must be suffixed with ".sock" to simplify the parsing.
+ *
+ * You can separate hosts and file system paths to UNIX domain sockets with
+ * ",".
+ *
+ * When you reach a "/" or "?" that is not part of a file-system path, we
+ * have completed our parsing of hosts.
+ */
+
+again:
+ if (((*str == '/') && (sock = strstr(str, ".sock"))) &&
+ (!(tmp = strstr(str, ",")) || (tmp > sock)) &&
+ (!(tmp = strstr(str, "?")) || (tmp > sock))) {
+ s = bson_strndup(str, sock + 5 - str);
+ if (!mongoc_uri_parse_host(uri, s)) {
+ bson_free(s);
+ return false;
+ }
+ bson_free(s);
+ str = sock + 5;
+ ret = true;
+ if (*str == ',') {
+ str++;
+ goto again;
+ }
+ } else if ((s = scan_to_unichar(str, ',', "/", &end_hostport))) {
+ if (!mongoc_uri_parse_host(uri, s)) {
+ bson_free(s);
+ return false;
+ }
+ bson_free(s);
+ str = end_hostport + 1;
+ ret = true;
+ goto again;
+ } else if ((s = scan_to_unichar(str, '/', "", &end_hostport)) ||
+ (s = scan_to_unichar(str, '?', "", &end_hostport))) {
+ if (!mongoc_uri_parse_host(uri, s)) {
+ bson_free(s);
+ return false;
+ }
+ bson_free(s);
+ *end = end_hostport;
+ return true;
+ } else if (*str) {
+ if (!mongoc_uri_parse_host(uri, str)) {
+ return false;
+ }
+ *end = str + strlen(str);
+ return true;
+ }
+
+ return ret;
+}
+
+
+static bool
+mongoc_uri_parse_database (mongoc_uri_t *uri,
+ const char *str,
+ const char **end)
+{
+ const char *end_database;
+
+ if ((uri->database = scan_to_unichar(str, '?', "", &end_database))) {
+ *end = end_database;
+ } else if (*str) {
+ uri->database = bson_strdup(str);
+ *end = str + strlen(str);
+ }
+
+ mongoc_uri_do_unescape(&uri->database);
+ if (!uri->database) {
+ /* invalid */
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool
+mongoc_uri_parse_auth_mechanism_properties (mongoc_uri_t *uri,
+ const char *str)
+{
+ char *field;
+ char *value;
+ const char *end_scan;
+ bson_t properties;
+
+ bson_init(&properties);
+
+ /* build up the properties document */
+ while ((field = scan_to_unichar(str, ':', "&", &end_scan))) {
+ str = end_scan + 1;
+ if (!(value = scan_to_unichar(str, ',', ":&", &end_scan))) {
+ value = bson_strdup(str);
+ str = "";
+ } else {
+ str = end_scan + 1;
+ }
+ bson_append_utf8(&properties, field, -1, value, -1);
+ bson_free(field);
+ bson_free(value);
+ }
+
+ /* append our auth properties to our credentials */
+ bson_append_document(&uri->credentials, "mechanismProperties",
+ -1, (const bson_t *)&properties);
+ return true;
+}
+
+static void
+mongoc_uri_parse_tags (mongoc_uri_t *uri, /* IN */
+ const char *str) /* IN */
+{
+ const char *end_keyval;
+ const char *end_key;
+ bson_t b;
+ char *keyval;
+ char *key;
+
+ bson_init(&b);
+
+again:
+ if ((keyval = scan_to_unichar(str, ',', "", &end_keyval))) {
+ if ((key = scan_to_unichar(keyval, ':', "", &end_key))) {
+ bson_append_utf8(&b, key, -1, end_key + 1, -1);
+ bson_free(key);
+ }
+ bson_free(keyval);
+ str = end_keyval + 1;
+ goto again;
+ } else {
+ if ((key = scan_to_unichar(str, ':', "", &end_key))) {
+ bson_append_utf8(&b, key, -1, end_key + 1, -1);
+ bson_free(key);
+ }
+ }
+
+ mongoc_read_prefs_add_tag(uri->read_prefs, &b);
+ bson_destroy(&b);
+}
+
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * mongoc_uri_bson_append_or_replace_key --
+ *
+ *
+ * Appends 'option' to the end of 'options' if not already set.
+ *
+ * Since we cannot grow utf8 strings inline, we have to allocate a temporary
+ * bson variable and splice in the new value if the key is already set.
+ *
+ * NOTE: This function keeps the order of the BSON keys.
+ *
+ * NOTE: 'option' is case*in*sensitive.
+ *
+ *
+ *--------------------------------------------------------------------------
+ */
+
+static void
+mongoc_uri_bson_append_or_replace_key (bson_t *options, const char *option, const char *value)
+{
+ bson_iter_t iter;
+ bool found = false;
+
+ if (bson_iter_init (&iter, options)) {
+ bson_t tmp = BSON_INITIALIZER;
+
+ while (bson_iter_next (&iter)) {
+ const bson_value_t *bvalue;
+
+ if (!strcasecmp(bson_iter_key (&iter), option)) {
+ bson_append_utf8(&tmp, option, -1, value, -1);
+ found = true;
+ continue;
+ }
+
+ bvalue = bson_iter_value (&iter);
+ BSON_APPEND_VALUE (&tmp, bson_iter_key (&iter), bvalue);
+ }
+
+ if (! found) {
+ bson_append_utf8(&tmp, option, -1, value, -1);
+ }
+
+ bson_destroy (options);
+ bson_copy_to (&tmp, options);
+ bson_destroy (&tmp);
+ }
+}
+
+
+bool
+mongoc_uri_option_is_int32 (const char *key)
+{
+ return !strcasecmp(key, "connecttimeoutms") ||
+ !strcasecmp(key, "heartbeatfrequencyms") ||
+ !strcasecmp(key, "serverselectiontimeoutms") ||
+ !strcasecmp(key, "socketcheckintervalms") ||
+ !strcasecmp(key, "sockettimeoutms") ||
+ !strcasecmp(key, "maxpoolsize") ||
+ !strcasecmp(key, "minpoolsize") ||
+ !strcasecmp(key, "maxidletimems") ||
+ !strcasecmp(key, "waitqueuemultiple") ||
+ !strcasecmp(key, "waitqueuetimeoutms") ||
+ !strcasecmp(key, "wtimeoutms");
+}
+
+bool
+mongoc_uri_option_is_bool (const char *key)
+{
+ return !strcasecmp(key, "canonicalizeHostname") ||
+ !strcasecmp(key, "journal") ||
+ !strcasecmp(key, "safe") ||
+ !strcasecmp(key, "serverSelectionTryOnce") ||
+ !strcasecmp(key, "slaveok") ||
+ !strcasecmp(key, "ssl");
+}
+
+bool
+mongoc_uri_option_is_utf8 (const char *key)
+{
+ if (mongoc_uri_option_is_bool(key) || mongoc_uri_option_is_int32(key)) {
+ return false;
+ }
+
+ if (!strcasecmp(key, "readpreferencetags") ||
+ !strcasecmp(key, "authmechanismproperties")) {
+ return false;
+ }
+
+ if (!strcasecmp(key, "username") || !strcasecmp(key, "password")
+ || !strcasecmp(key, "authsource") || !strcasecmp(key, "database")) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+mongoc_uri_parse_option (mongoc_uri_t *uri,
+ const char *str)
+{
+ int32_t v_int;
+ const char *end_key;
+ char *key = NULL;
+ char *value = NULL;
+ bool ret = false;
+
+ if (!(key = scan_to_unichar(str, '=', "", &end_key))) {
+ goto CLEANUP;
+ }
+
+ value = bson_strdup(end_key + 1);
+ mongoc_uri_do_unescape(&value);
+ if (!value) {
+ /* do_unescape detected invalid UTF-8 and freed value */
+ goto CLEANUP;
+ }
+
+ if (mongoc_uri_option_is_int32(key)) {
+ v_int = (int) strtol (value, NULL, 10);
+ BSON_APPEND_INT32 (&uri->options, key, v_int);
+ } else if (!strcasecmp(key, "w")) {
+ if (*value == '-' || isdigit(*value)) {
+ v_int = (int) strtol (value, NULL, 10);
+ BSON_APPEND_INT32 (&uri->options, "w", v_int);
+ } else if (0 == strcasecmp (value, "majority")) {
+ BSON_APPEND_UTF8 (&uri->options, "w", "majority");
+ } else if (*value) {
+ BSON_APPEND_UTF8 (&uri->options, "w", value);
+ }
+ } else if (mongoc_uri_option_is_bool(key)) {
+ bson_append_bool (&uri->options, key, -1,
+ (0 == strcasecmp (value, "true")) ||
+ (0 == strcasecmp (value, "t")) ||
+ (0 == strcmp (value, "1")));
+ } else if (!strcasecmp(key, "readpreferencetags")) {
+ mongoc_uri_parse_tags(uri, value);
+ } else if (!strcasecmp(key, "authmechanism") ||
+ !strcasecmp(key, "authsource")) {
+ bson_append_utf8(&uri->credentials, key, -1, value, -1);
+ } else if (!strcasecmp(key, "readconcernlevel")) {
+ mongoc_read_concern_set_level (uri->read_concern, value);
+ } else if (!strcasecmp(key, "authmechanismproperties")) {
+ if (!mongoc_uri_parse_auth_mechanism_properties(uri, value)) {
+ bson_free(key);
+ bson_free(value);
+ return false;
+ }
+ } else {
+ bson_append_utf8(&uri->options, key, -1, value, -1);
+ }
+
+ ret = true;
+
+CLEANUP:
+ bson_free(key);
+ bson_free(value);
+
+ return ret;
+}
+
+
+static bool
+mongoc_uri_parse_options (mongoc_uri_t *uri,
+ const char *str)
+{
+ const char *end_option;
+ char *option;
+
+again:
+ if ((option = scan_to_unichar(str, '&', "", &end_option))) {
+ if (!mongoc_uri_parse_option(uri, option)) {
+ bson_free(option);
+ return false;
+ }
+ bson_free(option);
+ str = end_option + 1;
+ goto again;
+ } else if (*str) {
+ if (!mongoc_uri_parse_option(uri, str)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+static bool
+mongoc_uri_finalize_auth (mongoc_uri_t *uri) {
+ bson_iter_t iter;
+ const char *source = NULL;
+ const char *mechanism = mongoc_uri_get_auth_mechanism(uri);
+
+ if (bson_iter_init_find_case(&iter, &uri->credentials, "authSource")) {
+ source = bson_iter_utf8(&iter, NULL);
+ }
+
+ /* authSource with GSSAPI or X509 should always be external */
+ if (mechanism) {
+ if (!strcasecmp(mechanism, "GSSAPI") ||
+ !strcasecmp(mechanism, "MONGODB-X509")) {
+ if (source) {
+ if (strcasecmp(source, "$external")) {
+ return false;
+ }
+ } else {
+ bson_append_utf8(&uri->credentials, "authsource", -1, "$external", -1);
+ }
+ }
+ }
+ return true;
+}
+
+static bool
+mongoc_uri_parse (mongoc_uri_t *uri,
+ const char *str)
+{
+ if (!mongoc_uri_parse_scheme(str, &str)) {
+ return false;
+ }
+
+ if (!*str || !mongoc_uri_parse_userpass(uri, str, &str)) {
+ return false;
+ }
+
+ if (!*str || !mongoc_uri_parse_hosts(uri, str, &str)) {
+ return false;
+ }
+
+ switch (*str) {
+ case '/':
+ str++;
+ if (*str && !mongoc_uri_parse_database(uri, str, &str)) {
+ return false;
+ }
+ if (!*str) {
+ break;
+ }
+ /* Fall through */
+ case '?':
+ str++;
+ if (*str && !mongoc_uri_parse_options(uri, str)) {
+ return false;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return mongoc_uri_finalize_auth(uri);
+}
+
+
+const mongoc_host_list_t *
+mongoc_uri_get_hosts (const mongoc_uri_t *uri)
+{
+ BSON_ASSERT (uri);
+ return uri->hosts;
+}
+
+
+const char *
+mongoc_uri_get_replica_set (const mongoc_uri_t *uri)
+{
+ bson_iter_t iter;
+
+ BSON_ASSERT (uri);
+
+ if (bson_iter_init_find_case(&iter, &uri->options, "replicaSet") &&
+ BSON_ITER_HOLDS_UTF8(&iter)) {
+ return bson_iter_utf8(&iter, NULL);
+ }
+
+ return NULL;
+}
+
+
+const bson_t *
+mongoc_uri_get_credentials (const mongoc_uri_t *uri)
+{
+ BSON_ASSERT (uri);
+ return &uri->credentials;
+}
+
+
+const char *
+mongoc_uri_get_auth_mechanism (const mongoc_uri_t *uri)
+{
+ bson_iter_t iter;
+
+ BSON_ASSERT (uri);
+
+ if (bson_iter_init_find_case (&iter, &uri->credentials, "authMechanism") &&
+ BSON_ITER_HOLDS_UTF8 (&iter)) {
+ return bson_iter_utf8 (&iter, NULL);
+ }
+
+ return NULL;
+}
+
+
+bool
+mongoc_uri_get_mechanism_properties (const mongoc_uri_t *uri, bson_t *properties)
+{
+ bson_iter_t iter;
+
+ if (!uri) {
+ return false;
+ }
+
+ if (bson_iter_init_find_case (&iter, &uri->credentials, "mechanismProperties") &&
+ BSON_ITER_HOLDS_DOCUMENT (&iter)) {
+ uint32_t len = 0;
+ const uint8_t *data = NULL;
+
+ bson_iter_document (&iter, &len, &data);
+ bson_init_static (properties, data, len);
+
+ return true;
+ }
+
+ return false;
+}
+
+
+static void
+_mongoc_uri_assign_read_prefs_mode (mongoc_uri_t *uri) /* IN */
+{
+ const char *str;
+ bson_iter_t iter;
+
+ BSON_ASSERT(uri);
+
+ if (mongoc_uri_get_option_as_bool (uri, "slaveok", false)) {
+ mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_SECONDARY_PREFERRED);
+ }
+
+ if (bson_iter_init_find_case(&iter, &uri->options, "readpreference") &&
+ BSON_ITER_HOLDS_UTF8(&iter)) {
+ str = bson_iter_utf8(&iter, NULL);
+
+ if (0 == strcasecmp("primary", str)) {
+ mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_PRIMARY);
+ } else if (0 == strcasecmp("primarypreferred", str)) {
+ mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_PRIMARY_PREFERRED);
+ } else if (0 == strcasecmp("secondary", str)) {
+ mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_SECONDARY);
+ } else if (0 == strcasecmp("secondarypreferred", str)) {
+ mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_SECONDARY_PREFERRED);
+ } else if (0 == strcasecmp("nearest", str)) {
+ mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_NEAREST);
+ } else {
+ MONGOC_WARNING("Unsupported readPreference value [readPreference=%s].", str);
+ }
+ }
+
+ /* Warn on conflict, since read preference will be validated later */
+ if (mongoc_read_prefs_get_mode(uri->read_prefs) == MONGOC_READ_PRIMARY &&
+ !bson_empty(mongoc_read_prefs_get_tags(uri->read_prefs))) {
+ MONGOC_WARNING("Primary read preference mode conflicts with tags.");
+ }
+}
+
+
+static void
+_mongoc_uri_build_write_concern (mongoc_uri_t *uri) /* IN */
+{
+ mongoc_write_concern_t *write_concern;
+ const char *str;
+ bson_iter_t iter;
+ int32_t wtimeoutms;
+ int value;
+
+ BSON_ASSERT (uri);
+
+ write_concern = mongoc_write_concern_new ();
+
+ if (bson_iter_init_find_case (&iter, &uri->options, "safe") &&
+ BSON_ITER_HOLDS_BOOL (&iter)) {
+ mongoc_write_concern_set_w (write_concern,
+ bson_iter_bool (&iter) ? 1 : MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED);
+ }
+
+ wtimeoutms = mongoc_uri_get_option_as_int32(uri, "wtimeoutms", 0);
+
+ if (bson_iter_init_find_case (&iter, &uri->options, "journal") &&
+ BSON_ITER_HOLDS_BOOL (&iter)) {
+ mongoc_write_concern_set_journal (write_concern, bson_iter_bool (&iter));
+ }
+
+ if (bson_iter_init_find_case (&iter, &uri->options, "w")) {
+ if (BSON_ITER_HOLDS_INT32 (&iter)) {
+ value = bson_iter_int32 (&iter);
+
+ switch (value) {
+ case MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED:
+ case MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED:
+ /* Warn on conflict, since write concern will be validated later */
+ if (mongoc_write_concern_get_journal(write_concern)) {
+ MONGOC_WARNING("Journal conflicts with w value [w=%d].", value);
+ }
+ mongoc_write_concern_set_w(write_concern, value);
+ break;
+ default:
+ if (value > 0) {
+ mongoc_write_concern_set_w (write_concern, value);
+ if (value > 1) {
+ mongoc_write_concern_set_wtimeout (write_concern, wtimeoutms);
+ }
+ break;
+ }
+ MONGOC_WARNING ("Unsupported w value [w=%d].", value);
+ break;
+ }
+ } else if (BSON_ITER_HOLDS_UTF8 (&iter)) {
+ str = bson_iter_utf8 (&iter, NULL);
+
+ if (0 == strcasecmp ("majority", str)) {
+ mongoc_write_concern_set_wmajority (write_concern, wtimeoutms);
+ } else {
+ mongoc_write_concern_set_wtag (write_concern, str);
+ mongoc_write_concern_set_wtimeout (write_concern, wtimeoutms);
+ }
+ } else {
+ BSON_ASSERT (false);
+ }
+ }
+
+ uri->write_concern = write_concern;
+}
+
+
+mongoc_uri_t *
+mongoc_uri_new (const char *uri_string)
+{
+ mongoc_uri_t *uri;
+
+ uri = (mongoc_uri_t *)bson_malloc0(sizeof *uri);
+ bson_init(&uri->options);
+ bson_init(&uri->credentials);
+
+ /* Initialize read_prefs since tag parsing may add to it */
+ uri->read_prefs = mongoc_read_prefs_new(MONGOC_READ_PRIMARY);
+
+ /* Initialize empty read_concern */
+ uri->read_concern = mongoc_read_concern_new ();
+
+ if (!uri_string) {
+ uri_string = "mongodb://127.0.0.1/";
+ }
+
+ if (!mongoc_uri_parse(uri, uri_string)) {
+ mongoc_uri_destroy(uri);
+ return NULL;
+ }
+
+ uri->str = bson_strdup(uri_string);
+
+ _mongoc_uri_assign_read_prefs_mode(uri);
+
+ if (!mongoc_read_prefs_is_valid(uri->read_prefs)) {
+ mongoc_uri_destroy(uri);
+ return NULL;
+ }
+
+ _mongoc_uri_build_write_concern (uri);
+
+ if (!_mongoc_write_concern_is_valid(uri->write_concern)) {
+ mongoc_uri_destroy(uri);
+ return NULL;
+ }
+
+ return uri;
+}
+
+
+mongoc_uri_t *
+mongoc_uri_new_for_host_port (const char *hostname,
+ uint16_t port)
+{
+ mongoc_uri_t *uri;
+ char *str;
+
+ BSON_ASSERT (hostname);
+ BSON_ASSERT (port);
+
+ str = bson_strdup_printf("mongodb://%s:%hu/", hostname, port);
+ uri = mongoc_uri_new(str);
+ bson_free(str);
+
+ return uri;
+}
+
+
+const char *
+mongoc_uri_get_username (const mongoc_uri_t *uri)
+{
+ BSON_ASSERT (uri);
+
+ return uri->username;
+}
+
+bool
+mongoc_uri_set_username (mongoc_uri_t *uri, const char *username)
+{
+ size_t len;
+
+ BSON_ASSERT (username);
+
+ len = strlen(username);
+
+ if (!bson_utf8_validate (username, len, false)) {
+ return false;
+ }
+
+ if (uri->username) {
+ bson_free (uri->username);
+ }
+
+ uri->username = bson_strdup (username);
+ return true;
+}
+
+
+const char *
+mongoc_uri_get_password (const mongoc_uri_t *uri)
+{
+ BSON_ASSERT (uri);
+
+ return uri->password;
+}
+
+bool
+mongoc_uri_set_password (mongoc_uri_t *uri, const char *password)
+{
+ size_t len;
+
+ BSON_ASSERT (password);
+
+ len = strlen(password);
+
+ if (!bson_utf8_validate (password, len, false)) {
+ return false;
+ }
+
+ if (uri->password) {
+ bson_free (uri->password);
+ }
+
+ uri->password = bson_strdup (password);
+ return true;
+}
+
+
+const char *
+mongoc_uri_get_database (const mongoc_uri_t *uri)
+{
+ BSON_ASSERT (uri);
+ return uri->database;
+}
+
+bool
+mongoc_uri_set_database (mongoc_uri_t *uri, const char *database)
+{
+ size_t len;
+
+ BSON_ASSERT (database);
+
+ len = strlen(database);
+
+ if (!bson_utf8_validate (database, len, false)) {
+ return false;
+ }
+
+ if (uri->database) {
+ bson_free (uri->database);
+ }
+
+ uri->database = bson_strdup(database);
+ return true;
+}
+
+
+const char *
+mongoc_uri_get_auth_source (const mongoc_uri_t *uri)
+{
+ bson_iter_t iter;
+
+ BSON_ASSERT (uri);
+
+ if (bson_iter_init_find_case(&iter, &uri->credentials, "authSource")) {
+ return bson_iter_utf8(&iter, NULL);
+ }
+
+ return uri->database ? uri->database : "admin";
+}
+
+
+bool
+mongoc_uri_set_auth_source (mongoc_uri_t *uri, const char *value)
+{
+ size_t len;
+
+ BSON_ASSERT (value);
+
+ len = strlen(value);
+
+ if (!bson_utf8_validate (value, len, false)) {
+ return false;
+ }
+
+ mongoc_uri_bson_append_or_replace_key (&uri->credentials, "authSource", value);
+
+ return true;
+}
+
+const bson_t *
+mongoc_uri_get_options (const mongoc_uri_t *uri)
+{
+ BSON_ASSERT (uri);
+ return &uri->options;
+}
+
+
+void
+mongoc_uri_destroy (mongoc_uri_t *uri)
+{
+ if (uri) {
+ _mongoc_host_list_destroy_all (uri->hosts);
+ bson_free(uri->str);
+ bson_free(uri->database);
+ bson_free(uri->username);
+ bson_destroy(&uri->options);
+ bson_destroy(&uri->credentials);
+ mongoc_read_prefs_destroy(uri->read_prefs);
+ mongoc_read_concern_destroy(uri->read_concern);
+ mongoc_write_concern_destroy(uri->write_concern);
+
+ if (uri->password) {
+ bson_zero_free(uri->password, strlen(uri->password));
+ }
+
+ bson_free(uri);
+ }
+}
+
+
+mongoc_uri_t *
+mongoc_uri_copy (const mongoc_uri_t *uri)
+{
+ mongoc_uri_t *copy;
+ mongoc_host_list_t *iter;
+
+ BSON_ASSERT (uri);
+
+ copy = (mongoc_uri_t *)bson_malloc0(sizeof (*copy));
+
+ copy->str = bson_strdup (uri->str);
+ copy->username = bson_strdup (uri->username);
+ copy->password = bson_strdup (uri->password);
+ copy->database = bson_strdup (uri->database);
+
+ copy->read_prefs = mongoc_read_prefs_copy (uri->read_prefs);
+ copy->read_concern = mongoc_read_concern_copy (uri->read_concern);
+ copy->write_concern = mongoc_write_concern_copy (uri->write_concern);
+
+ for (iter = uri->hosts; iter; iter = iter->next) {
+ mongoc_uri_append_host (copy, iter->host, iter->port);
+ }
+
+ bson_copy_to (&uri->options, &copy->options);
+ bson_copy_to (&uri->credentials, &copy->credentials);
+
+ return copy;
+}
+
+
+const char *
+mongoc_uri_get_string (const mongoc_uri_t *uri)
+{
+ BSON_ASSERT (uri);
+ return uri->str;
+}
+
+
+const bson_t *
+mongoc_uri_get_read_prefs (const mongoc_uri_t *uri)
+{
+ BSON_ASSERT (uri);
+ return mongoc_read_prefs_get_tags(uri->read_prefs);
+}
+
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * mongoc_uri_unescape --
+ *
+ * Escapes an UTF-8 encoded string containing URI escaped segments
+ * such as %20.
+ *
+ * It is a programming error to call this function with a string
+ * that is not UTF-8 encoded!
+ *
+ * Returns:
+ * A newly allocated string that should be freed with bson_free().
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------------------
+ */
+
+char *
+mongoc_uri_unescape (const char *escaped_string)
+{
+ bson_unichar_t c;
+ bson_string_t *str;
+ unsigned int hex = 0;
+ const char *ptr;
+ const char *end;
+ size_t len;
+
+ BSON_ASSERT (escaped_string);
+
+ len = strlen(escaped_string);
+
+ /*
+ * Double check that this is a UTF-8 valid string. Bail out if necessary.
+ */
+ if (!bson_utf8_validate(escaped_string, len, false)) {
+ MONGOC_WARNING("%s(): escaped_string contains invalid UTF-8",
+ BSON_FUNC);
+ return NULL;
+ }
+
+ ptr = escaped_string;
+ end = ptr + len;
+ str = bson_string_new(NULL);
+
+ for (; *ptr; ptr = bson_utf8_next_char(ptr)) {
+ c = bson_utf8_get_char(ptr);
+ switch (c) {
+ case '%':
+ if (((end - ptr) < 2) ||
+ !isxdigit(ptr[1]) ||
+ !isxdigit(ptr[2]) ||
+#ifdef _MSC_VER
+ (1 != sscanf_s(&ptr[1], "%02x", &hex)) ||
+#else
+ (1 != sscanf(&ptr[1], "%02x", &hex)) ||
+#endif
+ !isprint(hex)) {
+ bson_string_free(str, true);
+ return NULL;
+ }
+ bson_string_append_c(str, hex);
+ ptr += 2;
+ break;
+ default:
+ bson_string_append_unichar(str, c);
+ break;
+ }
+ }
+
+ return bson_string_free(str, false);
+}
+
+
+const mongoc_read_prefs_t *
+mongoc_uri_get_read_prefs_t (const mongoc_uri_t *uri) /* IN */
+{
+ BSON_ASSERT (uri);
+
+ return uri->read_prefs;
+}
+
+
+const mongoc_read_concern_t *
+mongoc_uri_get_read_concern (const mongoc_uri_t *uri) /* IN */
+{
+ BSON_ASSERT (uri);
+
+ return uri->read_concern;
+}
+
+
+const mongoc_write_concern_t *
+mongoc_uri_get_write_concern (const mongoc_uri_t *uri) /* IN */
+{
+ BSON_ASSERT (uri);
+
+ return uri->write_concern;
+}
+
+
+bool
+mongoc_uri_get_ssl (const mongoc_uri_t *uri) /* IN */
+{
+ bson_iter_t iter;
+
+ BSON_ASSERT (uri);
+
+ return (bson_iter_init_find_case (&iter, &uri->options, "ssl") &&
+ BSON_ITER_HOLDS_BOOL (&iter) &&
+ bson_iter_bool (&iter));
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * mongoc_uri_get_option_as_int32 --
+ *
+ * Checks if the URI 'option' is set and of correct type (int32).
+ * The special value '0' is considered as "unset".
+ * This is so users can provide
+ * sprintf(mongodb://localhost/?option=%d, myvalue) style connection strings,
+ * and still apply default values.
+ *
+ * If not set, or set to invalid type, 'fallback' is returned.
+ *
+ * NOTE: 'option' is case*in*sensitive.
+ *
+ * Returns:
+ * The value of 'option' if available as int32 (and not 0), or 'fallback'.
+ *
+ *--------------------------------------------------------------------------
+ */
+
+int32_t
+mongoc_uri_get_option_as_int32(const mongoc_uri_t *uri, const char *option,
+ int32_t fallback)
+{
+ const bson_t *options;
+ bson_iter_t iter;
+ int32_t retval = fallback;
+
+ if ((options = mongoc_uri_get_options (uri)) &&
+ bson_iter_init_find_case (&iter, options, option) &&
+ BSON_ITER_HOLDS_INT32 (&iter)) {
+
+ if (!(retval = bson_iter_int32(&iter))) {
+ retval = fallback;
+ }
+ }
+
+ return retval;
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * mongoc_uri_set_option_as_int32 --
+ *
+ * Sets a URI option 'after the fact'. Allows users to set individual
+ * URI options without passing them as a connection string.
+ *
+ * Only allows a set of known options to be set.
+ * @see mongoc_uri_option_is_int32 ().
+ *
+ * Does in-place-update of the option BSON if 'option' is already set.
+ * Appends the option to the end otherwise.
+ *
+ * NOTE: If 'option' is already set, and is of invalid type, this
+ * function will return false.
+ *
+ * NOTE: 'option' is case*in*sensitive.
+ *
+ * Returns:
+ * true on successfully setting the option, false on failure.
+ *
+ *--------------------------------------------------------------------------
+ */
+
+bool
+mongoc_uri_set_option_as_int32(mongoc_uri_t *uri, const char *option,
+ int32_t value)
+{
+ const bson_t *options;
+ bson_iter_t iter;
+
+ BSON_ASSERT (option);
+
+ if (!mongoc_uri_option_is_int32 (option)) {
+ return false;
+ }
+
+ if ((options = mongoc_uri_get_options (uri)) &&
+ bson_iter_init_find_case (&iter, options, option)) {
+ if (BSON_ITER_HOLDS_INT32 (&iter)) {
+ bson_iter_overwrite_int32 (&iter, value);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ bson_append_int32(&uri->options, option, -1, value);
+ return true;
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * mongoc_uri_get_option_as_bool --
+ *
+ * Checks if the URI 'option' is set and of correct type (bool).
+ *
+ * If not set, or set to invalid type, 'fallback' is returned.
+ *
+ * NOTE: 'option' is case*in*sensitive.
+ *
+ * Returns:
+ * The value of 'option' if available as bool, or 'fallback'.
+ *
+ *--------------------------------------------------------------------------
+ */
+
+bool
+mongoc_uri_get_option_as_bool (const mongoc_uri_t *uri, const char *option,
+ bool fallback)
+{
+ const bson_t *options;
+ bson_iter_t iter;
+
+ if ((options = mongoc_uri_get_options (uri)) &&
+ bson_iter_init_find_case (&iter, options, option) &&
+ BSON_ITER_HOLDS_BOOL (&iter)) {
+ return bson_iter_bool (&iter);
+ }
+
+ return fallback;
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * mongoc_uri_set_option_as_bool --
+ *
+ * Sets a URI option 'after the fact'. Allows users to set individual
+ * URI options without passing them as a connection string.
+ *
+ * Only allows a set of known options to be set.
+ * @see mongoc_uri_option_is_bool ().
+ *
+ * Does in-place-update of the option BSON if 'option' is already set.
+ * Appends the option to the end otherwise.
+ *
+ * NOTE: If 'option' is already set, and is of invalid type, this
+ * function will return false.
+ *
+ * NOTE: 'option' is case*in*sensitive.
+ *
+ * Returns:
+ * true on successfully setting the option, false on failure.
+ *
+ *--------------------------------------------------------------------------
+ */
+
+bool
+mongoc_uri_set_option_as_bool(mongoc_uri_t *uri, const char *option,
+ bool value)
+{
+ const bson_t *options;
+ bson_iter_t iter;
+
+ BSON_ASSERT (option);
+
+ if (!mongoc_uri_option_is_bool (option)) {
+ return false;
+ }
+
+ if ((options = mongoc_uri_get_options (uri)) &&
+ bson_iter_init_find_case (&iter, options, option)) {
+ if (BSON_ITER_HOLDS_BOOL (&iter)) {
+ bson_iter_overwrite_bool (&iter, value);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ bson_append_bool(&uri->options, option, -1, value);
+ return true;
+
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * mongoc_uri_get_option_as_utf8 --
+ *
+ * Checks if the URI 'option' is set and of correct type (utf8).
+ *
+ * If not set, or set to invalid type, 'fallback' is returned.
+ *
+ * NOTE: 'option' is case*in*sensitive.
+ *
+ * Returns:
+ * The value of 'option' if available as utf8, or 'fallback'.
+ *
+ *--------------------------------------------------------------------------
+ */
+
+const char*
+mongoc_uri_get_option_as_utf8 (const mongoc_uri_t *uri, const char *option,
+ const char *fallback)
+{
+ const bson_t *options;
+ bson_iter_t iter;
+
+ if ((options = mongoc_uri_get_options (uri)) &&
+ bson_iter_init_find_case (&iter, options, option) &&
+ BSON_ITER_HOLDS_UTF8 (&iter)) {
+ return bson_iter_utf8 (&iter, NULL);
+ }
+
+ return fallback;
+}
+
+/*
+ *--------------------------------------------------------------------------
+ *
+ * mongoc_uri_set_option_as_utf8 --
+ *
+ * Sets a URI option 'after the fact'. Allows users to set individual
+ * URI options without passing them as a connection string.
+ *
+ * Only allows a set of known options to be set.
+ * @see mongoc_uri_option_is_utf8 ().
+ *
+ * If the option is not already set, this function will append it to the end
+ * of the options bson.
+ * NOTE: If the option is already set the entire options bson will be
+ * overwritten, containing the new option=value (at the same position).
+ *
+ * NOTE: If 'option' is already set, and is of invalid type, this
+ * function will return false.
+ *
+ * NOTE: 'option' must be valid utf8.
+ *
+ * NOTE: 'option' is case*in*sensitive.
+ *
+ * Returns:
+ * true on successfully setting the option, false on failure.
+ *
+ *--------------------------------------------------------------------------
+ */
+
+bool
+mongoc_uri_set_option_as_utf8(mongoc_uri_t *uri, const char *option,
+ const char *value)
+{
+ size_t len;
+
+ BSON_ASSERT (option);
+
+ len = strlen(value);
+
+ if (!bson_utf8_validate (value, len, false)) {
+ return false;
+ }
+
+ if (!mongoc_uri_option_is_utf8 (option)) {
+ return false;
+ }
+
+ mongoc_uri_bson_append_or_replace_key (&uri->options, option, value);
+
+ return true;
+}
+
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-util-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-util-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-util-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-util-private.h
new file mode 100644
index 0000000..8e7f5a3
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-util-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-util-private.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2013 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_UTIL_PRIVATE_H
+#define MONGOC_UTIL_PRIVATE_H
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include <bson.h>
+
+/* string comparison functions for Windows */
+#ifdef _WIN32
+# define strcasecmp _stricmp
+# define strncasecmp _strnicmp
+#endif
+
+/* Suppress CWE-252 ("Unchecked return value") warnings for things we can't deal with */
+#if defined(__GNUC__) && __GNUC__ >= 4
+# define _ignore_value(x) (({ __typeof__ (x) __x = (x); (void) __x; }))
+#else
+# define _ignore_value(x) ((void) (x))
+#endif
+
+
+BSON_BEGIN_DECLS
+
+
+char *_mongoc_hex_md5 (const char *input);
+
+void _mongoc_usleep (int64_t usec);
+
+const char *_mongoc_get_command_name (const bson_t *command);
+
+void _mongoc_get_db_name (const char *ns,
+ char *db /* OUT */);
+
+void _mongoc_bson_destroy_if_set (bson_t *bson);
+BSON_END_DECLS
+
+
+#endif /* MONGOC_UTIL_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-write-command-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-write-command-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-write-command-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-write-command-private.h
new file mode 100644
index 0000000..c9525a8
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-write-command-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-write-command-private.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2014 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_WRITE_COMMAND_PRIVATE_H
+#define MONGOC_WRITE_COMMAND_PRIVATE_H
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include <bson.h>
+
+#include "mongoc-client.h"
+#include "mongoc-error.h"
+#include "mongoc-write-concern.h"
+#include "mongoc-server-stream-private.h"
+
+
+BSON_BEGIN_DECLS
+
+
+#define MONGOC_WRITE_COMMAND_DELETE 0
+#define MONGOC_WRITE_COMMAND_INSERT 1
+#define MONGOC_WRITE_COMMAND_UPDATE 2
+
+
+typedef enum
+{
+ MONGOC_BYPASS_DOCUMENT_VALIDATION_FALSE = 0,
+ MONGOC_BYPASS_DOCUMENT_VALIDATION_TRUE = 1 << 0,
+ MONGOC_BYPASS_DOCUMENT_VALIDATION_DEFAULT = 1 << 1,
+} mongoc_write_bypass_document_validation_t;
+
+struct _mongoc_bulk_write_flags_t
+{
+ bool ordered;
+ mongoc_write_bypass_document_validation_t bypass_document_validation;
+};
+
+
+typedef struct
+{
+ int type;
+ uint32_t hint;
+ bson_t *documents;
+ uint32_t n_documents;
+ mongoc_bulk_write_flags_t flags;
+ union {
+ struct {
+ bool multi;
+ } delete_;
+ struct {
+ bool allow_bulk_op_insert;
+ } insert;
+ } u;
+} mongoc_write_command_t;
+
+
+typedef struct
+{
+ /* true after a legacy update prevents us from calculating nModified */
+ bool omit_nModified;
+ uint32_t nInserted;
+ uint32_t nMatched;
+ uint32_t nModified;
+ uint32_t nRemoved;
+ uint32_t nUpserted;
+ /* like [{"index": int, "_id": value}, ...] */
+ bson_t writeErrors;
+ /* like [{"index": int, "code": int, "errmsg": str}, ...] */
+ bson_t upserted;
+ /* like [{"code": 64, "errmsg": "duplicate"}, ...] */
+ uint32_t n_writeConcernErrors;
+ bson_t writeConcernErrors;
+ bool failed;
+ bson_error_t error;
+ uint32_t upsert_append_count;
+} mongoc_write_result_t;
+
+
+void _mongoc_write_command_destroy (mongoc_write_command_t *command);
+void _mongoc_write_command_init_insert (mongoc_write_command_t *command,
+ const bson_t *document,
+ mongoc_bulk_write_flags_t flags,
+ bool allow_bulk_op_insert);
+void _mongoc_write_command_init_delete (mongoc_write_command_t *command,
+ const bson_t *selectors,
+ bool multi,
+ mongoc_bulk_write_flags_t flags);
+void _mongoc_write_command_init_update (mongoc_write_command_t *command,
+ const bson_t *selector,
+ const bson_t *update,
+ bool upsert,
+ bool multi,
+ mongoc_bulk_write_flags_t flags);
+void _mongoc_write_command_insert_append (mongoc_write_command_t *command,
+ const bson_t *document);
+void _mongoc_write_command_update_append (mongoc_write_command_t *command,
+ const bson_t *selector,
+ const bson_t *update,
+ bool upsert,
+ bool multi);
+
+void _mongoc_write_command_delete_append (mongoc_write_command_t *command,
+ const bson_t *selector);
+
+void _mongoc_write_command_execute (mongoc_write_command_t *command,
+ mongoc_client_t *client,
+ mongoc_server_stream_t *server_stream,
+ const char *database,
+ const char *collection,
+ const mongoc_write_concern_t *write_concern,
+ uint32_t offset,
+ mongoc_write_result_t *result);
+void _mongoc_write_result_init (mongoc_write_result_t *result);
+void _mongoc_write_result_merge (mongoc_write_result_t *result,
+ mongoc_write_command_t *command,
+ const bson_t *reply,
+ uint32_t offset);
+void _mongoc_write_result_merge_legacy (mongoc_write_result_t *result,
+ mongoc_write_command_t *command,
+ const bson_t *reply,
+ mongoc_error_code_t default_code,
+ uint32_t offset);
+bool _mongoc_write_result_complete (mongoc_write_result_t *result,
+ bson_t *reply,
+ bson_error_t *error);
+void _mongoc_write_result_destroy (mongoc_write_result_t *result);
+
+
+BSON_END_DECLS
+
+
+#endif /* MONGOC_WRITE_COMMAND_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-write-command.c b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-write-command.c
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-write-command.c b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-write-command.c
new file mode 100644
-index 0000000..3c44fb9
+index 0000000..a062c88
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-write-command.c
-@@ -0,0 +1,1519 @@
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-write-command.c
+@@ -0,0 +1,1527 @@
+/*
+ * Copyright 2014 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <bson.h>
+
+#include "mongoc-client-private.h"
+#include "mongoc-error.h"
+#include "mongoc-trace.h"
+#include "mongoc-write-command-private.h"
+#include "mongoc-write-concern-private.h"
+#include "mongoc-util-private.h"
+
+
+/*
+ * TODO:
+ *
+ * - Remove error parameter to ops, favor result->error.
+ */
+
+#define WRITE_CONCERN_DOC(wc) \
+ (wc && _mongoc_write_concern_needs_gle ((wc))) ? \
+ (_mongoc_write_concern_get_bson((mongoc_write_concern_t*)(wc))) : \
+ (&gEmptyWriteConcern)
+
+typedef void (*mongoc_write_op_t) (mongoc_write_command_t *command,
+ mongoc_client_t *client,
+ mongoc_server_stream_t *server_stream,
+ const char *database,
+ const char *collection,
+ const mongoc_write_concern_t *write_concern,
+ uint32_t offset,
+ mongoc_write_result_t *result,
+ bson_error_t *error);
+
+
+static bson_t gEmptyWriteConcern = BSON_INITIALIZER;
+
+/* indexed by MONGOC_WRITE_COMMAND_DELETE, INSERT, UPDATE */
+static const char *gCommandNames[] = { "delete", "insert", "update"};
+static const char *gCommandFields[] = { "deletes", "documents", "updates"};
++static const uint32_t gCommandFieldLens[] = { 7, 9, 7 };
+
+static int32_t
+_mongoc_write_result_merge_arrays (uint32_t offset,
+ mongoc_write_result_t *result,
+ bson_t *dest,
+ bson_iter_t *iter);
+
+void
+_mongoc_write_command_insert_append (mongoc_write_command_t *command,
+ const bson_t *document)
+{
+ const char *key;
+ bson_iter_t iter;
+ bson_oid_t oid;
+ bson_t tmp;
+ char keydata [16];
+
+ ENTRY;
+
+ BSON_ASSERT (command);
+ BSON_ASSERT (command->type == MONGOC_WRITE_COMMAND_INSERT);
+ BSON_ASSERT (document);
+ BSON_ASSERT (document->len >= 5);
+
+ key = NULL;
+ bson_uint32_to_string (command->n_documents,
+ &key, keydata, sizeof keydata);
+
+ BSON_ASSERT (key);
+
+ /*
+ * If the document does not contain an "_id" field, we need to generate
+ * a new oid for "_id".
+ */
+ if (!bson_iter_init_find (&iter, document, "_id")) {
+ bson_init (&tmp);
+ bson_oid_init (&oid, NULL);
+ BSON_APPEND_OID (&tmp, "_id", &oid);
+ bson_concat (&tmp, document);
+ BSON_APPEND_DOCUMENT (command->documents, key, &tmp);
+ bson_destroy (&tmp);
+ } else {
+ BSON_APPEND_DOCUMENT (command->documents, key, document);
+ }
+
+ command->n_documents++;
+
+ EXIT;
+}
+
+void
+_mongoc_write_command_update_append (mongoc_write_command_t *command,
+ const bson_t *selector,
+ const bson_t *update,
+ bool upsert,
+ bool multi)
+{
+ const char *key;
+ char keydata [16];
+ bson_t doc;
+
+ ENTRY;
+
+ BSON_ASSERT (command);
+ BSON_ASSERT (command->type == MONGOC_WRITE_COMMAND_UPDATE);
+ BSON_ASSERT (selector && update);
+
+ bson_init (&doc);
+ BSON_APPEND_DOCUMENT (&doc, "q", selector);
+ BSON_APPEND_DOCUMENT (&doc, "u", update);
+ BSON_APPEND_BOOL (&doc, "upsert", upsert);
+ BSON_APPEND_BOOL (&doc, "multi", multi);
+
+ key = NULL;
+ bson_uint32_to_string (command->n_documents, &key, keydata, sizeof keydata);
+ BSON_ASSERT (key);
+ BSON_APPEND_DOCUMENT (command->documents, key, &doc);
+ command->n_documents++;
+
+ bson_destroy (&doc);
+
+ EXIT;
+}
+
+void
+_mongoc_write_command_delete_append (mongoc_write_command_t *command,
+ const bson_t *selector)
+{
+ const char *key;
+ char keydata [16];
+ bson_t doc;
+
+ ENTRY;
+
+ BSON_ASSERT (command);
+ BSON_ASSERT (command->type == MONGOC_WRITE_COMMAND_DELETE);
+ BSON_ASSERT (selector);
+
+ BSON_ASSERT (selector->len >= 5);
+
+ bson_init (&doc);
+ BSON_APPEND_DOCUMENT (&doc, "q", selector);
+ BSON_APPEND_INT32 (&doc, "limit", command->u.delete_.multi ? 0 : 1);
+
+ key = NULL;
+ bson_uint32_to_string (command->n_documents, &key, keydata, sizeof keydata);
+ BSON_ASSERT (key);
+ BSON_APPEND_DOCUMENT (command->documents, key, &doc);
+ command->n_documents++;
+
+ bson_destroy (&doc);
+
+ EXIT;
+}
+
+void
+_mongoc_write_command_init_insert (mongoc_write_command_t *command, /* IN */
+ const bson_t *document, /* IN */
+ mongoc_bulk_write_flags_t flags, /* IN */
+ bool allow_bulk_op_insert) /* IN */
+{
+ ENTRY;
+
+ BSON_ASSERT (command);
+
+ command->type = MONGOC_WRITE_COMMAND_INSERT;
+ command->documents = bson_new ();
+ command->n_documents = 0;
+ command->flags = flags;
+ command->u.insert.allow_bulk_op_insert = (uint8_t)allow_bulk_op_insert;
+ command->hint = 0;
+
+ /* must handle NULL document from mongoc_collection_insert_bulk */
+ if (document) {
+ _mongoc_write_command_insert_append (command, document);
+ }
+
+ EXIT;
+}
+
+
+void
+_mongoc_write_command_init_delete (mongoc_write_command_t *command, /* IN */
+ const bson_t *selector, /* IN */
+ bool multi, /* IN */
+ mongoc_bulk_write_flags_t flags) /* IN */
+{
+ ENTRY;
+
+ BSON_ASSERT (command);
+ BSON_ASSERT (selector);
+
+ command->type = MONGOC_WRITE_COMMAND_DELETE;
+ command->documents = bson_new ();
+ command->n_documents = 0;
+ command->u.delete_.multi = (uint8_t)multi;
+ command->flags = flags;
+ command->hint = 0;
+
+ _mongoc_write_command_delete_append (command, selector);
+
+ EXIT;
+}
+
+
+void
+_mongoc_write_command_init_update (mongoc_write_command_t *command, /* IN */
+ const bson_t *selector, /* IN */
+ const bson_t *update, /* IN */
+ bool upsert, /* IN */
+ bool multi, /* IN */
+ mongoc_bulk_write_flags_t flags) /* IN */
+{
+ ENTRY;
+
+ BSON_ASSERT (command);
+ BSON_ASSERT (selector);
+ BSON_ASSERT (update);
+
+ command->type = MONGOC_WRITE_COMMAND_UPDATE;
+ command->documents = bson_new ();
+ command->n_documents = 0;
+ command->flags = flags;
+ command->hint = 0;
+
+ _mongoc_write_command_update_append (command, selector, update, upsert, multi);
+
+ EXIT;
+}
+
+
+static void
+_mongoc_write_command_delete_legacy (mongoc_write_command_t *command,
+ mongoc_client_t *client,
+ mongoc_server_stream_t *server_stream,
+ const char *database,
+ const char *collection,
+ const mongoc_write_concern_t *write_concern,
+ uint32_t offset,
+ mongoc_write_result_t *result,
+ bson_error_t *error)
+{
+ const uint8_t *data;
+ mongoc_rpc_t rpc;
+ bson_iter_t iter;
+ bson_iter_t q_iter;
+ uint32_t len;
+ bson_t *gle = NULL;
+ char ns [MONGOC_NAMESPACE_MAX + 1];
+ bool r;
+
+ ENTRY;
+
+ BSON_ASSERT (command);
+ BSON_ASSERT (client);
+ BSON_ASSERT (database);
+ BSON_ASSERT (server_stream);
+ BSON_ASSERT (collection);
+
+ r = bson_iter_init (&iter, command->documents);
+
+ if (!r) {
+ BSON_ASSERT (false);
+ EXIT;
+ }
+
+ if (!command->n_documents || !bson_iter_next (&iter)) {
+ bson_set_error (error,
+ MONGOC_ERROR_COLLECTION,
+ MONGOC_ERROR_COLLECTION_DELETE_FAILED,
+ "Cannot do an empty delete.");
+ result->failed = true;
+ EXIT;
+ }
+
+ bson_snprintf (ns, sizeof ns, "%s.%s", database, collection);
+
+ do {
+ /* the document is like { "q": { <selector> }, limit: <0 or 1> } */
+ r = (bson_iter_recurse (&iter, &q_iter) &&
+ bson_iter_find (&q_iter, "q") &&
+ BSON_ITER_HOLDS_DOCUMENT (&q_iter));
+
+ if (!r) {
+ BSON_ASSERT (false);
+ EXIT;
+ }
+
+ bson_iter_document (&q_iter, &len, &data);
+ BSON_ASSERT (data);
+ BSON_ASSERT (len >= 5);
+
+ rpc.delete_.msg_len = 0;
+ rpc.delete_.request_id = 0;
+ rpc.delete_.response_to = 0;
+ rpc.delete_.opcode = MONGOC_OPCODE_DELETE;
+ rpc.delete_.zero = 0;
+ rpc.delete_.collection = ns;
+ rpc.delete_.flags = command->u.delete_.multi ? MONGOC_DELETE_NONE
+ : MONGOC_DELETE_SINGLE_REMOVE;
+ rpc.delete_.selector = data;
+
+ if (!mongoc_cluster_sendv_to_server (&client->cluster,
+ &rpc, 1, server_stream,
+ write_concern, error)) {
+ result->failed = true;
+ EXIT;
+ }
+
+ if (_mongoc_write_concern_needs_gle (write_concern)) {
+ if (!_mongoc_client_recv_gle (client, server_stream, &gle, error)) {
+ result->failed = true;
+ EXIT;
+ }
+
+ _mongoc_write_result_merge_legacy (
+ result, command, gle,
+ MONGOC_ERROR_COLLECTION_DELETE_FAILED, offset);
+
+ offset++;
+ bson_destroy (gle);
+ }
+ } while (bson_iter_next (&iter));
+
+ EXIT;
+}
+
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * too_large_error --
+ *
+ * Fill a bson_error_t and optional bson_t with error info after
+ * receiving a document for bulk insert, update, or remove that is
+ * larger than max_bson_size.
+ *
+ * "err_doc" should be NULL or an empty initialized bson_t.
+ *
+ * Returns:
+ * None.
+ *
+ * Side effects:
+ * "error" and optionally "err_doc" are filled out.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+too_large_error (bson_error_t *error,
+ int32_t idx,
+ int32_t len,
+ int32_t max_bson_size,
+ bson_t *err_doc)
+{
+ /* MongoDB 2.6 uses code 2 for "too large". TODO: see CDRIVER-644 */
+ const int code = 2;
+
+ bson_set_error (error, MONGOC_ERROR_BSON, code,
+ "Document %u is too large for the cluster. "
+ "Document is %u bytes, max is %d.",
+ idx, len, max_bson_size);
+
+ if (err_doc) {
+ BSON_APPEND_INT32 (err_doc, "index", idx);
+ BSON_APPEND_UTF8 (err_doc, "err", error->message);
+ BSON_APPEND_INT32 (err_doc, "code", code);
+ }
+}
+
+
+static void
+_mongoc_write_command_insert_legacy (mongoc_write_command_t *command,
+ mongoc_client_t *client,
+ mongoc_server_stream_t *server_stream,
+ const char *database,
+ const char *collection,
+ const mongoc_write_concern_t *write_concern,
+ uint32_t offset,
+ mongoc_write_result_t *result,
+ bson_error_t *error)
+{
+ uint32_t current_offset;
+ mongoc_iovec_t *iov;
+ const uint8_t *data;
+ mongoc_rpc_t rpc;
+ bson_iter_t iter;
+ uint32_t len;
+ bson_t *gle = NULL;
+ uint32_t size = 0;
+ bool has_more;
+ char ns [MONGOC_NAMESPACE_MAX + 1];
+ bool r;
+ uint32_t n_docs_in_batch;
+ uint32_t idx = 0;
+ int32_t max_msg_size;
+ int32_t max_bson_obj_size;
+ bool singly;
+
+ ENTRY;
+
+ BSON_ASSERT (command);
+ BSON_ASSERT (client);
+ BSON_ASSERT (database);
+ BSON_ASSERT (server_stream);
+ BSON_ASSERT (collection);
+ BSON_ASSERT (command->type == MONGOC_WRITE_COMMAND_INSERT);
+
+ current_offset = offset;
+
+ max_bson_obj_size = mongoc_server_stream_max_bson_obj_size (server_stream);
+ max_msg_size = mongoc_server_stream_max_msg_size (server_stream);
+
+ singly = !command->u.insert.allow_bulk_op_insert;
+
+ r = bson_iter_init (&iter, command->documents);
+
+ if (!r) {
+ BSON_ASSERT (false);
+ EXIT;
+ }
+
+ if (!command->n_documents || !bson_iter_next (&iter)) {
+ bson_set_error (error,
+ MONGOC_ERROR_COLLECTION,
+ MONGOC_ERROR_COLLECTION_INSERT_FAILED,
+ "Cannot do an empty insert.");
+ result->failed = true;
+ EXIT;
+ }
+
+ bson_snprintf (ns, sizeof ns, "%s.%s", database, collection);
+
+ iov = (mongoc_iovec_t *)bson_malloc ((sizeof *iov) * command->n_documents);
+
+again:
+ has_more = false;
+ n_docs_in_batch = 0;
+ size = (uint32_t)(sizeof (mongoc_rpc_header_t) +
+ 4 +
+ strlen (database) +
+ 1 +
+ strlen (collection) +
+ 1);
+
+ do {
+ BSON_ASSERT (BSON_ITER_HOLDS_DOCUMENT (&iter));
+ BSON_ASSERT (n_docs_in_batch <= idx);
+ BSON_ASSERT (idx < command->n_documents);
+
+ bson_iter_document (&iter, &len, &data);
+
+ BSON_ASSERT (data);
+ BSON_ASSERT (len >= 5);
+
+ if (len > max_bson_obj_size) {
+ /* document is too large */
+ bson_t write_err_doc = BSON_INITIALIZER;
+
+ too_large_error (error, idx, len,
+ max_bson_obj_size, &write_err_doc);
+
+ _mongoc_write_result_merge_legacy (
+ result, command, &write_err_doc,
+ MONGOC_ERROR_COLLECTION_INSERT_FAILED, offset + idx);
+
+ bson_destroy (&write_err_doc);
+
+ if (command->flags.ordered) {
+ /* send the batch so far (if any) and return the error */
+ break;
+ }
+ } else if ((n_docs_in_batch == 1 && singly) || size > (max_msg_size - len)) {
+ /* batch is full, send it and then start the next batch */
+ has_more = true;
+ break;
+ } else {
+ /* add document to batch and continue building the batch */
+ iov[n_docs_in_batch].iov_base = (void *) data;
+ iov[n_docs_in_batch].iov_len = len;
+ size += len;
+ n_docs_in_batch++;
+ }
+
+ idx++;
+ } while (bson_iter_next (&iter));
+
+ if (n_docs_in_batch) {
+ rpc.insert.msg_len = 0;
+ rpc.insert.request_id = 0;
+ rpc.insert.response_to = 0;
+ rpc.insert.opcode = MONGOC_OPCODE_INSERT;
+ rpc.insert.flags = (
+ (command->flags.ordered) ? MONGOC_INSERT_NONE
+ : MONGOC_INSERT_CONTINUE_ON_ERROR);
+ rpc.insert.collection = ns;
+ rpc.insert.documents = iov;
+ rpc.insert.n_documents = n_docs_in_batch;
+
+ if (!mongoc_cluster_sendv_to_server (&client->cluster,
+ &rpc, 1, server_stream,
+ write_concern, error)) {
+ result->failed = true;
+ GOTO (cleanup);
+ }
+
+ if (_mongoc_write_concern_needs_gle (write_concern)) {
+ bool err = false;
+ bson_iter_t citer;
+
+ if (!_mongoc_client_recv_gle (client, server_stream, &gle, error)) {
+ result->failed = true;
+ GOTO (cleanup);
+ }
+
+ err = (bson_iter_init_find (&citer, gle, "err")
+ && bson_iter_as_bool (&citer));
+
+ /*
+ * Overwrite the "n" field since it will be zero. Otherwise, our
+ * merge_legacy code will not know how many we tried in this batch.
+ */
+ if (!err &&
+ bson_iter_init_find (&citer, gle, "n") &&
+ BSON_ITER_HOLDS_INT32 (&citer) &&
+ !bson_iter_int32 (&citer)) {
+ bson_iter_overwrite_int32 (&citer, n_docs_in_batch);
+ }
+ }
+ }
+
+cleanup:
+
+ if (gle) {
+ _mongoc_write_result_merge_legacy (
+ result, command, gle, MONGOC_ERROR_COLLECTION_INSERT_FAILED,
+ current_offset);
+
+ current_offset = offset + idx;
+ bson_destroy (gle);
+ gle = NULL;
+ }
+
+ if (has_more) {
+ GOTO (again);
+ }
+
+ bson_free (iov);
+
+ EXIT;
+}
+
+
+void
+_empty_error (mongoc_write_command_t *command,
+ bson_error_t *error)
+{
+ static const uint32_t codes[] = {
+ MONGOC_ERROR_COLLECTION_DELETE_FAILED,
+ MONGOC_ERROR_COLLECTION_INSERT_FAILED,
+ MONGOC_ERROR_COLLECTION_UPDATE_FAILED
+ };
+
+ bson_set_error (error,
+ MONGOC_ERROR_COLLECTION,
+ codes[command->type],
+ "Cannot do an empty %s",
+ gCommandNames[command->type]);
+}
+
+
+bool
+_mongoc_write_command_will_overflow (uint32_t len_so_far,
+ uint32_t document_len,
+ uint32_t n_documents_written,
+ int32_t max_bson_size,
+ int32_t max_write_batch_size)
+{
-+ /* max BSON object size + 16k - 2 bytes for ending NUL bytes.
++ /* max BSON object size + 16k bytes.
+ * server guarantees there is enough room: SERVER-10643
+ */
-+ int32_t max_cmd_size = max_bson_size + 16382;
++ int32_t max_cmd_size = max_bson_size + 16384;
+
+ BSON_ASSERT (max_bson_size);
+
-+
+ if (len_so_far + document_len > max_cmd_size) {
+ return true;
+ } else if (max_write_batch_size > 0 &&
+ n_documents_written >= max_write_batch_size) {
+ return true;
+ }
+
+ return false;
+}
+
+
+static void
+_mongoc_write_command_update_legacy (mongoc_write_command_t *command,
+ mongoc_client_t *client,
+ mongoc_server_stream_t *server_stream,
+ const char *database,
+ const char *collection,
+ const mongoc_write_concern_t *write_concern,
+ uint32_t offset,
+ mongoc_write_result_t *result,
+ bson_error_t *error)
+{
+ mongoc_rpc_t rpc;
+ bson_iter_t iter, subiter, subsubiter;
+ bson_t doc;
+ bool has_update, has_selector, is_upsert;
+ bson_t update, selector;
+ bson_t *gle = NULL;
+ const uint8_t *data = NULL;
+ uint32_t len = 0;
+ size_t err_offset;
+ bool val = false;
+ char ns [MONGOC_NAMESPACE_MAX + 1];
+ int32_t affected = 0;
+ int vflags = (BSON_VALIDATE_UTF8 | BSON_VALIDATE_UTF8_ALLOW_NULL
+ | BSON_VALIDATE_DOLLAR_KEYS | BSON_VALIDATE_DOT_KEYS);
+
+ ENTRY;
+
+ BSON_ASSERT (command);
+ BSON_ASSERT (client);
+ BSON_ASSERT (database);
+ BSON_ASSERT (server_stream);
+ BSON_ASSERT (collection);
+
+ bson_iter_init (&iter, command->documents);
+ while (bson_iter_next (&iter)) {
+ if (bson_iter_recurse (&iter, &subiter) &&
+ bson_iter_find (&subiter, "u") &&
+ BSON_ITER_HOLDS_DOCUMENT (&subiter)) {
+ bson_iter_document (&subiter, &len, &data);
+ bson_init_static (&doc, data, len);
+
+ if (bson_iter_init (&subsubiter, &doc) &&
+ bson_iter_next (&subsubiter) &&
+ (bson_iter_key (&subsubiter) [0] != '$') &&
+ !bson_validate (&doc, (bson_validate_flags_t)vflags, &err_offset)) {
+ result->failed = true;
+ bson_set_error (error,
+ MONGOC_ERROR_BSON,
+ MONGOC_ERROR_BSON_INVALID,
+ "update document is corrupt or contains "
+ "invalid keys including $ or .");
+ EXIT;
+ }
+ } else {
+ result->failed = true;
+ bson_set_error (error,
+ MONGOC_ERROR_BSON,
+ MONGOC_ERROR_BSON_INVALID,
+ "updates is malformed.");
+ EXIT;
+ }
+ }
+
+ bson_snprintf (ns, sizeof ns, "%s.%s", database, collection);
+
+ bson_iter_init (&iter, command->documents);
+ while (bson_iter_next (&iter)) {
+ rpc.update.msg_len = 0;
+ rpc.update.request_id = 0;
+ rpc.update.response_to = 0;
+ rpc.update.opcode = MONGOC_OPCODE_UPDATE;
+ rpc.update.zero = 0;
+ rpc.update.collection = ns;
+ rpc.update.flags = MONGOC_UPDATE_NONE;
+
+ has_update = false;
+ has_selector = false;
+ is_upsert = false;
+
+ bson_iter_recurse (&iter, &subiter);
+ while (bson_iter_next (&subiter)) {
+ if (strcmp (bson_iter_key (&subiter), "u") == 0) {
+ bson_iter_document (&subiter, &len, &data);
+ rpc.update.update = data;
+ bson_init_static (&update, data, len);
+ has_update = true;
+ } else if (strcmp (bson_iter_key (&subiter), "q") == 0) {
+ bson_iter_document (&subiter, &len, &data);
+ rpc.update.selector = data;
+ bson_init_static (&selector, data, len);
+ has_selector = true;
+ } else if (strcmp (bson_iter_key (&subiter), "multi") == 0) {
+ val = bson_iter_bool (&subiter);
+ if (val) {
+ rpc.update.flags = (mongoc_update_flags_t)(
+ rpc.update.flags | MONGOC_UPDATE_MULTI_UPDATE);
+ }
+ } else if (strcmp (bson_iter_key (&subiter), "upsert") == 0) {
+ val = bson_iter_bool (&subiter);
+ if (val) {
+ rpc.update.flags = (mongoc_update_flags_t)(
+ rpc.update.flags | MONGOC_UPDATE_UPSERT);
+ }
+ is_upsert = true;
+ }
+ }
+
+ if (!mongoc_cluster_sendv_to_server (&client->cluster,
+ &rpc, 1, server_stream,
+ write_concern, error)) {
+ result->failed = true;
+ EXIT;
+ }
+
+ if (_mongoc_write_concern_needs_gle (write_concern)) {
+ if (!_mongoc_client_recv_gle (client, server_stream, &gle, error)) {
+ result->failed = true;
+ EXIT;
+ }
+
+ if (bson_iter_init_find (&subiter, gle, "n") &&
+ BSON_ITER_HOLDS_INT32 (&subiter)) {
+ affected = bson_iter_int32 (&subiter);
+ }
+
+ /*
+ * CDRIVER-372:
+ *
+ * Versions of MongoDB before 2.6 don't return the _id for an
+ * upsert if _id is not an ObjectId.
+ */
+ if (is_upsert &&
+ affected &&
+ !bson_iter_init_find (&subiter, gle, "upserted") &&
+ bson_iter_init_find (&subiter, gle, "updatedExisting") &&
+ BSON_ITER_HOLDS_BOOL (&subiter) &&
+ !bson_iter_bool (&subiter)) {
+ if (has_update && bson_iter_init_find (&subiter, &update, "_id")) {
+ _ignore_value (bson_append_iter (gle, "upserted", 8, &subiter));
+ } else if (has_selector &&
+ bson_iter_init_find (&subiter, &selector, "_id")) {
+ _ignore_value (bson_append_iter (gle, "upserted", 8, &subiter));
+ }
+ }
+
+ _mongoc_write_result_merge_legacy (
+ result, command, gle,
+ MONGOC_ERROR_COLLECTION_UPDATE_FAILED, offset);
+
+ offset++;
+ bson_destroy (gle);
+ }
+ }
+
+ EXIT;
+}
+
+
+static mongoc_write_op_t gLegacyWriteOps[3] = {
+ _mongoc_write_command_delete_legacy,
+ _mongoc_write_command_insert_legacy,
+ _mongoc_write_command_update_legacy };
+
+
+static void
+_mongoc_write_command(mongoc_write_command_t *command,
+ mongoc_client_t *client,
+ mongoc_server_stream_t *server_stream,
+ const char *database,
+ const char *collection,
+ const mongoc_write_concern_t *write_concern,
+ uint32_t offset,
+ mongoc_write_result_t *result,
+ bson_error_t *error)
+{
+ const uint8_t *data;
+ bson_iter_t iter;
+ const char *key;
+ uint32_t len = 0;
+ bson_t tmp;
+ bson_t ar;
+ bson_t cmd;
+ bson_t reply;
+ char str [16];
+ bool has_more;
+ bool ret = false;
+ uint32_t i;
+ int32_t max_bson_obj_size;
+ int32_t max_write_batch_size;
+ int32_t min_wire_version;
++ uint32_t overhead;
+ uint32_t key_len;
+
+ ENTRY;
+
+ BSON_ASSERT (command);
+ BSON_ASSERT (client);
+ BSON_ASSERT (database);
+ BSON_ASSERT (server_stream);
+ BSON_ASSERT (collection);
+
+ max_bson_obj_size = mongoc_server_stream_max_bson_obj_size (server_stream);
+ max_write_batch_size = mongoc_server_stream_max_write_batch_size (server_stream);
+
+ /*
+ * If we have an unacknowledged write and the server supports the legacy
+ * opcodes, then submit the legacy opcode so we don't need to wait for
+ * a response from the server.
+ */
+
+ min_wire_version = server_stream->sd->min_wire_version;
+ if ((min_wire_version == 0) &&
+ !_mongoc_write_concern_needs_gle (write_concern)) {
+ if (command->flags.bypass_document_validation != MONGOC_BYPASS_DOCUMENT_VALIDATION_DEFAULT) {
+ bson_set_error (error,
+ MONGOC_ERROR_COMMAND,
+ MONGOC_ERROR_COMMAND_INVALID_ARG,
+ "Cannot set bypassDocumentValidation for unacknowledged writes");
+ EXIT;
+ }
+ gLegacyWriteOps[command->type] (command, client, server_stream, database,
+ collection, write_concern, offset,
+ result, error);
+ EXIT;
+ }
+
+ if (!command->n_documents ||
+ !bson_iter_init (&iter, command->documents) ||
+ !bson_iter_next (&iter)) {
+ _empty_error (command, error);
+ result->failed = true;
+ EXIT;
+ }
+
+again:
+ bson_init (&cmd);
+ has_more = false;
+ i = 0;
+
+ BSON_APPEND_UTF8 (&cmd, gCommandNames[command->type], collection);
+ BSON_APPEND_DOCUMENT (&cmd, "writeConcern",
+ WRITE_CONCERN_DOC (write_concern));
+ BSON_APPEND_BOOL (&cmd, "ordered", command->flags.ordered);
+ if (command->flags.bypass_document_validation != MONGOC_BYPASS_DOCUMENT_VALIDATION_DEFAULT) {
+ BSON_APPEND_BOOL (&cmd, "bypassDocumentValidation",
+ !!command->flags.bypass_document_validation);
+ }
+
-+ if (!_mongoc_write_command_will_overflow (0,
++ /* 1 byte to specify array type, 1 byte for field name's null terminator */
++ overhead = cmd.len + 2 + gCommandFieldLens[command->type];
++
++ if (!_mongoc_write_command_will_overflow (overhead,
+ command->documents->len,
+ command->n_documents,
+ max_bson_obj_size,
+ max_write_batch_size)) {
+ /* copy the whole documents buffer as e.g. "updates": [...] */
-+ BSON_APPEND_ARRAY (&cmd,
++ bson_append_array (&cmd,
+ gCommandFields[command->type],
++ gCommandFieldLens[command->type],
+ command->documents);
+ i = command->n_documents;
+ } else {
-+ bson_append_array_begin (&cmd, gCommandFields[command->type], -1, &ar);
++ bson_append_array_begin (&cmd,
++ gCommandFields[command->type],
++ gCommandFieldLens[command->type],
++ &ar);
+
+ do {
+ if (!BSON_ITER_HOLDS_DOCUMENT (&iter)) {
+ BSON_ASSERT (false);
+ }
+
+ bson_iter_document (&iter, &len, &data);
+ key_len = (uint32_t) bson_uint32_to_string (i, &key, str, sizeof str);
+
-+ if (_mongoc_write_command_will_overflow (ar.len,
-+ key_len + len + 2,
++ if (_mongoc_write_command_will_overflow (overhead,
++ key_len + len + 2 + ar.len,
+ i,
+ max_bson_obj_size,
+ max_write_batch_size)) {
+ has_more = true;
+ break;
+ }
+
+ if (!bson_init_static (&tmp, data, len)) {
+ BSON_ASSERT (false);
+ }
+
+ BSON_APPEND_DOCUMENT (&ar, key, &tmp);
+
+ bson_destroy (&tmp);
+
+ i++;
+ } while (bson_iter_next (&iter));
+
+ bson_append_array_end (&cmd, &ar);
+ }
+
+ if (!i) {
+ too_large_error (error, i, len, max_bson_obj_size, NULL);
+ result->failed = true;
+ ret = false;
+ } else {
+ ret = mongoc_cluster_run_command (&client->cluster, server_stream->stream,
-+ MONGOC_QUERY_NONE, database, &cmd,
-+ &reply, error);
++ server_stream->sd->id, MONGOC_QUERY_NONE,
++ database, &cmd, &reply, error);
+
+ if (!ret) {
+ result->failed = true;
+ }
+
+ _mongoc_write_result_merge (result, command, &reply, offset);
+ offset += i;
+ bson_destroy (&reply);
+ }
+
+ bson_destroy (&cmd);
+
+ if (has_more && (ret || !command->flags.ordered)) {
+ GOTO (again);
+ }
+
+ EXIT;
+}
+
+
+void
+_mongoc_write_command_execute (mongoc_write_command_t *command, /* IN */
+ mongoc_client_t *client, /* IN */
+ mongoc_server_stream_t *server_stream, /* IN */
+ const char *database, /* IN */
+ const char *collection, /* IN */
+ const mongoc_write_concern_t *write_concern, /* IN */
+ uint32_t offset, /* IN */
+ mongoc_write_result_t *result) /* OUT */
+{
+ ENTRY;
+
+ BSON_ASSERT (command);
+ BSON_ASSERT (client);
+ BSON_ASSERT (server_stream);
+ BSON_ASSERT (database);
+ BSON_ASSERT (collection);
+ BSON_ASSERT (result);
+
+ if (!write_concern) {
+ write_concern = client->write_concern;
+ }
+
+ if (!_mongoc_write_concern_is_valid(write_concern)) {
+ bson_set_error (&result->error,
+ MONGOC_ERROR_COMMAND,
+ MONGOC_ERROR_COMMAND_INVALID_ARG,
+ "The write concern is invalid.");
+ result->failed = true;
+ EXIT;
+ }
+
+ if (!command->hint) {
+ command->hint = server_stream->sd->id;
+ } else {
+ BSON_ASSERT (command->hint == server_stream->sd->id);
+ }
+
+ if (server_stream->sd->max_wire_version >= WIRE_VERSION_WRITE_CMD) {
+ _mongoc_write_command (command, client, server_stream, database,
+ collection, write_concern, offset,
+ result, &result->error);
+ } else {
+ gLegacyWriteOps[command->type] (command, client, server_stream, database,
+ collection, write_concern, offset,
+ result, &result->error);
+ }
+
+ EXIT;
+}
+
+
+void
+_mongoc_write_command_destroy (mongoc_write_command_t *command)
+{
+ ENTRY;
+
+ if (command) {
+ bson_destroy (command->documents);
+ }
+
+ EXIT;
+}
+
+
+void
+_mongoc_write_result_init (mongoc_write_result_t *result) /* IN */
+{
+ ENTRY;
+
+ BSON_ASSERT (result);
+
+ memset (result, 0, sizeof *result);
+
+ bson_init (&result->upserted);
+ bson_init (&result->writeConcernErrors);
+ bson_init (&result->writeErrors);
+
+ EXIT;
+}
+
+
+void
+_mongoc_write_result_destroy (mongoc_write_result_t *result)
+{
+ ENTRY;
+
+ BSON_ASSERT (result);
+
+ bson_destroy (&result->upserted);
+ bson_destroy (&result->writeConcernErrors);
+ bson_destroy (&result->writeErrors);
+
+ EXIT;
+}
+
+
+static void
+_mongoc_write_result_append_upsert (mongoc_write_result_t *result,
+ int32_t idx,
+ const bson_value_t *value)
+{
+ bson_t child;
+ const char *keyptr = NULL;
+ char key[12];
+ int len;
+
+ BSON_ASSERT (result);
+ BSON_ASSERT (value);
+
+ len = (int)bson_uint32_to_string (result->upsert_append_count, &keyptr, key,
+ sizeof key);
+
+ bson_append_document_begin (&result->upserted, keyptr, len, &child);
+ BSON_APPEND_INT32 (&child, "index", idx);
+ BSON_APPEND_VALUE (&child, "_id", value);
+ bson_append_document_end (&result->upserted, &child);
+
+ result->upsert_append_count++;
+}
+
+
+static void
+_append_write_concern_err_legacy (mongoc_write_result_t *result,
+ const char *err,
+ int32_t code)
+{
+ char str[16];
+ const char *key;
+ size_t keylen;
+ bson_t write_concern_error;
+
+ /* don't set result->failed; record the write concern err and continue */
+ keylen = bson_uint32_to_string (result->n_writeConcernErrors, &key,
+ str, sizeof str);
+
+ BSON_ASSERT (keylen < INT_MAX);
+
+ bson_append_document_begin (&result->writeConcernErrors, key, (int) keylen,
+ &write_concern_error);
+
+ bson_append_int32 (&write_concern_error, "code", 4, code);
+ bson_append_utf8 (&write_concern_error, "errmsg", 6, err, -1);
+ bson_append_document_end (&result->writeConcernErrors, &write_concern_error);
+ result->n_writeConcernErrors++;
+}
+
+
+static void
+_append_write_err_legacy (mongoc_write_result_t *result,
+ const char *err,
+ int32_t code,
+ uint32_t offset)
+{
+ bson_t holder, write_errors, child;
+ bson_iter_t iter;
+
+ BSON_ASSERT (code > 0);
+
+ bson_set_error (&result->error, MONGOC_ERROR_COLLECTION, (uint32_t) code,
+ "%s", err);
+
+ /* stop processing, if result->ordered */
+ result->failed = true;
+
+ bson_init (&holder);
+ bson_append_array_begin (&holder, "0", 1, &write_errors);
+ bson_append_document_begin (&write_errors, "0", 1, &child);
+
+ /* set error's "index" to 0; fixed up in _mongoc_write_result_merge_arrays */
+ bson_append_int32 (&child, "index", 5, 0);
+ bson_append_int32 (&child, "code", 4, code);
+ bson_append_utf8 (&child, "errmsg", 6, err, -1);
+ bson_append_document_end (&write_errors, &child);
+ bson_append_array_end (&holder, &write_errors);
+ bson_iter_init (&iter, &holder);
+ bson_iter_next (&iter);
+
+ _mongoc_write_result_merge_arrays (offset, result,
+ &result->writeErrors, &iter);
+
+ bson_destroy (&holder);
+}
+
+
+void
+_mongoc_write_result_merge_legacy (mongoc_write_result_t *result, /* IN */
+ mongoc_write_command_t *command, /* IN */
+ const bson_t *reply, /* IN */
+ mongoc_error_code_t default_code,
+ uint32_t offset)
+{
+ const bson_value_t *value;
+ bson_iter_t iter;
+ bson_iter_t ar;
+ bson_iter_t citer;
+ const char *err = NULL;
+ int32_t code = 0;
+ int32_t n = 0;
+ int32_t upsert_idx = 0;
+
+ ENTRY;
+
+ BSON_ASSERT (result);
+ BSON_ASSERT (reply);
+
+ if (bson_iter_init_find (&iter, reply, "n") &&
+ BSON_ITER_HOLDS_INT32 (&iter)) {
+ n = bson_iter_int32 (&iter);
+ }
+
+ if (bson_iter_init_find (&iter, reply, "err") &&
+ BSON_ITER_HOLDS_UTF8 (&iter)) {
+ err = bson_iter_utf8 (&iter, NULL);
+ }
+
+ if (bson_iter_init_find (&iter, reply, "code") &&
+ BSON_ITER_HOLDS_INT32 (&iter)) {
+ code = bson_iter_int32 (&iter);
+ }
+
+ if (code || err) {
+ if (!err) {
+ err = "unknown error";
+ }
+
+ if (bson_iter_init_find (&iter, reply, "wtimeout") &&
+ bson_iter_as_bool (&iter)) {
+
+ if (!code) {
+ code = (int32_t) MONGOC_ERROR_WRITE_CONCERN_ERROR;
+ }
+
+ _append_write_concern_err_legacy (result, err, code);
+ } else {
+ if (!code) {
+ code = (int32_t) default_code;
+ }
+
+ _append_write_err_legacy (result, err, code, offset);
+ }
+ }
+
+ switch (command->type) {
+ case MONGOC_WRITE_COMMAND_INSERT:
+ if (n) {
+ result->nInserted += n;
+ }
+ break;
+ case MONGOC_WRITE_COMMAND_DELETE:
+ result->nRemoved += n;
+ break;
+ case MONGOC_WRITE_COMMAND_UPDATE:
+ if (bson_iter_init_find (&iter, reply, "upserted") &&
+ !BSON_ITER_HOLDS_ARRAY (&iter)) {
+ result->nUpserted += n;
+ value = bson_iter_value (&iter);
+ _mongoc_write_result_append_upsert (result, offset, value);
+ } else if (bson_iter_init_find (&iter, reply, "upserted") &&
+ BSON_ITER_HOLDS_ARRAY (&iter)) {
+ result->nUpserted += n;
+ if (bson_iter_recurse (&iter, &ar)) {
+ while (bson_iter_next (&ar)) {
+ if (BSON_ITER_HOLDS_DOCUMENT (&ar) &&
+ bson_iter_recurse (&ar, &citer) &&
+ bson_iter_find (&citer, "_id")) {
+ value = bson_iter_value (&citer);
+ _mongoc_write_result_append_upsert (result,
+ offset + upsert_idx,
+ value);
+ upsert_idx++;
+ }
+ }
+ }
+ } else if ((n == 1) &&
+ bson_iter_init_find (&iter, reply, "updatedExisting") &&
+ BSON_ITER_HOLDS_BOOL (&iter) &&
+ !bson_iter_bool (&iter)) {
+ result->nUpserted += n;
+ } else {
+ result->nMatched += n;
+ }
+ break;
+ default:
+ break;
+ }
+
+ result->omit_nModified = true;
+
+ EXIT;
+}
+
+
+static int32_t
+_mongoc_write_result_merge_arrays (uint32_t offset,
+ mongoc_write_result_t *result, /* IN */
+ bson_t *dest, /* IN */
+ bson_iter_t *iter) /* IN */
+{
+ const bson_value_t *value;
+ bson_iter_t ar;
+ bson_iter_t citer;
+ int32_t idx;
+ int32_t count = 0;
+ int32_t aridx;
+ bson_t child;
+ const char *keyptr = NULL;
+ char key[12];
+ int len;
+
+ ENTRY;
+
+ BSON_ASSERT (result);
+ BSON_ASSERT (dest);
+ BSON_ASSERT (iter);
+ BSON_ASSERT (BSON_ITER_HOLDS_ARRAY (iter));
+
+ aridx = bson_count_keys (dest);
+
+ if (bson_iter_recurse (iter, &ar)) {
+ while (bson_iter_next (&ar)) {
+ if (BSON_ITER_HOLDS_DOCUMENT (&ar) &&
+ bson_iter_recurse (&ar, &citer)) {
+ len = (int)bson_uint32_to_string (aridx++, &keyptr, key,
+ sizeof key);
+ bson_append_document_begin (dest, keyptr, len, &child);
+ while (bson_iter_next (&citer)) {
+ if (BSON_ITER_IS_KEY (&citer, "index")) {
+ idx = bson_iter_int32 (&citer) + offset;
+ BSON_APPEND_INT32 (&child, "index", idx);
+ } else {
+ value = bson_iter_value (&citer);
+ BSON_APPEND_VALUE (&child, bson_iter_key (&citer), value);
+ }
+ }
+ bson_append_document_end (dest, &child);
+ count++;
+ }
+ }
+ }
+
+ RETURN (count);
+}
+
+
+void
+_mongoc_write_result_merge (mongoc_write_result_t *result, /* IN */
+ mongoc_write_command_t *command, /* IN */
+ const bson_t *reply, /* IN */
+ uint32_t offset)
+{
+ int32_t server_index = 0;
+ const bson_value_t *value;
+ bson_iter_t iter;
+ bson_iter_t citer;
+ bson_iter_t ar;
+ int32_t n_upserted = 0;
+ int32_t affected = 0;
+
+ ENTRY;
+
+ BSON_ASSERT (result);
+ BSON_ASSERT (reply);
+
+ if (bson_iter_init_find (&iter, reply, "n") &&
+ BSON_ITER_HOLDS_INT32 (&iter)) {
+ affected = bson_iter_int32 (&iter);
+ }
+
+ if (bson_iter_init_find (&iter, reply, "writeErrors") &&
+ BSON_ITER_HOLDS_ARRAY (&iter) &&
+ bson_iter_recurse (&iter, &citer) &&
+ bson_iter_next (&citer)) {
+ result->failed = true;
+ }
+
+ switch (command->type) {
+ case MONGOC_WRITE_COMMAND_INSERT:
+ result->nInserted += affected;
+ break;
+ case MONGOC_WRITE_COMMAND_DELETE:
+ result->nRemoved += affected;
+ break;
+ case MONGOC_WRITE_COMMAND_UPDATE:
+
+ /* server returns each upserted _id with its index into this batch
+ * look for "upserted": [{"index": 4, "_id": ObjectId()}, ...] */
+ if (bson_iter_init_find (&iter, reply, "upserted")) {
+ if (BSON_ITER_HOLDS_ARRAY (&iter) &&
+ (bson_iter_recurse (&iter, &ar))) {
+
+ while (bson_iter_next (&ar)) {
+ if (BSON_ITER_HOLDS_DOCUMENT (&ar) &&
+ bson_iter_recurse (&ar, &citer) &&
+ bson_iter_find (&citer, "index") &&
+ BSON_ITER_HOLDS_INT32 (&citer)) {
+ server_index = bson_iter_int32 (&citer);
+
+ if (bson_iter_recurse (&ar, &citer) &&
+ bson_iter_find (&citer, "_id")) {
+ value = bson_iter_value (&citer);
+ _mongoc_write_result_append_upsert (result,
+ offset + server_index,
+ value);
+ n_upserted++;
+ }
+ }
+ }
+ }
+ result->nUpserted += n_upserted;
+ /*
+ * XXX: The following addition to nMatched needs some checking.
+ * I'm highly skeptical of it.
+ */
+ result->nMatched += BSON_MAX (0, (affected - n_upserted));
+ } else {
+ result->nMatched += affected;
+ }
+ /*
+ * SERVER-13001 - in a mixed sharded cluster a call to update could
+ * return nModified (>= 2.6) or not (<= 2.4). If any call does not
+ * return nModified we can't report a valid final count so omit the
+ * field completely.
+ */
+ if (bson_iter_init_find (&iter, reply, "nModified") &&
+ BSON_ITER_HOLDS_INT32 (&iter)) {
+ result->nModified += bson_iter_int32 (&iter);
+ } else {
+ /*
+ * nModified could be BSON_TYPE_NULL, which should also be omitted.
+ */
+ result->omit_nModified = true;
+ }
+ break;
+ default:
+ BSON_ASSERT (false);
+ break;
+ }
+
+ if (bson_iter_init_find (&iter, reply, "writeErrors") &&
+ BSON_ITER_HOLDS_ARRAY (&iter)) {
+ _mongoc_write_result_merge_arrays (offset, result, &result->writeErrors,
+ &iter);
+ }
+
+ if (bson_iter_init_find (&iter, reply, "writeConcernError") &&
+ BSON_ITER_HOLDS_DOCUMENT (&iter)) {
+
+ uint32_t len;
+ const uint8_t *data;
+ bson_t write_concern_error;
+ char str[16];
+ const char *key;
+
+ /* writeConcernError is a subdocument in the server response
+ * append it to the result->writeConcernErrors array */
+ bson_iter_document (&iter, &len, &data);
+ bson_init_static (&write_concern_error, data, len);
+
+ bson_uint32_to_string (result->n_writeConcernErrors, &key,
+ str, sizeof str);
+
+ bson_append_document (&result->writeConcernErrors,
+ key, -1, &write_concern_error);
+
+ result->n_writeConcernErrors++;
+ }
+
+ EXIT;
+}
+
+
+/*
+ * If error is not set, set code from first document in array like
+ * [{"code": 64, "errmsg": "duplicate"}, ...]. Format the error message
+ * from all errors in array.
+*/
+static void
+_set_error_from_response (bson_t *bson_array,
+ mongoc_error_domain_t domain,
+ const char *error_type,
+ bson_error_t *error /* OUT */)
+{
+ bson_iter_t array_iter;
+ bson_iter_t doc_iter;
+ bson_string_t *compound_err;
+ const char *errmsg = NULL;
+ int32_t code = 0;
+ uint32_t n_keys, i;
+
+ compound_err = bson_string_new (NULL);
+ n_keys = bson_count_keys (bson_array);
+ if (n_keys > 1) {
+ bson_string_append_printf (compound_err,
+ "Multiple %s errors: ",
+ error_type);
+ }
+
+ if (!bson_empty0 (bson_array) && bson_iter_init (&array_iter, bson_array)) {
+
+ /* get first code and all error messages */
+ i = 0;
+
+ while (bson_iter_next (&array_iter)) {
+ if (BSON_ITER_HOLDS_DOCUMENT (&array_iter) &&
+ bson_iter_recurse (&array_iter, &doc_iter)) {
+
+ /* parse doc, which is like {"code": 64, "errmsg": "duplicate"} */
+ while (bson_iter_next (&doc_iter)) {
+
+ /* use the first error code we find */
+ if (BSON_ITER_IS_KEY (&doc_iter, "code") && code == 0) {
+ code = bson_iter_int32 (&doc_iter);
+ } else if (BSON_ITER_IS_KEY (&doc_iter, "errmsg")) {
+ errmsg = bson_iter_utf8 (&doc_iter, NULL);
+
+ /* build message like 'Multiple write errors: "foo", "bar"' */
+ if (n_keys > 1) {
+ bson_string_append_printf (compound_err, "\"%s\"", errmsg);
+ if (i < n_keys - 1) {
+ bson_string_append (compound_err, ", ");
+ }
+ } else {
+ /* single error message */
+ bson_string_append (compound_err, errmsg);
+ }
+ }
+ }
+
+ i++;
+ }
+ }
+
+ if (code && compound_err->len) {
+ bson_set_error (error, domain, (uint32_t) code,
+ "%s", compound_err->str);
+ }
+ }
+
+ bson_string_free (compound_err, true);
+}
+
+
+bool
+_mongoc_write_result_complete (mongoc_write_result_t *result,
+ bson_t *bson,
+ bson_error_t *error)
+{
+ ENTRY;
+
+ BSON_ASSERT (result);
+
+ if (bson) {
+ BSON_APPEND_INT32 (bson, "nInserted", result->nInserted);
+ BSON_APPEND_INT32 (bson, "nMatched", result->nMatched);
+ if (!result->omit_nModified) {
+ BSON_APPEND_INT32 (bson, "nModified", result->nModified);
+ }
+ BSON_APPEND_INT32 (bson, "nRemoved", result->nRemoved);
+ BSON_APPEND_INT32 (bson, "nUpserted", result->nUpserted);
+ if (!bson_empty0 (&result->upserted)) {
+ BSON_APPEND_ARRAY (bson, "upserted", &result->upserted);
+ }
+ BSON_APPEND_ARRAY (bson, "writeErrors", &result->writeErrors);
+ if (result->n_writeConcernErrors) {
+ BSON_APPEND_ARRAY (bson, "writeConcernErrors",
+ &result->writeConcernErrors);
+ }
+ }
+
+ /* set bson_error_t from first write error or write concern error */
+ _set_error_from_response (&result->writeErrors,
+ MONGOC_ERROR_COMMAND,
+ "write",
+ &result->error);
+
+ if (!result->error.code) {
+ _set_error_from_response (&result->writeConcernErrors,
+ MONGOC_ERROR_WRITE_CONCERN,
+ "write concern",
+ &result->error);
+ }
+
+ if (error) {
+ memcpy (error, &result->error, sizeof *error);
+ }
+
+ RETURN (!result->failed && result->error.code == 0);
+}
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-write-concern-private.h b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-write-concern-private.h
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-write-concern-private.h b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-write-concern-private.h
new file mode 100644
index 0000000..991afa9
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-write-concern-private.h
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-write-concern-private.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MONGOC_WRITE_CONCERN_PRIVATE_H
+#define MONGOC_WRITE_CONCERN_PRIVATE_H
+
+#if !defined (MONGOC_I_AM_A_DRIVER) && !defined (MONGOC_COMPILATION)
+#error "Only <mongoc.h> can be included directly."
+#endif
+
+#include <bson.h>
+
+
+BSON_BEGIN_DECLS
+
+
+#define MONGOC_WRITE_CONCERN_FSYNC_DEFAULT -1
+#define MONGOC_WRITE_CONCERN_JOURNAL_DEFAULT -1
+
+
+struct _mongoc_write_concern_t
+{
+ int8_t fsync_;
+ int8_t journal;
+ int32_t w;
+ int32_t wtimeout;
+ char *wtag;
+ bool frozen;
+ bson_t compiled;
+ bson_t compiled_gle;
+};
+
+
+const bson_t *_mongoc_write_concern_get_gle (mongoc_write_concern_t *write_concern);
+const bson_t *_mongoc_write_concern_get_bson (mongoc_write_concern_t *write_concern);
+bool _mongoc_write_concern_needs_gle (const mongoc_write_concern_t *write_concern);
+bool _mongoc_write_concern_is_valid (const mongoc_write_concern_t *write_concern);
+
+BSON_END_DECLS
+
+
+#endif /* MONGOC_WRITE_CONCERN_PRIVATE_H */
-diff --git a/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-write-concern.c b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-write-concern.c
+diff --git a/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-write-concern.c b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-write-concern.c
new file mode 100644
index 0000000..634288d
--- /dev/null
-+++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-write-concern.c
++++ b/mongodb-1.1.4/src/libmongoc-priv/src/mongoc/mongoc-write-concern.c
@@ -0,0 +1,436 @@
+/*
+ * Copyright 2013 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "mongoc-log.h"
+#include "mongoc-write-concern.h"
+#include "mongoc-write-concern-private.h"
+
+
+static BSON_INLINE bool
+_mongoc_write_concern_warn_frozen (mongoc_write_concern_t *write_concern)
+{
+ if (write_concern->frozen) {
+ MONGOC_WARNING("Cannot modify a frozen write-concern.");
+ }
+
+ return write_concern->frozen;
+}
+
+static void
+_mongoc_write_concern_freeze (mongoc_write_concern_t *write_concern);
+
+
+/**
+ * mongoc_write_concern_new:
+ *
+ * Create a new mongoc_write_concern_t.
+ *
+ * Returns: A newly allocated mongoc_write_concern_t. This should be freed
+ * with mongoc_write_concern_destroy().
+ */
+mongoc_write_concern_t *
+mongoc_write_concern_new (void)
+{
+ mongoc_write_concern_t *write_concern;
+
+ write_concern = (mongoc_write_concern_t *)bson_malloc0(sizeof *write_concern);
+ write_concern->w = MONGOC_WRITE_CONCERN_W_DEFAULT;
+ write_concern->fsync_ = MONGOC_WRITE_CONCERN_FSYNC_DEFAULT;
+ write_concern->journal = MONGOC_WRITE_CONCERN_JOURNAL_DEFAULT;
+
+ return write_concern;
+}
+
+
+mongoc_write_concern_t *
+mongoc_write_concern_copy (const mongoc_write_concern_t *write_concern)
+{
+ mongoc_write_concern_t *ret = NULL;
+
+ if (write_concern) {
+ ret = mongoc_write_concern_new();
+ ret->fsync_ = write_concern->fsync_;
+ ret->journal = write_concern->journal;
+ ret->w = write_concern->w;
+ ret->wtimeout = write_concern->wtimeout;
+ ret->frozen = false;
+ ret->wtag = bson_strdup (write_concern->wtag);
+ }
+
+ return ret;
+}
+
+
+/**
+ * mongoc_write_concern_destroy:
+ * @write_concern: A mongoc_write_concern_t.
+ *
+ * Releases a mongoc_write_concern_t and all associated memory.
+ */
+void
+mongoc_write_concern_destroy (mongoc_write_concern_t *write_concern)
+{
+ if (write_concern) {
+ if (write_concern->compiled.len) {
+ bson_destroy (&write_concern->compiled);
+ bson_destroy (&write_concern->compiled_gle);
+ }
+
+ bson_free (write_concern->wtag);
+ bson_free (write_concern);
+ }
+}
+
+
+bool
+mongoc_write_concern_get_fsync (const mongoc_write_concern_t *write_concern)
+{
+ BSON_ASSERT (write_concern);
+ return (write_concern->fsync_ == true);
+}
+
+
+/**
+ * mongoc_write_concern_set_fsync:
+ * @write_concern: A mongoc_write_concern_t.
+ * @fsync_: If the write concern requires fsync() by the server.
+ *
+ * Set if fsync() should be called on the server before acknowledging a
+ * write request.
+ */
+void
+mongoc_write_concern_set_fsync (mongoc_write_concern_t *write_concern,
+ bool fsync_)
+{
+ BSON_ASSERT (write_concern);
+
+ if (!_mongoc_write_concern_warn_frozen(write_concern)) {
+ write_concern->fsync_ = !!fsync_;
+ }
+}
+
+
+bool
+mongoc_write_concern_get_journal (const mongoc_write_concern_t *write_concern)
+{
+ BSON_ASSERT (write_concern);
+ return (write_concern->journal == true);
+}
+
+
+/**
+ * mongoc_write_concern_set_journal:
+ * @write_concern: A mongoc_write_concern_t.
+ * @journal: If the write should be journaled.
+ *
+ * Set if the write request should be journaled before acknowledging the
+ * write request.
+ */
+void
+mongoc_write_concern_set_journal (mongoc_write_concern_t *write_concern,
+ bool journal)
+{
+ BSON_ASSERT (write_concern);
+
+ if (!_mongoc_write_concern_warn_frozen(write_concern)) {
+ write_concern->journal = !!journal;
+ }
+}
+
+
+int32_t
+mongoc_write_concern_get_w (const mongoc_write_concern_t *write_concern)
+{
+ BSON_ASSERT (write_concern);
+ return write_concern->w;
+}
+
+
+/**
+ * mongoc_write_concern_set_w:
+ * @w: The number of nodes for write or MONGOC_WRITE_CONCERN_W_MAJORITY
+ * for "majority".
+ *
+ * Sets the number of nodes that must acknowledge the write request before
+ * acknowledging the write request to the client.
+ *
+ * You may specifiy @w as MONGOC_WRITE_CONCERN_W_MAJORITY to request that
+ * a "majority" of nodes acknowledge the request.
+ */
+void
+mongoc_write_concern_set_w (mongoc_write_concern_t *write_concern,
+ int32_t w)
+{
+ BSON_ASSERT (write_concern);
+ BSON_ASSERT (w >= -3);
+
+ if (!_mongoc_write_concern_warn_frozen(write_concern)) {
+ write_concern->w = w;
+ }
+}
+
+
+int32_t
+mongoc_write_concern_get_wtimeout (const mongoc_write_concern_t *write_concern)
+{
+ BSON_ASSERT (write_concern);
+ return write_concern->wtimeout;
+}
+
+
+/**
+ * mongoc_write_concern_set_wtimeout:
+ * @write_concern: A mongoc_write_concern_t.
+ * @wtimeout_msec: Number of milliseconds before timeout.
+ *
+ * Sets the number of milliseconds to wait before considering a write
+ * request as failed. A value of 0 indicates no write timeout.
+ *
+ * The @wtimeout_msec parameter must be positive or zero. Negative values will
+ * be ignored.
+ */
+void
+mongoc_write_concern_set_wtimeout (mongoc_write_concern_t *write_concern,
+ int32_t wtimeout_msec)
+{
+ BSON_ASSERT (write_concern);
+
+ if (wtimeout_msec < 0) {
+ return;
+ }
+
+ if (!_mongoc_write_concern_warn_frozen(write_concern)) {
+ write_concern->wtimeout = wtimeout_msec;
+ }
+}
+
+
+bool
+mongoc_write_concern_get_wmajority (const mongoc_write_concern_t *write_concern)
+{
+ BSON_ASSERT (write_concern);
+ return (write_concern->w == MONGOC_WRITE_CONCERN_W_MAJORITY);
+}
+
+
+/**
+ * mongoc_write_concern_set_wmajority:
+ * @write_concern: A mongoc_write_concern_t.
+ * @wtimeout_msec: Number of milliseconds before timeout.
+ *
+ * Sets the "w" of a write concern to "majority". It is suggested that
+ * you provide a reasonable @wtimeout_msec to wait before considering the
+ * write request failed. A @wtimeout_msec value of 0 indicates no write timeout.
+ *
+ * The @wtimeout_msec parameter must be positive or zero. Negative values will
+ * be ignored.
+ */
+void
+mongoc_write_concern_set_wmajority (mongoc_write_concern_t *write_concern,
+ int32_t wtimeout_msec)
+{
+ BSON_ASSERT (write_concern);
+
+ if (!_mongoc_write_concern_warn_frozen(write_concern)) {
+ write_concern->w = MONGOC_WRITE_CONCERN_W_MAJORITY;
+
+ if (wtimeout_msec >= 0) {
+ write_concern->wtimeout = wtimeout_msec;
+ }
+ }
+}
+
+
+const char *
+mongoc_write_concern_get_wtag (const mongoc_write_concern_t *write_concern)
+{
+ BSON_ASSERT (write_concern);
+
+ if (write_concern->w == MONGOC_WRITE_CONCERN_W_TAG) {
+ return write_concern->wtag;
+ }
+
+ return NULL;
+}
+
+
+void
+mongoc_write_concern_set_wtag (mongoc_write_concern_t *write_concern,
+ const char *wtag)
+{
+ BSON_ASSERT (write_concern);
+
+ if (!_mongoc_write_concern_warn_frozen (write_concern)) {
+ bson_free (write_concern->wtag);
+ write_concern->wtag = bson_strdup (wtag);
+ write_concern->w = MONGOC_WRITE_CONCERN_W_TAG;
+ }
+}
+
+/**
+ * mongoc_write_concern_get_bson:
+ * @write_concern: A mongoc_write_concern_t.
+ *
+ * This is an internal function.
+ *
+ * Freeze the write concern if necessary and retrieve the encoded bson_t
+ * representing the write concern.
+ *
+ * You may not modify the write concern further after calling this function.
+ *
+ * Returns: A bson_t that should not be modified or freed as it is owned by
+ * the mongoc_write_concern_t instance.
+ */
+const bson_t *
+_mongoc_write_concern_get_bson (mongoc_write_concern_t *write_concern) {
+ if (!write_concern->frozen) {
+ _mongoc_write_concern_freeze(write_concern);
+ }
+
+ return &write_concern->compiled;
+}
+
+/**
+ * mongoc_write_concern_get_gle:
+ * @write_concern: A mongoc_write_concern_t.
+ *
+ * This is an internal function.
+ *
+ * Freeze the write concern if necessary and retrieve the encoded bson_t
+ * representing the write concern as a get last error command.
+ *
+ * You may not modify the write concern further after calling this function.
+ *
+ * Returns: A bson_t that should not be modified or freed as it is owned by
+ * the mongoc_write_concern_t instance.
+ */
+const bson_t *
+_mongoc_write_concern_get_gle (mongoc_write_concern_t *write_concern) {
+ if (!write_concern->frozen) {
+ _mongoc_write_concern_freeze(write_concern);
+ }
+
+ return &write_concern->compiled_gle;
+}
+
+/**
+ * mongoc_write_concern_freeze:
+ * @write_concern: A mongoc_write_concern_t.
+ *
+ * This is an internal function.
+ *
+ * Freeze the write concern if necessary and encode it into a bson_ts which
+ * represent the raw bson form and the get last error command form.
+ *
+ * You may not modify the write concern further after calling this function.
+ */
+static void
+_mongoc_write_concern_freeze (mongoc_write_concern_t *write_concern)
+{
+ bson_t *compiled;
+ bson_t *compiled_gle;
+
+ BSON_ASSERT (write_concern);
+
+ compiled = &write_concern->compiled;
+ compiled_gle = &write_concern->compiled_gle;
+
+ write_concern->frozen = true;
+
+ bson_init (compiled);
+ bson_init (compiled_gle);
+
+ if (write_concern->w == MONGOC_WRITE_CONCERN_W_TAG) {
+ BSON_ASSERT (write_concern->wtag);
+ BSON_APPEND_UTF8 (compiled, "w", write_concern->wtag);
+ } else if (write_concern->w == MONGOC_WRITE_CONCERN_W_MAJORITY) {
+ BSON_APPEND_UTF8 (compiled, "w", "majority");
+ } else if (write_concern->w == MONGOC_WRITE_CONCERN_W_DEFAULT) {
+ /* Do Nothing */
+ } else if (write_concern->w > 0) {
+ BSON_APPEND_INT32 (compiled, "w", write_concern->w);
+ }
+
+ if (write_concern->fsync_ != MONGOC_WRITE_CONCERN_FSYNC_DEFAULT) {
+ bson_append_bool(compiled, "fsync", 5, !!write_concern->fsync_);
+ }
+
+ if (write_concern->journal != MONGOC_WRITE_CONCERN_JOURNAL_DEFAULT) {
+ bson_append_bool(compiled, "j", 1, !!write_concern->journal);
+ }
+
+ if (write_concern->wtimeout) {
+ bson_append_int32(compiled, "wtimeout", 8, write_concern->wtimeout);
+ }
+
+ BSON_APPEND_INT32 (compiled_gle, "getlasterror", 1);
+ bson_concat (compiled_gle, compiled);
+}
+
+
+/**
+ * mongoc_write_concern_needs_gle:
+ * @concern: (in): A mongoc_write_concern_t.
+ *
+ * Checks to see if @write_concern requests that a getlasterror command is to
+ * be delivered to the MongoDB server.
+ *
+ * Returns: true if a getlasterror command should be sent.
+ */
+bool
+_mongoc_write_concern_needs_gle (const mongoc_write_concern_t *write_concern)
+{
+ if (write_concern) {
+ return (((write_concern->w != MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED) &&
+ (write_concern->w != MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED)) ||
+ mongoc_write_concern_get_fsync(write_concern) ||
+ mongoc_write_concern_get_journal(write_concern));
+ }
+ return false;
+}
+
+
+/**
+ * _mongoc_write_concern_is_valid:
+ * @write_concern: (in): A mongoc_write_concern_t.
+ *
+ * Checks to see if @write_concern is valid and does not contain conflicting
+ * options.
+ *
+ * Returns: true if the write concern is valid; otherwise false.
+ */
+bool
+_mongoc_write_concern_is_valid (const mongoc_write_concern_t *write_concern)
+{
+ if (!write_concern) {
+ return false;
+ }
+
+ /* Journal or fsync should require acknowledgement. */
+ if ((mongoc_write_concern_get_fsync (write_concern) ||
+ mongoc_write_concern_get_journal (write_concern)) &&
+ (write_concern->w == MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED ||
+ write_concern->w == MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED)) {
+ return false;
+ }
+
+ if (write_concern->wtimeout < 0) {
+ return false;
+ }
+
+ return true;
+}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jun 16, 12:18 AM (2 w, 2 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
70369
Default Alt Text
(315 KB)

Event Timeline