Skip site navigation (1)Skip section navigation (2)

  
 
  

home | help
MONGOC_REFERENCE(3)		    libmongoc		     MONGOC_REFERENCE(3)

LIBMONGOC - API
     A Cross Platform MongoDB Client Library for C

     This  site  documents the API. For tutorials, guides, and explainers, see -
     MongoDB C Driver.

   Introduction
     The MongoDB C Driver, also known as "libmongoc", is  a  library  for  using
     MongoDB   from   C   applications,  and  for  writing  MongoDB  drivers  in
     higher-level languages.

     It depends on libbson to generate and parse BSON documents, the native data
     format of MongoDB.

   API Reference
   Initialization and cleanup
   Synopsis
     Initialize the MongoDB C Driver by calling mongoc_init()  exactly	once  at
     the  beginning  of  your program. It is responsible for initializing global
     state such as process counters, SSL, and threading primitives.

     Exception to this is mongoc_log_set_handler(), which should be  called  be-
     fore mongoc_init() or some log traces would not use your log handling func-
     tion. See Custom Log Handlers for a detailed example.

     Call  mongoc_cleanup()  exactly  once at the end of your program to release
     all memory and other resources allocated by the driver. You must  not  call
     any  other  MongoDB  C  Driver  functions after mongoc_cleanup(). Note that
     mongoc_init() does not reinitialize the driver after mongoc_cleanup().

   Deprecated feature: automatic initialization and cleanup
     On some platforms the driver can automatically  call  mongoc_init()  before
     main,  and  call mongoc_cleanup() as the process exits. This is problematic
     in situations where related libraries also execute cleanup  code  on  shut-
     down, and it creates inconsistent rules across platforms. Therefore the au-
     tomatic  initialization  and  cleanup  feature  is  deprecated, and will be
     dropped in version 2.0. Meanwhile, for backward compatibility, the  feature
     is enabled by default on platforms where it is available.

     For   portable,   future-proof   code,   always   call   mongoc_init()  and
     mongoc_cleanup() yourself, and configure the driver like:

	cmake -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF

   Logging
     The MongoDB C driver has two different types of logging available:

     * The original mongoc_log facility supports freeform string  messages  that
       originate  from the driver itself or from application code. This has been
       retroactively termed "unstructured logging".

     * A new mongoc_structured_log facility reports messages from the driver it-
       self using a BSON format defined across driver implementations by  the  -
       MongoDB Logging Specification.

     These two systems are configured and used independently.

   Unstructured Logging
     This  is  the  original logging facility that supports freeform string mes-
     sages originating from the driver itself or from application code. This has
     been retroactively termed "unstructured logging".	See  Structured  Logging
     for the newer standardized logging facility.

	typedef enum {
	   MONGOC_LOG_LEVEL_ERROR,
	   MONGOC_LOG_LEVEL_CRITICAL,
	   MONGOC_LOG_LEVEL_WARNING,
	   MONGOC_LOG_LEVEL_MESSAGE,
	   MONGOC_LOG_LEVEL_INFO,
	   MONGOC_LOG_LEVEL_DEBUG,
	   MONGOC_LOG_LEVEL_TRACE,
	} mongoc_log_level_t;

	#define MONGOC_ERROR(...)
	#define MONGOC_CRITICAL(...)
	#define MONGOC_WARNING(...)
	#define MONGOC_MESSAGE(...)
	#define MONGOC_INFO(...)
	#define MONGOC_DEBUG(...)

	typedef void (*mongoc_log_func_t) (mongoc_log_level_t log_level,
					   const char *log_domain,
					   const char *message,
					   void *user_data);

	void
	mongoc_log_set_handler (mongoc_log_func_t log_func, void *user_data);
	void
	mongoc_log (mongoc_log_level_t log_level,
		    const char *log_domain,
		    const char *format,
		    ...);
	const char *
	mongoc_log_level_str (mongoc_log_level_t log_level);
	void
	mongoc_log_default_handler (mongoc_log_level_t log_level,
				    const char *log_domain,
				    const char *message,
				    void *user_data);
	void
	mongoc_log_trace_enable (void);
	void
	mongoc_log_trace_disable (void);

     This  abstraction	can  be used for logging in your application, or you can
     integrate the driver with an existing logging system.

   Macros
     To make logging a little less painful, various helper macros are  provided.
     See the following example.

	#undef MONGOC_LOG_DOMAIN
	#define MONGOC_LOG_DOMAIN "my-custom-domain"

	MONGOC_WARNING ("An error occurred: %s", strerror (errno));

   Custom Log Handlers
     The  default  log handler prints a timestamp and the log message to stdout,
     or to stderr for warnings, critical messages, and errors.	You can override
     the handler with mongoc_log_set_handler().  Your handler function is called
     in a mutex for thread safety.

     For example, you could register a custom handler to  suppress  messages  at
     INFO level and below:

	void
	my_logger (mongoc_log_level_t log_level,
		   const char *log_domain,
		   const char *message,
		   void *user_data)
	{
	   /* smaller values are more important */
	   if (log_level < MONGOC_LOG_LEVEL_INFO) {
	      mongoc_log_default_handler (log_level, log_domain, message, user_data);
	   }
	}

	int
	main (int argc, char *argv[])
	{
	   mongoc_log_set_handler (my_logger, NULL);
	   mongoc_init ();

	   /* ... your code ...  */

	   mongoc_cleanup ();
	   return 0;
	}

     Note  that  in  the example above mongoc_log_set_handler() is called before
     mongoc_init().  Otherwise, some log traces could not be  processed  by  the
     log handler.

     To restore the default handler:

	mongoc_log_set_handler (mongoc_log_default_handler, NULL);

   Disable logging
     To  disable  all logging, including warnings, critical messages and errors,
     provide an empty log handler:

	mongoc_log_set_handler (NULL, NULL);

   Tracing
     If compiling your own copy of the MongoDB C  driver,  consider  configuring
     with  -DENABLE_TRACING=ON	to enable function tracing and hex dumps of net-
     work packets to STDERR and STDOUT during development and debugging.

     This is especially useful when debugging what may be going on internally in
     the driver.

     Trace messages can be enabled and disabled by calling  mongoc_log_trace_en-
     able() and mongoc_log_trace_disable()

     NOTE:
	Compiling  the	driver	with -DENABLE_TRACING=ON will affect its perfor-
	mance. Disabling tracing with  mongoc_log_trace_disable()  significantly
	reduces the overhead, but cannot remove it completely.

   Structured Logging
     This document describes a newer "structured" logging facility which reports
     messages  from  the driver itself using a BSON format defined across driver
     implementations by the MongoDB  Logging  Specification.   See  Unstructured
     Logging for the original freeform logging facility.

     These two systems are configured and used independently.

     Unstructured  logging  is global to the entire process, but structured log-
     ging   is	 configured   separately    for    each    mongoc_client_t    or
     mongoc_client_pool_t.    See   mongoc_client_set_structured_log_opts()  and
     mongoc_client_pool_set_structured_log_opts().

   Options
     Structured    log	  settings    are    tracked	 explicitly	by     a
     mongoc_structured_log_opts_t instance.

     Like  other drivers supporting structured logging, we take default settings
     from environment variables and offer additional optional programmatic  con-
     figuration.       Environment     variables     are     captured	  during
     mongoc_structured_log_opts_new(), refer there for a full list of  the  sup-
     ported variables.

     Normally environment variables provide defaults that can be overridden pro-
     grammatically.   To  request the opposite behavior, where your programmatic
     defaults	 can	be    overridden     by     the     environment,     see
     mongoc_structured_log_opts_set_max_levels_from_env().

     Structured  log  messages may be filtered in arbitrary ways by the handler,
     but as both a performance optimization and a convenience, a built-in filter
     limits the maximum log level of reported messages with a per-component set-
     ting.

   mongoc_structured_log_opts_t
   Synopsis
	typedef struct mongoc_structured_log_opts_t mongoc_structured_log_opts_t;

     mongoc_structured_log_opts_t is an opaque type that  contains  options  for
     the  structured  logging  subsystem:  per-component  log  levels, a maximum
     logged document length, and a handler function.

     Create	       a	    mongoc_structured_log_opts_t	    with
     mongoc_structured_log_opts_new(),	set  options  and a callback on it, then
     pass      it      to	mongoc_client_set_structured_log_opts()       or
     mongoc_client_pool_set_structured_log_opts().  Must be destroyed by calling
     mongoc_structured_log_opts_destroy().

   Functions
   mongoc_structured_log_opts_new()
   Synopsis
	mongoc_structured_log_opts_t *
	mongoc_structured_log_opts_new (void);

     Creates  a  new mongoc_structured_log_opts_t, filled with defaults captured
     from the current environment.

     Sets a default log handler which would write a text representation of  each
     log  message  to  stderr,	stdout,  or another file configurable using MON-
     GODB_LOG_PATH.  This setting has no effect if the default	handler  is  re-
     placed using mongoc_structured_log_opts_set_handler().

     Environment  variable errors are non-fatal, and result in one-time warnings
     delivered as an unstructured log.

     Per-component maximum levels are initialized equivalently to:

	mongoc_structured_log_opts_set_max_level_for_all_components(opts, MONGOC_STRUCTURED_LOG_LEVEL_WARNING);
	mongoc_structured_log_opts_set_max_levels_from_env(opts);

   Environment Variables
     This is a full list of the captured environment variables.

     * MONGODB_LOG_MAX_DOCUMENT_LENGTH: Maximum length for JSON-serialized docu-
       ments that appear within a log message.	It may be a number, in bytes, or
       unlimited (case insensitive) to choose an  implementation-specific  value
       near  the  maximum  representable  length.  By default, the limit is 1000
       bytes.  This limit affects interior documents like commands and	replies,
       not the total length of a structured log message.

     * MONGODB_LOG_PATH:  A  file  path  or one of the special strings stderr or
       stdout (case insensitive) specifying the destination for structured  logs
       seen by the default handler.  By default, it writes to stderr.  This path
       will be captured during mongoc_structured_log_opts_new(), but it will not
       immediately  be	opened.   If the file can't be opened, a warning is then
       written to the unstructured log and the handler writes structured logs to
       stderr instead.

       WARNING:
	  When a file path is given for MONGODB_LOG_PATH, each log instance (one
	  stand-alone client or pool) will separately open this file for append.
	  The results are operating system specific. On UNIX-like platforms each
	  instance's output will be interleaved, in most cases without splitting
	  individual log messages. Notably on Windows the file will be opened in
	  exclusive mode by the first instance	and  subsequent  instances  will
	  fail,  falling  back	on the default of stderr.  Applications that use
	  multiple processes or multiple client pools will likely want to supply
	  a log handler that annotates each message with information  about  its
	  originating log instance.

     * MONGODB_LOG_COMMAND:  A	log  level  name  to set as the maximum for MON-
       GOC_STRUCTURED_LOG_COMPONENT_COMMAND.

     * MONGODB_LOG_TOPOLOGY: A log level name to set as  the  maximum  for  MON-
       GOC_STRUCTURED_LOG_COMPONENT_TOPOLOGY.

     * MONGODB_LOG_SERVER_SELECTION:  A log level name to set as the maximum for
       MONGOC_STRUCTURED_LOG_COMPONENT_SERVER_SELECTION.

     * MONGODB_LOG_CONNECTION: A log level name to set as the maximum  for  MON-
       GOC_STRUCTURED_LOG_COMPONENT_CONNECTION.

     * MONGODB_LOG_ALL: A log level name applied to all components not otherwise
       specified.

     Note that log level names are always case insensitive.  This is a full list
     of recognized names, including allowed aliases:

     * emergency, off

     * alert

     * critical

     * error

     * warning, warn

     * notice

     * informational, info

     * debug

     * trace

   Returns
     A newly allocated mongoc_structured_log_opts_t.

   mongoc_structured_log_opts_destroy()
   Synopsis
	void
	mongoc_structured_log_opts_destroy (mongoc_structured_log_opts_t *opts);

   Parameters
     * opts:   Pointer	 to   a   mongoc_structured_log_opts_t	 allocated  with
       mongoc_structured_log_opts_new(), or NULL.

   Description
     This    function	 releases    all    resources	 associated    with    a
     mongoc_structured_log_opts_t.  Does nothing if opts is NULL.

   mongoc_structured_log_opts_set_handler()
   Synopsis
	void
	mongoc_structured_log_opts_set_handler (mongoc_structured_log_opts_t *opts,
						mongoc_structured_log_func_t log_func,
						void *user_data);

     Sets  the	function  to  be  called to handle structured log messages, as a
     mongoc_structured_log_func_t.

     The callback is given a mongoc_structured_log_entry_t as a handle	for  ob-
     taining  additional  information about the log message.  This entry pointer
     is only valid during a callback, because it's a low cost reference to  tem-
     porary data.

     Structured  log  handlers	must  be  thread-safe  if they will be used with
     mongoc_client_pool_t.  Handlers must avoid unbounded recursion,  preferably
     by  avoiding  the	use  of any libmongoc client or pool which uses the same
     handler.

     This   function   always	replaces   the	 default   log	 handler    from
     mongoc_structured_log_opts_new(),	if it was still set.  If the log_func is
     set to NULL, structured logging will be disabled.

   Parameters
     * opts:	  Structured	   log	     options,	    allocated	    with
       mongoc_structured_log_opts_new().

     * log_func: The handler to install, a mongoc_structured_log_func_t, or NULL
       to disable structured logging.

     * user_data: Optional user data, passed on to the handler.

     SEE ALSO:
	Structured Logging

   mongoc_structured_log_opts_set_max_level_for_component()
   Synopsis
	bool
	mongoc_structured_log_opts_set_max_level_for_component (mongoc_structured_log_opts_t *opts,
								mongoc_structured_log_component_t component,
								mongoc_structured_log_level_t level);

     Sets  the	maximum  log level per-component.  Only log messages at or below
     this severity level will be passed to mongoc_structured_log_func_t.

     By default, each component's log level may come from environment variables.
     See mongoc_structured_log_opts_set_max_levels_from_env().

   Parameters
     * opts:	  Structured	   log	     options,	    allocated	    with
       mongoc_structured_log_opts_new().

     * component:   The   component   to   set	a  max	log  level.  for,  as  a
       mongoc_structured_log_component_t.

     * level:	The   new   max   log	level	for   this   component,   as   a
       mongoc_structured_log_level_t.

   Returns
     Returns  true  on	success, or false if the supplied parameters were incor-
     rect.

     SEE ALSO:
	Structured Logging

   mongoc_structured_log_opts_set_max_level_for_all_components()
   Synopsis
	bool
	mongoc_structured_log_opts_set_max_level_for_all_components (mongoc_structured_log_opts_t *opts,
								     mongoc_structured_log_level_t level);

     Sets all per-component maximum log levels to the same value.  Only log mes-
     sages   at   or   below   this   severity	 level	 will	be   passed   to
     mongoc_structured_log_func_t.   Effective	even  for logging components not
     known at compile-time.

   Parameters
     * opts:	  Structured	   log	     options,	    allocated	    with
       mongoc_structured_log_opts_new().

     * level:	 The	max    log    level    for    all   components,   as   a
       mongoc_structured_log_level_t.

   Returns
     Returns true on success, or false if the supplied	parameters  were  incor-
     rect.

     SEE ALSO:
	Structured Logging

   mongoc_structured_log_opts_set_max_levels_from_env()
   Synopsis
	bool
	mongoc_structured_log_opts_set_max_levels_from_env (mongoc_structured_log_opts_t *opts);

     Sets  any	maximum  log  levels  requested  by  environment variables: MON-
     GODB_LOG_ALL for all components, followed by per-component log levels  MON-
     GODB_LOG_COMMAND,	MONGODB_LOG_CONNECTION,  MONGODB_LOG_TOPOLOGY,	and MON-
     GODB_LOG_SERVER_SELECTION.

     Expects	   the	     value	 to	  be	   recognizable       by
     mongoc_structured_log_get_named_level().	Parse errors may cause a warning
     message, delivered via unstructured logging.

     Component levels with no valid environment variable setting  will	be  left
     unmodified.

     This  happens  automatically  when  mongoc_structured_log_opts_new() estab-
     lishes  defaults.	 Any  subsequent  programmatic	modifications	to   the
     mongoc_structured_log_opts_t  will  override  the environment variable set-
     tings.  For applications that desire the opposite behavior, where	environ-
     ment  variables  may  override  programmatic  settings,  they may call mon-
     goc_structured_log_opts_set_max_levels_from_env()	     after	 calling
     mongoc_structured_log_opts_set_max_level_for_component()		     and
     mongoc_structured_log_opts_set_max_level_for_all_components().   This  will
     process  the  environment a second time, allowing it to override customized
     defaults.

   Returns
     Returns true on success.  If warnings are encountered in  the  environment,
     returns  false  and may log additional information to the unstructured log-
     ging facility.  Note that, by design, these errors are by	default  non-fa-
     tal.  When mongoc_structured_log_opts_new() internally calls this function,
     it ignores the return value.

     SEE ALSO:
	Structured Logging

   mongoc_structured_log_opts_get_max_level_for_component()
   Synopsis
	mongoc_structured_log_level_t
	mongoc_structured_log_opts_get_max_level_for_component (const mongoc_structured_log_opts_t *opts,
								mongoc_structured_log_component_t component);

   Parameters
     * opts:	   Structured	    log       options,	     allocated	    with
       mongoc_structured_log_opts_new().

     * component: Log component as a mongoc_structured_log_component_t.

   Returns
     Returns the configured maximum log level for a  specific  component,  as  a
     mongoc_structured_log_level_t.   This  may  be  the  last	value  set  with
     mongoc_structured_log_opts_set_max_level_for_component()		      or
     mongoc_structured_log_opts_set_max_level_for_all_components(), or it may be
     the  default obtained from environment variables.	If an invalid or unknown
     component enum is given, returns the lowest log level.

     SEE ALSO:
	Structured Logging

   mongoc_structured_log_opts_set_max_document_length()
   Synopsis
	bool
	mongoc_structured_log_opts_set_max_document_length (mongoc_structured_log_opts_t *opts,
							    size_t max_document_length);

     Sets a maximum length for BSON documents that  appear  serialized	in  JSON
     form as part of a structured log message.

     Serialized  JSON will be truncated at this limit, interpreted as a count of
     UTF-8 encoded bytes. Truncation will be indicated with a  ...  suffix,  the
     length  of  which is not included in the max document length. If truncation
     at the exact indicated length would split a valid UTF-8  sequence,  we  in-
     stead  truncate  the  document earlier at the nearest boundary between code
     points.

   Parameters
     * opts:	  Structured	   log	     options,	    allocated	    with
       mongoc_structured_log_opts_new().

     * max_document_length:  Maximum  length for each embedded JSON document, in
       bytes, not including an ellipsis (...) added to indicate truncation. Val-
       ues near or above INT_MAX will be rejected.

   Returns
     Returns true on success, or false if the supplied	maximum  length  is  too
     large.

     SEE ALSO:
	Structured Logging
	mongoc_structured_log_opts_set_max_document_length_from_env()

   mongoc_structured_log_opts_set_max_document_length_from_env()
   Synopsis
	bool
	mongoc_structured_log_opts_set_max_document_length_from_env (mongoc_structured_log_opts_t *opts);

     Sets a maximum document length from the MONGODB_LOG_MAX_DOCUMENT_LENGTH en-
     vironment	  variable,    if    a	  valid    setting    is   found.    See
     mongoc_structured_log_opts_new() for a description of the	supported  envi-
     ronment variable formats.

     Parse  errors  may cause a warning message, delivered via unstructured log-
     ging.

     This happens  automatically  when	mongoc_structured_log_opts_new()  estab-
     lishes   defaults.    Any	subsequent  programmatic  modifications  to  the
     mongoc_structured_log_opts_t will override the  environment  variable  set-
     tings.   For applications that desire the opposite behavior, where environ-
     ment variables may override  programmatic	settings,  they  may  call  mon-
     goc_structured_log_opts_set_max_document_length_from_env()   after  calling
     mongoc_structured_log_opts_set_max_document_length().   This  will  process
     the environment a second time, allowing it to override customized defaults.

   Returns
     Returns  true  on success: either a valid environment setting was found, or
     the value is unset and opts will not be modified.	If warnings are  encoun-
     tered  in the environment, returns false and may log additional information
     to the unstructured logging facility.  Note that, by design,  these  errors
     are by default non-fatal.	When mongoc_structured_log_opts_new() internally
     calls this function, it ignores the return value.

     SEE ALSO:
	Structured Logging

   mongoc_structured_log_opts_get_max_document_length()
   Synopsis
	size_t
	mongoc_structured_log_opts_get_max_document_length (const mongoc_structured_log_opts_t *opts);

   Parameters
     * opts:	   Structured	    log       options,	     allocated	    with
       mongoc_structured_log_opts_new().

   Returns
     Returns the current maximum document length set in opts, as a size_t.

     SEE ALSO:
	Structured Logging

     SEE ALSO:
	Structured Logging

   Levels and Components
     Log levels and components are defined as mongoc_structured_log_level_t  and
     mongoc_structured_log_component_t	enumerations.  Utilities are provided to
     convert between these values and their standard string representations. The
     string values are case-insensitive.

	typedef enum {
	  MONGOC_STRUCTURED_LOG_LEVEL_EMERGENCY = 0,  // "Emergency" ("off" also accepted)
	  MONGOC_STRUCTURED_LOG_LEVEL_ALERT = 1,      // "Alert"
	  MONGOC_STRUCTURED_LOG_LEVEL_CRITICAL = 2,   // "Critical"
	  MONGOC_STRUCTURED_LOG_LEVEL_ERROR = 3,      // "Error"
	  MONGOC_STRUCTURED_LOG_LEVEL_WARNING = 4,    // "Warning" ("warn" also accepted)
	  MONGOC_STRUCTURED_LOG_LEVEL_NOTICE = 5,     // "Notice"
	  MONGOC_STRUCTURED_LOG_LEVEL_INFO = 6,       // "Informational" ("info" also accepted)
	  MONGOC_STRUCTURED_LOG_LEVEL_DEBUG = 7,      // "Debug"
	  MONGOC_STRUCTURED_LOG_LEVEL_TRACE = 8,      // "Trace"
	} mongoc_structured_log_level_t;

	typedef enum {
	  MONGOC_STRUCTURED_LOG_COMPONENT_COMMAND = 0,		 // "command"
	  MONGOC_STRUCTURED_LOG_COMPONENT_TOPOLOGY = 1, 	 // "topology"
	  MONGOC_STRUCTURED_LOG_COMPONENT_SERVER_SELECTION = 2,  // "serverSelection"
	  MONGOC_STRUCTURED_LOG_COMPONENT_CONNECTION = 3,	 // "connection"
	} mongoc_structured_log_component_t;

   mongoc_structured_log_level_t
   Synopsis
	typedef enum {
	   MONGOC_STRUCTURED_LOG_LEVEL_EMERGENCY = 0,
	   MONGOC_STRUCTURED_LOG_LEVEL_ALERT = 1,
	   MONGOC_STRUCTURED_LOG_LEVEL_CRITICAL = 2,
	   MONGOC_STRUCTURED_LOG_LEVEL_ERROR = 3,
	   MONGOC_STRUCTURED_LOG_LEVEL_WARNING = 4,
	   MONGOC_STRUCTURED_LOG_LEVEL_NOTICE = 5,
	   MONGOC_STRUCTURED_LOG_LEVEL_INFO = 6,
	   MONGOC_STRUCTURED_LOG_LEVEL_DEBUG = 7,
	   MONGOC_STRUCTURED_LOG_LEVEL_TRACE = 8,
	} mongoc_structured_log_level_t;

     mongoc_structured_log_level_t enumerates the available log levels	for  use
     with structured logging.

   Functions
   mongoc_structured_log_get_level_name()
   Synopsis
	const char *
	mongoc_structured_log_get_level_name (mongoc_structured_log_level_t level);

   Parameters
     * level: Log level as a mongoc_structured_log_level_t.

   Returns
     If  the  level is known, returns a pointer to a constant string that should
     not be freed.  If the level has no known name, returns NULL.

     SEE ALSO:
	Structured Logging

   mongoc_structured_log_get_named_level()
   Synopsis
	bool
	mongoc_structured_log_get_named_level (const char *name, mongoc_structured_log_level_t *out);

     Look up a log level by name. Case insensitive.

   Parameters
     * name: A name to look up as a log level.

     * out: On success, the corresponding mongoc_structured_log_level_t is writ-
       ten here.

   Returns
     If the level name is known, returns true and writes the level enum to *out.
     If the level name is not known, returns false and does not write *out.

     SEE ALSO:
	Structured Logging

     SEE ALSO:
	Structured Logging

   mongoc_structured_log_component_t
   Synopsis
	typedef enum {
	   MONGOC_STRUCTURED_LOG_COMPONENT_COMMAND = 0,
	   MONGOC_STRUCTURED_LOG_COMPONENT_TOPOLOGY = 1,
	   MONGOC_STRUCTURED_LOG_COMPONENT_SERVER_SELECTION = 2,
	   MONGOC_STRUCTURED_LOG_COMPONENT_CONNECTION = 3,
	} mongoc_structured_log_component_t;

     mongoc_structured_log_component_t enumerates the structured logging  compo-
     nents.   Applications should never rely on having an exhaustive list of all
     log		components.		    Instead,		     use
     mongoc_structured_log_opts_set_max_level_for_all_components()  to set a de-
     fault level if needed.

   Functions
   mongoc_structured_log_get_component_name()
   Synopsis
	const char *
	mongoc_structured_log_get_component_name (mongoc_structured_log_component_t component);

   Parameters
     * component: Log component as a mongoc_structured_log_component_t.

   Returns
     If the component is known, returns a pointer  to  a  constant  string  that
     should not be freed.  If the component has no known name, returns NULL.

     SEE ALSO:
	Structured Logging

   mongoc_structured_log_get_named_component()
   Synopsis
	bool
	mongoc_structured_log_get_named_component (const char *name, mongoc_structured_log_component_t *out);

     Look up a component by name. Case insensitive.

   Parameters
     * name: A name to look up as a log component.

     * out:  On  success, the corresponding mongoc_structured_log_component_t is
       written here.

   Returns
     If the component name is known, returns true and writes the component  enum
     to  *out.	 If  the component name is not known, returns false and does not
     write *out.

     SEE ALSO:
	Structured Logging

     SEE ALSO:
	Structured Logging

     SEE ALSO:
	mongoc_structured_log_get_level_name			   mongoc_struc-
	tured_log_get_named_level  mongoc_structured_log_get_component_name mon-
	goc_structured_log_get_named_component

   Log Handlers
     Each mongoc_client_pool_t or standalone mongoc_client_t  has  its	own  in-
     stance  of the structured logging subsystem, with its own settings and han-
     dler.

     When using mongoc_client_pool_t, the pooled clients all share a common log-
     ging instance. Handlers must be thread-safe.

     The handler is called for each log entry with a level no greater  than  its
     component's  maximum.  A mongoc_structured_log_entry_t pointer provides ac-
     cess to further details, during the handler only.

     Handlers  must  take  care  not  to  re-enter  libmongoc  with   the   same
     mongoc_client_t  or  mongoc_client_pool_t	that the handler has been called
     by.

   mongoc_structured_log_func_t
   Synopsis
	typedef void (*mongoc_structured_log_func_t)
	(const mongoc_structured_log_entry_t *entry, void *user_data);

     Callback function for mongoc_structured_log_opts_set_handler().  Structured
     log  handlers  must  be   thread-safe   if   they	 will	be   used   with
     mongoc_client_pool_t.   Handlers must avoid unbounded recursion, preferably
     by avoiding the use of any libmongoc client or pool  which  uses  the  same
     handler.

   Parameters
     * entry:  A  mongoc_structured_log_entry_t  pointer,  only valid during the
       handler invocation.

     * user_data:	   Optional	      user	     data	    from
       mongoc_structured_log_opts_set_handler().

     SEE ALSO:
	Structured Logging

   Log Entries
     Each  log	entry  is  represented	within	the  handler  by  a  short-lived
     mongoc_structured_log_entry_t pointer.  During the  handler,  this  pointer
     can  be  used  to	access the individual properties of an entry: its level,
     component, and message.

     The message will be assembled as a bson_t only when explicitly requested by
     a call to mongoc_structured_log_entry_message_as_bson().  This results in a
     standalone document that may be retained for any amount of time and must be
     explicitly destroyed.

   mongoc_structured_log_entry_t
   Synopsis
	typedef struct mongoc_structured_log_entry_t mongoc_structured_log_entry_t;

     mongoc_structured_log_entry_t is an opaque structure which  represents  the
     temporary	state of an in-progress log entry.  It can only be used during a
     mongoc_structured_log_func_t, it is not valid after  the  log  handler  re-
     turns.   Use the functions below to query individual aspects of the log en-
     try.

   Functions
   mongoc_structured_log_entry_get_component()
   Synopsis
	mongoc_structured_log_component_t
	mongoc_structured_log_entry_get_component (const mongoc_structured_log_entry_t *entry);

   Parameters
     * entry: A mongoc_structured_log_entry_t pointer.

   Returns
     The mongoc_structured_log_component_t associated with this log entry.

     SEE ALSO:
	Structured Logging

   mongoc_structured_log_entry_get_level()
   Synopsis
	mongoc_structured_log_level_t
	mongoc_structured_log_entry_get_level (const mongoc_structured_log_entry_t *entry);

   Parameters
     * entry: A mongoc_structured_log_entry_t pointer.

   Returns
     The mongoc_structured_log_level_t associated with this log entry.

     SEE ALSO:
	Structured Logging

   mongoc_structured_log_entry_get_message_string()
   Synopsis
	const char *
	mongoc_structured_log_entry_get_message_string (const mongoc_structured_log_entry_t *entry);

   Parameters
     * entry: A mongoc_structured_log_entry_t pointer.

   Returns
     A string, guaranteed to be valid only during the lifetime of the structured
     log handler.  It should not be freed or modified.

     Identical to the value of the message  key  in  the  document  returned  by
     mongoc_structured_log_entry_message_as_bson().

     This  is  not  a  complete string representation of the structured log, but
     rather a standardized identifier for a particular log event.

     SEE ALSO:
	Structured Logging

   mongoc_structured_log_entry_message_as_bson()
   Synopsis
	bson_t *
	mongoc_structured_log_entry_message_as_bson (const mongoc_structured_log_entry_t *entry);

     Make a new copy, as a bson_t, of the log entry's standardized  BSON  repre-
     sentation.   When possible, a log handler should avoid serializing log mes-
     sages that will be discarded.  Each call allocates an independent	copy  of
     the message that must be freed.

   Parameters
     * entry: A mongoc_structured_log_entry_t pointer.

   Returns
     A new allocated bson_t that must be freed with a call to bson_destroy().

     SEE ALSO:
	Structured Logging

     SEE ALSO:
	Structured Logging

   Example
     example-structured-log.c

	/* gcc example-structured-log.c -o example-structured-log \
	 *     $(pkg-config --cflags --libs libmongoc-1.0) */

	#include <mongoc/mongoc.h>
	#include <pthread.h>
	#include <stdio.h>
	#include <stdlib.h>

	static pthread_mutex_t handler_mutex;

	static void
	example_handler (const mongoc_structured_log_entry_t *entry, void *user_data)
	{
	   mongoc_structured_log_component_t component = mongoc_structured_log_entry_get_component (entry);
	   mongoc_structured_log_level_t level = mongoc_structured_log_entry_get_level (entry);
	   const char *message_string = mongoc_structured_log_entry_get_message_string (entry);

	   /*
	    * With a single-threaded mongoc_client_t, handlers will always be called
	    * by the thread that owns the client. On a mongoc_client_pool_t, handlers
	    * are shared by multiple threads and must be reentrant.
	    *
	    * Note that unstructured logging includes a global mutex in the API,
	    * but structured logging allows applications to avoid lock contention
	    * even when multiple threads are issuing commands simultaneously.
	    *
	    * Simple apps like this example can achieve thread safety by adding their
	    * own global mutex. For other apps, this would be a performance bottleneck
	    * and it would be more appropriate for handlers to process their log
	    * messages concurrently.
	    *
	    * In this example, our mutex protects access to a global log counter.
	    * In a real application, you may need to protect access to a shared stream
	    * or queue.
	    */
	   pthread_mutex_lock (&handler_mutex);

	   static unsigned log_serial_number = 0;

	   printf ("%u. Log entry with component=%s level=%s message_string='%s'\n",
		   ++log_serial_number,
		   mongoc_structured_log_get_component_name (component),
		   mongoc_structured_log_get_level_name (level),
		   message_string);

	   /*
	    * At this point, the handler might make additional filtering decisions
	    * before asking for a bson_t. As an example, let's log the component and
	    * level for all messages but only show contents for command logs.
	    */
	   if (component == MONGOC_STRUCTURED_LOG_COMPONENT_COMMAND) {
	      bson_t *message = mongoc_structured_log_entry_message_as_bson (entry);
	      char *json = bson_as_relaxed_extended_json (message, NULL);
	      printf ("Full log message, as json: %s\n", json);
	      bson_destroy (message);
	      bson_free (json);
	   }

	   pthread_mutex_unlock (&handler_mutex);
	}

	int
	main (void)
	{
	   const char *uri_string = "mongodb://localhost:27017";
	   int result = EXIT_FAILURE;
	   bson_error_t error;
	   mongoc_uri_t *uri = NULL;
	   mongoc_structured_log_opts_t *log_opts = NULL;
	   mongoc_client_t *client = NULL;
	   mongoc_client_pool_t *pool = NULL;

	   /*
	    * Note that structured logging only applies per-client or per-pool,
	    * and it won't be used during or before mongoc_init.
	    */
	   mongoc_init ();

	   /*
	    * Logging options are represented by a mongoc_structured_log_opts_t,
	    * which can be copied into a mongoc_client_t or mongoc_client_pool_t
	    * using mongoc_client_set_structured_log_opts() or
	    * mongoc_client_pool_set_structured_log_opts(), respectively.
	    *
	    * Default settings are captured from the environment into
	    * this structure when it's constructed.
	    */
	   log_opts = mongoc_structured_log_opts_new ();

	   /*
	    * For demonstration purposes, set up a handler that receives all possible log messages.
	    */
	   pthread_mutex_init (&handler_mutex, NULL);
	   mongoc_structured_log_opts_set_max_level_for_all_components (log_opts, MONGOC_STRUCTURED_LOG_LEVEL_TRACE);
	   mongoc_structured_log_opts_set_handler (log_opts, example_handler, NULL);

	   /*
	    * By default libmongoc proceses log options from the environment first,
	    * and then allows you to apply programmatic overrides. To request the
	    * opposite behavior, allowing the environment to override programmatic
	    * defaults, you can ask for the environment to be re-read after setting
	    * your own defaults.
	    */
	   mongoc_structured_log_opts_set_max_levels_from_env (log_opts);

	   /*
	    * Create a MongoDB URI object. This example assumes a local server.
	    */
	   uri = mongoc_uri_new_with_error (uri_string, &error);
	   if (!uri) {
	      fprintf (stderr, "URI parse error: %s\n", error.message);
	      goto done;
	   }

	   /*
	    * Create a new client pool.
	    */
	   pool = mongoc_client_pool_new (uri);
	   if (!pool) {
	      goto done;
	   }

	   /*
	    * Set the client pool's log options.
	    * This must happen only once, and only before the first mongoc_client_pool_pop.
	    * There's no need to keep log_opts after this point.
	    */
	   mongoc_client_pool_set_structured_log_opts (pool, log_opts);

	   /*
	    * Check out a client, and do some work that we'll see logs from.
	    * This example just sends a 'ping' command.
	    */
	   client = mongoc_client_pool_pop (pool);
	   if (!client) {
	      goto done;
	   }

	   bson_t *command = BCON_NEW ("ping", BCON_INT32 (1));
	   bson_t reply;
	   bool command_ret = mongoc_client_command_simple (client, "admin", command, NULL, &reply, &error);
	   bson_destroy (command);
	   bson_destroy (&reply);
	   mongoc_client_pool_push (pool, client);
	   if (!command_ret) {
	      fprintf (stderr, "Command error: %s\n", error.message);
	      goto done;
	   }

	   result = EXIT_SUCCESS;
	done:
	   mongoc_uri_destroy (uri);
	   mongoc_structured_log_opts_destroy (log_opts);
	   mongoc_client_pool_destroy (pool);
	   mongoc_cleanup ();
	   return result;
	}

     SEE ALSO:
	mongoc_structured_log_entry_get_component      mongoc_structured_log_en-
	try_get_level mongoc_structured_log_entry_message_as_bson
     A<< libmongoc - API

   Error Reporting
   Description
     Many C Driver functions report errors by returning false or -1 and  filling
     out a bson_error_t structure with an error domain, error code, and message.
     Use  domain  to determine which subsystem generated the error, and code for
     the specific error. message is a human-readable error description.

     SEE ALSO:
	Handling Errors in libbson.

