Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
301 KB
Referenced Files
None
Subscribers
None
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/debian/control b/debian/control
index 78499a1f..91d1e01e 100644
--- a/debian/control
+++ b/debian/control
@@ -1,27 +1,27 @@
Source: php-mongodb
Section: php
Priority: optional
Maintainer: Debian PHP PECL Maintainers <pkg-php-pecl@lists.alioth.debian.org>
Uploaders: Ondřej Surý <ondrej@debian.org>
+Build-Conflicts: libmongoc-priv-dev (>= 1.3.0-1~)
Build-Depends: debhelper (>= 9~),
dh-php,
libpcre3-dev,
libsasl2-dev,
libbson-dev (>= 1.3.0-1~),
libmongoc-dev (>= 1.3.0-1~),
- libmongoc-priv-dev (>= 1.3.0-1~),
php-all-dev
Standards-Version: 3.9.6
Homepage: https://pecl.php.net/package/mongodb
Package: php-mongodb
Architecture: any
Depends: ucf,
${misc:Depends},
${php:Depends},
${shlibs:Depends}
Description: MongoDB driver for PHP
The purpose of this driver is to provide exceptionally thin glue
between MongoDB and PHP, implementing only fundemental and
performance-critical components necessary to build a fully-functional
MongoDB driver.
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 e2253f3a..4ae7cdf8 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,38 +1,9281 @@
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 | 10 ++++------
- 1 file changed, 4 insertions(+), 6 deletions(-)
+ mongodb-1.1.2/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-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-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 +++++++++++++++++
+ .../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-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
diff --git a/mongodb-1.1.2/config.m4 b/mongodb-1.1.2/config.m4
-index 4d03388..f28e95b 100644
+index 4d03388..b99fbdd 100644
--- a/mongodb-1.1.2/config.m4
+++ b/mongodb-1.1.2/config.m4
-@@ -68,8 +68,6 @@ AC_DEFUN([PHP_BSON_CLOCK],
- fi
- ])
+@@ -287,6 +287,17 @@ MONGOC_SOURCES_SSL="\
+ MONGOC_SOURCES_SASL=mongoc-sasl.c
--MONGOC_SYMBOL_SUFFIX="priv"
--
- AC_MSG_CHECKING(PHP version)
- PHP_FOUND_VERSION=`${PHP_CONFIG} --version`
- PHP_FOUND_VERNUM=`echo "${PHP_FOUND_VERSION}" | $AWK 'BEGIN { FS = "."; } { printf "%d", ([$]1 * 100 + [$]2) * 100 + [$]3;}'`
-@@ -339,11 +337,11 @@ PHP_ARG_WITH(libmongoc, whether to use system libmongoc,
+
++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
- 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)
+ 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
+new file mode 100644
+index 0000000..5674a0b
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..30a82f2
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..663f819
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..b42eb7d
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..0b9b890
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..88e8b68
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..72c625e
+--- /dev/null
++++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-cluster-private.h
+@@ -0,0 +1,150 @@
++/*
++ * 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,
++ 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,
++ 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
+new file mode 100644
+index 0000000..9147822
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..4d93164
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..d789780
+--- /dev/null
++++ b/mongodb-1.1.2/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;
++ 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,
++ 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
+new file mode 100644
+index 0000000..9cf93fd
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..5a6c431
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..49bf1cc
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..47e13f3
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..3de75a1
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..4983500
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..f742db3
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..621003e
+--- /dev/null
++++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-server-description-private.h
+@@ -0,0 +1,114 @@
++/*
++ * 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
++
++
++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;
++ 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_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_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
+new file mode 100644
+index 0000000..0a2cde3
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..896dfe3
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..1c42d93
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..b71d139
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..fd428c2
+--- /dev/null
++++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology-description-private.h
+@@ -0,0 +1,97 @@
++/*
++ * 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;
++ 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
+new file mode 100644
+index 0000000..678b5fb
+--- /dev/null
++++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-topology-description.c
+@@ -0,0 +1,1351 @@
++/*
++ * 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->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.
++ *
++ * 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;
++}
++
++/*
++ *--------------------------------------------------------------------------
++ *
++ * _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_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_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)) {
++ /* 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);
++ }
++
++ /* '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
+new file mode 100644
+index 0000000..fc7f982
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..c8517ac
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..be7eb9a
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..df33181
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..c58ae5d
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..8e7f5a3
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..c9525a8
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..3c44fb9
+--- /dev/null
++++ b/mongodb-1.1.2/src/libmongoc-priv/src/mongoc/mongoc-write-command.c
+@@ -0,0 +1,1519 @@
++/*
++ * 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 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.
++ * server guarantees there is enough room: SERVER-10643
++ */
++ int32_t max_cmd_size = max_bson_size + 16382;
++
++ 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 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,
++ 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,
++ gCommandFields[command->type],
++ command->documents);
++ i = command->n_documents;
++ } else {
++ bson_append_array_begin (&cmd, gCommandFields[command->type], -1, &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,
++ 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);
++
++ 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
+new file mode 100644
+index 0000000..991afa9
+--- /dev/null
++++ b/mongodb-1.1.2/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
+new file mode 100644
+index 0000000..634288d
+--- /dev/null
++++ b/mongodb-1.1.2/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:30 AM (2 w, 1 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
71164
Default Alt Text
(301 KB)

Event Timeline