+----------------------+----------------------------------+--------------------------------------------+
| Code		       | Description			  |					       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ERROR_CLIENT  | MONGOC_ER-			  | You tried to send  a		       |
|		       | ROR_CLIENT_TOO_BIG		  | message  larger than		       |
|		       |				  | the   server's   max		       |
|		       |				  | message size.			       |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ER-			  | Wrong   credentials,		       |
|		       | ROR_CLIENT_AUTHENTI-		  | or	failure  sending		       |
|		       | CATE				  | or receiving authen-		       |
|		       |				  | tication messages.			       |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ER-			  | You   tried  an  TLS		       |
|		       | ROR_CLIENT_NO_AC-		  | connection	but  the		       |
|		       | CEPTABLE_PEER			  | driver was not built		       |
|		       |				  | with TLS.				       |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ER-			  | You  began iterating		       |
|		       | ROR_CLIENT_IN_EX-		  | an	exhaust  cursor,		       |
|		       | HAUST				  | then  tried to begin		       |
|		       |				  | another    operation		       |
|		       |				  | with     the    same		       |
|		       |				  | mongoc_client_t.			       |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ER-			  | Failure  related  to		       |
|		       | ROR_CLIENT_SES-		  | creating  or using a		       |
|		       | SION_FAILURE			  | logical session.			       |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ER-			  | Failure  related  to		       |
|		       | ROR_CLIENT_IN- 		  | arguments	  passed		       |
|		       | VALID_ENCRYPTION_ARG		  | when    initializing		       |
|		       |				  | In-Use Encryption.			       |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ER-			  | Failure  related  to		       |
|		       | ROR_CLIENT_IN- 		  | In-Use Encryption.			       |
|		       | VALID_ENCRYP-			  |					       |
|		       | TION_STATE			  |					       |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ER-			  | You   attempted   to		       |
|		       | ROR_CLIENT_IN- 		  | connect to a MongoDB		       |
|		       | VALID_LOAD_BALANCER		  | server behind a load		       |
|		       |				  | balancer,	but  the		       |
|		       |				  | server does not  ad-		       |
|		       |				  | vertize   load  bal-		       |
|		       |				  | anced support.			       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ERROR_STREAM  | MONGOC_ER-			  | DNS failure.			       |
|		       | ROR_STREAM_NAME_RES-		  |					       |
|		       | OLUTION			  |					       |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ER-			  | Timeout  communicat-		       |
|		       | ROR_STREAM_SOCKET		  | ing  with server, or		       |
|		       |				  | connection closed.			       |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ER-			  | Failed to connect to		       |
|		       | ROR_STREAM_CONNECT		  | server.				       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ERROR_PROTO-  | MONGOC_ERROR_PROTO-		  | Corrupt	response		       |
| COL		       | COL_INVALID_REPLY		  | from server.			       |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ERROR_PROTO-		  | The  server  version		       |
|		       | COL_BAD_WIRE_VERSION		  | is too  old  or  too		       |
|		       |				  | new  to  communicate		       |
|		       |				  | with the driver.			       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ERROR_CURSOR  | MONGOC_ERROR_CUR-		  | You passed bad argu-		       |
|		       | SOR_INVALID_CURSOR		  | ments	      to		       |
|		       |				  | mongoc_collection_find_with_opts(),        |
|		       |				  | or	   you	  called		       |
|		       |				  | mongoc_cursor_next()		       |
|		       |				  | on	a  completed  or		       |
|		       |				  | failed   cursor,  or		       |
|		       |				  | the cursor timed out		       |
|		       |				  | on the server.			       |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ER-			  | A resume token was not returned  in        |
|		       | ROR_CHANGE_STREAM_NO_RE-	  | a	   document	 found	   with        |
|		       | SUME_TOKEN			  | mongoc_change_stream_next() 	       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ERROR_QUERY   | MONGOC_ERROR_QUERY_FAIL-	  | Error API Version 1:  Server  error        |
|		       | URE				  | from  command  or query. The server        |
|		       |				  | error message is in message.	       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ERROR_SERVER  | MONGOC_ERROR_QUERY_FAIL-	  | Error API Version 2:  Server  error        |
|		       | URE				  | from  command  or query. The server        |
|		       |				  | error message is in message.	       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ERROR_SASL    | A SASL error code.		  | man  sasl_errors  for  a  list   of        |
|		       |				  | codes.				       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ERROR_BSON    | MONGOC_ERROR_BSON_IN-		  | You  passed an invalid or oversized        |
|		       | VALID				  | BSON document as  a  parameter,  or        |
|		       |				  | called				       |
|		       |				  | mongoc_collection_create_index()	       |
|		       |				  | with  invalid  keys,  or the server        |
|		       |				  | reply was corrupt.			       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ERROR_NAME-   | MONGOC_ERROR_NAME-		  | You tried to  create  a  collection        |
| SPACE 	       | SPACE_INVALID			  | with an invalid name.		       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ERROR_COMMAND | MONGOC_ERROR_COMMAND_IN-	  | Many  functions set this error code        |
|		       | VALID_ARG			  | when passed bad  parameters.  Print        |
|		       |				  | the error message for details.	       |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ERROR_PROTO-		  | You  tried	to use a command option        |
|		       | COL_BAD_WIRE_VERSION		  | the server does not support.	       |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ERROR_DUPLI-		  | An insert or update failed	because        |
|		       | CATE_KEY			  | because of a duplicate _id or other        |
|		       |				  | unique-index violation.		       |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ER-			  | The  operation  failed because max-        |
|		       | ROR_MAX_TIME_MS_EXPIRED	  | TimeMS expired.			       |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ERROR_SERVER_SE-	  | The serverId option for  an  opera-        |
|		       | LECTION_INVALID_ID		  | tion   conflicts  with  the  pinned        |
|		       |				  | server for that operation's  client        |
|		       |				  | session  (denoted  by the sessionId        |
|		       |				  | option).				       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ERROR_COMMAND | Error code from server.	  | Error API Version 1:  Server  error        |
|		       |				  | from  a  command.  The server error        |
|		       |				  | message is in message.		       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ERROR_SERVER  | Error code from server.	  | Error API Version 2:  Server  error        |
|		       |				  | from  a  command.  The server error        |
|		       |				  | message is in message.		       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ERROR_COLLEC- | MONGOC_ERROR_COLLEC-		  | Invalid    or    empty   input   to        |
| TION		       | TION_INSERT_FAILED, MON-	  | mongoc_collection_insert_one(),	       |
|		       | GOC_ERROR_COLLECTION_UP-	  | mongoc_collection_insert_bulk(),	       |
|		       | DATE_FAILED,  MONGOC_ER-	  | mongoc_collection_update_one(),	       |
|		       | ROR_COLLEC-			  | mongoc_collection_update_many(),	       |
|		       | TION_DELETE_FAILED.		  | mongoc_collection_replace_one(),	       |
|		       |				  | mongoc_collection_delete_one(),  or        |
|		       |				  | mongoc_collection_delete_many().	       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ERROR_COLLEC- | Error code from server.	  | Error  API	Version 1: Server error        |
| TION		       |				  | from				       |
|		       |				  | mongoc_collection_insert_one(),	       |
|		       |				  | mongoc_collection_insert_bulk(),	       |
|		       |				  | mongoc_collection_update_one(),	       |
|		       |				  | mongoc_collection_update_many(),	       |
|		       |				  | mongoc_collection_replace_one(),	       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ERROR_SERVER  | Error code from server.	  | Error API Version 2:  Server  error        |
|		       |				  | from				       |
|		       |				  | mongoc_collection_insert_one(),	       |
|		       |				  | mongoc_collection_insert_bulk(),	       |
|		       |				  | mongoc_collection_update_one(),	       |
|		       |				  | mongoc_collection_update_many(),	       |
|		       |				  | mongoc_collection_replace_one(),	       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ERROR_GRIDFS  | MONGOC_ER-			  | The  GridFS file is missing a docu-        |
|		       | ROR_GRIDFS_CHUNK_MISSING	  | ment in its chunks collection.	       |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ERROR_GRIDFS_COR-	  | A data inconsistency  was  detected        |
|		       | RUPT				  | in GridFS.				       |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ERROR_GRIDFS_IN-	  | You   passed  a  NULL  filename  to        |
|		       | VALID_FILENAME 		  | mongoc_gridfs_remove_by_filename().        |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ERROR_GRIDFS_PRO-	  | You 			 called        |
|		       | TOCOL_ERROR			  | mongoc_gridfs_file_set_id()   after        |
|		       |				  | mongoc_gridfs_file_save(), or tried        |
|		       |				  | to write on a closed GridFS stream.        |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ER-			  | A GridFS file is missing from files        |
|		       | ROR_GRIDFS_BUCKET_FILE_NOT_FOUND | collection. 			       |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ER-			  | An error occurred on a stream  cre-        |
|		       | ROR_GRIDFS_BUCKET_STREAM	  | ated  from	a GridFS operation like        |
|		       |				  | mongoc_gridfs_bucket_upload_from_stream(). |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ERROR_SCRAM   | MONGOC_ERROR_SCRAM_PROTOCOL_ER-  | Failure in	SCRAM-SHA-1  or  SCRAM-SHA-256 |
|		       | ROR				  | authentication.			       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ER-	       | MONGOC_ERROR_SERVER_SELEC-	  | No	replica set member or mongos is avail- |
| ROR_SERVER_SELECTION | TION_FAILURE			  | able, or none matches  your  read  prefer- |
|		       |				  | ence,   or	 you   supplied   an   invalid |
|		       |				  | mongoc_read_prefs_t.		       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ER-	       | Error code from server.	  | There was a write concern error or timeout |
| ROR_WRITE_CONCERN    |				  | from the server.			       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ERROR_TRANS-  | MONGOC_ERROR_TRANSACTION_INVALID | You attempted to start a transaction  when |
| ACTION	       |				  | one  is  already in progress, or commit or |
|		       |				  | abort when there is no transaction.        |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ER-	       | Error code produced  by  libmon- | An error occurred in the library responsi- |
| ROR_CLIENT_SIDE_EN-  | gocrypt.			  | ble for In-Use Encryption		       |
| CRYPTION	       |				  |					       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ERROR_AZURE   | MONGOC_ERROR_KMS_SERVER_HTTP	  | An	Azure  HTTP  service responded with an |
|		       |				  | error status			       |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ERROR_KMS_SERVER_BAD_JSON | An Azure service  responded  with  invalid |
|		       |				  | JSON data				       |
+----------------------+----------------------------------+--------------------------------------------+
| MONGOC_ERROR_GCP     | MONGOC_ERROR_KMS_SERVER_HTTP	  | A GCP HTTP service responded with an error |
|		       |				  | status				       |
+----------------------+----------------------------------+--------------------------------------------+
|		       | MONGOC_ERROR_KMS_SERVER_BAD_JSON | A  GCP service responded with invalid JSON |
|		       |				  | data				       |
+----------------------+----------------------------------+--------------------------------------------+

   Error Labels
     In some cases your application must make decisions based on  what	category
     of  error	the  driver has returned, but these categories do not correspond
     perfectly to an error domain or code. In such cases, error labels provide a
     reliable way to determine how your application should respond to an error.

     Any C Driver function that has a bson_t out-parameter named reply	may  in-
     clude  error labels to the reply, in the form of a BSON field named "error-
     Labels" containing an array of strings:

	{ "errorLabels": [ "TransientTransactionError" ] }

     Use mongoc_error_has_label() to test if a reply contains a specific  label.
     See  mongoc_client_session_start_transaction() for example code that demon-
     strates the use of error labels in application logic.

     The following error labels are currently defined. Future versions	of  Mon-
     goDB may introduce new labels.

   TransientTransactionError
     Within  a multi-document transaction, certain errors can leave the transac-
     tion in an unknown or aborted state. These include write conflicts, primary
     stepdowns, and network errors. In response, the  application  should  abort
     the  transaction  and  try  the  same sequence of operations again in a new
     transaction.

   UnknownTransactionCommitResult
     When mongoc_client_session_commit_transaction() encounters a network  error
     or  certain server errors, it is not known whether the transaction was com-
     mitted. Applications should attempt to commit the transaction again  until:
     the  commit  succeeds, the commit fails with an error not labeled "Unknown-
     TransactionCommitResult", or the application chooses to give up.

   Setting the Error API Version
     The driver's error reporting began with a design flaw: when the  error  do-
     main  is  MONGOC_ERROR_COLLECTION, MONGOC_ERROR_QUERY, or MONGOC_ERROR_COM-
     MAND, the error code might originate from the server or the driver. An  ap-
     plication	cannot always know where an error originated, and therefore can-
     not tell what the code means.

     For example, if mongoc_collection_update_one() sets the error's  domain  to
     MONGOC_ERROR_COLLECTION  and  its	code  to 24, the application cannot know
     whether 24 is the generic	driver	error  code  MONGOC_ERROR_COLLECTION_UP-
     DATE_FAILED or the specific server error code "LockTimeout".

     To  fix this flaw while preserving backward compatibility, the C Driver 1.4
     introduces "Error API Versions". Version 1, the default Error API	Version,
     maintains	the  flawed  behavior.	Version  2 adds a new error domain, MON-
     GOC_ERROR_SERVER. In Version 2, error codes originating on the  server  al-
     ways  have  error domain MONGOC_ERROR_SERVER or MONGOC_ERROR_WRITE_CONCERN.
     When the driver uses Version 2 the application  can  always  determine  the
     origin  and  meaning of error codes. New applications should use Version 2,
     and existing applications should be updated to use Version 2 as well.
+-----------------------------------------------+----------------------+---------------------+
| Error Source					| API Version 1        | API Version 2	     |
+-----------------------------------------------+----------------------+---------------------+
| mongoc_cursor_error() 			| MONGOC_ERROR_QUERY   | MONGOC_ERROR_SERVER |
+-----------------------------------------------+----------------------+---------------------+
| mongoc_client_command_with_opts(),		| MONGOC_ERROR_QUERY   | MONGOC_ERROR_SERVER |
| mongoc_database_command_with_opts(),		|		       |		     |
| and	other	command 			|		       |		     |
| functions					|		       |		     |
+-----------------------------------------------+----------------------+---------------------+
| mongoc_collection_count_with_opts()		| MONGOC_ERROR_QUERY   | MONGOC_ERROR_SERVER |
| mongoc_client_get_database_names_with_opts(), |		       |		     |
| and other command helper functions		|		       |		     |
+-----------------------------------------------+----------------------+---------------------+
| mongoc_collection_insert_one()		| MONGOC_ERROR_COMMAND | MONGOC_ERROR_SERVER |
| mongoc_collection_insert_bulk()		|		       |		     |
| mongoc_collection_update_one()		|		       |		     |
| mongoc_collection_update_many()		|		       |		     |
| mongoc_collection_replace_one()		|		       |		     |
| mongoc_collection_delete_one()		|		       |		     |
| mongoc_collection_delete_many()		|		       |		     |
+-----------------------------------------------+----------------------+---------------------+
| mongoc_bulk_operation_execute()		| MONGOC_ERROR_COMMAND | MONGOC_ERROR_SERVER |
+-----------------------------------------------+----------------------+---------------------+
| Write-concern timeout 			| MONGOC_ER-	       | MONGOC_ER-	     |
|						| ROR_WRITE_CONCERN    | ROR_WRITE_CONCERN   |
+-----------------------------------------------+----------------------+---------------------+

     The Error API Versions are defined with MONGOC_ERROR_API_VERSION_LEGACY and
     MONGOC_ERROR_API_VERSION_2.	Set	   the	      version	    with
     mongoc_client_set_error_api() or mongoc_client_pool_set_error_api().

     SEE ALSO:
	MongoDB Server Error Codes

   Object Lifecycle
     This page documents the order of creation and destruction	for  libmongoc's
     main struct types.

   Clients and pools
     Call  mongoc_init() once, before calling any other libmongoc functions, and
     call mongoc_cleanup() once before your program exits.

     A program that  uses  libmongoc  from  multiple  threads  should  create  a
     mongoc_client_pool_t  with mongoc_client_pool_new(). Each thread acquires a
     mongoc_client_t from the pool with mongoc_client_pool_pop() and returns  it
     with mongoc_client_pool_push() when the thread is finished using it. To de-
     stroy    the    pool,    first    return	 all	clients,    then    call
     mongoc_client_pool_destroy().

     If  your  program	uses  libmongoc  from  only   one   thread,   create   a
     mongoc_client_t	   directly	  with	     mongoc_client_new()      or
     mongoc_client_new_from_uri(). Destroy it with mongoc_client_destroy().

   Databases, collections, and related objects
     You  can  create  a  mongoc_database_t  or   mongoc_collection_t	from   a
     mongoc_client_t,  and  create  a mongoc_cursor_t or mongoc_bulk_operation_t
     from a mongoc_collection_t.

     Each of these objects must be destroyed before the client they were created
     from, but their lifetimes are otherwise independent.

   GridFS objects
     You  can  create  a  mongoc_gridfs_t  from  a  mongoc_client_t,  create   a
     mongoc_gridfs_file_t  or  mongoc_gridfs_file_list_t from a mongoc_gridfs_t,
     create a mongoc_gridfs_file_t from a mongoc_gridfs_file_list_t, and  create
     a mongoc_stream_t from a mongoc_gridfs_file_t.

     Each of these objects depends on the object it was created from. Always de-
     stroy  GridFS  objects  in  the reverse of the order they were created. The
     sole exception is that a mongoc_gridfs_file_t need not be destroyed  before
     the mongoc_gridfs_file_list_t it was created from.

   GridFS bucket objects
     Create  mongoc_gridfs_bucket_t  with  a  mongoc_database_t  derived  from a
     mongoc_client_t.	The   mongoc_database_t   is   independent   from    the
     mongoc_gridfs_bucket_t.   But   the   mongoc_client_t   must   outlive  the
     mongoc_gridfs_bucket_t.

     A mongoc_stream_t may  be	created  from  the  mongoc_gridfs_bucket_t.  The
     mongoc_gridfs_bucket_t must outlive the mongoc_stream_t.

   Sessions
     Start  a  session with mongoc_client_start_session(), use the session for a
     sequence of operations and multi-document transactions, then free	it  with
     mongoc_client_session_destroy().	     Any	mongoc_cursor_t       or
     mongoc_change_stream_t using a session must be destroyed  before  the  ses-
     sion,  and  a  session must be destroyed before the mongoc_client_t it came
     from.

     By default, sessions are causally consistent.  To	disable  causal  consis-
     tency,  before  starting  a  session  create  a  mongoc_session_opt_t  with
     mongoc_session_opts_new()			   and			    call
     mongoc_session_opts_set_causal_consistency(),  then  free	the  struct with
     mongoc_session_opts_destroy().

     Unacknowledged writes are prohibited with sessions.

     A mongoc_client_session_t must be used by only one thread at a time. Due to
     session pooling, mongoc_client_start_session() may return	a  session  that
     has  been idle for some time and is about to be closed after its idle time-
     out. Use the session within one minute of acquiring it to refresh the  ses-
     sion and avoid a timeout.

   Client Side Encryption
     When   configuring   a   mongoc_client_t	for   automatic  encryption  via
     mongoc_client_enable_auto_encryption(), if a separate key vault  client  is
     set  in the options (via mongoc_auto_encryption_opts_set_keyvault_client())
     the key vault client must outlive the encrypted client.

     When  configuring	a  mongoc_client_pool_t  for  automatic  encryption  via
     mongoc_client_pool_enable_auto_encryption(), if a separate key vault client
     pool	  is	     set	in	  the	     options	    (via
     mongoc_auto_encryption_opts_set_keyvault_client_pool())   the   key   vault
     client pool must outlive the encrypted client pool.

     When creating a mongoc_client_encryption_t, the configured key vault client
     (set  via mongoc_client_encryption_opts_set_keyvault_client()) must outlive
     the mongoc_client_encryption_t.

   GridFS
     The C driver includes two APIs for GridFS.

     The older API consists of mongoc_gridfs_t and its derivatives. It	contains
     deprecated  API,  does not support read preferences, and is not recommended
     in new applications. It does not conform to the MongoDB  GridFS  specifica-
     tion.

     The newer API consists of mongoc_gridfs_bucket_t and allows uploading/down-
     loading through derived mongoc_stream_t objects. It conforms to the MongoDB
     GridFS specification.

     There  is	not  always  a	straightforward upgrade path from an application
     built   with   mongoc_gridfs_t   to    mongoc_gridfs_bucket_t    (e.g.    a
     mongoc_gridfs_file_t  provides  functions	to seek but mongoc_stream_t does
     not). But users are encouraged to upgrade when possible.

   mongoc_auto_encryption_opts_t
     Options for enabling automatic encryption and decryption for In-Use Encryp-
     tion.

   Synopsis
	typedef struct _mongoc_auto_encryption_opts_t mongoc_auto_encryption_opts_t;

     SEE ALSO:
	In-Use Encryption

   mongoc_bulkwrite_t
   Synopsis
	typedef struct _mongoc_bulkwrite_t mongoc_bulkwrite_t;

   Description
     mongoc_bulkwrite_t provides an abstraction for  submitting  multiple  write
     operations as a single batch.

     After  adding  all  of the write operations to the mongoc_bulkwrite_t, call
     mongoc_bulkwrite_execute() to execute the operation.

     WARNING:
	It  is	only  valid  to  call	mongoc_bulkwrite_execute()   once.   The
	mongoc_bulkwrite_t must be destroyed afterwards.

     NOTE:
	If   using   MongoDB   server	8.0+,	prefer	mongoc_bulkwrite_t  over
	mongoc_bulk_operation_t to reduce network round trips.

	mongoc_bulkwrite_t uses the bulkWrite server command introduced in  Mon-
	goDB  server  8.0. bulkWrite command supports insert, update, and delete
	operations in the same payload. bulkWrite supports use of multiple  col-
	lection namespaces in the same payload.

	mongoc_bulk_operation_t  uses  the insert, update and delete server com-
	mands available in all current MongoDB server versions. Write operations
	are grouped by type (insert, update, delete) and sent in  separate  com-
	mands. Only one collection may be specified per bulk write.

   mongoc_bulkwriteopts_t
   Synopsis
	typedef struct _mongoc_bulkwriteopts_t mongoc_bulkwriteopts_t;

   mongoc_bulkwriteresult_t
   Synopsis
	typedef struct _mongoc_bulkwriteresult_t mongoc_bulkwriteresult_t;

   mongoc_bulkwriteexception_t
   Synopsis
	typedef struct _mongoc_bulkwriteexception_t mongoc_bulkwriteexception_t;

   mongoc_bulk_operation_t
     Bulk Write Operations

   Synopsis
	typedef struct _mongoc_bulk_operation_t mongoc_bulk_operation_t;

   Description
     mongoc_bulk_operation_t  provides	an  abstraction  for submitting multiple
     write operations as a single batch.

     After adding all of the write operations  to  the	mongoc_bulk_operation_t,
     call mongoc_bulk_operation_execute() to execute the operation.

     WARNING:
	It  is only valid to call mongoc_bulk_operation_execute() once. The mon-
	goc_bulk_operation_t must be destroyed afterwards.

     SEE ALSO:
	Bulk Write Operations
	mongoc_bulkwrite_t

     NOTE:
	If  using  MongoDB   server   8.0+,   prefer   mongoc_bulkwrite_t   over
	mongoc_bulk_operation_t to reduce network round trips.

	mongoc_bulkwrite_t  uses the bulkWrite server command introduced in Mon-
	goDB server 8.0. bulkWrite command supports insert, update,  and  delete
	operations  in the same payload. bulkWrite supports use of multiple col-
	lection namespaces in the same payload.

	mongoc_bulk_operation_t uses the insert, update and delete  server  com-
	mands available in all current MongoDB server versions. Write operations
	are  grouped  by type (insert, update, delete) and sent in separate com-
	mands. Only one collection may be specified per bulk write.

   mongoc_change_stream_t
   Synopsis
	#include <mongoc/mongoc.h>

	typedef struct _mongoc_change_stream_t mongoc_change_stream_t;

     mongoc_change_stream_t is a handle to a change stream. A collection  change
     stream can be obtained using mongoc_collection_watch().

     It is recommended to use a mongoc_change_stream_t and its functions instead
     of  a  raw aggregation with a $changeStream stage. For more information see
     the MongoDB Manual Entry on Change Streams.

   Example
     example-collection-watch.c

	#include <mongoc/mongoc.h>

	int
	main (void)
	{
	   bson_t empty = BSON_INITIALIZER;
	   const bson_t *doc;
	   bson_t *to_insert = BCON_NEW ("x", BCON_INT32 (1));
	   const bson_t *err_doc;
	   bson_error_t error;
	   const char *uri_string;
	   mongoc_uri_t *uri;
	   mongoc_client_t *client;
	   mongoc_collection_t *coll;
	   mongoc_change_stream_t *stream;
	   mongoc_write_concern_t *wc = mongoc_write_concern_new ();
	   bson_t opts = BSON_INITIALIZER;
	   bool r;

	   mongoc_init ();

	   uri_string = "mongodb://"
			"localhost:27017,localhost:27018,localhost:"
			"27019/db?replicaSet=rs0";

	   uri = mongoc_uri_new_with_error (uri_string, &error);
	   if (!uri) {
	      fprintf (stderr,
		       "failed to parse URI: %s\n"
		       "error message:	     %s\n",
		       uri_string,
		       error.message);
	      return EXIT_FAILURE;
	   }

	   client = mongoc_client_new_from_uri (uri);
	   if (!client) {
	      return EXIT_FAILURE;
	   }

	   coll = mongoc_client_get_collection (client, "db", "coll");
	   stream = mongoc_collection_watch (coll, &empty, NULL);

	   mongoc_write_concern_set_wmajority (wc, 10000);
	   mongoc_write_concern_append (wc, &opts);
	   r = mongoc_collection_insert_one (coll, to_insert, &opts, NULL, &error);
	   if (!r) {
	      fprintf (stderr, "Error: %s\n", error.message);
	      return EXIT_FAILURE;
	   }

	   while (mongoc_change_stream_next (stream, &doc)) {
	      char *as_json = bson_as_relaxed_extended_json (doc, NULL);
	      fprintf (stderr, "Got document: %s\n", as_json);
	      bson_free (as_json);
	   }

	   if (mongoc_change_stream_error_document (stream, &error, &err_doc)) {
	      if (!bson_empty (err_doc)) {
		 fprintf (stderr, "Server Error: %s\n", bson_as_relaxed_extended_json (err_doc, NULL));
	      } else {
		 fprintf (stderr, "Client Error: %s\n", error.message);
	      }
	      return EXIT_FAILURE;
	   }

	   bson_destroy (to_insert);
	   mongoc_write_concern_destroy (wc);
	   bson_destroy (&opts);
	   mongoc_change_stream_destroy (stream);
	   mongoc_collection_destroy (coll);
	   mongoc_uri_destroy (uri);
	   mongoc_client_destroy (client);
	   mongoc_cleanup ();

	   return EXIT_SUCCESS;
	}

   Starting and Resuming
     All watch functions accept several  options  to  indicate	where  a  change
     stream  should  start  returning changes from: resumeAfter, startAfter, and
     startAtOperationTime.

     All changes returned by mongoc_change_stream_next() include a resume  token
     in  the  _id field. MongoDB 4.2 also includes an additional resume token in
     each "aggregate" and "getMore" command response, which points to the end of
     that response's batch. The current token is automatically cached by libmon-
     goc. In the event of an error, libmongoc attempts to  recreate  the  change
     stream  starting where it left off by passing the cached resume token. lib-
     mongoc only attempts to resume once, but client applications can access the
     cached resume token with mongoc_change_stream_get_resume_token() and use it
     for their own resume logic by passing  it	as  either  the  resumeAfter  or
     startAfter option.

     Additionally,  change  streams  can start returning changes at an operation
     time by using the startAtOperationTime field. This can be the timestamp re-
     turned in the operationTime field of a command reply.

     resumeAfter, startAfter, and startAtOperationTime	are  mutually  exclusive
     options. Setting more than one will result in a server error.

     The  following example implements custom resuming logic, persisting the re-
     sume token in a file.

     example-resume.c

	#include <mongoc/mongoc.h>

	/* An example implementation of custom resume logic in a change stream.
	 * example-resume starts a client-wide change stream and persists the resume
	 * token in a file "resume-token.json". On restart, if "resume-token.json"
	 * exists, the change stream starts watching after the persisted resume token.
	 *
	 * This behavior allows a user to exit example-resume, and restart it later
	 * without missing any change events.
	 */
	#include <unistd.h>

	static const char *RESUME_TOKEN_PATH = "resume-token.json";

	static bool
	_save_resume_token (const bson_t *doc)
	{
	   FILE *file_stream;
	   bson_iter_t iter;
	   bson_t resume_token_doc;
	   char *as_json = NULL;
	   size_t as_json_len;
	   ssize_t r, n_written;
	   const bson_value_t *resume_token;

	   if (!bson_iter_init_find (&iter, doc, "_id")) {
	      fprintf (stderr, "reply does not contain operationTime.");
	      return false;
	   }
	   resume_token = bson_iter_value (&iter);
	   /* store the resume token in a document, { resumeAfter: <resume token> }
	    * which we can later append easily. */
	   file_stream = fopen (RESUME_TOKEN_PATH, "w+");
	   if (!file_stream) {
	      fprintf (stderr, "failed to open %s for writing\n", RESUME_TOKEN_PATH);
	      return false;
	   }
	   bson_init (&resume_token_doc);
	   BSON_APPEND_VALUE (&resume_token_doc, "resumeAfter", resume_token);
	   as_json = bson_as_canonical_extended_json (&resume_token_doc, &as_json_len);
	   bson_destroy (&resume_token_doc);
	   n_written = 0;
	   while (n_written < as_json_len) {
	      r = fwrite ((void *) (as_json + n_written), sizeof (char), as_json_len - n_written, file_stream);
	      if (r == -1) {
		 fprintf (stderr, "failed to write to %s\n", RESUME_TOKEN_PATH);
		 bson_free (as_json);
		 fclose (file_stream);
		 return false;
	      }
	      n_written += r;
	   }

	   bson_free (as_json);
	   fclose (file_stream);
	   return true;
	}

	bool
	_load_resume_token (bson_t *opts)
	{
	   bson_error_t error;
	   bson_json_reader_t *reader;
	   bson_t doc;

	   /* if the file does not exist, skip. */
	   if (-1 == access (RESUME_TOKEN_PATH, R_OK)) {
	      return true;
	   }
	   reader = bson_json_reader_new_from_file (RESUME_TOKEN_PATH, &error);
	   if (!reader) {
	      fprintf (stderr, "failed to open %s for reading: %s\n", RESUME_TOKEN_PATH, error.message);
	      return false;
	   }

	   bson_init (&doc);
	   if (-1 == bson_json_reader_read (reader, &doc, &error)) {
	      fprintf (stderr, "failed to read doc from %s\n", RESUME_TOKEN_PATH);
	      bson_destroy (&doc);
	      bson_json_reader_destroy (reader);
	      return false;
	   }

	   printf ("found cached resume token in %s, resuming change stream.\n", RESUME_TOKEN_PATH);

	   bson_concat (opts, &doc);
	   bson_destroy (&doc);
	   bson_json_reader_destroy (reader);
	   return true;
	}

	int
	main (void)
	{
	   int exit_code = EXIT_FAILURE;
	   const char *uri_string;
	   mongoc_uri_t *uri = NULL;
	   bson_error_t error;
	   mongoc_client_t *client = NULL;
	   bson_t pipeline = BSON_INITIALIZER;
	   bson_t opts = BSON_INITIALIZER;
	   mongoc_change_stream_t *stream = NULL;
	   const bson_t *doc;

	   const int max_time = 30; /* max amount of time, in seconds, that
				       mongoc_change_stream_next can block. */

	   mongoc_init ();
	   uri_string = "mongodb://localhost:27017/db?replicaSet=rs0";
	   uri = mongoc_uri_new_with_error (uri_string, &error);
	   if (!uri) {
	      fprintf (stderr,
		       "failed to parse URI: %s\n"
		       "error message:	     %s\n",
		       uri_string,
		       error.message);
	      goto cleanup;
	   }

	   client = mongoc_client_new_from_uri (uri);
	   if (!client) {
	      goto cleanup;
	   }

	   if (!_load_resume_token (&opts)) {
	      goto cleanup;
	   }
	   BSON_APPEND_INT64 (&opts, "maxAwaitTimeMS", max_time * 1000);

	   printf ("listening for changes on the client (max %d seconds).\n", max_time);
	   stream = mongoc_client_watch (client, &pipeline, &opts);

	   while (mongoc_change_stream_next (stream, &doc)) {
	      char *as_json;

	      as_json = bson_as_canonical_extended_json (doc, NULL);
	      printf ("change received: %s\n", as_json);
	      bson_free (as_json);
	      if (!_save_resume_token (doc)) {
		 goto cleanup;
	      }
	   }

	   exit_code = EXIT_SUCCESS;

	cleanup:
	   mongoc_uri_destroy (uri);
	   bson_destroy (&pipeline);
	   bson_destroy (&opts);
	   mongoc_change_stream_destroy (stream);
	   mongoc_client_destroy (client);
	   mongoc_cleanup ();
	   return exit_code;
	}

     The following example shows using	startAtOperationTime  to  synchronize  a
     change stream with another operation.

     example-start-at-optime.c

	/* An example of starting a change stream with startAtOperationTime. */
	#include <mongoc/mongoc.h>

	int
	main (void)
	{
	   int exit_code = EXIT_FAILURE;
	   const char *uri_string;
	   mongoc_uri_t *uri = NULL;
	   bson_error_t error;
	   mongoc_client_t *client = NULL;
	   mongoc_collection_t *coll = NULL;
	   bson_t pipeline = BSON_INITIALIZER;
	   bson_t opts = BSON_INITIALIZER;
	   mongoc_change_stream_t *stream = NULL;
	   bson_iter_t iter;
	   const bson_t *doc;
	   bson_value_t cached_operation_time = {0};
	   int i;
	   bool r;

	   mongoc_init ();
	   uri_string = "mongodb://localhost:27017/db?replicaSet=rs0";
	   uri = mongoc_uri_new_with_error (uri_string, &error);
	   if (!uri) {
	      fprintf (stderr,
		       "failed to parse URI: %s\n"
		       "error message:	     %s\n",
		       uri_string,
		       error.message);
	      goto cleanup;
	   }

	   client = mongoc_client_new_from_uri (uri);
	   if (!client) {
	      goto cleanup;
	   }

	   /* insert five documents. */
	   coll = mongoc_client_get_collection (client, "db", "coll");
	   for (i = 0; i < 5; i++) {
	      bson_t reply;
	      bson_t *insert_cmd = BCON_NEW ("insert", "coll", "documents", "[", "{", "x", BCON_INT64 (i), "}", "]");

	      r = mongoc_collection_write_command_with_opts (coll, insert_cmd, NULL, &reply, &error);
	      bson_destroy (insert_cmd);
	      if (!r) {
		 bson_destroy (&reply);
		 fprintf (stderr, "failed to insert: %s\n", error.message);
		 goto cleanup;
	      }
	      if (i == 0) {
		 /* cache the operation time in the first reply. */
		 if (bson_iter_init_find (&iter, &reply, "operationTime")) {
		    bson_value_copy (bson_iter_value (&iter), &cached_operation_time);
		 } else {
		    fprintf (stderr, "reply does not contain operationTime.");
		    bson_destroy (&reply);
		    goto cleanup;
		 }
	      }
	      bson_destroy (&reply);
	   }

	   /* start a change stream at the first returned operationTime. */
	   BSON_APPEND_VALUE (&opts, "startAtOperationTime", &cached_operation_time);
	   stream = mongoc_collection_watch (coll, &pipeline, &opts);

	   /* since the change stream started at the operation time of the first
	    * insert, the five inserts are returned. */
	   printf ("listening for changes on db.coll:\n");
	   while (mongoc_change_stream_next (stream, &doc)) {
	      char *as_json;

	      as_json = bson_as_canonical_extended_json (doc, NULL);
	      printf ("change received: %s\n", as_json);
	      bson_free (as_json);
	   }

	   exit_code = EXIT_SUCCESS;

	cleanup:
	   mongoc_uri_destroy (uri);
	   bson_destroy (&pipeline);
	   bson_destroy (&opts);
	   if (cached_operation_time.value_type) {
	      bson_value_destroy (&cached_operation_time);
	   }
	   mongoc_change_stream_destroy (stream);
	   mongoc_collection_destroy (coll);
	   mongoc_client_destroy (client);
	   mongoc_cleanup ();
	   return exit_code;
	}

   mongoc_client_encryption_t
   Synopsis
	typedef struct _mongoc_client_encryption_t mongoc_client_encryption_t;

     mongoc_client_encryption_t  provides  utility  functions for In-Use Encryp-
     tion.

   Thread Safety
     mongoc_client_encryption_t is NOT thread-safe and should only  be	used  in
     the   same   thread   as	the   mongoc_client_t  that  is  configured  via
     mongoc_client_encryption_opts_set_keyvault_client().

   Lifecycle
     The	key	    vault	  client,	  configured	     via
     mongoc_client_encryption_opts_set_keyvault_client(),   must   outlive   the
     mongoc_client_encryption_t.

     SEE ALSO:
	mongoc_client_enable_auto_encryption()

	mongoc_client_pool_enable_auto_encryption()

	In-Use Encryption for libmongoc

	The MongoDB Manual for Client-Side Field Level Encryption

	The MongoDB Manual for Queryable Encryption

   mongoc_client_encryption_datakey_opts_t
   Synopsis
	typedef struct _mongoc_client_encryption_datakey_opts_t mongoc_client_encryption_datakey_opts_t;

     Used to set options for mongoc_client_encryption_create_datakey().

     SEE ALSO:
	mongoc_client_encryption_create_datakey()

   mongoc_client_encryption_rewrap_many_datakey_result_t
   Synopsis
	typedef struct _mongoc_client_encryption_rewrap_many_datakey_result_t
	   mongoc_client_encryption_rewrap_many_datakey_result_t;

     Used	   to	       access	       the	     result	      of
     mongoc_client_encryption_rewrap_many_datakey().

     SEE ALSO:
	mongoc_client_encryption_rewrap_many_datakey()

   mongoc_client_encryption_encrypt_opts_t
   Synopsis
	typedef struct _mongoc_client_encryption_encrypt_opts_t mongoc_client_encryption_encrypt_opts_t;

     Used to set options for mongoc_client_encryption_encrypt().

     SEE ALSO:
	mongoc_client_encryption_encrypt()

   mongoc_client_encryption_encrypt_range_opts_t
   Synopsis
	typedef struct _mongoc_client_encryption_encrypt_range_opts_t mongoc_client_encryption_encrypt_range_opts_t;

     Added in version 1.24.0.

     RangeOpts specifies index options for a Queryable Encryption field support-
     ing      "range"	   queries.	 Used	  to	 set	 options     for
     mongoc_client_encryption_encrypt().

     The options min, max, trim factor, sparsity, and range must match the  val-
     ues set in the encryptedFields of the destination collection.

     For double and decimal128 fields, min/max/precision must all be set, or all
     be unset.

     SEE ALSO:
	mongoc_client_encryption_encrypt()
	mongoc_client_encryption_encrypt_opts_t

   mongoc_client_encryption_opts_t
   Synopsis
	typedef struct _mongoc_client_encryption_opts_t mongoc_client_encryption_opts_t;

     Used to set options for mongoc_client_encryption_new().

     SEE ALSO:
	mongoc_client_encryption_new()

   mongoc_client_pool_t
     A connection pool for multi-threaded programs. See Connection Pooling.

   Synopsis
	typedef struct _mongoc_client_pool_t mongoc_client_pool_t

     mongoc_client_pool_t is the basis for multi-threading in the MongoDB C dri-
     ver.  Since  mongoc_client_t structures are not thread-safe, this structure
     is used to retrieve a new mongoc_client_t for a given thread.  This  struc-
     ture    is    thread-safe,    except    for    its    destructor	 method,
     mongoc_client_pool_destroy(), which is not thread-safe  and  must	only  be
     called from one thread.

   Example
     example-pool.c

	/* gcc example-pool.c -o example-pool $(pkg-config --cflags --libs
	 * libmongoc-1.0) */

	/* ./example-pool [CONNECTION_STRING] */

	#include <mongoc/mongoc.h>
	#include <pthread.h>
	#include <stdio.h>

	static pthread_mutex_t mutex;
	static bool in_shutdown = false;

	static void *
	worker (void *data)
	{
	   mongoc_client_pool_t *pool = data;
	   mongoc_client_t *client;
	   bson_t ping = BSON_INITIALIZER;
	   bson_error_t error;
	   bool r;

	   BSON_APPEND_INT32 (&ping, "ping", 1);

	   while (true) {
	      client = mongoc_client_pool_pop (pool);
	      /* Do something with client. If you are writing an HTTP server, you
	       * probably only want to hold onto the client for the portion of the
	       * request performing database queries.
	       */
	      r = mongoc_client_command_simple (client, "admin", &ping, NULL, NULL, &error);

	      if (!r) {
		 fprintf (stderr, "%s\n", error.message);
	      }

	      mongoc_client_pool_push (pool, client);

	      pthread_mutex_lock (&mutex);
	      if (in_shutdown || !r) {
		 pthread_mutex_unlock (&mutex);
		 break;
	      }

	      pthread_mutex_unlock (&mutex);
	   }

	   bson_destroy (&ping);
	   return NULL;
	}

	int
	main (int argc, char *argv[])
	{
	   const char *uri_string = "mongodb://127.0.0.1/?appname=pool-example";
	   mongoc_uri_t *uri;
	   bson_error_t error;
	   mongoc_client_pool_t *pool;
	   pthread_t threads[10];
	   unsigned i;
	   void *ret;

	   pthread_mutex_init (&mutex, NULL);
	   mongoc_init ();

	   if (argc > 1) {
	      uri_string = argv[1];
	   }

	   uri = mongoc_uri_new_with_error (uri_string, &error);
	   if (!uri) {
	      fprintf (stderr,
		       "failed to parse URI: %s\n"
		       "error message:	     %s\n",
		       uri_string,
		       error.message);
	      return EXIT_FAILURE;
	   }

	   pool = mongoc_client_pool_new (uri);
	   mongoc_client_pool_set_error_api (pool, 2);

	   for (i = 0; i < 10; i++) {
	      pthread_create (&threads[i], NULL, worker, pool);
	   }

	   sleep (10);
	   pthread_mutex_lock (&mutex);
	   in_shutdown = true;
	   pthread_mutex_unlock (&mutex);

	   for (i = 0; i < 10; i++) {
	      pthread_join (threads[i], &ret);
	   }

	   mongoc_client_pool_destroy (pool);
	   mongoc_uri_destroy (uri);

	   mongoc_cleanup ();

	   return EXIT_SUCCESS;
	}

   mongoc_client_session_t
     Use  a session for a sequence of operations, optionally with causal consis-
     tency. See the MongoDB Manual Entry for Causal Consistency.

   Synopsis
     Start a session with mongoc_client_start_session(), use the session  for  a
     sequence  of  operations and multi-document transactions, then free it with
     mongoc_client_session_destroy().	    Any        mongoc_cursor_t	      or
     mongoc_change_stream_t  using  a  session must be destroyed before the ses-
     sion, and a session must be destroyed before the  mongoc_client_t	it  came
     from.

     By  default,  sessions  are  causally consistent. To disable causal consis-
     tency,  before  starting  a  session  create  a  mongoc_session_opt_t  with
     mongoc_session_opts_new()			    and 		    call
     mongoc_session_opts_set_causal_consistency(), then  free  the  struct  with
     mongoc_session_opts_destroy().

     Unacknowledged writes are prohibited with sessions.

     A mongoc_client_session_t must be used by only one thread at a time. Due to
     session  pooling,	mongoc_client_start_session()  may return a session that
     has been idle for some time and is about to be closed after its idle  time-
     out.  Use the session within one minute of acquiring it to refresh the ses-
     sion and avoid a timeout.

   Fork Safety
     A mongoc_client_session_t is only usable in  the  parent  process	after  a
     fork.  The  child	process  must  call  mongoc_client_reset() on the client
     field.

   Example
     example-session.c

	/* gcc example-session.c -o example-session \
	 *     $(pkg-config --cflags --libs libmongoc-1.0) */

	/* ./example-session [CONNECTION_STRING] */

	#include <stdio.h>
	#include <mongoc/mongoc.h>

	int
	main (int argc, char *argv[])
	{
	   int exit_code = EXIT_FAILURE;

	   mongoc_client_t *client = NULL;
	   const char *uri_string = "mongodb://127.0.0.1/?appname=session-example";
	   mongoc_uri_t *uri = NULL;
	   mongoc_client_session_t *client_session = NULL;
	   mongoc_collection_t *collection = NULL;
	   bson_error_t error;
	   bson_t *selector = NULL;
	   bson_t *update = NULL;
	   bson_t *update_opts = NULL;
	   bson_t *find_opts = NULL;
	   mongoc_read_prefs_t *secondary = NULL;
	   mongoc_cursor_t *cursor = NULL;
	   const bson_t *doc;
	   char *str;
	   bool r;

	   mongoc_init ();

	   if (argc > 1) {
	      uri_string = argv[1];
	   }

	   uri = mongoc_uri_new_with_error (uri_string, &error);
	   if (!uri) {
	      fprintf (stderr,
		       "failed to parse URI: %s\n"
		       "error message:	     %s\n",
		       uri_string,
		       error.message);
	      goto done;
	   }

	   client = mongoc_client_new_from_uri (uri);
	   if (!client) {
	      goto done;
	   }

	   mongoc_client_set_error_api (client, 2);

	   /* pass NULL for options - by default the session is causally consistent */
	   client_session = mongoc_client_start_session (client, NULL, &error);
	   if (!client_session) {
	      fprintf (stderr, "Failed to start session: %s\n", error.message);
	      goto done;
	   }

	   collection = mongoc_client_get_collection (client, "test", "collection");
	   selector = BCON_NEW ("_id", BCON_INT32 (1));
	   update = BCON_NEW ("$inc", "{", "x", BCON_INT32 (1), "}");
	   update_opts = bson_new ();
	   if (!mongoc_client_session_append (client_session, update_opts, &error)) {
	      fprintf (stderr, "Could not add session to opts: %s\n", error.message);
	      goto done;
	   }

	   r = mongoc_collection_update_one (collection, selector, update, update_opts, NULL /* reply */, &error);

	   if (!r) {
	      fprintf (stderr, "Update failed: %s\n", error.message);
	      goto done;
	   }

	   bson_destroy (selector);
	   selector = BCON_NEW ("_id", BCON_INT32 (1));
	   secondary = mongoc_read_prefs_new (MONGOC_READ_SECONDARY);

	   find_opts = BCON_NEW ("maxTimeMS", BCON_INT32 (2000));
	   if (!mongoc_client_session_append (client_session, find_opts, &error)) {
	      fprintf (stderr, "Could not add session to opts: %s\n", error.message);
	      goto done;
	   }

	   /* read from secondary. since we're in a causally consistent session, the
	    * data is guaranteed to reflect the update we did on the primary. the query
	    * blocks waiting for the secondary to catch up, if necessary, or times out
	    * and fails after 2000 ms.
	    */
	   cursor = mongoc_collection_find_with_opts (collection, selector, find_opts, secondary);

	   while (mongoc_cursor_next (cursor, &doc)) {
	      str = bson_as_relaxed_extended_json (doc, NULL);
	      fprintf (stdout, "%s\n", str);
	      bson_free (str);
	   }

	   if (mongoc_cursor_error (cursor, &error)) {
	      fprintf (stderr, "Cursor Failure: %s\n", error.message);
	      goto done;
	   }

	   exit_code = EXIT_SUCCESS;

	done:
	   if (find_opts) {
	      bson_destroy (find_opts);
	   }
	   if (update) {
	      bson_destroy (update);
	   }
	   if (selector) {
	      bson_destroy (selector);
	   }
	   if (update_opts) {
	      bson_destroy (update_opts);
	   }
	   if (secondary) {
	      mongoc_read_prefs_destroy (secondary);
	   }
	   /* destroy cursor, collection, session before the client they came from */
	   if (cursor) {
	      mongoc_cursor_destroy (cursor);
	   }
	   if (collection) {
	      mongoc_collection_destroy (collection);
	   }
	   if (client_session) {
	      mongoc_client_session_destroy (client_session);
	   }
	   if (uri) {
	      mongoc_uri_destroy (uri);
	   }
	   if (client) {
	      mongoc_client_destroy (client);
	   }

	   mongoc_cleanup ();

	   return exit_code;
	}

   mongoc_client_session_with_transaction_cb_t
   Synopsis
	typedef bool (*mongoc_client_session_with_transaction_cb_t) (
	   mongoc_client_session_t *session,
	   void *ctx,
	   bson_t **reply,
	   bson_error_t *error);

     Provide  this  callback  to  mongoc_client_session_with_transaction().  The
     callback should run a sequence of operations meant to be contained within a
     transaction.   The  callback should not attempt to start or commit transac-
     tions.

   Parameters
     * session: A mongoc_client_session_t.

     * ctx:  A	void*	set   to   the	 the   user-provided   ctx   passed   to
       mongoc_client_session_with_transaction().

     * reply: An optional location for a bson_t or NULL. The callback should set
       this if it runs any operations against the server and receives replies.

     * error:  A  bson_error_t.  The callback should set this if it receives any
       errors while running operations against the server.

   Return
     Returns true for success and false on failure. If cb returns false then  it
     should also set error.

     SEE ALSO:
	mongoc_client_session_with_transaction()

   mongoc_client_t
     A single-threaded MongoDB connection. See Connection Pooling.

   Synopsis
	typedef struct _mongoc_client_t mongoc_client_t;

	typedef mongoc_stream_t *(*mongoc_stream_initiator_t) (
	   const mongoc_uri_t *uri,
	   const mongoc_host_list_t *host,
	   void *user_data,
	   bson_error_t *error);

     mongoc_client_t is an opaque type that provides access to a MongoDB server,
     replica  set,  or	sharded  cluster.  It maintains management of underlying
     sockets and routing to individual nodes  based  on  mongoc_read_prefs_t  or
     mongoc_write_concern_t.

   Streams
     The  underlying  transport for a given client can be customized, wrapped or
     replaced by any implementation  that  fulfills  mongoc_stream_t.  A  custom
     transport can be set with mongoc_client_set_stream_initiator().

   Thread Safety
     mongoc_client_t  is NOT thread-safe and should only be used from one thread
     at a time. When used in multi-threaded scenarios, it  is  recommended  that
     you  use the thread-safe mongoc_client_pool_t to retrieve a mongoc_client_t
     for your thread.

   Fork Safety
     A mongoc_client_t is only usable in the parent process after  a  fork.  The
     child process must call mongoc_client_reset().

   Example
     example-client.c

	/* gcc example-client.c -o example-client $(pkg-config --cflags --libs
	 * libmongoc-1.0) */

	/* ./example-client [CONNECTION_STRING [COLLECTION_NAME]] */

	#include <mongoc/mongoc.h>
	#include <stdio.h>
	#include <stdlib.h>

	int
	main (int argc, char *argv[])
	{
	   mongoc_client_t *client;
	   mongoc_collection_t *collection;
	   mongoc_cursor_t *cursor;
	   bson_error_t error;
	   const bson_t *doc;
	   const char *collection_name = "test";
	   bson_t query;
	   char *str;
	   const char *uri_string = "mongodb://127.0.0.1/?appname=client-example";
	   mongoc_uri_t *uri;

	   mongoc_init ();
	   if (argc > 1) {
	      uri_string = argv[1];
	   }

	   if (argc > 2) {
	      collection_name = argv[2];
	   }

	   uri = mongoc_uri_new_with_error (uri_string, &error);
	   if (!uri) {
	      fprintf (stderr,
		       "failed to parse URI: %s\n"
		       "error message:	     %s\n",
		       uri_string,
		       error.message);
	      return EXIT_FAILURE;
	   }

	   client = mongoc_client_new_from_uri (uri);
	   if (!client) {
	      return EXIT_FAILURE;
	   }

	   mongoc_client_set_error_api (client, 2);

	   bson_init (&query);
	   collection = mongoc_client_get_collection (client, "test", collection_name);
	   cursor = mongoc_collection_find_with_opts (collection,
						      &query,
						      NULL,  /* additional options */
						      NULL); /* read prefs, NULL for default */

	   while (mongoc_cursor_next (cursor, &doc)) {
	      str = bson_as_canonical_extended_json (doc, NULL);
	      fprintf (stdout, "%s\n", str);
	      bson_free (str);
	   }

	   if (mongoc_cursor_error (cursor, &error)) {
	      fprintf (stderr, "Cursor Failure: %s\n", error.message);
	      return EXIT_FAILURE;
	   }

	   bson_destroy (&query);
	   mongoc_cursor_destroy (cursor);
	   mongoc_collection_destroy (collection);
	   mongoc_uri_destroy (uri);
	   mongoc_client_destroy (client);
	   mongoc_cleanup ();

	   return EXIT_SUCCESS;
	}

   mongoc_collection_t
   Synopsis
	typedef struct _mongoc_collection_t mongoc_collection_t;

     mongoc_collection_t  provides  access to a MongoDB collection.  This handle
     is useful for actions  for  most  CRUD  operations,  I.e.	insert,  update,
     delete, find, etc.

   Read Preferences and Write Concerns
     Read  preferences	and write concerns are inherited from the parent client.
     They can be overridden by set_* commands if so desired.

   mongoc_cursor_t
     Client-side cursor abstraction

   Synopsis
	typedef struct _mongoc_cursor_t mongoc_cursor_t;

     mongoc_cursor_t provides access to a MongoDB query cursor.  It wraps up the
     wire protocol negotiation required to initiate a query and retrieve an  un-
     known number of documents.

     Common cursor operations include:

     * Determine which host we've connected to with mongoc_cursor_get_host().

     * Retrieve more records with repeated calls to mongoc_cursor_next().

     * Clone   a   query   to	repeat	 execution   at   a   later  point  with
       mongoc_cursor_clone().

     * Test for errors with mongoc_cursor_error().

     Cursors are lazy, meaning that no connection is established and no  network
     traffic occurs until the first call to mongoc_cursor_next().

   Thread Safety
     mongoc_cursor_t  is  NOT  thread  safe. It may only be used from within the
     thread in which it was created.

   Example
     Query MongoDB and iterate results

	/* gcc example-client.c -o example-client $(pkg-config --cflags --libs
	 * libmongoc-1.0) */

	/* ./example-client [CONNECTION_STRING [COLLECTION_NAME]] */

	#include <mongoc/mongoc.h>
	#include <stdio.h>
	#include <stdlib.h>

	int
	main (int argc, char *argv[])
	{
	   mongoc_client_t *client;
	   mongoc_collection_t *collection;
	   mongoc_cursor_t *cursor;
	   bson_error_t error;
	   const bson_t *doc;
	   const char *collection_name = "test";
	   bson_t query;
	   char *str;
	   const char *uri_string = "mongodb://127.0.0.1/?appname=client-example";
	   mongoc_uri_t *uri;

	   mongoc_init ();
	   if (argc > 1) {
	      uri_string = argv[1];
	   }

	   if (argc > 2) {
	      collection_name = argv[2];
	   }

	   uri = mongoc_uri_new_with_error (uri_string, &error);
	   if (!uri) {
	      fprintf (stderr,
		       "failed to parse URI: %s\n"
		       "error message:	     %s\n",
		       uri_string,
		       error.message);
	      return EXIT_FAILURE;
	   }

	   client = mongoc_client_new_from_uri (uri);
	   if (!client) {
	      return EXIT_FAILURE;
	   }

	   mongoc_client_set_error_api (client, 2);

	   bson_init (&query);
	   collection = mongoc_client_get_collection (client, "test", collection_name);
	   cursor = mongoc_collection_find_with_opts (collection,
						      &query,
						      NULL,  /* additional options */
						      NULL); /* read prefs, NULL for default */

	   while (mongoc_cursor_next (cursor, &doc)) {
	      str = bson_as_canonical_extended_json (doc, NULL);
	      fprintf (stdout, "%s\n", str);
	      bson_free (str);
	   }

	   if (mongoc_cursor_error (cursor, &error)) {
	      fprintf (stderr, "Cursor Failure: %s\n", error.message);
	      return EXIT_FAILURE;
	   }

	   bson_destroy (&query);
	   mongoc_cursor_destroy (cursor);
	   mongoc_collection_destroy (collection);
	   mongoc_uri_destroy (uri);
	   mongoc_client_destroy (client);
	   mongoc_cleanup ();

	   return EXIT_SUCCESS;
	}

   mongoc_database_t
     MongoDB Database Abstraction

   Synopsis
	typedef struct _mongoc_database_t mongoc_database_t;

     mongoc_database_t provides access to a MongoDB  database.	This  handle  is
     useful  for actions a particular database object. It is not a container for
     mongoc_collection_t structures.

     Read preferences and write concerns are inherited from the  parent  client.
     They   can   be   overridden   with   mongoc_database_set_read_prefs()  and
     mongoc_database_set_write_concern().

   Examples
	#include <mongoc/mongoc.h>

	int
	main (int argc, char *argv[])
	{
	   mongoc_database_t *database;
	   mongoc_client_t *client;

	   mongoc_init ();

	   client = mongoc_client_new ("mongodb://localhost/");
	   database = mongoc_client_get_database (client, "test");

	   mongoc_database_destroy (database);
	   mongoc_client_destroy (client);

	   mongoc_cleanup ();

	   return 0;
	}

   mongoc_delete_flags_t
     WARNING:
	Deprecated since version 1.9.0:  Use  mongoc_collection_delete_one()  or
	mongoc_collection_delete_many() instead.

   Synopsis
	typedef enum {
	   MONGOC_DELETE_NONE = 0,
	   MONGOC_DELETE_SINGLE_REMOVE = 1 << 0,
	} mongoc_delete_flags_t;

     Flags for deletion operations

   mongoc_find_and_modify_opts_t
     find_and_modify abstraction

   Synopsis
     mongoc_find_and_modify_opts_t is a builder interface to construct the find-
     AndModify command.

     It was created to be able to accommodate new arguments to the findAndModify
     command.

     As   of   MongoDB	 3.2,	the   mongoc_write_concern_t  specified  on  the
     mongoc_collection_t will be used, if any.

   Example
     flags.c

	void
	fam_flags (mongoc_collection_t *collection)
	{
	   mongoc_find_and_modify_opts_t *opts;
	   bson_t reply;
	   bson_error_t error;
	   bson_t query = BSON_INITIALIZER;
	   bson_t *update;
	   bool success;

	   /* Find Zlatan Ibrahimovic, the striker */
	   BSON_APPEND_UTF8 (&query, "firstname", "Zlatan");
	   BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic");
	   BSON_APPEND_UTF8 (&query, "profession", "Football player");
	   BSON_APPEND_INT32 (&query, "age", 34);
	   BSON_APPEND_INT32 (&query, "goals", (16 + 35 + 23 + 57 + 16 + 14 + 28 + 84) + (1 + 6 + 62));

	   /* Add his football position */
	   update = BCON_NEW ("$set", "{", "position", BCON_UTF8 ("striker"), "}");

	   opts = mongoc_find_and_modify_opts_new ();

	   mongoc_find_and_modify_opts_set_update (opts, update);

	   /* Create the document if it didn't exist, and return the updated document */
	   mongoc_find_and_modify_opts_set_flags (opts, MONGOC_FIND_AND_MODIFY_UPSERT | MONGOC_FIND_AND_MODIFY_RETURN_NEW);

	   success = mongoc_collection_find_and_modify_with_opts (collection, &query, opts, &reply, &error);

	   if (success) {
	      char *str;

	      str = bson_as_canonical_extended_json (&reply, NULL);
	      printf ("%s\n", str);
	      bson_free (str);
	   } else {
	      fprintf (stderr, "Got error: \"%s\" on line %d\n", error.message, (int) (__LINE__));
	   }

	   bson_destroy (&reply);
	   bson_destroy (update);
	   bson_destroy (&query);
	   mongoc_find_and_modify_opts_destroy (opts);
	}

     bypass.c

	void
	fam_bypass (mongoc_collection_t *collection)
	{
	   mongoc_find_and_modify_opts_t *opts;
	   bson_t reply;
	   bson_t *update;
	   bson_error_t error;
	   bson_t query = BSON_INITIALIZER;
	   bool success;

	   /* Find Zlatan Ibrahimovic, the striker */
	   BSON_APPEND_UTF8 (&query, "firstname", "Zlatan");
	   BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic");
	   BSON_APPEND_UTF8 (&query, "profession", "Football player");

	   /* Bump his age */
	   update = BCON_NEW ("$inc", "{", "age", BCON_INT32 (1), "}");

	   opts = mongoc_find_and_modify_opts_new ();
	   mongoc_find_and_modify_opts_set_update (opts, update);
	   /* He can still play, even though he is pretty old. */
	   mongoc_find_and_modify_opts_set_bypass_document_validation (opts, true);

	   success = mongoc_collection_find_and_modify_with_opts (collection, &query, opts, &reply, &error);

	   if (success) {
	      char *str;

	      str = bson_as_canonical_extended_json (&reply, NULL);
	      printf ("%s\n", str);
	      bson_free (str);
	   } else {
	      fprintf (stderr, "Got error: \"%s\" on line %d\n", error.message, (int) (__LINE__));
	   }

	   bson_destroy (&reply);
	   bson_destroy (update);
	   bson_destroy (&query);
	   mongoc_find_and_modify_opts_destroy (opts);
	}

     update.c

	void
	fam_update (mongoc_collection_t *collection)
	{
	   mongoc_find_and_modify_opts_t *opts;
	   bson_t *update;
	   bson_t reply;
	   bson_error_t error;
	   bson_t query = BSON_INITIALIZER;
	   bool success;

	   /* Find Zlatan Ibrahimovic */
	   BSON_APPEND_UTF8 (&query, "firstname", "Zlatan");
	   BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic");

	   /* Make him a book author */
	   update = BCON_NEW ("$set", "{", "author", BCON_BOOL (true), "}");

	   opts = mongoc_find_and_modify_opts_new ();
	   /* Note that the document returned is the _previous_ version of the document
	    * To fetch the modified new version, use
	    * mongoc_find_and_modify_opts_set_flags (opts,
	    * MONGOC_FIND_AND_MODIFY_RETURN_NEW);
	    */
	   mongoc_find_and_modify_opts_set_update (opts, update);

	   success = mongoc_collection_find_and_modify_with_opts (collection, &query, opts, &reply, &error);

	   if (success) {
	      char *str;

	      str = bson_as_canonical_extended_json (&reply, NULL);
	      printf ("%s\n", str);
	      bson_free (str);
	   } else {
	      fprintf (stderr, "Got error: \"%s\" on line %d\n", error.message, (int) (__LINE__));
	   }

	   bson_destroy (&reply);
	   bson_destroy (update);
	   bson_destroy (&query);
	   mongoc_find_and_modify_opts_destroy (opts);
	}

     fields.c

	void
	fam_fields (mongoc_collection_t *collection)
	{
	   mongoc_find_and_modify_opts_t *opts;
	   bson_t fields = BSON_INITIALIZER;
	   bson_t *update;
	   bson_t reply;
	   bson_error_t error;
	   bson_t query = BSON_INITIALIZER;
	   bool success;

	   /* Find Zlatan Ibrahimovic */
	   BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic");
	   BSON_APPEND_UTF8 (&query, "firstname", "Zlatan");

	   /* Return his goal tally */
	   BSON_APPEND_INT32 (&fields, "goals", 1);

	   /* Bump his goal tally */
	   update = BCON_NEW ("$inc", "{", "goals", BCON_INT32 (1), "}");

	   opts = mongoc_find_and_modify_opts_new ();
	   mongoc_find_and_modify_opts_set_update (opts, update);
	   mongoc_find_and_modify_opts_set_fields (opts, &fields);
	   /* Return the new tally */
	   mongoc_find_and_modify_opts_set_flags (opts, MONGOC_FIND_AND_MODIFY_RETURN_NEW);

	   success = mongoc_collection_find_and_modify_with_opts (collection, &query, opts, &reply, &error);

	   if (success) {
	      char *str;

	      str = bson_as_canonical_extended_json (&reply, NULL);
	      printf ("%s\n", str);
	      bson_free (str);
	   } else {
	      fprintf (stderr, "Got error: \"%s\" on line %d\n", error.message, (int) (__LINE__));
	   }

	   bson_destroy (&reply);
	   bson_destroy (update);
	   bson_destroy (&fields);
	   bson_destroy (&query);
	   mongoc_find_and_modify_opts_destroy (opts);
	}

     sort.c

	void
	fam_sort (mongoc_collection_t *collection)
	{
	   mongoc_find_and_modify_opts_t *opts;
	   bson_t *update;
	   bson_t sort = BSON_INITIALIZER;
	   bson_t reply;
	   bson_error_t error;
	   bson_t query = BSON_INITIALIZER;
	   bool success;

	   /* Find all users with the lastname Ibrahimovic */
	   BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic");

	   /* Sort by age (descending) */
	   BSON_APPEND_INT32 (&sort, "age", -1);

	   /* Bump his goal tally */
	   update = BCON_NEW ("$set", "{", "oldest", BCON_BOOL (true), "}");

	   opts = mongoc_find_and_modify_opts_new ();
	   mongoc_find_and_modify_opts_set_update (opts, update);
	   mongoc_find_and_modify_opts_set_sort (opts, &sort);

	   success = mongoc_collection_find_and_modify_with_opts (collection, &query, opts, &reply, &error);

	   if (success) {
	      char *str;

	      str = bson_as_canonical_extended_json (&reply, NULL);
	      printf ("%s\n", str);
	      bson_free (str);
	   } else {
	      fprintf (stderr, "Got error: \"%s\" on line %d\n", error.message, (int) (__LINE__));
	   }

	   bson_destroy (&reply);
	   bson_destroy (update);
	   bson_destroy (&sort);
	   bson_destroy (&query);
	   mongoc_find_and_modify_opts_destroy (opts);
	}

     opts.c

	void
	fam_opts (mongoc_collection_t *collection)
	{
	   mongoc_find_and_modify_opts_t *opts;
	   bson_t reply;
	   bson_t *update;
	   bson_error_t error;
	   bson_t query = BSON_INITIALIZER;
	   mongoc_write_concern_t *wc;
	   bson_t extra = BSON_INITIALIZER;
	   bool success;

	   /* Find Zlatan Ibrahimovic, the striker */
	   BSON_APPEND_UTF8 (&query, "firstname", "Zlatan");
	   BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic");
	   BSON_APPEND_UTF8 (&query, "profession", "Football player");

	   /* Bump his age */
	   update = BCON_NEW ("$inc", "{", "age", BCON_INT32 (1), "}");

	   opts = mongoc_find_and_modify_opts_new ();
	   mongoc_find_and_modify_opts_set_update (opts, update);

	   /* Abort if the operation takes too long. */
	   mongoc_find_and_modify_opts_set_max_time_ms (opts, 100);

	   /* Set write concern w: 2 */
	   wc = mongoc_write_concern_new ();
	   mongoc_write_concern_set_w (wc, 2);
	   mongoc_write_concern_append (wc, &extra);

	   /* Some future findAndModify option the driver doesn't support conveniently
	    */
	   BSON_APPEND_INT32 (&extra, "futureOption", 42);
	   mongoc_find_and_modify_opts_append (opts, &extra);

	   success = mongoc_collection_find_and_modify_with_opts (collection, &query, opts, &reply, &error);

	   if (success) {
	      char *str;

	      str = bson_as_canonical_extended_json (&reply, NULL);
	      printf ("%s\n", str);
	      bson_free (str);
	   } else {
	      fprintf (stderr, "Got error: \"%s\" on line %d\n", error.message, (int) (__LINE__));
	   }

	   bson_destroy (&reply);
	   bson_destroy (&extra);
	   bson_destroy (update);
	   bson_destroy (&query);
	   mongoc_write_concern_destroy (wc);
	   mongoc_find_and_modify_opts_destroy (opts);
	}

     fam.c

	int
	main (void)
	{
	   mongoc_collection_t *collection;
	   mongoc_database_t *database;
	   mongoc_client_t *client;
	   const char *uri_string = "mongodb://localhost:27017/admin?appname=find-and-modify-opts-example";
	   mongoc_uri_t *uri;
	   bson_error_t error;
	   bson_t *options;

	   mongoc_init ();

	   uri = mongoc_uri_new_with_error (uri_string, &error);
	   if (!uri) {
	      fprintf (stderr,
		       "failed to parse URI: %s\n"
		       "error message:	     %s\n",
		       uri_string,
		       error.message);
	      return EXIT_FAILURE;
	   }

	   client = mongoc_client_new_from_uri (uri);
	   if (!client) {
	      return EXIT_FAILURE;
	   }

	   mongoc_client_set_error_api (client, 2);
	   database = mongoc_client_get_database (client, "databaseName");

	   options = BCON_NEW ("validator",
			       "{",
			       "age",
			       "{",
			       "$lte",
			       BCON_INT32 (34),
			       "}",
			       "}",
			       "validationAction",
			       BCON_UTF8 ("error"),
			       "validationLevel",
			       BCON_UTF8 ("moderate"));

	   collection = mongoc_database_create_collection (database, "collectionName", options, &error);
	   if (!collection) {
	      fprintf (stderr, "Got error: \"%s\" on line %d\n", error.message, (int) (__LINE__));
	      return EXIT_FAILURE;
	   }

	   fam_flags (collection);
	   fam_bypass (collection);
	   fam_update (collection);
	   fam_fields (collection);
	   fam_opts (collection);
	   fam_sort (collection);

	   mongoc_collection_drop (collection, NULL);
	   bson_destroy (options);
	   mongoc_uri_destroy (uri);
	   mongoc_database_destroy (database);
	   mongoc_collection_destroy (collection);
	   mongoc_client_destroy (client);

	   mongoc_cleanup ();
	   return EXIT_SUCCESS;
	}

     Outputs:

	{
	    "lastErrorObject": {
		"updatedExisting": false,
		"n": 1,
		"upserted": {
		    "$oid": "56562a99d13e6d86239c7b00"
		}
	    },
	    "value": {
		"_id": {
		    "$oid": "56562a99d13e6d86239c7b00"
		},
		"age": 34,
		"firstname": "Zlatan",
		"goals": 342,
		"lastname": "Ibrahimovic",
		"profession": "Football player",
		"position": "striker"
	    },
	    "ok": 1
	}
	{
	    "lastErrorObject": {
		"updatedExisting": true,
		"n": 1
	    },
	    "value": {
		"_id": {
		    "$oid": "56562a99d13e6d86239c7b00"
		},
		"age": 34,
		"firstname": "Zlatan",
		"goals": 342,
		"lastname": "Ibrahimovic",
		"profession": "Football player",
		"position": "striker"
	    },
	    "ok": 1
	}
	{
	    "lastErrorObject": {
		"updatedExisting": true,
		"n": 1
	    },
	    "value": {
		"_id": {
		    "$oid": "56562a99d13e6d86239c7b00"
		},
		"age": 35,
		"firstname": "Zlatan",
		"goals": 342,
		"lastname": "Ibrahimovic",
		"profession": "Football player",
		"position": "striker"
	    },
	    "ok": 1
	}
	{
	    "lastErrorObject": {
		"updatedExisting": true,
		"n": 1
	    },
	    "value": {
		"_id": {
		    "$oid": "56562a99d13e6d86239c7b00"
		},
		"goals": 343
	    },
	    "ok": 1
	}
	{
	    "lastErrorObject": {
		"updatedExisting": true,
		"n": 1
	    },
	    "value": {
		"_id": {
		    "$oid": "56562a99d13e6d86239c7b00"
		},
		"age": 35,
		"firstname": "Zlatan",
		"goals": 343,
		"lastname": "Ibrahimovic",
		"profession": "Football player",
		"position": "striker",
		"author": true
	    },
	    "ok": 1
	}

   mongoc_gridfs_file_list_t
   Synopsis
	#include <mongoc/mongoc.h>

	typedef struct _mongoc_gridfs_file_list_t mongoc_gridfs_file_list_t;

   Description
     mongoc_gridfs_file_list_t provides a gridfs file list abstraction.  It pro-
     vides   iteration	 and   basic   marshalling   on   top	of   a	 regular
     mongoc_collection_find_with_opts()  style	query. In interface, it's styled
     after mongoc_cursor_t.

   Example
	mongoc_gridfs_file_list_t *list;
	mongoc_gridfs_file_t *file;

	list = mongoc_gridfs_find (gridfs, query);

	while ((file = mongoc_gridfs_file_list_next (list))) {
	   do_something (file);

	   mongoc_gridfs_file_destroy (file);
	}

	mongoc_gridfs_file_list_destroy (list);

   mongoc_gridfs_file_opt_t
   Synopsis
	typedef struct {
	   const char *md5;
	   const char *filename;
	   const char *content_type;
	   const bson_t *aliases;
	   const bson_t *metadata;
	   uint32_t chunk_size;
	} mongoc_gridfs_file_opt_t;

   Description
     This structure contains options that can be set on a  mongoc_gridfs_file_t.
     It can be used by various functions when creating a new gridfs file.

   mongoc_gridfs_file_t
   Synopsis
	typedef struct _mongoc_gridfs_file_t mongoc_gridfs_file_t;

   Description
     This structure provides a MongoDB GridFS file abstraction. It provides sev-
     eral APIs.

     * readv, writev, seek, and tell.

     * General file metadata such as filename and length.

     * GridFS  metadata  such as md5, filename, content_type, aliases, metadata,
       chunk_size, and upload_date.

   Thread Safety
     This structure is NOT thread-safe and should only be used from  one  thread
     at a time.

   Related
     * mongoc_client_t

     * mongoc_gridfs_t

     * mongoc_gridfs_file_list_t

     * mongoc_gridfs_file_opt_t

   mongoc_gridfs_bucket_t
   Synopsis
	#include <mongoc/mongoc.h>

	typedef struct _mongoc_gridfs_bucket_t mongoc_gridfs_bucket_t;

   Description
     mongoc_gridfs_bucket_t provides a spec-compliant MongoDB GridFS implementa-
     tion, superseding mongoc_gridfs_t. See the GridFS MongoDB documentation.

   Thread Safety
     mongoc_gridfs_bucket_t  is  NOT  thread-safe and should only be used in the
     same thread as the owning mongoc_client_t.

   Lifecycle
     It is an error to free a mongoc_gridfs_bucket_t before freeing all  derived
     instances	of  mongoc_stream_t. The owning mongoc_client_t must outlive the
     mongoc_gridfs_bucket_t.

   Example
     example-gridfs-bucket.c

	#include <stdio.h>
	#include <stdlib.h>

	#include <mongoc/mongoc.h>

	int
	main (int argc, char *argv[])
	{
	   const char *uri_string = "mongodb://localhost:27017/?appname=new-gridfs-example";
	   mongoc_client_t *client;
	   mongoc_database_t *db;
	   mongoc_stream_t *file_stream;
	   mongoc_gridfs_bucket_t *bucket;
	   mongoc_cursor_t *cursor;
	   bson_t filter;
	   bool res;
	   bson_value_t file_id;
	   bson_error_t error;
	   const bson_t *doc;
	   char *str;
	   mongoc_init ();

	   if (argc != 3) {
	      fprintf (stderr, "usage: %s SOURCE_FILE_PATH FILE_COPY_PATH\n", argv[0]);
	      return EXIT_FAILURE;
	   }

	   /* 1. Make a bucket. */
	   client = mongoc_client_new (uri_string);
	   db = mongoc_client_get_database (client, "test");
	   bucket = mongoc_gridfs_bucket_new (db, NULL, NULL, &error);
	   if (!bucket) {
	      printf ("Error creating gridfs bucket: %s\n", error.message);
	      return EXIT_FAILURE;
	   }

	   /* 2. Insert a file.  */
	   file_stream = mongoc_stream_file_new_for_path (argv[1], O_RDONLY, 0);
	   res = mongoc_gridfs_bucket_upload_from_stream (bucket, "my-file", file_stream, NULL, &file_id, &error);
	   if (!res) {
	      printf ("Error uploading file: %s\n", error.message);
	      return EXIT_FAILURE;
	   }

	   mongoc_stream_close (file_stream);
	   mongoc_stream_destroy (file_stream);

	   /* 3. Download the file in GridFS to a local file. */
	   file_stream = mongoc_stream_file_new_for_path (argv[2], O_CREAT | O_RDWR, 0);
	   if (!file_stream) {
	      perror ("Error opening file stream");
	      return EXIT_FAILURE;
	   }

	   res = mongoc_gridfs_bucket_download_to_stream (bucket, &file_id, file_stream, &error);
	   if (!res) {
	      printf ("Error downloading file to stream: %s\n", error.message);
	      return EXIT_FAILURE;
	   }
	   mongoc_stream_close (file_stream);
	   mongoc_stream_destroy (file_stream);

	   /* 4. List what files are available in GridFS. */
	   bson_init (&filter);
	   cursor = mongoc_gridfs_bucket_find (bucket, &filter, NULL);

	   while (mongoc_cursor_next (cursor, &doc)) {
	      str = bson_as_canonical_extended_json (doc, NULL);
	      printf ("%s\n", str);
	      bson_free (str);
	   }

	   /* 5. Delete the file that we added. */
	   res = mongoc_gridfs_bucket_delete_by_id (bucket, &file_id, &error);
	   if (!res) {
	      printf ("Error deleting the file: %s\n", error.message);
	      return EXIT_FAILURE;
	   }

	   /* 6. Cleanup. */
	   mongoc_stream_close (file_stream);
	   mongoc_stream_destroy (file_stream);
	   mongoc_cursor_destroy (cursor);
	   bson_destroy (&filter);
	   mongoc_gridfs_bucket_destroy (bucket);
	   mongoc_database_destroy (db);
	   mongoc_client_destroy (client);
	   mongoc_cleanup ();

	   return EXIT_SUCCESS;
	}

     SEE ALSO:
	The MongoDB GridFS specification.

	The non spec-compliant mongoc_gridfs_t.

   mongoc_gridfs_t
     WARNING:
	This GridFS implementation does not conform to the MongoDB GridFS speci-
	fication.    For    a	  spec	   compliant	 implementation,     use
	mongoc_gridfs_bucket_t.

   Synopsis
	#include <mongoc/mongoc.h>

	typedef struct _mongoc_gridfs_t mongoc_gridfs_t;

   Description
     mongoc_gridfs_t  provides	a MongoDB gridfs implementation. The system as a
     whole is  made  up  of  gridfs  objects,  which  contain  gridfs_files  and
     gridfs_file_lists.  Essentially, a basic file system API.

     There are extensive caveats about the kind of use cases gridfs is practical
     for.  In  particular,  any writing after initial file creation is likely to
     both break any concurrent readers and be quite expensive. That  said,  this
     implementation  does  allow for arbitrary writes to existing gridfs object,
     just use them with caution.

     mongoc_gridfs also integrates tightly with the mongoc_stream_t abstraction,
     which provides some convenient wrapping for file creation and reading/writ-
     ing.  It can be used without, but its worth looking to see if your  problem
     can fit that model.

     WARNING:
	mongoc_gridfs_t  does  not  support  read preferences. In a replica set,
	GridFS queries are always routed to the primary.

   Thread Safety
     mongoc_gridfs_t is NOT thread-safe and should only  be  used  in  the  same
     thread as the owning mongoc_client_t.

   Lifecycle
     It  is  an  error	to free a mongoc_gridfs_t before freeing all related in-
     stances of mongoc_gridfs_file_t and mongoc_gridfs_file_list_t.

   Example
     example-gridfs.c

	#include <assert.h>
	#include <mongoc/mongoc.h>
	#include <stdio.h>
	#include <stdlib.h>
	#include <fcntl.h>

	int
	main (int argc, char *argv[])
	{
	   mongoc_gridfs_t *gridfs;
	   mongoc_gridfs_file_t *file;
	   mongoc_gridfs_file_list_t *list;
	   mongoc_gridfs_file_opt_t opt = {0};
	   mongoc_client_t *client;
	   const char *uri_string = "mongodb://127.0.0.1:27017/?appname=gridfs-example";
	   mongoc_uri_t *uri;
	   mongoc_stream_t *stream;
	   bson_t filter;
	   bson_t opts;
	   bson_t child;
	   bson_error_t error;
	   ssize_t r;
	   char buf[4096];
	   mongoc_iovec_t iov;
	   const char *filename;
	   const char *command;
	   bson_value_t id;

	   if (argc < 2) {
	      fprintf (stderr, "usage - %s command ...\n", argv[0]);
	      return EXIT_FAILURE;
	   }

	   mongoc_init ();

	   iov.iov_base = (void *) buf;
	   iov.iov_len = sizeof buf;

	   /* connect to localhost client */
	   uri = mongoc_uri_new_with_error (uri_string, &error);
	   if (!uri) {
	      fprintf (stderr,
		       "failed to parse URI: %s\n"
		       "error message:	     %s\n",
		       uri_string,
		       error.message);
	      return EXIT_FAILURE;
	   }

	   client = mongoc_client_new_from_uri (uri);
	   assert (client);
	   mongoc_client_set_error_api (client, 2);

	   /* grab a gridfs handle in test prefixed by fs */
	   gridfs = mongoc_client_get_gridfs (client, "test", "fs", &error);
	   assert (gridfs);

	   command = argv[1];
	   filename = argv[2];

	   if (strcmp (command, "read") == 0) {
	      if (argc != 3) {
		 fprintf (stderr, "usage - %s read filename\n", argv[0]);
		 return EXIT_FAILURE;
	      }
	      file = mongoc_gridfs_find_one_by_filename (gridfs, filename, &error);
	      assert (file);

	      stream = mongoc_stream_gridfs_new (file);
	      assert (stream);

	      for (;;) {
		 r = mongoc_stream_readv (stream, &iov, 1, -1, 0);

		 assert (r >= 0);

		 if (r == 0) {
		    break;
		 }

		 if (fwrite (iov.iov_base, 1, r, stdout) != r) {
		    MONGOC_ERROR ("Failed to write to stdout. Exiting.\n");
		    exit (1);
		 }
	      }

	      mongoc_stream_destroy (stream);
	      mongoc_gridfs_file_destroy (file);
	   } else if (strcmp (command, "list") == 0) {
	      bson_init (&filter);

	      bson_init (&opts);
	      bson_append_document_begin (&opts, "sort", -1, &child);
	      BSON_APPEND_INT32 (&child, "filename", 1);
	      bson_append_document_end (&opts, &child);

	      list = mongoc_gridfs_find_with_opts (gridfs, &filter, &opts);

	      bson_destroy (&filter);
	      bson_destroy (&opts);

	      while ((file = mongoc_gridfs_file_list_next (list))) {
		 const char *name = mongoc_gridfs_file_get_filename (file);
		 printf ("%s\n", name ? name : "?");

		 mongoc_gridfs_file_destroy (file);
	      }

	      mongoc_gridfs_file_list_destroy (list);
	   } else if (strcmp (command, "write") == 0) {
	      if (argc != 4) {
		 fprintf (stderr, "usage - %s write filename input_file\n", argv[0]);
		 return EXIT_FAILURE;
	      }

	      stream = mongoc_stream_file_new_for_path (argv[3], O_RDONLY, 0);
	      assert (stream);

	      opt.filename = filename;

	      /* the driver generates a file_id for you */
	      file = mongoc_gridfs_create_file_from_stream (gridfs, stream, &opt);
	      assert (file);

	      id.value_type = BSON_TYPE_INT32;
	      id.value.v_int32 = 1;

	      /* optional: the following method specifies a file_id of any
		 BSON type */
	      if (!mongoc_gridfs_file_set_id (file, &id, &error)) {
		 fprintf (stderr, "%s\n", error.message);
		 return EXIT_FAILURE;
	      }

	      if (!mongoc_gridfs_file_save (file)) {
		 mongoc_gridfs_file_error (file, &error);
		 fprintf (stderr, "Could not save: %s\n", error.message);
		 return EXIT_FAILURE;
	      }

	      mongoc_gridfs_file_destroy (file);
	   } else {
	      fprintf (stderr, "Unknown command");
	      return EXIT_FAILURE;
	   }

	   mongoc_gridfs_destroy (gridfs);
	   mongoc_uri_destroy (uri);
	   mongoc_client_destroy (client);

	   mongoc_cleanup ();

	   return EXIT_SUCCESS;
	}

     SEE ALSO:
	The MongoDB GridFS specification.

	The spec-compliant mongoc_gridfs_bucket_t.

   mongoc_host_list_t
   Synopsis
	typedef struct {
	   mongoc_host_list_t *next;
	   char host[BSON_HOST_NAME_MAX + 1];
	   char host_and_port[BSON_HOST_NAME_MAX + 7];
	   uint16_t port;
	   int family;
	   void *padding[4];
	} mongoc_host_list_t;

   Description
     The host and port of a MongoDB server. Can be part of a  linked  list:  for
     example  the return value of mongoc_uri_get_hosts() when multiple hosts are
     provided in the MongoDB URI.

     SEE ALSO:
	mongoc_uri_get_hosts() and mongoc_cursor_get_host().

   mongoc_index_opt_geo_t
   Synopsis
	#include <mongoc/mongoc.h>

	typedef struct {
	   uint8_t twod_sphere_version;
	   uint8_t twod_bits_precision;
	   double twod_location_min;
	   double twod_location_max;
	   double haystack_bucket_size;
	   uint8_t *padding[32];
	} mongoc_index_opt_geo_t;

   Description
     This structure contains the options that may be used for tuning a	GEO  in-
     dex.

     SEE ALSO:
	mongoc_index_opt_t

	mongoc_index_opt_wt_t

   mongoc_index_opt_t
     WARNING:
	Deprecated since version 1.8.0: See Manage Collection Indexes for alter-
	natives.

   Synopsis
	#include <mongoc/mongoc.h>

	typedef struct {
	   bool is_initialized;
	   bool background;
	   bool unique;
	   const char *name;
	   bool drop_dups;
	   bool sparse;
	   int32_t expire_after_seconds;
	   int32_t v;
	   const bson_t *weights;
	   const char *default_language;
	   const char *language_override;
	   mongoc_index_opt_geo_t *geo_options;
	   mongoc_index_opt_storage_t *storage_options;
	   const bson_t *partial_filter_expression;
	   const bson_t *collation;
	   void *padding[4];
	} mongoc_index_opt_t;

   Description
     This  structure contains the options that may be used for tuning a specific
     index.

     See the createIndexes documentations in the MongoDB manual for descriptions
     of individual options.

     NOTE:
	dropDups is deprecated as of MongoDB  version  3.0.0.	This  option  is
	silently ignored by the server and unique index builds using this option
	will fail if a duplicate value is detected.

   Example
	{
	   bson_t keys;
	   bson_error_t error;
	   mongoc_index_opt_t opt;
	   mongoc_index_opt_geo_t geo_opt;

	   mongoc_index_opt_init (&opt);
	   mongoc_index_opt_geo_init (&geo_opt);

	   bson_init (&keys);
	   BSON_APPEND_UTF8 (&keys, "location", "2d");

	   geo_opt.twod_location_min = -123;
	   geo_opt.twod_location_max = +123;
	   geo_opt.twod_bits_precision = 30;
	   opt.geo_options = &geo_opt;

	   collection = mongoc_client_get_collection (client, "test", "geo_test");
	   if (mongoc_collection_create_index (collection, &keys, &opt, &error)) {
	      /* Successfully created the geo index */
	   }
	   bson_destroy (&keys);
	   mongoc_collection_destroy (&collection);
	}

     SEE ALSO:
	mongoc_index_opt_geo_t

	mongoc_index_opt_wt_t

   mongoc_index_opt_wt_t
   Synopsis
	#include <mongoc/mongoc.h>

	typedef struct {
	   mongoc_index_opt_storage_t base;
	   const char *config_str;
	   void *padding[8];
	} mongoc_index_opt_wt_t;

   Description
     This  structure  contains	the  options  that  may  be  used  for	tuning a
     WiredTiger specific index.

     SEE ALSO:
	mongoc_index_opt_t

	mongoc_index_opt_geo_t

   mongoc_insert_flags_t
     Flags for insert operations

   Synopsis
	typedef enum {
	   MONGOC_INSERT_NONE = 0,
	   MONGOC_INSERT_CONTINUE_ON_ERROR = 1 << 0,
	} mongoc_insert_flags_t;

	#define MONGOC_INSERT_NO_VALIDATE (1U << 31)

   Description
     These flags correspond to the MongoDB wire protocol. They	may  be  bitwise
     or'd together. They may modify how an insert happens on the MongoDB server.

   Flag Values
	    +---------------------------+-----------------------------+
	    | MONGOC_INSERT_NONE	| Specify no insert flags.    |
	    +---------------------------+-----------------------------+
	    | MONGOC_INSERT_CON-	| Continue   inserting	docu- |
	    | TINUE_ON_ERROR		| ments  from  the  insertion |
	    |				| set	even  if  one  insert |
	    |				| fails.		      |
	    +---------------------------+-----------------------------+
	    | MONGOC_INSERT_NO_VALIDATE | Do not  validate  insertion |
	    |				| documents before performing |
	    |				| an  insert.  Validation can |
	    |				| be expensive, so  this  can |
	    |				| save	some time if you know |
	    |				| your documents are  already |
	    |				| valid.		      |
	    +---------------------------+-----------------------------+

   mongoc_iovec_t
   Synopsis
   Synopsis
	#include <mongoc/mongoc.h>

	#ifdef _WIN32
	typedef struct {
	   u_long iov_len;
	   char *iov_base;
	} mongoc_iovec_t;
	#else
	typedef struct iovec mongoc_iovec_t;
	#endif

     The  mongoc_iovec_t structure is a portability abstraction for consumers of
     the mongoc_stream_t interfaces. It allows for  scatter/gather  I/O  through
     the socket subsystem.

     WARNING:
	When  writing  portable  code,	beware	of  the  ordering of iov_len and
	iov_base as they are different	on  various  platforms.  Therefore,  you
	should not use C initializers for initialization.

   mongoc_optional_t
     A struct to store optional boolean values.

   Synopsis
     Used to specify optional boolean flags, which may remain unset.

     This is used within mongoc_server_api_t to track whether a flag was explic-
     itly set.

   mongoc_query_flags_t
     Flags for query operations

   Synopsis
	typedef enum {
	   MONGOC_QUERY_NONE = 0,
	   MONGOC_QUERY_TAILABLE_CURSOR = 1 << 1,
	   MONGOC_QUERY_SECONDARY_OK = 1 << 2,
	   MONGOC_QUERY_OPLOG_REPLAY = 1 << 3,
	   MONGOC_QUERY_NO_CURSOR_TIMEOUT = 1 << 4,
	   MONGOC_QUERY_AWAIT_DATA = 1 << 5,
	   MONGOC_QUERY_EXHAUST = 1 << 6,
	   MONGOC_QUERY_PARTIAL = 1 << 7,
	} mongoc_query_flags_t;

   Description
     These  flags  correspond  to the MongoDB wire protocol. They may be bitwise
     or'd together. They may modify how a query  is  performed	in  the  MongoDB
     server.

   Flag Values
	    +----------------------------+-----------------------------+
	    | MONGOC_QUERY_NONE 	 | Specify no query flags.     |
	    +----------------------------+-----------------------------+
	    | MONGOC_QUERY_TAILABLE_CUR- | Cursor  will  not be closed |
	    | SOR			 | when the last data  is  re- |
	    |				 | trieved.   You  can	resume |
	    |				 | this cursor later.	       |
	    +----------------------------+-----------------------------+
	    | MONGOC_QUERY_SECONDARY_OK  | Allow query of replica  set |
	    |				 | secondaries. 	       |
	    +----------------------------+-----------------------------+
	    | MONGOC_QUERY_OPLOG_REPLAY  | Used internally by MongoDB. |
	    +----------------------------+-----------------------------+
	    | MONGOC_QUERY_NO_CUR-	 | The	server	normally times |
	    | SOR_TIMEOUT		 | out an idle cursor after an |
	    |				 | inactivity period (10  min- |
	    |				 | utes). This prevents that.  |
	    +----------------------------+-----------------------------+
	    | MONGOC_QUERY_AWAIT_DATA	 | Use with MONGOC_QUERY_TAIL- |
	    |				 | ABLE_CURSOR.  Block	rather |
	    |				 | than returning no data. Af- |
	    |				 | ter a period, time out.     |
	    +----------------------------+-----------------------------+
	    | MONGOC_QUERY_EXHAUST	 | Stream the data  down  full |
	    |				 | blast  in  multiple "reply" |
	    |				 | packets.  Faster  when  you |
	    |				 | are	pulling  down a lot of |
	    |				 | data and you know you  want |
	    |				 | to  retrieve  it all.  Only |
	    |				 | applies to cursors  created |
	    |				 | from a find operation (i.e. |
	    |				 | mongoc_collection_find()).  |
	    +----------------------------+-----------------------------+
	    | MONGOC_QUERY_PARTIAL	 | Get	partial  results  from |
	    |				 | mongos if some  shards  are |
	    |				 | down  (instead  of throwing |
	    |				 | an error).		       |
	    +----------------------------+-----------------------------+

   mongoc_rand
     MongoDB Random Number Generator

   Synopsis
	void
	mongoc_rand_add (const void *buf, int num, double entropy);

	void
	mongoc_rand_seed (const void *buf, int num);

	int
	mongoc_rand_status (void);

   Description
     The mongoc_rand family of functions provide access to the low level random-
     ness primitives used by the MongoDB C Driver.  In particular, they  control
     the  creation  of	cryptographically strong pseudo-random bytes required by
     some security mechanisms.

     While we can usually pull enough entropy from the environment, you  may  be
     required to seed the PRNG manually depending on your OS, hardware and other
     entropy consumers running on the same system.

   Entropy
     mongoc_rand_add and mongoc_rand_seed allow the user to directly provide en-
     tropy.  They differ insofar as mongoc_rand_seed requires that each bit pro-
     vided  is fully random.  mongoc_rand_add allows the user to specify the de-
     gree of randomness in the provided bytes as well.

   Status
     The mongoc_rand_status function allows the user to check the status of  the
     mongoc  PRNG.   This can be used to guarantee sufficient entropy at program
     startup, rather than waiting for runtime errors to occur.

   mongoc_read_concern_t
     Read Concern abstraction

   Synopsis
     New in MongoDB 3.2.

     The mongoc_read_concern_t allows clients to choose a level of isolation for
     their reads. The default, MONGOC_READ_CONCERN_LEVEL_LOCAL, is right for the
     great majority of applications.

     You can specify a read concern on connection objects, database objects,  or
     collection objects.

     See readConcern on the MongoDB website for more information.

     Read  Concern  is	only  sent to MongoDB when it has explicitly been set by
     mongoc_read_concern_set_level() to anything other than NULL.

   Read Concern Levels
       +----------------------+----------------------+----------------------+
       | Macro		      | Description	     | First  MongoDB  ver- |
       |		      | 		     | sion		    |
       +----------------------+----------------------+----------------------+
       | MONGOC_READ_CON-     | Level  "local",  the | 3.2		    |
       | CERN_LEVEL_LOCAL     | default.	     |			    |
       +----------------------+----------------------+----------------------+
       | MONGOC_READ_CON-     | Level "majority".    | 3.2		    |
       | CERN_LEVEL_MAJORITY  | 		     |			    |
       +----------------------+----------------------+----------------------+
       | MONGOC_READ_CON-     | Level	  "lineariz- | 3.4		    |
       | CERN_LEVEL_LINEARIZ- | able".		     |			    |
       | ABLE		      | 		     |			    |
       +----------------------+----------------------+----------------------+
       | MONGOC_READ_CON-     | Level "available".   | 3.6		    |
       | CERN_LEVEL_AVAILABLE | 		     |			    |
       +----------------------+----------------------+----------------------+
       | MONGOC_READ_CON-     | Level "snapshot".    | 4.0		    |
       | CERN_LEVEL_SNAPSHOT  | 		     |			    |
       +----------------------+----------------------+----------------------+

     For   the	 sake	of   compatibility  with  future  versions  of	MongoDB,
     mongoc_read_concern_set_level() allows any string, not just  this	list  of
     known read concern levels.

     See  Read	Concern  Levels in the MongoDB manual for more information about
     the individual read concern levels.

   mongoc_read_mode_t
     Read Preference Modes

   Synopsis
	typedef enum {
	   MONGOC_READ_PRIMARY = (1 << 0),
	   MONGOC_READ_SECONDARY = (1 << 1),
	   MONGOC_READ_PRIMARY_PREFERRED = (1 << 2) | MONGOC_READ_PRIMARY,
	   MONGOC_READ_SECONDARY_PREFERRED = (1 << 2) | MONGOC_READ_SECONDARY,
	   MONGOC_READ_NEAREST = (1 << 3) | MONGOC_READ_SECONDARY,
	} mongoc_read_mode_t;

   Description
     This enum describes how reads should be dispatched.  The  default	is  MON-
     GOC_READ_PRIMARY.

     Please see the MongoDB website for a description of Read Preferences.

   mongoc_read_prefs_t
     A read preference abstraction

   Synopsis
     mongoc_read_prefs_t  provides  an abstraction on top of the MongoDB connec-
     tion read preferences. It allows for hinting to the driver which nodes in a
     replica set should be accessed first and how.

     You can specify a read preference mode on connection objects, database  ob-
     jects,  collection objects, or per-operation.  Generally, it makes the most
     sense to stick with the global default mode, MONGOC_READ_PRIMARY.	 All  of
     the  other  modes	come  with caveats that won't be covered in great detail
     here.

   Read Modes
	    +----------------------------+-----------------------------+
	    | MONGOC_READ_PRIMARY	 | Default  mode.  All	opera- |
	    |				 | tions read from the current |
	    |				 | replica set primary.        |
	    +----------------------------+-----------------------------+
	    | MONGOC_READ_SECONDARY	 | All	operations  read  from |
	    |				 | among the nearest secondary |
	    |				 | members of the replica set. |
	    +----------------------------+-----------------------------+
	    | MONGOC_READ_PRIMARY_PRE-	 | In most situations,	opera- |
	    | FERRED			 | tions read from the primary |
	    |				 | but	if  it is unavailable, |
	    |				 | operations read  from  sec- |
	    |				 | ondary members.	       |
	    +----------------------------+-----------------------------+
	    | MONGOC_READ_SECONDARY_PRE- | In  most situations, opera- |
	    | FERRED			 | tions read from  among  the |
	    |				 | nearest  secondary members, |
	    |				 | but if no  secondaries  are |
	    |				 | available,  operations read |
	    |				 | from the primary.	       |
	    +----------------------------+-----------------------------+
	    | MONGOC_READ_NEAREST	 | Operations read from  among |
	    |				 | the	nearest members of the |
	    |				 | replica  set,  irrespective |
	    |				 | of the member's type.       |
	    +----------------------------+-----------------------------+

   Tag Sets
     Tag sets allow you to specify custom read preferences and write concerns so
     that your application can target operations to specific members.

     Custom  read preferences and write concerns evaluate tags sets in different
     ways: read preferences consider the value of a tag when selecting a  member
     to read from, while write concerns ignore the value of a tag when selecting
     a member, except to consider whether or not the value is unique.

     You can specify tag sets with the following read preference modes:

     * primaryPreferred

     * secondary

     * secondaryPreferred

     * nearest

     Tags  are not compatible with MONGOC_READ_PRIMARY and, in general, only ap-
     ply when selecting a secondary member of a set for a read	operation.  How-
     ever,  the nearest read mode, when combined with a tag set, will select the
     nearest member that matches the specified tag set, which may be  a  primary
     or secondary.

     Tag  sets	are  represented  as  a  comma-separated list of colon-separated
     key-value pairs when provided as a connection string, e.g. dc:ny,rack:1.

     To specify a list of tag sets, using multiple readPreferenceTags, e.g.

	readPreferenceTags=dc:ny,rack:1;readPreferenceTags=dc:ny;readPreferenceTags=

     Note the empty value for the last one, which means "match any secondary  as
     a last resort".

     Order matters when using multiple readPreferenceTags.

     Tag Sets can also be configured using mongoc_read_prefs_set_tags().

     All  interfaces use the same member selection logic to choose the member to
     which to direct read operations, basing the choice on read preference  mode
     and tag sets.

   Max Staleness
     When  connected to replica set running MongoDB 3.4 or later, the driver es-
     timates the staleness of each secondary based on lastWriteDate values  pro-
     vided in server hello responses.

     Max  Staleness  is the maximum replication lag in seconds (wall clock time)
     that a secondary can suffer and still be eligible for reads. The default is
     MONGOC_NO_MAX_STALENESS, which disables  staleness  checks.  Otherwise,  it
     must  be  a positive integer at least MONGOC_SMALLEST_MAX_STALENESS_SECONDS
     (90 seconds).

     Max Staleness is also supported by sharded clusters of replica sets if  all
     servers run MongoDB 3.4 or later.

   Hedged Reads
     When  connecting  to  a sharded cluster running MongoDB 4.4 or later, reads
     can be sent in parallel to the two "best" hosts.  Once one result	returns,
     any other outstanding operations that were part of the hedged read are can-
     celled.

     When  the read preference mode is MONGOC_READ_NEAREST and the sharded clus-
     ter is running MongoDB 4.4 or later, hedged reads are enabled  by	default.
     Additionally, hedged reads may be explicitly enabled or disabled by calling
     mongoc_read_prefs_set_hedge() with a BSON document, e.g.

	{
	   enabled: true
	}

     Appropriate values for the enabled key are true or false.

   mongoc_remove_flags_t
     Flags for deletion operations

   Synopsis
	typedef enum {
	   MONGOC_REMOVE_NONE = 0,
	   MONGOC_REMOVE_SINGLE_REMOVE = 1 << 0,
	} mongoc_remove_flags_t;

   Description
     These  flags  correspond  to the MongoDB wire protocol. They may be bitwise
     or'd together. They may change the number of  documents  that  are  removed
     during a remove command.

   Flag Values
	   +-----------------------------+-----------------------------+
	   | MONGOC_REMOVE_NONE 	 | Specify  no	removal flags. |
	   |				 | All matching documents will |
	   |				 | be removed.		       |
	   +-----------------------------+-----------------------------+
	   | MONGOC_REMOVE_SINGLE_REMOVE | Only   remove   the	 first |
	   |				 | matching  document from the |
	   |				 | selector.		       |
	   +-----------------------------+-----------------------------+

   mongoc_reply_flags_t
     Flags from server replies

   Synopsis
	typedef enum {
	   MONGOC_REPLY_NONE = 0,
	   MONGOC_REPLY_CURSOR_NOT_FOUND = 1 << 0,
	   MONGOC_REPLY_QUERY_FAILURE = 1 << 1,
	   MONGOC_REPLY_SHARD_CONFIG_STALE = 1 << 2,
	   MONGOC_REPLY_AWAIT_CAPABLE = 1 << 3,
	} mongoc_reply_flags_t;

   Description
     These flags correspond to the wire protocol. They may be bitwise  or'd  to-
     gether.

   Flag Values
	    +----------------------------+-----------------------------+
	    | MONGOC_REPLY_NONE 	 | No flags set.	       |
	    +----------------------------+-----------------------------+
	    | MONGOC_REPLY_CUR- 	 | No	matching   cursor  was |
	    | SOR_NOT_FOUND		 | found on the server.        |
	    +----------------------------+-----------------------------+
	    | MONGOC_REPLY_QUERY_FAILURE | The query failed or was in- |
	    |				 | valid. Error  document  has |
	    |				 | been provided.	       |
	    +----------------------------+-----------------------------+
	    | MONGOC_REPLY_SHARD_CON-	 | Shard config is stale.      |
	    | FIG_STALE 		 |			       |
	    +----------------------------+-----------------------------+
	    | MONGOC_REPLY_AWAIT_CAPABLE | If  the  returned cursor is |
	    |				 | capable	 of	  MON- |
	    |				 | GOC_QUERY_AWAIT_DATA.       |
	    +----------------------------+-----------------------------+

   mongoc_server_api_t
     A versioned API to use for connections.

   Synopsis
     Used to specify which version of the MongoDB server's API to use for driver
     connections.

     The  server API type takes a mongoc_server_api_version_t. It can optionally
     be strict about the list of allowed commands in that API version,	and  can
     also optionally provide errors for deprecated commands in that API version.

     A mongoc_server_api_t can be set on a client, and will then be sent to Mon-
     goDB for most commands run using that client.

   mongoc_server_api_version_t
     A representation of server API version numbers.

   Synopsis
     Used to specify which version of the MongoDB server's API to use for driver
     connections.

   Supported API Versions
     The driver currently supports the following MongoDB API versions:
		 +----------------------+------------------------+
		 | Enum value		| MongoDB version string |
		 +----------------------+------------------------+
		 | MONGOC_SERVER_API_V1 | "1"			 |
		 +----------------------+------------------------+

   mongoc_server_description_t
     Server description

   Synopsis
	#include <mongoc/mongoc.h>
	typedef struct _mongoc_server_description_t mongoc_server_description_t

     mongoc_server_description_t  holds information about a mongod or mongos the
     driver is connected to.

   Lifecycle
     Clean	   up	      a 	mongoc_server_description_t	    with
     mongoc_server_description_destroy() when necessary.

     Applications receive a temporary reference to a mongoc_server_description_t
     as  a  parameter to an SDAM Monitoring callback that must not be destroyed.
     See Introduction to Application Performance Monitoring.

     SEE ALSO:
	mongoc_client_get_server_descriptions().

   mongoc_session_opt_t
	#include <mongoc/mongoc.h>

	typedef struct _mongoc_session_opt_t mongoc_session_opt_t;

   Synopsis
     Start a session with mongoc_client_start_session(), use the session  for  a
     sequence  of  operations and multi-document transactions, then free it with
     mongoc_client_session_destroy().	    Any        mongoc_cursor_t	      or
     mongoc_change_stream_t  using  a  session must be destroyed before the ses-
     sion, and a session must be destroyed before the  mongoc_client_t	it  came
     from.

     By  default,  sessions  are  causally consistent. To disable causal consis-
     tency,  before  starting  a  session  create  a  mongoc_session_opt_t  with
     mongoc_session_opts_new()			    and 		    call
     mongoc_session_opts_set_causal_consistency(), then  free  the  struct  with
     mongoc_session_opts_destroy().

     Unacknowledged writes are prohibited with sessions.

     A mongoc_client_session_t must be used by only one thread at a time. Due to
     session  pooling,	mongoc_client_start_session()  may return a session that
     has been idle for some time and is about to be closed after its idle  time-
     out.  Use the session within one minute of acquiring it to refresh the ses-
     sion and avoid a timeout.

     See the example code for mongoc_session_opts_set_causal_consistency().

   mongoc_socket_t
     Portable socket abstraction

   Synopsis
	#include <mongoc/mongoc.h>

	typedef struct _mongoc_socket_t mongoc_socket_t

   Synopsis
     This structure provides a socket abstraction that is friendlier for  porta-
     bility  than  BSD	sockets directly. Inconsistencies between Linux, various
     BSDs, Solaris, and Windows are handled here.

   mongoc_ssl_opt_t
   Synopsis
	typedef struct {
	   const char *pem_file;
	   const char *pem_pwd;
	   const char *ca_file;
	   const char *ca_dir;
	   const char *crl_file;
	   bool weak_cert_validation;
	   bool allow_invalid_hostname;
	   void *internal;
	   void *padding[6];
	} mongoc_ssl_opt_t;

     NOTE:
	Though some API names include the term "ssl", the C driver only  support
	TLS protocols, which supersede SSL.

   Description
     This  structure  is  used	to  set the TLS options for a mongoc_client_t or
     mongoc_client_pool_t.

     Beginning in version 1.2.0, once a pool or client has any TLS options  set,
     all  connections use TLS, even if ssl=true is omitted from the MongoDB URI.
     Before, TLS options were ignored unless tls=true was included in the URI.

     As     of	   1.4.0,     the     mongoc_client_pool_set_ssl_opts()      and
     mongoc_client_set_ssl_opts()  will  not  only  shallow copy the struct, but
     will also copy the const char*. It is therefore no longer	needed	to  make
     sure the values remain valid after setting them.

     SEE ALSO:
	Configuring TLS

	mongoc_client_set_ssl_opts()

	mongoc_client_pool_set_ssl_opts()

   mongoc_stream_buffered_t
   Synopsis
	typedef struct _mongoc_stream_buffered_t mongoc_stream_buffered_t;

   Description
     mongoc_stream_buffered_t	 should    be	 considered    a   subclass   of
     mongoc_stream_t. It performs buffering on an underlying stream.

     SEE ALSO:
	mongoc_stream_buffered_new()

	mongoc_stream_destroy()

   mongoc_stream_file_t
   Synopsis
	typedef struct _mongoc_stream_file_t mongoc_stream_file_t

     mongoc_stream_file_t is a mongoc_stream_t subclass for working  with  stan-
     dard UNIX style file-descriptors.

   mongoc_stream_socket_t
   Synopsis
	typedef struct _mongoc_stream_socket_t mongoc_stream_socket_t

     mongoc_stream_socket_t  should  be considered a subclass of mongoc_stream_t
     that works upon socket streams.

   mongoc_stream_t
   Synopsis
	typedef struct _mongoc_stream_t mongoc_stream_t

     mongoc_stream_t provides a generic streaming  IO  abstraction  based  on  a
     struct  of pointers interface. The idea is to allow wrappers, perhaps other
     language drivers, to easily shim their IO system on top of mongoc_stream_t.

     The API for the stream abstraction is currently private and non-extensible.

   Stream Types
     There are a number of built in stream types that come with mongoc. The  de-
     fault  configuration  is  a buffered unix stream. If TLS is in use, that in
     turn is wrapped in a tls stream.

     SEE ALSO:
	mongoc_stream_buffered_t

	mongoc_stream_file_t

	mongoc_stream_socket_t

	mongoc_stream_tls_t

   mongoc_stream_tls_t
   Synopsis
	typedef struct _mongoc_stream_tls_t mongoc_stream_tls_t

     mongoc_stream_tls_t is a mongoc_stream_t  subclass  for  working  with  TLS
     streams.

   mongoc_topology_description_t
     Status of MongoDB Servers

   Synopsis
	typedef struct _mongoc_topology_description_t mongoc_topology_description_t;

     mongoc_topology_description_t  is	an opaque type representing the driver's
     knowledge of the MongoDB server or servers it is  connected  to.	Its  API
     conforms to the SDAM Monitoring Specification.

     Applications  receive  a  temporary reference to a mongoc_topology_descrip-
     tion_t as a parameter to an SDAM Monitoring callback that must not  be  de-
     stroyed. See Introduction to Application Performance Monitoring.

   mongoc_transaction_opt_t
	#include <mongoc/mongoc.h>

	typedef struct _mongoc_transaction_opt_t mongoc_transaction_opt_t;

   Synopsis
     Options for starting a multi-document transaction.

     When  a session is first created with mongoc_client_start_session(), it in-
     herits from the client the read concern, write concern, and read preference
     with which to start transactions. Each of these fields  can  be  overridden
     independently.	  Create       a      mongoc_transaction_opt_t	    with
     mongoc_transaction_opts_new(), and pass a non-NULL option	to  any  of  the
     mongoc_transaction_opt_t setter functions:

     * mongoc_transaction_opts_set_read_concern()

     * mongoc_transaction_opts_set_write_concern()

     * mongoc_transaction_opts_set_read_prefs()

     Pass	 the	    resulting	     transaction	options       to
     mongoc_client_session_start_transaction(). Each field set in  the	transac-
     tion options overrides the inherited client configuration.

   Example
     example-transaction.c

	/* gcc example-transaction.c -o example-transaction \
	 *     $(pkg-config --cflags --libs libmongoc-1.0) */

	/* ./example-transaction [CONNECTION_STRING] */

	#include <stdio.h>
	#include <mongoc/mongoc.h>

	int
	main (int argc, char *argv[])
	{
	   int exit_code = EXIT_FAILURE;

	   mongoc_client_t *client = NULL;
	   mongoc_database_t *database = NULL;
	   mongoc_collection_t *collection = NULL;
	   mongoc_client_session_t *session = NULL;
	   mongoc_session_opt_t *session_opts = NULL;
	   mongoc_transaction_opt_t *default_txn_opts = NULL;
	   mongoc_transaction_opt_t *txn_opts = NULL;
	   mongoc_read_concern_t *read_concern = NULL;
	   mongoc_write_concern_t *write_concern = NULL;
	   const char *uri_string = "mongodb://127.0.0.1/?appname=transaction-example";
	   mongoc_uri_t *uri;
	   bson_error_t error;
	   bson_t *doc = NULL;
	   bson_t *insert_opts = NULL;
	   int32_t i;
	   int64_t start;
	   bson_t reply = BSON_INITIALIZER;
	   char *reply_json;
	   bool r;

	   mongoc_init ();

	   if (argc > 1) {
	      uri_string = argv[1];
	   }

	   uri = mongoc_uri_new_with_error (uri_string, &error);
	   if (!uri) {
	      MONGOC_ERROR ("failed to parse URI: %s\n"
			    "error message:	  %s\n",
			    uri_string,
			    error.message);
	      goto done;
	   }

	   client = mongoc_client_new_from_uri (uri);
	   if (!client) {
	      goto done;
	   }

	   mongoc_client_set_error_api (client, 2);
	   database = mongoc_client_get_database (client, "example-transaction");

	   /* inserting into a nonexistent collection normally creates it, but a
	    * collection can't be created in a transaction; create it now */
	   collection = mongoc_database_create_collection (database, "collection", NULL, &error);

	   if (!collection) {
	      /* code 48 is NamespaceExists, see error_codes.err in mongodb source */
	      if (error.code == 48) {
		 collection = mongoc_database_get_collection (database, "collection");
	      } else {
		 MONGOC_ERROR ("Failed to create collection: %s", error.message);
		 goto done;
	      }
	   }

	   /* a transaction's read preferences, read concern, and write concern can be
	    * set on the client, on the default transaction options, or when starting
	    * the transaction. for the sake of this example, set read concern on the
	    * default transaction options. */
	   default_txn_opts = mongoc_transaction_opts_new ();
	   read_concern = mongoc_read_concern_new ();
	   mongoc_read_concern_set_level (read_concern, "snapshot");
	   mongoc_transaction_opts_set_read_concern (default_txn_opts, read_concern);
	   session_opts = mongoc_session_opts_new ();
	   mongoc_session_opts_set_default_transaction_opts (session_opts, default_txn_opts);

	   session = mongoc_client_start_session (client, session_opts, &error);
	   if (!session) {
	      MONGOC_ERROR ("Failed to start session: %s", error.message);
	      goto done;
	   }

	   /* in this example, set write concern when starting the transaction */
	   txn_opts = mongoc_transaction_opts_new ();
	   write_concern = mongoc_write_concern_new ();
	   mongoc_write_concern_set_wmajority (write_concern, 1000 /* wtimeout */);
	   mongoc_transaction_opts_set_write_concern (txn_opts, write_concern);

	   insert_opts = bson_new ();
	   if (!mongoc_client_session_append (session, insert_opts, &error)) {
	      MONGOC_ERROR ("Could not add session to opts: %s", error.message);
	      goto done;
	   }

	retry_transaction:
	   r = mongoc_client_session_start_transaction (session, txn_opts, &error);
	   if (!r) {
	      MONGOC_ERROR ("Failed to start transaction: %s", error.message);
	      goto done;
	   }

	   /* insert two documents - on error, retry the whole transaction */
	   for (i = 0; i < 2; i++) {
	      doc = BCON_NEW ("_id", BCON_INT32 (i));
	      bson_destroy (&reply);
	      r = mongoc_collection_insert_one (collection, doc, insert_opts, &reply, &error);

	      bson_destroy (doc);

	      if (!r) {
		 MONGOC_ERROR ("Insert failed: %s", error.message);
		 mongoc_client_session_abort_transaction (session, NULL);

		 /* a network error, primary failover, or other temporary error in a
		  * transaction includes {"errorLabels": ["TransientTransactionError"]},
		  * meaning that trying the entire transaction again may succeed
		  */
		 if (mongoc_error_has_label (&reply, "TransientTransactionError")) {
		    goto retry_transaction;
		 }

		 goto done;
	      }

	      reply_json = bson_as_relaxed_extended_json (&reply, NULL);
	      printf ("%s\n", reply_json);
	      bson_free (reply_json);
	   }

	   /* in case of transient errors, retry for 5 seconds to commit transaction */
	   start = bson_get_monotonic_time ();
	   while (bson_get_monotonic_time () - start < 5 * 1000 * 1000) {
	      bson_destroy (&reply);
	      r = mongoc_client_session_commit_transaction (session, &reply, &error);
	      if (r) {
		 /* success */
		 break;
	      } else {
		 MONGOC_ERROR ("Warning: commit failed: %s", error.message);
		 if (mongoc_error_has_label (&reply, "TransientTransactionError")) {
		    goto retry_transaction;
		 } else if (mongoc_error_has_label (&reply, "UnknownTransactionCommitResult")) {
		    /* try again to commit */
		    continue;
		 }

		 /* unrecoverable error trying to commit */
		 break;
	      }
	   }

	   exit_code = EXIT_SUCCESS;

	done:
	   bson_destroy (&reply);
	   bson_destroy (insert_opts);
	   mongoc_write_concern_destroy (write_concern);
	   mongoc_read_concern_destroy (read_concern);
	   mongoc_transaction_opts_destroy (txn_opts);
	   mongoc_transaction_opts_destroy (default_txn_opts);
	   mongoc_client_session_destroy (session);
	   mongoc_collection_destroy (collection);
	   mongoc_database_destroy (database);
	   mongoc_uri_destroy (uri);
	   mongoc_client_destroy (client);

	   mongoc_cleanup ();

	   return exit_code;
	}

   mongoc_transaction_state_t
     Constants for transaction states

   Synopsis
	typedef enum {
	  MONGOC_TRANSACTION_NONE = 0,
	  MONGOC_TRANSACTION_STARTING = 1,
	  MONGOC_TRANSACTION_IN_PROGRESS = 2,
	  MONGOC_TRANSACTION_COMMITTED = 3,
	  MONGOC_TRANSACTION_ABORTED = 4,
	} mongoc_transaction_state_t;

   Description
     These constants describe the current transaction state of a session.

   Flag Values
	   +-----------------------------+-----------------------------+
	   | MONGOC_TRANSACTION_NONE	 | There  is no transaction in |
	   |				 | progress.		       |
	   +-----------------------------+-----------------------------+
	   | MONGOC_TRANSACTION_STARTING | A  transaction   has   been |
	   |				 | started,  but  no operation |
	   |				 | has	been   sent   to   the |
	   |				 | server.		       |
	   +-----------------------------+-----------------------------+
	   | MONGOC_TRANSAC-		 | A	transaction    is   in |
	   | TION_IN_PROGRESS		 | progress.		       |
	   +-----------------------------+-----------------------------+
	   | MONGOC_TRANSACTION_COMMIT-  | The transaction was commit- |
	   | TED			 | ted. 		       |
	   +-----------------------------+-----------------------------+
	   | MONGOC_TRANSACTION_ABORTED  | The	   transaction	   was |
	   |				 | aborted.		       |
	   +-----------------------------+-----------------------------+

   mongoc_update_flags_t
     Flags for update operations

   Synopsis
	typedef enum {
	   MONGOC_UPDATE_NONE = 0,
	   MONGOC_UPDATE_UPSERT = 1 << 0,
	   MONGOC_UPDATE_MULTI_UPDATE = 1 << 1,
	} mongoc_update_flags_t;

	#define MONGOC_UPDATE_NO_VALIDATE (1U << 31)

   Description
     These  flags  correspond  to the MongoDB wire protocol. They may be bitwise
     or'd together. The allow for modifying the way an update  is  performed  in
     the MongoDB server.

   Flag Values
	    +----------------------------+-----------------------------+
	    | MONGOC_UPDATE_NONE	 | No update flags set.        |
	    +----------------------------+-----------------------------+
	    | MONGOC_UPDATE_UPSERT	 | If an upsert should be per- |
	    |				 | formed.		       |
	    +----------------------------+-----------------------------+
	    | MONGOC_UPDATE_MULTI_UPDATE | If	more   than  a	single |
	    |				 | matching document should be |
	    |				 | updated.  By  default  only |
	    |				 | the	first  document is up- |
	    |				 | dated.		       |
	    +----------------------------+-----------------------------+
	    | MONGOC_UPDATE_NO_VALIDATE  | Do not perform client  side |
	    |				 | BSON  validations when per- |
	    |				 | forming an update. This  is |
	    |				 | useful  if you already know |
	    |				 | your  BSON  documents   are |
	    |				 | valid.		       |
	    +----------------------------+-----------------------------+

   mongoc_uri_t
   Synopsis
	typedef struct _mongoc_uri_t mongoc_uri_t;

   Description
     mongoc_uri_t  provides  an abstraction on top of the MongoDB connection URI
     format. It provides standardized parsing as well as convenience methods for
     extracting useful information such as replica hosts or authorization infor-
     mation.

     See Connection String URI Reference on the MongoDB website for more  infor-
     mation.

   Format
	mongodb[+srv]://			     <1>
	   [username:password@] 		     <2>
	   host1				     <3>
	   [:port1]				     <4>
	   [,host2[:port2],...[,hostN[:portN]]]      <5>
	   [/[database] 			     <6>
	   [?options]]				     <7>

     1. "mongodb"  is  the  specifier of the MongoDB protocol. Use "mongodb+srv"
	with a single service name in place of "host1" to  specify  the  initial
	list of servers with an SRV record.

     2. An optional username and password.

     3. The  only  required  part of the uri.  This specifies either a hostname,
	IPv4 address, IPv6 address enclosed in	"["  and  "]",	or  UNIX  domain
	socket.

     4. An optional port number.  Defaults to :27017.

     5. Extra  optional  hosts and ports.  You would specify multiple hosts, for
	example, for connections to replica sets.

     6. The name of the database to authenticate if the  connection  string  in-
	cludes	authentication	credentials.   If /database is not specified and
	the connection string includes	credentials,  defaults	to  the  'admin'
	database.

     7. Connection specific options.

     NOTE:
	Option	names  are case-insensitive. Do not repeat the same option (e.g.
	"mongodb://localhost/db?opt=value1&OPT=value2") since this may have  un-
	expected results.

     The  MongoDB  C  Driver exposes constants for each supported connection op-
     tion. These constants make it easier to discover  connection  options,  but
     their string values can be used as well.

     For example, the following calls are equal.

	uri = mongoc_uri_new ("mongodb://localhost/?" MONGOC_URI_APPNAME "=applicationName");
	uri = mongoc_uri_new ("mongodb://localhost/?appname=applicationName");
	uri = mongoc_uri_new ("mongodb://localhost/?appName=applicationName");

   Replica Set Example
     To  describe  a connection to a replica set named 'test' with the following
     mongod hosts:

     * db1.example.com on port 27017

     * db2.example.com on port 2500

     You would use a connection string that resembles the following.

	mongodb://db1.example.com,db2.example.com:2500/?replicaSet=test

   SRV Example
     If  you  have  configured	an  SRV  record  with	a   name   like   "_mon-
     godb._tcp.server.example.com"  whose records are a list of one or more Mon-
     goDB server hostnames, use a connection string like this:

	uri = mongoc_uri_new ("mongodb+srv://server.example.com/?replicaSet=rs&appName=applicationName");

     The driver prefixes the service name with "_mongodb._tcp.", then performs a
     DNS SRV query to resolve the service name to one or more hostnames. If this
     query succeeds, the driver performs a DNS TXT query  on  the  service  name
     (without  the "_mongodb._tcp" prefix) for additional URI options configured
     as TXT records.

     On Unix, the MongoDB C Driver relies on libresolv to look up  SRV	and  TXT
     records.  If  libresolv is unavailable, then using a "mongodb+srv" URI will
     cause an error. If your libresolv lacks res_nsearch then  the  driver  will
     fall back to res_search, which is not thread-safe.

     Set  the  environment variable MONGOC_EXPERIMENTAL_SRV_PREFER_TCP to prefer
     TCP for the initial  queries.  The  environment  variable	is  ignored  for
     res_search.  Large  DNS responses over UDP may be truncated due to UDP size
     limitations. DNS resolvers are expected to retry over TCP if  the	UDP  re-
     sponse  indicates truncation. Some observed DNS environments do not set the
     truncation flag (TC), preventing the TCP retry. This  environment	variable
     is currently experimental and subject to change.

   IPv4 and IPv6
     If  connecting  to  a hostname that has both IPv4 and IPv6 DNS records, the
     behavior follows RFC-6555. A connection to the IPv6  address  is  attempted
     first.  If  IPv6 fails, then a connection is attempted to the IPv4 address.
     If the connection attempt to IPv6 does not complete within 250ms, then IPv4
     is tried in parallel.  Whichever  succeeds  connection  first  cancels  the
     other. The successful DNS result is cached for 10 minutes.

     As  a  consequence,  attempts to connect to a mongod only listening on IPv4
     may be delayed if there are both A (IPv4) and AAAA (IPv6) DNS records asso-
     ciated with the host.

     To avoid a delay, configure hostnames to match the  MongoDB  configuration.
     That is, only create an A record if the mongod is only listening on IPv4.

   Connection Options
+--------------------+------------------+------------------+-------------------------------------+
| Constant	     | Key		| Default	   | Description			 |
+--------------------+------------------+------------------+-------------------------------------+
| MON-		     | retryreads	| true		   | If   "true"  and			 |
| GOC_URI_RETRYREADS |			|		   | the server is  a			 |
|		     |			|		   | MongoDB	 3.6+			 |
|		     |			|		   | standalone,			 |
|		     |			|		   | replica set,  or			 |
|		     |			|		   | sharded cluster,			 |
|		     |			|		   | the       driver			 |
|		     |			|		   | safely retries a			 |
|		     |			|		   | read that failed			 |
|		     |			|		   | due to a network			 |
|		     |			|		   | error or replica			 |
|		     |			|		   | set failover.			 |
+--------------------+------------------+------------------+-------------------------------------+
| MONGOC_URI_RETRY-  | retrywrites	| true	if  driver | If   "true"  and			 |
| WRITES	     |			| built w/ TLS	   | the server is  a			 |
|		     |			|		   | MongoDB	 3.6+			 |
|		     |			|		   | replica  set  or			 |
|		     |			|		   | sharded cluster,			 |
|		     |			|		   | the       driver			 |
|		     |			|		   | safely retries a			 |
|		     |			|		   | write	 that			 |
|		     |			|		   | failed  due to a			 |
|		     |			|		   | network error or			 |
|		     |			|		   | replica	  set			 |
|		     |			|		   | failover.	 Only			 |
|		     |			|		   | inserts, updates			 |
|		     |			|		   | of single	docu-			 |
|		     |			|		   | ments,	   or			 |
|		     |			|		   | deletes of  sin-			 |
|		     |			|		   | gle    documents			 |
|		     |			|		   | are retried.			 |
+--------------------+------------------+------------------+-------------------------------------+
| MONGOC_URI_APPNAME | appname		| Empty  (no  app- | The  client  ap-			 |
|		     |			| name) 	   | plication	name.			 |
|		     |			|		   | This   value  is			 |
|		     |			|		   | used by  MongoDB			 |
|		     |			|		   | when   it	 logs			 |
|		     |			|		   | connection   in-			 |
|		     |			|		   | formation	  and			 |
|		     |			|		   | profile informa-			 |
|		     |			|		   | tion,  such   as			 |
|		     |			|		   | slow queries.			 |
+--------------------+------------------+------------------+-------------------------------------+
| MONGOC_URI_TLS     | tls		| Empty  (not set, | {true|false},			 |
|		     |			| same as false)   | indicating    if			 |
|		     |			|		   | TLS    must   be			 |
|		     |			|		   | used. (See  also			 |
|		     |			|		   | mongoc_client_set_ssl_opts()	 |
|		     |			|		   | and				 |
|		     |			|		   | mongoc_client_pool_set_ssl_opts().) |
+--------------------+------------------+------------------+-------------------------------------+
| MONGOC_URI_COM-    | compressors	| Empty  (no  com- | Comma separated  list  of	compres- |
| PRESSORS	     |			| pressors)	   | sors,  if	any,  to use to compress |
|		     |			|		   | the wire protocol messages. Snappy, |
|		     |			|		   | zlib, and zstd are  optional  build |
|		     |			|		   | time  dependencies,  and enable the |
|		     |			|		   | "snappy", "zlib", and "zstd" values |
|		     |			|		   | respectively.			 |
+--------------------+------------------+------------------+-------------------------------------+
| MONGOC_URI_CON-    | connecttimeoutms | 10,000  ms   (10 | This  setting applies to new server |
| NECTTIMEOUTMS      |			| seconds)	   | connections. It is also used as the |
|		     |			|		   | socket timeout for server discovery |
|		     |			|		   | and monitoring operations. 	 |
+--------------------+------------------+------------------+-------------------------------------+
| MONGOC_URI_SOCKET- | sockettimeoutms	| 300,000  ms	(5 | The time in milliseconds to attempt |
| TIMEOUTMS	     |			| minutes)	   | to  send or receive on a socket be- |
|		     |			|		   | fore the attempt times out.	 |
+--------------------+------------------+------------------+-------------------------------------+
| MONGOC_URI_REPLI-  | replicaset	| Empty (no repli- | The name of the  Replica  Set  that |
| CASET 	     |			| caset)	   | the driver should connect to.	 |
+--------------------+------------------+------------------+-------------------------------------+
| MONGOC_URI_ZLIB-   | zlibcompression- | -1		   | When the MONGOC_URI_COMPRESSORS in- |
| COMPRESSIONLEVEL   | level		|		   | cludes  "zlib" this options config- |
|		     |			|		   | ures the  zlib  compression  level, |
|		     |			|		   | when the zlib compressor is used to |
|		     |			|		   | compress client data.		 |
+--------------------+------------------+------------------+-------------------------------------+
| MONGOC_URI_LOAD-   | loadbalanced	| false 	   | If  true, this indicates the driver |
| BALANCED	     |			|		   | is connecting to a MongoDB  cluster |
|		     |			|		   | behind a load balancer.		 |
+--------------------+------------------+------------------+-------------------------------------+
| MONGOC_URI_SRVMAX- | srvmaxhosts	| 0		   | If zero, the number of hosts in DNS |
| HOSTS 	     |			|		   | results  is  unlimited.  If greater |
|		     |			|		   | than zero, the number of  hosts  in |
|		     |			|		   | DNS  results  is  limited	to being |
|		     |			|		   | less than or  equal  to  the  given |
|		     |			|		   | value.				 |
+--------------------+------------------+------------------+-------------------------------------+

     WARNING:
	Setting  any  of  the *timeoutMS options above to either 0 or a negative
	value is discouraged due to unspecified and inconsistent behavior.   The
	"default value" historically specified as a fallback for 0 or a negative
	value  is  NOT	related to the default values for the *timeoutMS options
	documented above.  The meaning of a timeout of 0 or a negative value may
	vary depending on the operation being executed, even when  specified  by
	the  same  URI	option.   To  specify the documented default value for a
	*timeoutMS option, use the MONGOC_DEFAULT_* constants  defined	in  mon-
	goc-client.h instead.

   Authentication Options
       +----------------------+----------------------+----------------------+
       | Constant	      | Key		     | Description	    |
       +----------------------+----------------------+----------------------+
       | MONGOC_URI_AUTHMECH- | authmechanism	     | Specifies the mecha- |
       | ANISM		      | 		     | nism to use when au- |
       |		      | 		     | thenticating  as the |
       |		      | 		     | provided user. See - |
       |		      | 		     | Authentication	for |
       |		      | 		     | supported values.    |
       +----------------------+----------------------+----------------------+
       | MONGOC_URI_AUTHMECH- | authmechanismproper- | Certain	authentica- |
       | ANISMPROPERTIES      | ties		     | tion mechanisms have |
       |		      | 		     | additional   options |
       |		      | 		     | that  can be config- |
       |		      | 		     | ured. These  options |
       |		      | 		     | should  be  provided |
       |		      | 		     | as  comma  separated |
       |		      | 		     | option_key:op-	    |
       |		      | 		     | tion_value  pair and |
       |		      | 		     | provided  as   auth- |
       |		      | 		     | MechanismProperties. |
       |		      | 		     | Specifying  the same |
       |		      | 		     | option_key  multiple |
       |		      | 		     | times  has undefined |
       |		      | 		     | behavior.	    |
       +----------------------+----------------------+----------------------+
       | MONGOC_URI_AUTH-     | authsource	     | The  authSource	de- |
       | SOURCE 	      | 		     | fines  the  database |
       |		      | 		     | that should be  used |
       |		      | 		     | to  authenticate to. |
       |		      | 		     | It is unnecessary to |
       |		      | 		     | provide this  option |
       |		      | 		     | the database name is |
       |		      | 		     | the   same   as	the |
       |		      | 		     | database used in the |
       |		      | 		     | URI.		    |
       +----------------------+----------------------+----------------------+

   Mechanism Properties
       +---------------------+----------------------+----------------------+
       | Constant	     | Key		    | Description	   |
       +---------------------+----------------------+----------------------+
       | MONGOC_URI_CANONI-  | canonicalizehostname | Use  the	 canonical |
       | CALIZEHOSTNAME      |			    | hostname of the ser- |
       |		     |			    | vice,   rather  than |
       |		     |			    | its	configured |
       |		     |			    | alias,  when authen- |
       |		     |			    | ticating	      with |
       |		     |			    | Cyrus-SASL Kerberos. |
       +---------------------+----------------------+----------------------+
       | MONGOC_URI_GSSAPIS- | gssapiservicename    | Use alternative ser- |
       | ERVICENAME	     |			    | vice  name.  The de- |
       |		     |			    | fault is mongodb.    |
       +---------------------+----------------------+----------------------+

   TLS Options
       +----------------------+----------------------+----------------------+
       | Constant	      | Key		     | Description	    |
       +----------------------+----------------------+----------------------+
       | MONGOC_URI_TLS       | tls		     | {true|false},  indi- |
       |		      | 		     | cating  if  TLS must |
       |		      | 		     | be used. 	    |
       +----------------------+----------------------+----------------------+
       | MONGOC_URI_TLSCER-   | tlscertificatekey-   | Path to PEM  format- |
       | TIFICATEKEYFILE      | file		     | ted   Private   Key, |
       |		      | 		     | with its Public Cer- |
       |		      | 		     | tificate    concate- |
       |		      | 		     | nated at the end.    |
       +----------------------+----------------------+----------------------+
       | MONGOC_URI_TLSCER-   | tlscertificatekey-   | The   password,	 if |
       | TIFICATEKEYFILEPASS- | password	     | any, to use  to	un- |
       | WORD		      | 		     | lock  encrypted Pri- |
       |		      | 		     | vate Key.	    |
       +----------------------+----------------------+----------------------+
       | MONGOC_URI_TLSCAFILE | tlscafile	     | One, or a bundle of, |
       |		      | 		     | Certificate Authori- |
       |		      | 		     | ties whom should  be |
       |		      | 		     | considered   to	 be |
       |		      | 		     | trusted. 	    |
       +----------------------+----------------------+----------------------+
       | MONGOC_URI_TLSALLOW- | tlsallowinvalidcer-  | Accept  and   ignore |
       | INVALIDCERTIFICATES  | tificates	     | certificate  verifi- |
       |		      | 		     | cation errors  (e.g. |
       |		      | 		     | untrusted    issuer, |
       |		      | 		     | expired, etc.)	    |
       +----------------------+----------------------+----------------------+
       | MONGOC_URI_TLSALLOW- | tlsallowinvalidhost- | Ignore hostname ver- |
       | INVALIDHOSTNAMES     | names		     | ification   of	the |
       |		      | 		     | certificate    (e.g. |
       |		      | 		     | Man In  The  Middle, |
       |		      | 		     | using valid certifi- |
       |		      | 		     | cate, but issued for |
       |		      | 		     | another hostname)    |
       +----------------------+----------------------+----------------------+
       | MONGOC_URI_TLSINSE-  | tlsinsecure	     | {true|false},  indi- |
       | CURE		      | 		     | cating  if  insecure |
       |		      | 		     | TLS  options  should |
       |		      | 		     | be  used.  Currently |
       |		      | 		     | this   implies  MON- |
       |		      | 		     | GOC_URI_TLSALLOWIN-  |
       |		      | 		     | VALIDCERTIFICATES    |
       |		      | 		     | and   MONGOC_URI_TL- |
       |		      | 		     | SALLOWINVALIDHOST-   |
       |		      | 		     | NAMES.		    |
       +----------------------+----------------------+----------------------+
       | MONGOC_URI_TLSDIS-   | tlsdisablecertifi-   | {true|false},  indi- |
       | ABLECERTIFICATEREVO- | caterevocationcheck  | cates if  revocation |
       | CATIONCHECK	      | 		     | checking    (CRL   / |
       |		      | 		     | OCSP) should be dis- |
       |		      | 		     | abled.		    |
       +----------------------+----------------------+----------------------+
       | MONGOC_URI_TLSDIS-   | tlsdisableocspend-   | {true|false},  indi- |
       | ABLEOCSPEND-	      | pointcheck	     | cates  if  OCSP	re- |
       | POINTCHECK	      | 		     | sponder	  endpoints |
       |		      | 		     | should  not  be	re- |
       |		      | 		     | quested when an OCSP |
       |		      | 		     | response is not sta- |
       |		      | 		     | pled.		    |
       +----------------------+----------------------+----------------------+

     See Configuring TLS for details about these options and about building lib-
     mongoc with TLS support.

   Deprecated SSL Options
     The following options have been deprecated and may be removed  from  future
     releases of libmongoc.
+-----------------------+------------------+-------------------+------------------+
| Constant		| Key		   | Deprecated For    | Key		  |
+-----------------------+------------------+-------------------+------------------+
| MONGOC_URI_SSL	| ssl		   | MONGOC_URI_TLS    | tls		  |
+-----------------------+------------------+-------------------+------------------+
| MON-			| sslclientcer-    | MON-	       | tlscertifi-	  |
| GOC_URI_SSLCLIENTCER- | tificatekeyfile  | GOC_URI_TLSCER-   | catekeyfile	  |
| TIFICATEKEYFILE	|		   | TIFICATEKEYFILE   |		  |
+-----------------------+------------------+-------------------+------------------+
| MON-			| sslclientcer-    | MON-	       | tlscertifi-	  |
| GOC_URI_SSLCLIENTCER- | tificatekeypass- | GOC_URI_TLSCER-   | catekeypassword  |
| TIFICATEKEYPASSWORD	| word		   | TIFICATEKEY-      |		  |
|			|		   | FILEPASSWORD      |		  |
+-----------------------+------------------+-------------------+------------------+
| MONGOC_URI_SSLCER-	| sslcertifi-	   | MON-	       | tlscafile	  |
| TIFICATEAUTHORITYFILE | cateauthority-   | GOC_URI_TLSCAFILE |		  |
|			| file		   |		       |		  |
+-----------------------+------------------+-------------------+------------------+
| MONGOC_URI_SSLALLOW-	| sslallowinvalid- | MONGOC_URI_TLSAL- | tlsallowinvalid- |
| INVALIDCERTIFICATES	| certificates	   | LOWINVALIDCER-    | certificates	  |
|			|		   | TIFICATES	       |		  |
+-----------------------+------------------+-------------------+------------------+
| MONGOC_URI_SSLALLOW-	| sslallowinvalid- | MONGOC_URI_TLSAL- | tlsallowinvalid- |
| INVALIDHOSTNAMES	| hostnames	   | LOWINVALIDHOST-   | hostnames	  |
|			|		   | NAMES	       |		  |
+-----------------------+------------------+-------------------+------------------+

   Server Discovery, Monitoring, and Selection Options
     Clients  in  a mongoc_client_pool_t share a topology scanner that runs on a
     background thread. The thread wakes every heartbeatFrequencyMS (default  10
     seconds)  to  scan all MongoDB servers in parallel. Whenever an application
     operation requires a server that is not known--for example, if there is  no
     known  primary  and your application attempts an insert--the thread rescans
     all servers every half-second. In this situation the pooled client waits up
     to serverSelectionTimeoutMS (default 30 seconds) for the thread to  find  a
     server  suitable  for the operation, then returns an error with domain MON-
     GOC_ERROR_SERVER_SELECTION.

     Technically, the total time an operation may wait	while  a  pooled  client
     scans  the topology is controlled both by serverSelectionTimeoutMS and con-
     nectTimeoutMS. The longest wait occurs if the last scan begins just at  the
     end  of  the selection timeout, and a slow or down server requires the full
     connection timeout before the client gives up.

     A non-pooled client  is  single-threaded.	Every  heartbeatFrequencyMS,  it
     blocks  the  next application operation while it does a parallel scan. This
     scan takes as long as needed to check the slowest server: roughly	connect-
     TimeoutMS.  Therefore  the default heartbeatFrequencyMS for single-threaded
     clients is greater than for pooled clients: 60 seconds.

     By default, single-threaded (non-pooled) clients scan only once when an op-
     eration requires a server that is not known. If you attempt an  insert  and
     there  is	no  known  primary, the client checks all servers once trying to
     find  it,	then  succeeds	or  returns  an  error	with  domain  MONGOC_ER-
     ROR_SERVER_SELECTION. But if you set serverSelectionTryOnce to "false", the
     single-threaded client loops, checking all servers every half-second, until
     serverSelectionTimeoutMS.

     The  total  time an operation may wait for a single-threaded client to scan
     the topology is determined by connectTimeoutMS in	the  try-once  case,  or
     serverSelectionTimeoutMS  and connectTimeoutMS if serverSelectionTryOnce is
     set "false".
       +----------------------+----------------------+----------------------+
       | Constant	      | Key		     | Description	    |
       +----------------------+----------------------+----------------------+
       | MONGOC_URI_HEART-    | heartbeatfrequencyms | The interval between |
       | BEATFREQUENCYMS      | 		     | server	 monitoring |
       |		      | 		     | checks.	Defaults to |
       |		      | 		     | 10,000ms  (10   sec- |
       |		      | 		     | onds)	in   pooled |
       |		      | 		     | (multi-threaded)     |
       |		      | 		     | mode,  60,000ms	(60 |
       |		      | 		     | seconds) 	 in |
       |		      | 		     | non-pooled      mode |
       |		      | 		     | (single-threaded).   |
       +----------------------+----------------------+----------------------+
       | MONGOC_URI_SERVERSE- | serverselectiontime- | A  timeout  in  mil- |
       | LECTIONTIMEOUTMS     | outms		     | liseconds  to  block |
       |		      | 		     | for server selection |
       |		      | 		     | before  throwing  an |
       |		      | 		     | exception.  The	de- |
       |		      | 		     | fault  is  30,0000ms |
       |		      | 		     | (30 seconds).	    |
       +----------------------+----------------------+----------------------+
       | MONGOC_URI_SERVERSE- | serverselectiontry-  | If "true", the  dri- |
       | LECTIONTRYONCE       | once		     | ver scans the topol- |
       |		      | 		     | ogy exactly once af- |
       |		      | 		     | ter server selection |
       |		      | 		     | fails,  then  either |
       |		      | 		     | selects a server  or |
       |		      | 		     | returns an error. If |
       |		      | 		     | it  is  false,  then |
       |		      | 		     | the  driver  repeat- |
       |		      | 		     | edly  searches for a |
       |		      | 		     | suitable server	for |
       |		      | 		     | up  to  serverSelec- |
       |		      | 		     | tionTimeoutMS   mil- |
       |		      | 		     | liseconds (pausing a |
       |		      | 		     | half  second between |
       |		      | 		     | attempts).  The	de- |
       |		      | 		     | fault  for serverSe- |
       |		      | 		     | lectionTryOnce	 is |
       |		      | 		     | "false"	for  pooled |
       |		      | 		     | clients,   otherwise |
       |		      | 		     | "true".	     Pooled |
       |		      | 		     | clients ignore  ser- |
       |		      | 		     | verSelectionTryOnce; |
       |		      | 		     | they    signal	the |
       |		      | 		     | thread to rescan the |
       |		      | 		     | topology       every |
       |		      | 		     | half-second    until |
       |		      | 		     | serverSelectionTime- |
       |		      | 		     | outMS expires.	    |
       +----------------------+----------------------+----------------------+
       | MONGOC_URI_SOCK-     | socketcheckinter-    | Only applies to sin- |
       | ETCHECKINTERVALMS    | valms		     | gle	   threaded |
       |		      | 		     | clients. If a socket |
       |		      | 		     | has  not  been  used |
       |		      | 		     | within  this   time, |
       |		      | 		     | its   connection  is |
       |		      | 		     | checked with a quick |
       |		      | 		     | "hello" call  before |
       |		      | 		     | it  is  used  again. |
       |		      | 		     | Defaults to  5,000ms |
       |		      | 		     | (5 seconds).	    |
       +----------------------+----------------------+----------------------+
       | MONGOC_URI_DIRECT-   | directconnection     | If  "true", the dri- |
       | CONNECTION	      | 		     | ver  connects  to  a |
       |		      | 		     | single	server	di- |
       |		      | 		     | rectly and will	not |
       |		      | 		     | monitor	 additional |
       |		      | 		     | servers. 	 If |
       |		      | 		     | "false",  the driver |
       |		      | 		     | connects  based	 on |
       |		      | 		     | the   presence	and |
       |		      | 		     | value of the  repli- |
       |		      | 		     | caSet option.	    |
       +----------------------+----------------------+----------------------+

     Setting  any  of  the  *TimeoutMS options above to 0 will be interpreted as
     "use the default value".

   Connection Pool Options
     These options govern the behavior of a mongoc_client_pool_t. They	are  ig-
     nored by a non-pooled mongoc_client_t.
      +---------------------+--------------------+--------------------------+
      | Constant	    | Key		 | Description		    |
      +---------------------+--------------------+--------------------------+
      | MONGOC_URI_MAXPOOL- | maxpoolsize	 | The	maximum  number     |
      | SIZE		    |			 | of  clients	created     |
      | 		    |			 | by		      a     |
      | 		    |			 | mongoc_client_pool_t     |
      | 		    |			 | total (both	in  the     |
      | 		    |			 | pool   and	checked     |
      | 		    |			 | out).  The	default     |
      | 		    |			 | value  is  100. Once     |
      | 		    |			 | it	 is    reached,     |
      | 		    |			 | mongoc_client_pool_pop() |
      | 		    |			 | blocks until another     |
      | 		    |			 | thread    pushes   a     |
      | 		    |			 | client.		    |
      +---------------------+--------------------+--------------------------+
      | MONGOC_URI_MINPOOL- | minpoolsize	 | Deprecated.	 This	op- |
      | SIZE		    |			 | tion's behavior does not |
      | 		    |			 | match  its name, and its |
      | 		    |			 | actual   behavior   will |
      | 		    |			 | likely hurt performance. |
      +---------------------+--------------------+--------------------------+
      | MONGOC_URI_MAXIDLE- | maxidletimems	 | Not implemented.	    |
      | TIMEMS		    |			 |			    |
      +---------------------+--------------------+--------------------------+
      | MONGOC_URI_WAIT-    | waitqueuemultiple  | Not implemented.	    |
      | QUEUEMULTIPLE	    |			 |			    |
      +---------------------+--------------------+--------------------------+
      | MONGOC_URI_WAIT-    | waitqueuetimeoutms | The maximum time to wait |
      | QUEUETIMEOUTMS	    |			 | for	a  client to become |
      | 		    |			 | available from the pool. |
      +---------------------+--------------------+--------------------------+

   Write Concern Options
	     +--------------------+------------+----------------------+
	     | Constant 	  | Key        | Description	      |
	     +--------------------+------------+----------------------+
	     | MONGOC_URI_W	  | w	       | Determines the write |
	     |			  |	       | concern (guarantee). |
	     |			  |	       | Valid values:	      |
	     |			  |	       |		      |
	     |			  |	       |      * 0 = The  dri- |
	     |			  |	       |	ver  will not |
	     |			  |	       |	acknowledge   |
	     |			  |	       |	write  opera- |
	     |			  |	       |	tions	  but |
	     |			  |	       |	will pass  or |
	     |			  |	       |	handle	  any |
	     |			  |	       |	network   and |
	     |			  |	       |	socket errors |
	     |			  |	       |	that  it  re- |
	     |			  |	       |	ceives to the |
	     |			  |	       |	client.    If |
	     |			  |	       |	you   disable |
	     |			  |	       |	write concern |
	     |			  |	       |	but    enable |
	     |			  |	       |	the	 get- |
	     |			  |	       |	LastError     |
	     |			  |	       |	commandas   w |
	     |			  |	       |	option,     w |
	     |			  |	       |	overrides the |
	     |			  |	       |	w option.     |
	     |			  |	       |		      |
	     |			  |	       |      * 1 =  Provides |
	     |			  |	       |	basic	  ac- |
	     |			  |	       |	knowledgement |
	     |			  |	       |	of write  op- |
	     |			  |	       |	erations.  By |
	     |			  |	       |	specifying 1, |
	     |			  |	       |	you   require |
	     |			  |	       |	that a stand- |
	     |			  |	       |	alone  mongod |
	     |			  |	       |	instance,  or |
	     |			  |	       |	the   primary |
	     |			  |	       |	for   replica |
	     |			  |	       |	sets,	  ac- |
	     |			  |	       |	knowledge all |
	     |			  |	       |	write  opera- |
	     |			  |	       |	tions.	  For |
	     |			  |	       |	drivers   re- |
	     |			  |	       |	leased	after |
	     |			  |	       |	the   default |
	     |			  |	       |	write concern |
	     |			  |	       |	change,  this |
	     |			  |	       |	is  the   de- |
	     |			  |	       |	fault	write |
	     |			  |	       |	concern  set- |
	     |			  |	       |	ting.	      |
	     |			  |	       |		      |
	     |			  |	       |      * majority    = |
	     |			  |	       |	For   replica |
	     |			  |	       |	sets,  if you |
	     |			  |	       |	specify   the |
	     |			  |	       |	special   ma- |
	     |			  |	       |	jority	value |
	     |			  |	       |	to  w option, |
	     |			  |	       |	write  opera- |
	     |			  |	       |	tions	 will |
	     |			  |	       |	only   return |
	     |			  |	       |	successfully  |
	     |			  |	       |	after  a  ma- |
	     |			  |	       |	jority of the |
	     |			  |	       |	configured    |
	     |			  |	       |	replica   set |
	     |			  |	       |	members  have |
	     |			  |	       |	acknowledged  |
	     |			  |	       |	the write op- |
	     |			  |	       |	eration.      |
	     |			  |	       |		      |
	     |			  |	       |      * n    =	  For |
	     |			  |	       |	replica sets, |
	     |			  |	       |	if  you spec- |
	     |			  |	       |	ify a  number |
	     |			  |	       |	n     greater |
	     |			  |	       |	than 1, oper- |
	     |			  |	       |	ations	 with |
	     |			  |	       |	this	write |
	     |			  |	       |	concern   re- |
	     |			  |	       |	turn only af- |
	     |			  |	       |	ter n members |
	     |			  |	       |	of   the  set |
	     |			  |	       |	have acknowl- |
	     |			  |	       |	edged	  the |
	     |			  |	       |	write. If you |
	     |			  |	       |	set  n	to  a |
	     |			  |	       |	number	 that |
	     |			  |	       |	is    greater |
	     |			  |	       |	than the num- |
	     |			  |	       |	ber of avail- |
	     |			  |	       |	able set mem- |
	     |			  |	       |	bers or  mem- |
	     |			  |	       |	bers	 that |
	     |			  |	       |	hold	data, |
	     |			  |	       |	MongoDB  will |
	     |			  |	       |	wait,  poten- |
	     |			  |	       |	tially indef- |
	     |			  |	       |	initely,  for |
	     |			  |	       |	these members |
	     |			  |	       |	to     become |
	     |			  |	       |	available.    |
	     |			  |	       |		      |
	     |			  |	       |      * tags   =  For |
	     |			  |	       |	replica sets, |
	     |			  |	       |	you can spec- |
	     |			  |	       |	ify a tag set |
	     |			  |	       |	to    require |
	     |			  |	       |	that all mem- |
	     |			  |	       |	bers  of  the |
	     |			  |	       |	set that have |
	     |			  |	       |	these	 tags |
	     |			  |	       |	configured    |
	     |			  |	       |	return	 con- |
	     |			  |	       |	firmation  of |
	     |			  |	       |	the write op- |
	     |			  |	       |	eration.      |
	     +--------------------+------------+----------------------+
	     | MONGOC_URI_WTIME-  | wtimeoutms | The   time  in  mil- |
	     | OUTMS		  |	       | liseconds  to	 wait |
	     |			  |	       | for  replication  to |
	     |			  |	       | succeed,  as  speci- |
	     |			  |	       | fied  in  the	w op- |
	     |			  |	       | tion, before  timing |
	     |			  |	       | out. When wtimeoutMS |
	     |			  |	       | is  0,  write opera- |
	     |			  |	       | tions	 will	never |
	     |			  |	       | time out.	      |
	     +--------------------+------------+----------------------+
	     | MONGOC_URI_JOURNAL | journal    | Controls     whether |
	     |			  |	       | write	   operations |
	     |			  |	       | will  wait until the |
	     |			  |	       | mongod  acknowledges |
	     |			  |	       | the write operations |
	     |			  |	       | and commits the data |
	     |			  |	       | to the on disk jour- |
	     |			  |	       | nal.		      |
	     |			  |	       |		      |
	     |			  |	       |      * true   =  En- |
	     |			  |	       |	ables journal |
	     |			  |	       |	commit	  ac- |
	     |			  |	       |	knowledgement |
	     |			  |	       |	write	 con- |
	     |			  |	       |	cern. Equiva- |
	     |			  |	       |	lent to spec- |
	     |			  |	       |	ifying	  the |
	     |			  |	       |	getLastError  |
	     |			  |	       |	command  with |
	     |			  |	       |	the j  option |
	     |			  |	       |	enabled.      |
	     |			  |	       |		      |
	     |			  |	       |      * false  = Does |
	     |			  |	       |	not   require |
	     |			  |	       |	that   mongod |
	     |			  |	       |	commit	write |
	     |			  |	       |	operations to |
	     |			  |	       |	the   journal |
	     |			  |	       |	before	  ac- |
	     |			  |	       |	knowledging   |
	     |			  |	       |	the write op- |
	     |			  |	       |	eration. This |
	     |			  |	       |	is   the  de- |
	     |			  |	       |	fault  option |
	     |			  |	       |	for the jour- |
	     |			  |	       |	nal   parame- |
	     |			  |	       |	ter.	      |
	     +--------------------+------------+----------------------+

   Read Concern Options
	 +---------------------+------------------+----------------------+
	 | Constant	       | Key		  | Description 	 |
	 +---------------------+------------------+----------------------+
	 | MONGOC_URI_READCON- | readconcernlevel | The level of  isola- |
	 | CERNLEVEL	       |		  | tion for read opera- |
	 |		       |		  | tions.  If the level |
	 |		       |		  | is left unspecified, |
	 |		       |		  | the  server  default |
	 |		       |		  | will  be used. See - |
	 |		       |		  | readConcern  in  the |
	 |		       |		  | MongoDB  Manual  for |
	 |		       |		  | details.		 |
	 +---------------------+------------------+----------------------+

   Read Preference Options
     When connected to a replica set, the driver chooses which member  to  query
     using the read preference:

     1. Choose members whose type matches "readPreference".

     2. From these, if there are any tags sets configured, choose members match-
	ing  the first tag set. If there are none, fall back to the next tag set
	and so on, until some members are chosen or the tag sets are exhausted.

     3. From the chosen servers, distribute queries randomly  among  the  server
	with  the  fastest  round-trip	times. These include the server with the
	fastest time and any whose round-trip time is no more than "localThresh-
	oldMS" slower.
       +----------------------+---------------------+----------------------+
       | Constant	      | Key		    | Description	   |
       +----------------------+---------------------+----------------------+
       | MONGOC_URI_READPREF- | readpreference	    | Specifies        the |
       | ERENCE 	      | 		    | replica	set   read |
       |		      | 		    | preference for  this |
       |		      | 		    | connection.     This |
       |		      | 		    | setting	 overrides |
       |		      | 		    | any      secondaryOk |
       |		      | 		    | value.   The    read |
       |		      | 		    | preference    values |
       |		      | 		    | are the following:   |
       |		      | 		    |			   |
       |		      | 		    |	   * primary  (de- |
       |		      | 		    |	     fault)	   |
       |		      | 		    |			   |
       |		      | 		    |	   * primaryPre-   |
       |		      | 		    |	     ferred	   |
       |		      | 		    |			   |
       |		      | 		    |	   * secondary	   |
       |		      | 		    |			   |
       |		      | 		    |	   * secondaryPre- |
       |		      | 		    |	     ferred	   |
       |		      | 		    |			   |
       |		      | 		    |	   * nearest	   |
       +----------------------+---------------------+----------------------+
       | MONGOC_URI_READPREF- | readpreferencetags  | A  representation of |
       | ERENCETAGS	      | 		    | a tag set. See  also |
       |		      | 		    | Tag Sets. 	   |
       +----------------------+---------------------+----------------------+
       | MONGOC_URI_LO-       | localthresholdms    | How  far to distrib- |
       | CALTHRESHOLDMS       | 		    | ute queries,  beyond |
       |		      | 		    | the  server with the |
       |		      | 		    | fastest	round-trip |
       |		      | 		    | time.   By  default, |
       |		      | 		    | only servers  within |
       |		      | 		    | 15ms  of the fastest |
       |		      | 		    | round-trip time  re- |
       |		      | 		    | ceive queries.	   |
       +----------------------+---------------------+----------------------+
       | MONGOC_URI_MAXSTALE- | maxstalenessseconds | The maximum replica- |
       | NESSSECONDS	      | 		    | tion  lag,  in  wall |
       |		      | 		    | clock time,  that  a |
       |		      | 		    | secondary can suffer |
       |		      | 		    | and  still be eligi- |
       |		      | 		    | ble.  The   smallest |
       |		      | 		    | allowed	value  for |
       |		      | 		    | maxStalenessSeconds  |
       |		      | 		    | is 90 seconds.	   |
       +----------------------+---------------------+----------------------+

     NOTE:
	When connecting to more than one  mongos,  libmongoc's	localThresholdMS
	applies  only  to the selection of mongos servers. The threshold for se-
	lecting among replica set members in  shards  is  controlled  by  the  -
	mongos's localThreshold command line option.

   Legacy Options
     For  historical  reasons,	the following options are available. They should
     however not be used.
		 +-----------------+------+----------------------+
		 | Constant	   | Key  | Description 	 |
		 +-----------------+------+----------------------+
		 | MONGOC_URI_SAFE | safe | {true|false} Same as |
		 |		   |	  | w={1|0}		 |
		 +-----------------+------+----------------------+

   Version Checks
     Conditional compilation based on mongoc version

   Description
     The following preprocessor macros can be used  to	perform  various  checks
     based on the version of the library you are compiling against.  This may be
     useful if you only want to enable a feature on a certain version of the li-
     brary.

	#include <mongoc/mongoc.h>

	#define MONGOC_MAJOR_VERSION (x)
	#define MONGOC_MINOR_VERSION (y)
	#define MONGOC_MICRO_VERSION (z)
	#define MONGOC_VERSION_S     "x.y.z"
	#define MONGOC_VERSION_HEX   ((1 << 24) | (0 << 16) | (0 << 8) | 0)
	#define MONGOC_CHECK_VERSION(major, minor, micro)

     Only compile a block on MongoDB C Driver 1.1.0 and newer.

	#if MONGOC_CHECK_VERSION(1, 1, 0)
	static void
	do_something (void)
	{
	}
	#endif

   mongoc_write_concern_t
     Write Concern abstraction

   Synopsis
     mongoc_write_concern_t  tells  the  driver what level of acknowledgement to
     await from the  server.  The  default,  MONGOC_WRITE_CONCERN_W_DEFAULT,  is
     right for the great majority of applications.

     You  can  specify	a write concern on connection objects, database objects,
     collection objects, or per-operation. Data-modifying  operations  typically
     use  the  write concern of the object they operate on, and check the server
     response for a write concern error or write concern timeout.  For	example,
     mongoc_collection_drop_index()  uses  the collection's write concern, and a
     write concern error or timeout in the response is considered a failure.

     Exceptions to this principle are the generic command functions:

     * mongoc_client_command()

     * mongoc_client_command_simple()

     * mongoc_database_command()

     * mongoc_database_command_simple()

     * mongoc_collection_command()

     * mongoc_collection_command_simple()

     These generic command functions do not automatically apply a write concern,
     and they do not check the server response for  a  write  concern  error  or
     write concern timeout.

     See Write Concern on the MongoDB website for more information.

   Write Concern Levels
     Set the write concern level with mongoc_write_concern_set_w().
	    +----------------------------+-----------------------------+
	    | MONGOC_WRITE_CONCERN_W_DE- | By  default,  writes  block |
	    | FAULT (1) 		 | awaiting    acknowledgement |
	    |				 | from  MongoDB. Acknowledged |
	    |				 | write    concern	allows |
	    |				 | clients  to	catch network, |
	    |				 | duplicate  key,  and  other |
	    |				 | errors.		       |
	    +----------------------------+-----------------------------+
	    | MONGOC_WRITE_CONCERN_W_UN- | With  this  write  concern, |
	    | ACKNOWLEDGED (0)		 | MongoDB does  not  acknowl- |
	    |				 | edge  the  receipt of write |
	    |				 | operation.	Unacknowledged |
	    |				 | is  similar	to  errors ig- |
	    |				 | nored; however, mongoc  at- |
	    |				 | tempts  to receive and han- |
	    |				 | dle	network  errors   when |
	    |				 | possible.		       |
	    +----------------------------+-----------------------------+
	    | MONGOC_WRITE_CONCERN_W_MA- | Block  until  a  write  has |
	    | JORITY (majority) 	 | been propagated to a major- |
	    |				 | ity of  the	nodes  in  the |
	    |				 | replica set. 	       |
	    +----------------------------+-----------------------------+
	    | n 			 | Block  until  a  write  has |
	    |				 | been propagated to at least |
	    |				 | n nodes in the replica set. |
	    +----------------------------+-----------------------------+

   Deprecations
     The write concern MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED  (value  -1)  is  a
     deprecated synonym for MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED (value 0), and
     will be removed in the next major release.

     mongoc_write_concern_set_fsync() is deprecated.

   Application Performance Monitoring (APM)
     The  MongoDB  C Driver allows you to monitor all the MongoDB operations the
     driver executes. This event-notification system  conforms	to  two  MongoDB
     driver specs:

     * Command	Logging and Monitoring: events related to all application opera-
       tions.

     * SDAM Monitoring: events related to the driver's Server Discovery And Mon-
       itoring logic.

     To   receive   notifications,   create   a   mongoc_apm_callbacks_t    with
     mongoc_apm_callbacks_new(),   set	 callbacks   on  it,  then  pass  it  to
     mongoc_client_set_apm_callbacks()					      or
     mongoc_client_pool_set_apm_callbacks().

   Command-Monitoring Example
     example-command-monitoring.c

	/* gcc example-command-monitoring.c -o example-command-monitoring \
	 *     $(pkg-config --cflags --libs libmongoc-1.0) */

	/* ./example-command-monitoring [CONNECTION_STRING] */

	#include <mongoc/mongoc.h>
	#include <stdio.h>

	typedef struct {
	   int started;
	   int succeeded;
	   int failed;
	} stats_t;

	void
	command_started (const mongoc_apm_command_started_t *event)
	{
	   char *s;

	   s = bson_as_relaxed_extended_json (mongoc_apm_command_started_get_command (event), NULL);
	   printf ("Command %s started on %s:\n%s\n\n",
		   mongoc_apm_command_started_get_command_name (event),
		   mongoc_apm_command_started_get_host (event)->host,
		   s);

	   ((stats_t *) mongoc_apm_command_started_get_context (event))->started++;

	   bson_free (s);
	}

	void
	command_succeeded (const mongoc_apm_command_succeeded_t *event)
	{
	   char *s;

	   s = bson_as_relaxed_extended_json (mongoc_apm_command_succeeded_get_reply (event), NULL);
	   printf ("Command %s succeeded:\n%s\n\n", mongoc_apm_command_succeeded_get_command_name (event), s);

	   ((stats_t *) mongoc_apm_command_succeeded_get_context (event))->succeeded++;

	   bson_free (s);
	}

	void
	command_failed (const mongoc_apm_command_failed_t *event)
	{
	   bson_error_t error;

	   mongoc_apm_command_failed_get_error (event, &error);
	   printf ("Command %s failed:\n\"%s\"\n\n", mongoc_apm_command_failed_get_command_name (event), error.message);

	   ((stats_t *) mongoc_apm_command_failed_get_context (event))->failed++;
	}

	int
	main (int argc, char *argv[])
	{
	   mongoc_client_t *client;
	   mongoc_apm_callbacks_t *callbacks;
	   stats_t stats = {0};
	   mongoc_collection_t *collection;
	   bson_error_t error;
	   const char *uri_string = "mongodb://127.0.0.1/?appname=cmd-monitoring-example";
	   mongoc_uri_t *uri;
	   const char *collection_name = "test";
	   bson_t *docs[2];

	   mongoc_init ();

	   if (argc > 1) {
	      uri_string = argv[1];
	   }

	   uri = mongoc_uri_new_with_error (uri_string, &error);
	   if (!uri) {
	      fprintf (stderr,
		       "failed to parse URI: %s\n"
		       "error message:	     %s\n",
		       uri_string,
		       error.message);
	      return EXIT_FAILURE;
	   }

	   client = mongoc_client_new_from_uri (uri);
	   if (!client) {
	      return EXIT_FAILURE;
	   }

	   mongoc_client_set_error_api (client, 2);
	   callbacks = mongoc_apm_callbacks_new ();
	   mongoc_apm_set_command_started_cb (callbacks, command_started);
	   mongoc_apm_set_command_succeeded_cb (callbacks, command_succeeded);
	   mongoc_apm_set_command_failed_cb (callbacks, command_failed);
	   mongoc_client_set_apm_callbacks (client, callbacks, (void *) &stats /* context pointer */);

	   collection = mongoc_client_get_collection (client, "test", collection_name);
	   mongoc_collection_drop (collection, NULL);

	   docs[0] = BCON_NEW ("_id", BCON_INT32 (0));
	   docs[1] = BCON_NEW ("_id", BCON_INT32 (1));
	   mongoc_collection_insert_many (collection, (const bson_t **) docs, 2, NULL, NULL, NULL);

	   /* duplicate key error on the second insert */
	   mongoc_collection_insert_one (collection, docs[0], NULL, NULL, NULL);

	   mongoc_collection_destroy (collection);
	   mongoc_apm_callbacks_destroy (callbacks);
	   mongoc_uri_destroy (uri);
	   mongoc_client_destroy (client);

	   printf ("started: %d\nsucceeded: %d\nfailed: %d\n", stats.started, stats.succeeded, stats.failed);

	   bson_destroy (docs[0]);
	   bson_destroy (docs[1]);

	   mongoc_cleanup ();

	   return EXIT_SUCCESS;
	}

     This example program prints:

	Command drop started on 127.0.0.1:
	{ "drop" : "test" }

	Command drop succeeded:
	{ "ns" : "test.test", "nIndexesWas" : 1, "ok" : 1.0 }

	Command insert started on 127.0.0.1:
	{
	  "insert" : "test",
	  "ordered" : true,
	  "documents" : [
	    { "_id" : 0 }, { "_id" : 1 }
	  ]
	}

	Command insert succeeded:
	{ "n" : 2, "ok" : 1.0 }

	Command insert started on 127.0.0.1:
	{
	  "insert" : "test",
	  "ordered" : true,
	  "documents" : [
	    { "_id" : 0 }
	  ]
	}

	Command insert succeeded:
	{
	  "n" : 0,
	  "writeErrors" : [
	    { "index" : 0, "code" : 11000, "errmsg" : "duplicate key" }
	  ],
	  "ok" : 1.0
	}

	started: 3
	succeeded: 3
	failed: 0

     The  output  has  been  edited and formatted for clarity. Depending on your
     server configuration, messages may include  metadata  like  database  name,
     logical session ids, or cluster times that are not shown here.

     The  final  "insert" command is considered successful, despite the writeEr-
     ror, because the server replied to the overall command with "ok": 1.

   SDAM Monitoring Example
     example-sdam-monitoring.c

	/* gcc example-sdam-monitoring.c -o example-sdam-monitoring \
	 *     $(pkg-config --cflags --libs libmongoc-1.0) */

	/* ./example-sdam-monitoring [CONNECTION_STRING] */

	#include <mongoc/mongoc.h>
	#include <stdio.h>

	typedef struct {
	   int server_changed_events;
	   int server_opening_events;
	   int server_closed_events;
	   int topology_changed_events;
	   int topology_opening_events;
	   int topology_closed_events;
	   int heartbeat_started_events;
	   int heartbeat_succeeded_events;
	   int heartbeat_failed_events;
	} stats_t;

	static void
	server_changed (const mongoc_apm_server_changed_t *event)
	{
	   stats_t *context;
	   const mongoc_server_description_t *prev_sd, *new_sd;

	   context = (stats_t *) mongoc_apm_server_changed_get_context (event);
	   context->server_changed_events++;

	   prev_sd = mongoc_apm_server_changed_get_previous_description (event);
	   new_sd = mongoc_apm_server_changed_get_new_description (event);

	   printf ("server changed: %s %s -> %s\n",
		   mongoc_apm_server_changed_get_host (event)->host_and_port,
		   mongoc_server_description_type (prev_sd),
		   mongoc_server_description_type (new_sd));
	}

	static void
	server_opening (const mongoc_apm_server_opening_t *event)
	{
	   stats_t *context;

	   context = (stats_t *) mongoc_apm_server_opening_get_context (event);
	   context->server_opening_events++;

	   printf ("server opening: %s\n", mongoc_apm_server_opening_get_host (event)->host_and_port);
	}

	static void
	server_closed (const mongoc_apm_server_closed_t *event)
	{
	   stats_t *context;

	   context = (stats_t *) mongoc_apm_server_closed_get_context (event);
	   context->server_closed_events++;

	   printf ("server closed: %s\n", mongoc_apm_server_closed_get_host (event)->host_and_port);
	}

	static void
	topology_changed (const mongoc_apm_topology_changed_t *event)
	{
	   stats_t *context;
	   const mongoc_topology_description_t *prev_td;
	   const mongoc_topology_description_t *new_td;
	   mongoc_server_description_t **prev_sds;
	   size_t n_prev_sds;
	   mongoc_server_description_t **new_sds;
	   size_t n_new_sds;
	   size_t i;
	   mongoc_read_prefs_t *prefs;

	   context = (stats_t *) mongoc_apm_topology_changed_get_context (event);
	   context->topology_changed_events++;

	   prev_td = mongoc_apm_topology_changed_get_previous_description (event);
	   prev_sds = mongoc_topology_description_get_servers (prev_td, &n_prev_sds);
	   new_td = mongoc_apm_topology_changed_get_new_description (event);
	   new_sds = mongoc_topology_description_get_servers (new_td, &n_new_sds);

	   printf ("topology changed: %s -> %s\n",
		   mongoc_topology_description_type (prev_td),
		   mongoc_topology_description_type (new_td));

	   if (n_prev_sds) {
	      printf ("  previous servers:\n");
	      for (i = 0; i < n_prev_sds; i++) {
		 printf ("	%s %s\n",
			 mongoc_server_description_type (prev_sds[i]),
			 mongoc_server_description_host (prev_sds[i])->host_and_port);
	      }
	   }

	   if (n_new_sds) {
	      printf ("  new servers:\n");
	      for (i = 0; i < n_new_sds; i++) {
		 printf ("	%s %s\n",
			 mongoc_server_description_type (new_sds[i]),
			 mongoc_server_description_host (new_sds[i])->host_and_port);
	      }
	   }

	   prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY);

	   if (mongoc_topology_description_has_readable_server (new_td, prefs)) {
	      printf ("  secondary AVAILABLE\n");
	   } else {
	      printf ("  secondary UNAVAILABLE\n");
	   }

	   if (mongoc_topology_description_has_writable_server (new_td)) {
	      printf ("  primary AVAILABLE\n");
	   } else {
	      printf ("  primary UNAVAILABLE\n");
	   }

	   mongoc_read_prefs_destroy (prefs);
	   mongoc_server_descriptions_destroy_all (prev_sds, n_prev_sds);
	   mongoc_server_descriptions_destroy_all (new_sds, n_new_sds);
	}

	static void
	topology_opening (const mongoc_apm_topology_opening_t *event)
	{
	   stats_t *context;

	   context = (stats_t *) mongoc_apm_topology_opening_get_context (event);
	   context->topology_opening_events++;

	   printf ("topology opening\n");
	}

	static void
	topology_closed (const mongoc_apm_topology_closed_t *event)
	{
	   stats_t *context;

	   context = (stats_t *) mongoc_apm_topology_closed_get_context (event);
	   context->topology_closed_events++;

	   printf ("topology closed\n");
	}

	static void
	server_heartbeat_started (const mongoc_apm_server_heartbeat_started_t *event)
	{
	   stats_t *context;

	   context = (stats_t *) mongoc_apm_server_heartbeat_started_get_context (event);
	   context->heartbeat_started_events++;

	   printf ("%s heartbeat started\n", mongoc_apm_server_heartbeat_started_get_host (event)->host_and_port);
	}

	static void
	server_heartbeat_succeeded (const mongoc_apm_server_heartbeat_succeeded_t *event)
	{
	   stats_t *context;
	   char *reply;

	   context = (stats_t *) mongoc_apm_server_heartbeat_succeeded_get_context (event);
	   context->heartbeat_succeeded_events++;

	   reply = bson_as_canonical_extended_json (mongoc_apm_server_heartbeat_succeeded_get_reply (event), NULL);

	   printf (
	      "%s heartbeat succeeded: %s\n", mongoc_apm_server_heartbeat_succeeded_get_host (event)->host_and_port, reply);

	   bson_free (reply);
	}

	static void
	server_heartbeat_failed (const mongoc_apm_server_heartbeat_failed_t *event)
	{
	   stats_t *context;
	   bson_error_t error;

	   context = (stats_t *) mongoc_apm_server_heartbeat_failed_get_context (event);
	   context->heartbeat_failed_events++;
	   mongoc_apm_server_heartbeat_failed_get_error (event, &error);

	   printf (
	      "%s heartbeat failed: %s\n", mongoc_apm_server_heartbeat_failed_get_host (event)->host_and_port, error.message);
	}

	int
	main (int argc, char *argv[])
	{
	   mongoc_client_t *client;
	   mongoc_apm_callbacks_t *cbs;
	   stats_t stats = {0};
	   const char *uri_string = "mongodb://127.0.0.1/?appname=sdam-monitoring-example";
	   mongoc_uri_t *uri;
	   bson_t cmd = BSON_INITIALIZER;
	   bson_t reply;
	   bson_error_t error;

	   mongoc_init ();

	   if (argc > 1) {
	      uri_string = argv[1];
	   }

	   uri = mongoc_uri_new_with_error (uri_string, &error);
	   if (!uri) {
	      fprintf (stderr,
		       "failed to parse URI: %s\n"
		       "error message:	     %s\n",
		       uri_string,
		       error.message);
	      return EXIT_FAILURE;
	   }

	   client = mongoc_client_new_from_uri (uri);
	   if (!client) {
	      return EXIT_FAILURE;
	   }

	   mongoc_client_set_error_api (client, 2);
	   cbs = mongoc_apm_callbacks_new ();
	   mongoc_apm_set_server_changed_cb (cbs, server_changed);
	   mongoc_apm_set_server_opening_cb (cbs, server_opening);
	   mongoc_apm_set_server_closed_cb (cbs, server_closed);
	   mongoc_apm_set_topology_changed_cb (cbs, topology_changed);
	   mongoc_apm_set_topology_opening_cb (cbs, topology_opening);
	   mongoc_apm_set_topology_closed_cb (cbs, topology_closed);
	   mongoc_apm_set_server_heartbeat_started_cb (cbs, server_heartbeat_started);
	   mongoc_apm_set_server_heartbeat_succeeded_cb (cbs, server_heartbeat_succeeded);
	   mongoc_apm_set_server_heartbeat_failed_cb (cbs, server_heartbeat_failed);
	   mongoc_client_set_apm_callbacks (client, cbs, (void *) &stats /* context pointer */);

	   /* the driver connects on demand to perform first operation */
	   BSON_APPEND_INT32 (&cmd, "buildinfo", 1);
	   mongoc_client_command_simple (client, "admin", &cmd, NULL, &reply, &error);
	   mongoc_uri_destroy (uri);
	   mongoc_client_destroy (client);

	   printf ("Events:\n"
		   "   server changed: %d\n"
		   "   server opening: %d\n"
		   "   server closed: %d\n"
		   "   topology changed: %d\n"
		   "   topology opening: %d\n"
		   "   topology closed: %d\n"
		   "   heartbeat started: %d\n"
		   "   heartbeat succeeded: %d\n"
		   "   heartbeat failed: %d\n",
		   stats.server_changed_events,
		   stats.server_opening_events,
		   stats.server_closed_events,
		   stats.topology_changed_events,
		   stats.topology_opening_events,
		   stats.topology_closed_events,
		   stats.heartbeat_started_events,
		   stats.heartbeat_succeeded_events,
		   stats.heartbeat_failed_events);

	   bson_destroy (&cmd);
	   bson_destroy (&reply);
	   mongoc_apm_callbacks_destroy (cbs);

	   mongoc_cleanup ();

	   return EXIT_SUCCESS;
	}

     Start a 3-node replica set on localhost with set name "rs"  and  start  the
     program:

	./example-sdam-monitoring "mongodb://localhost:27017,localhost:27018/?replicaSet=rs"

     This example program prints something like:

	topology opening
	topology changed: Unknown -> ReplicaSetNoPrimary
	  secondary UNAVAILABLE
	  primary UNAVAILABLE
	server opening: localhost:27017
	server opening: localhost:27018
	localhost:27017 heartbeat started
	localhost:27018 heartbeat started
	localhost:27017 heartbeat succeeded: { ... reply ... }
	server changed: localhost:27017 Unknown -> RSPrimary
	server opening: localhost:27019
	topology changed: ReplicaSetNoPrimary -> ReplicaSetWithPrimary
	  new servers:
	      RSPrimary localhost:27017
	  secondary UNAVAILABLE
	  primary AVAILABLE
	localhost:27019 heartbeat started
	localhost:27018 heartbeat succeeded: { ... reply ... }
	server changed: localhost:27018 Unknown -> RSSecondary
	topology changed: ReplicaSetWithPrimary -> ReplicaSetWithPrimary
	  previous servers:
	      RSPrimary localhost:27017
	  new servers:
	      RSPrimary localhost:27017
	      RSSecondary localhost:27018
	  secondary AVAILABLE
	  primary AVAILABLE
	localhost:27019 heartbeat succeeded: { ... reply ... }
	server changed: localhost:27019 Unknown -> RSSecondary
	topology changed: ReplicaSetWithPrimary -> ReplicaSetWithPrimary
	  previous servers:
	      RSPrimary localhost:27017
	      RSSecondary localhost:27018
	  new servers:
	      RSPrimary localhost:27017
	      RSSecondary localhost:27018
	      RSSecondary localhost:27019
	  secondary AVAILABLE
	  primary AVAILABLE
	topology closed

	Events:
	   server changed: 3
	   server opening: 3
	   server closed: 0
	   topology changed: 4
	   topology opening: 1
	   topology closed: 1
	   heartbeat started: 3
	   heartbeat succeeded: 3
	   heartbeat failed: 0

     The  driver  connects  to	the mongods on ports 27017 and 27018, which were
     specified in the URI, and determines which is primary.  It  also  discovers
     the third member, "localhost:27019", and adds it to the topology.

AUTHOR
     MongoDB, Inc

COPYRIGHT
     2009-present, MongoDB, Inc.

1.30.8				  Aug 27, 2026		     MONGOC_REFERENCE(3)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=mongoc_reference&sektion=3&manpath=FreeBSD+Ports+15.1.quarterly>

home | help