mod_cdr_mongodb: update MongoDB driver to v0.6

This commit is contained in:
Daniel Swarbrick 2012-10-14 13:45:50 +02:00
parent 6533c9b92b
commit 10093b44c0
10 changed files with 543 additions and 126 deletions

View File

@ -1,5 +1,37 @@
# MongoDB C Driver History
## 0.6
2012-6-3
** API CHANGE **
Version 0.6 supports write concern. This involves a backward-breaking
API change, as the write functions now take an optional write_concern
object.
The driver now also supports the MONGO_CONTINUE_ON_ERROR flag for
batch inserts.
The new function prototypes are as follows:
* int mongo_insert( mongo *conn, const char *ns, const bson *data,
mongo_write_concern *custom_write_concern );
* int mongo_insert_batch( mongo *conn, const char *ns,
const bson **data, int num, mongo_write_concern *custom_write_concern );
* int mongo_update( mongo *conn, const char *ns, const bson *cond,
const bson *op, int flags, mongo_write_concern *custom_write_concern,
int flags );
* int mongo_remove( mongo *conn, const char *ns, const bson *cond,
mongo_write_concern *custom_write_concern );
* Allow DBRefs (i.e., allows keys $ref, $id, and $db)
* Added mongo_create_capped_collection().
* Fixed some bugs in the SCons and Makefile build scripts.
* Fixes for SCons and Makefile shared library install targets.
* Other minor bug fixes.
## 0.5.2
2012-5-4

View File

@ -9,17 +9,31 @@ by providing an interface for platform-specific modules.
Until the 1.0 release, this driver should be considered alpha. Keep in mind that the API will be in flux until then.
# Documentation
Documentation exists in the project's `docs` folder. You can read the latest
docs online at (http://api.mongodb.org/c/current/).
The docs are built using Sphinx and Doxygen. If you have these tools installed, then
you can build the docs with scons:
scons docs
The html docs will appear in docs/html.
# Building
First check out the version you want to build. *Always build from a particular tag, since HEAD may be
a work in progress.* For example, to build version 0.5.2, run:
a work in progress.* For example, to build version 0.6, run:
git checkout v0.5.2
git checkout v0.6
You can then build the driver with scons:
scons
For more build options, see the docs.
## Running the tests
Make sure that you're running mongod on 127.0.0.1 on the default port (27017). The replica set
test assumes a replica set with at least three nodes running at 127.0.0.1 and starting at port
@ -35,14 +49,6 @@ Specific error codes and error strings are then stored in the `err` and `errstr`
`mongo` and `bson` objects. It is the client's responsibility to check for errors and handle
them appropriately.
# Docs
The docs are built using Sphinx and Doxygen. If you have these tools installed, then
you can build the docs with scons:
scons docs
The html docs will appear in docs/html.
# ISSUES
You can report bugs, request new features, and view this driver's roadmap

View File

@ -32,7 +32,7 @@ static const int zero = 0;
/* Custom standard function pointers. */
void *( *bson_malloc_func )( size_t ) = malloc;
void *( *bson_realloc_func )( void *, size_t ) = realloc;
void ( *bson_free )( void * ) = free;
void ( *bson_free_func )( void * ) = free;
#ifdef R_SAFETY_NET
bson_printf_func bson_printf;
#else
@ -308,7 +308,7 @@ MONGO_EXPORT void bson_print_raw( const char *data , int depth ) {
------------------------------ */
MONGO_EXPORT bson_iterator* bson_iterator_create() {
return (bson_iterator*)malloc(sizeof(bson_iterator*));
return ( bson_iterator* )malloc( sizeof( bson_iterator ) );
}
MONGO_EXPORT void bson_iterator_dispose(bson_iterator* i) {
@ -973,6 +973,10 @@ MONGO_EXPORT bson_err_handler set_bson_err_handler( bson_err_handler func ) {
return old;
}
MONGO_EXPORT void bson_free( void *ptr ) {
bson_free_func( ptr );
}
MONGO_EXPORT void *bson_malloc( int size ) {
void *p;
p = bson_malloc_func( size );

View File

@ -959,13 +959,15 @@ typedef int (*bson_sprintf_func)( char *, const char *, ... );
extern void *( *bson_malloc_func )( size_t );
extern void *( *bson_realloc_func )( void *, size_t );
extern void ( *bson_free )( void * );
extern void ( *bson_free_func )( void * );
extern bson_printf_func bson_printf;
extern bson_fprintf_func bson_fprintf;
extern bson_sprintf_func bson_sprintf;
extern bson_printf_func bson_errprintf;
MONGO_EXPORT void bson_free( void *ptr );
/**
* Allocates memory and checks return value, exiting fatally if malloc() fails.
*

View File

@ -101,6 +101,24 @@ static int isLegalUTF8( const unsigned char *source, int length ) {
return 1;
}
/* If the name is part of a db ref ($ref, $db, or $id), then return true. */
static int bson_string_is_db_ref( const unsigned char *string, const int length ) {
int result = 0;
if( length >= 4 ) {
if( string[1] == 'r' && string[2] == 'e' && string[3] == 'f' )
result = 1;
}
else if( length >= 3 ) {
if( string[1] == 'i' && string[2] == 'd' )
result = 1;
else if( string[1] == 'd' && string[2] == 'b' )
result = 1;
}
return result;
}
static int bson_validate_string( bson *b, const unsigned char *string,
const int length, const char check_utf8, const char check_dot,
const char check_dollar ) {
@ -109,7 +127,8 @@ static int bson_validate_string( bson *b, const unsigned char *string,
int sequence_length = 1;
if( check_dollar && string[0] == '$' ) {
b->err |= BSON_FIELD_INIT_DOLLAR;
if( !bson_string_is_db_ref( string, length ) )
b->err |= BSON_FIELD_INIT_DOLLAR;
}
while ( position < length ) {

View File

@ -24,8 +24,8 @@
#include <ws2tcpip.h> // send,recv,socklen_t etc
#include <wspiapi.h> // addrinfo
#else
#include <windows.h>
#include <winsock.h>
#include <ws2tcpip.h> // send,recv,socklen_t etc
#include <winsock2.h>
typedef int socklen_t;
#endif
@ -33,11 +33,6 @@ typedef int socklen_t;
# define NI_MAXSERV 32
#endif
static void mongo_clear_errors( mongo *conn ) {
conn->err = 0;
memset( conn->errstr, 0, MONGO_ERR_LEN );
}
int mongo_env_close_socket( int socket ) {
return closesocket( socket );
}

View File

@ -170,7 +170,7 @@ static int gridfs_insert_file( gridfs *gfs, const char *name,
bson_append_string( &ret, "contentType", contenttype );
}
bson_finish( &ret );
result = mongo_insert( gfs->client, gfs->files_ns, &ret );
result = mongo_insert( gfs->client, gfs->files_ns, &ret, NULL );
bson_destroy( &ret );
return result;
@ -198,7 +198,7 @@ MONGO_EXPORT int gridfs_store_buffer( gridfs *gfs, const char *data,
chunkLen = DEFAULT_CHUNK_SIZE < ( unsigned int )( end - data_ptr ) ?
DEFAULT_CHUNK_SIZE : ( unsigned int )( end - data_ptr );
oChunk = chunk_new( id, chunkNumber, data_ptr, chunkLen );
mongo_insert( gfs->client, gfs->chunks_ns, oChunk );
mongo_insert( gfs->client, gfs->chunks_ns, oChunk, NULL );
chunk_free( oChunk );
chunkNumber++;
data_ptr += chunkLen;
@ -259,7 +259,7 @@ MONGO_EXPORT void gridfile_write_buffer( gridfile *gfile, const char *data,
memcpy( buffer + gfile->pending_len, data, data_partial_len );
oChunk = chunk_new( gfile->id, gfile->chunk_num, buffer, DEFAULT_CHUNK_SIZE );
mongo_insert( gfile->gfs->client, gfile->gfs->chunks_ns, oChunk );
mongo_insert( gfile->gfs->client, gfile->gfs->chunks_ns, oChunk, NULL );
chunk_free( oChunk );
gfile->chunk_num++;
gfile->length += DEFAULT_CHUNK_SIZE;
@ -272,7 +272,7 @@ MONGO_EXPORT void gridfile_write_buffer( gridfile *gfile, const char *data,
while( chunks_to_write > 0 ) {
oChunk = chunk_new( gfile->id, gfile->chunk_num, data, DEFAULT_CHUNK_SIZE );
mongo_insert( gfile->gfs->client, gfile->gfs->chunks_ns, oChunk );
mongo_insert( gfile->gfs->client, gfile->gfs->chunks_ns, oChunk, NULL );
chunk_free( oChunk );
gfile->chunk_num++;
chunks_to_write--;
@ -302,7 +302,7 @@ MONGO_EXPORT int gridfile_writer_done( gridfile *gfile ) {
int response;
if( gfile->pending_data ) {
oChunk = chunk_new( gfile->id, gfile->chunk_num, gfile->pending_data, gfile->pending_len );
mongo_insert( gfile->gfs->client, gfile->gfs->chunks_ns, oChunk );
mongo_insert( gfile->gfs->client, gfile->gfs->chunks_ns, oChunk, NULL );
chunk_free( oChunk );
bson_free( gfile->pending_data );
gfile->length += gfile->pending_len;
@ -344,7 +344,7 @@ int gridfs_store_file( gridfs *gfs, const char *filename,
chunkLen = fread( buffer, 1, DEFAULT_CHUNK_SIZE, fd );
do {
oChunk = chunk_new( id, chunkNumber, buffer, chunkLen );
mongo_insert( gfs->client, gfs->chunks_ns, oChunk );
mongo_insert( gfs->client, gfs->chunks_ns, oChunk, NULL );
chunk_free( oChunk );
length += chunkLen;
chunkNumber++;
@ -390,14 +390,14 @@ MONGO_EXPORT void gridfs_remove_filename( gridfs *gfs, const char *filename ) {
bson_init( &b );
bson_append_oid( &b, "_id", &id );
bson_finish( &b );
mongo_remove( gfs->client, gfs->files_ns, &b );
mongo_remove( gfs->client, gfs->files_ns, &b, NULL );
bson_destroy( &b );
/* Remove all chunks from the file with the specified id */
bson_init( &b );
bson_append_oid( &b, "files_id", &id );
bson_finish( &b );
mongo_remove( gfs->client, gfs->chunks_ns, &b );
mongo_remove( gfs->client, gfs->chunks_ns, &b, NULL );
bson_destroy( &b );
}

View File

@ -57,6 +57,8 @@ const char* _get_host_port(mongo_host_port* hp) {
MONGO_EXPORT const char* mongo_get_primary(mongo* conn) {
mongo* conn_ = (mongo*)conn;
if( !(conn_->connected) || (conn_->primary->host == '\0') )
return NULL;
return _get_host_port(conn_->primary);
}
@ -122,7 +124,7 @@ MONGO_EXPORT void __mongo_set_error( mongo *conn, mongo_error_t err, const char
str_size = strlen( str ) + 1;
errstr_size = str_size > MONGO_ERR_LEN ? MONGO_ERR_LEN : str_size;
memcpy( conn->errstr, str, errstr_size );
conn->errstr[errstr_size] = '\0';
conn->errstr[errstr_size-1] = '\0';
}
}
@ -134,6 +136,23 @@ MONGO_EXPORT void mongo_clear_errors( mongo *conn ) {
memset( conn->lasterrstr, 0, MONGO_ERR_LEN );
}
/* Note: this function returns a char* which must be freed. */
static char *mongo_ns_to_cmd_db( const char *ns ) {
char *current = NULL;
char *cmd_db_name = NULL;
int len = 0;
for( current = (char *)ns; *current != '.'; current++ ) {
len++;
}
cmd_db_name = (char *)bson_malloc( len + 6 );
strncpy( cmd_db_name, ns, len );
strncpy( cmd_db_name + len, ".$cmd", 6 );
return cmd_db_name;
}
MONGO_EXPORT int mongo_validate_ns( mongo *conn, const char *ns ) {
char *last = NULL;
char *current = NULL;
@ -378,7 +397,6 @@ MONGO_EXPORT void mongo_init_sockets( void ) {
mongo_env_sock_init();
}
MONGO_EXPORT void mongo_init( mongo *conn ) {
memset( conn, 0, sizeof( mongo ) );
conn->max_bson_size = MONGO_DEFAULT_MAX_BSON_SIZE;
@ -412,6 +430,8 @@ MONGO_EXPORT void mongo_replset_init( mongo *conn, const char *name ) {
memcpy( conn->replset->name, name, strlen( name ) + 1 );
conn->primary = bson_malloc( sizeof( mongo_host_port ) );
conn->primary->host[0] = '\0';
conn->primary->next = NULL;
}
static void mongo_replset_add_node( mongo_host_port **list, const char *host, int port ) {
@ -736,12 +756,109 @@ static int mongo_cursor_bson_valid( mongo_cursor *cursor, const bson *bson ) {
return MONGO_OK;
}
/* MongoDB CRUD API */
static int mongo_check_last_error( mongo *conn, const char *ns,
mongo_write_concern *write_concern ) {
bson response = {NULL, 0};
bson fields;
bson_iterator it;
int res = 0;
char *cmd_ns = mongo_ns_to_cmd_db( ns );
res = mongo_find_one( conn, cmd_ns, write_concern->cmd, bson_empty( &fields ), &response );
bson_free( cmd_ns );
if( res != MONGO_OK )
return MONGO_ERROR;
else {
if( ( bson_find( &it, &response, "$err" ) == BSON_STRING ) ||
( bson_find( &it, &response, "err" ) == BSON_STRING ) ) {
__mongo_set_error( conn, MONGO_WRITE_ERROR,
"See conn->lasterrstr for details.", 0 );
mongo_set_last_error( conn, &it, &response );
return MONGO_ERROR;
} else
return MONGO_OK;
}
}
static int mongo_choose_write_concern( mongo *conn,
mongo_write_concern *custom_write_concern,
mongo_write_concern **write_concern ) {
if( custom_write_concern ) {
*write_concern = custom_write_concern;
}
else if( conn->write_concern ) {
*write_concern = conn->write_concern;
}
if( *write_concern && !((*write_concern)->cmd) ) {
__mongo_set_error( conn, MONGO_WRITE_CONCERN_INVALID,
"Must call mongo_write_concern_finish() before using *write_concern.", 0 );
return MONGO_ERROR;
}
else
return MONGO_OK;
}
/*********************************************************************
CRUD API
**********************************************************************/
MONGO_EXPORT int mongo_insert( mongo *conn, const char *ns,
const bson *bson, mongo_write_concern *custom_write_concern ) {
char *data;
mongo_message *mm;
mongo_write_concern *write_concern = NULL;
if( mongo_validate_ns( conn, ns ) != MONGO_OK )
return MONGO_ERROR;
if( mongo_bson_valid( conn, bson, 1 ) != MONGO_OK ) {
return MONGO_ERROR;
}
if( mongo_choose_write_concern( conn, custom_write_concern,
&write_concern ) == MONGO_ERROR ) {
return MONGO_ERROR;
}
mm = mongo_message_create( 16 /* header */
+ 4 /* ZERO */
+ strlen( ns )
+ 1 + bson_size( bson )
, 0, 0, MONGO_OP_INSERT );
data = &mm->data;
data = mongo_data_append32( data, &ZERO );
data = mongo_data_append( data, ns, strlen( ns ) + 1 );
data = mongo_data_append( data, bson->data, bson_size( bson ) );
/* TODO: refactor so that we can send the insert message
and the getlasterror messages together. */
if( write_concern ) {
if( mongo_message_send( conn, mm ) == MONGO_ERROR ) {
return MONGO_ERROR;
}
return mongo_check_last_error( conn, ns, write_concern );
}
else {
return mongo_message_send( conn, mm );
}
}
MONGO_EXPORT int mongo_insert_batch( mongo *conn, const char *ns,
const bson **bsons, int count ) {
const bson **bsons, int count, mongo_write_concern *custom_write_concern,
int flags ) {
mongo_message *mm;
mongo_write_concern *write_concern = NULL;
int i;
char *data;
int overhead = 16 + 4 + strlen( ns ) + 1;
@ -761,51 +878,44 @@ MONGO_EXPORT int mongo_insert_batch( mongo *conn, const char *ns,
return MONGO_ERROR;
}
if( mongo_choose_write_concern( conn, custom_write_concern,
&write_concern ) == MONGO_ERROR ) {
return MONGO_ERROR;
}
mm = mongo_message_create( size , 0 , 0 , MONGO_OP_INSERT );
data = &mm->data;
data = mongo_data_append32( data, &ZERO );
if( flags & MONGO_CONTINUE_ON_ERROR )
data = mongo_data_append32( data, &ONE );
else
data = mongo_data_append32( data, &ZERO );
data = mongo_data_append( data, ns, strlen( ns ) + 1 );
for( i=0; i<count; i++ ) {
data = mongo_data_append( data, bsons[i]->data, bson_size( bsons[i] ) );
}
return mongo_message_send( conn, mm );
}
/* TODO: refactor so that we can send the insert message
* and the getlasterror messages together. */
if( write_concern ) {
if( mongo_message_send( conn, mm ) == MONGO_ERROR ) {
return MONGO_ERROR;
}
MONGO_EXPORT int mongo_insert( mongo *conn , const char *ns , const bson *bson ) {
char *data;
mongo_message *mm;
if( mongo_validate_ns( conn, ns ) != MONGO_OK )
return MONGO_ERROR;
/* Make sure that BSON is valid for insert. */
if( mongo_bson_valid( conn, bson, 1 ) != MONGO_OK ) {
return MONGO_ERROR;
return mongo_check_last_error( conn, ns, write_concern );
}
else {
return mongo_message_send( conn, mm );
}
mm = mongo_message_create( 16 /* header */
+ 4 /* ZERO */
+ strlen( ns )
+ 1 + bson_size( bson )
, 0, 0, MONGO_OP_INSERT );
data = &mm->data;
data = mongo_data_append32( data, &ZERO );
data = mongo_data_append( data, ns, strlen( ns ) + 1 );
data = mongo_data_append( data, bson->data, bson_size( bson ) );
return mongo_message_send( conn, mm );
}
MONGO_EXPORT int mongo_update( mongo *conn, const char *ns, const bson *cond,
const bson *op, int flags ) {
const bson *op, int flags, mongo_write_concern *custom_write_concern ) {
char *data;
mongo_message *mm;
mongo_write_concern *write_concern = NULL;
/* Make sure that the op BSON is valid UTF-8.
* TODO: decide whether to check cond as well.
@ -814,6 +924,11 @@ MONGO_EXPORT int mongo_update( mongo *conn, const char *ns, const bson *cond,
return MONGO_ERROR;
}
if( mongo_choose_write_concern( conn, custom_write_concern,
&write_concern ) == MONGO_ERROR ) {
return MONGO_ERROR;
}
mm = mongo_message_create( 16 /* header */
+ 4 /* ZERO */
+ strlen( ns ) + 1
@ -829,12 +944,26 @@ MONGO_EXPORT int mongo_update( mongo *conn, const char *ns, const bson *cond,
data = mongo_data_append( data, cond->data, bson_size( cond ) );
data = mongo_data_append( data, op->data, bson_size( op ) );
return mongo_message_send( conn, mm );
/* TODO: refactor so that we can send the insert message
* and the getlasterror messages together. */
if( write_concern ) {
if( mongo_message_send( conn, mm ) == MONGO_ERROR ) {
return MONGO_ERROR;
}
return mongo_check_last_error( conn, ns, write_concern );
}
else {
return mongo_message_send( conn, mm );
}
}
MONGO_EXPORT int mongo_remove( mongo *conn, const char *ns, const bson *cond ) {
MONGO_EXPORT int mongo_remove( mongo *conn, const char *ns, const bson *cond,
mongo_write_concern *custom_write_concern ) {
char *data;
mongo_message *mm;
mongo_write_concern *write_concern = NULL;
/* Make sure that the BSON is valid UTF-8.
* TODO: decide whether to check cond as well.
@ -843,6 +972,11 @@ MONGO_EXPORT int mongo_remove( mongo *conn, const char *ns, const bson *cond ) {
return MONGO_ERROR;
}
if( mongo_choose_write_concern( conn, custom_write_concern,
&write_concern ) == MONGO_ERROR ) {
return MONGO_ERROR;
}
mm = mongo_message_create( 16 /* header */
+ 4 /* ZERO */
+ strlen( ns ) + 1
@ -856,10 +990,99 @@ MONGO_EXPORT int mongo_remove( mongo *conn, const char *ns, const bson *cond ) {
data = mongo_data_append32( data, &ZERO );
data = mongo_data_append( data, cond->data, bson_size( cond ) );
return mongo_message_send( conn, mm );
/* TODO: refactor so that we can send the insert message
* and the getlasterror messages together. */
if( write_concern ) {
if( mongo_message_send( conn, mm ) == MONGO_ERROR ) {
return MONGO_ERROR;
}
return mongo_check_last_error( conn, ns, write_concern );
}
else {
return mongo_message_send( conn, mm );
}
}
/*********************************************************************
Write Concern API
**********************************************************************/
MONGO_EXPORT void mongo_write_concern_init( mongo_write_concern *write_concern ) {
memset( write_concern, 0, sizeof( mongo_write_concern ) );
}
MONGO_EXPORT int mongo_write_concern_finish( mongo_write_concern *write_concern ) {
bson *command;
/* Destory any existing serialized write concern object and reuse it. */
if( write_concern->cmd ) {
bson_destroy( write_concern->cmd );
command = write_concern->cmd;
}
else
command = (bson *)bson_malloc( sizeof( bson ) );
if( !command ) {
return MONGO_ERROR;
}
bson_init( command );
bson_append_int( command, "getlasterror", 1 );
if( write_concern->mode ) {
bson_append_string( command, "w", write_concern->mode );
}
else if( write_concern->w ) {
bson_append_int( command, "w", write_concern->w );
}
if( write_concern->wtimeout ) {
bson_append_int( command, "wtimeout", write_concern->wtimeout );
}
if( write_concern->j ) {
bson_append_int( command, "j", write_concern->j );
}
if( write_concern->fsync ) {
bson_append_int( command, "fsync", write_concern->fsync );
}
bson_finish( command );
/* write_concern now owns the BSON command object.
* This is freed in mongo_write_concern_destroy(). */
write_concern->cmd = command;
return MONGO_OK;
}
MONGO_EXPORT void mongo_write_concern_destroy( mongo_write_concern *write_concern ) {
if( !write_concern )
return;
if( write_concern->cmd )
bson_destroy( write_concern->cmd );
bson_free( write_concern->cmd );
}
MONGO_EXPORT void mongo_set_write_concern( mongo *conn,
mongo_write_concern *write_concern ) {
conn->write_concern = write_concern;
}
/**
* Free the write_concern object (specifically, the BSON object that it holds).
*/
MONGO_EXPORT void mongo_write_concern_destroy( mongo_write_concern *write_concern );
static int mongo_cursor_op_query( mongo_cursor *cursor ) {
int res;
bson empty;
@ -1008,10 +1231,12 @@ MONGO_EXPORT int mongo_find_one( mongo *conn, const char *ns, const bson *query,
mongo_cursor_set_limit( cursor, 1 );
if ( mongo_cursor_next( cursor ) == MONGO_OK ) {
bson_init_size( out, bson_size( (bson *)&cursor->current ) );
memcpy( out->data, cursor->current.data,
bson_size( (bson *)&cursor->current ) );
out->finished = 1;
if( out ) {
bson_init_size( out, bson_size( (bson *)&cursor->current ) );
memcpy( out->data, cursor->current.data,
bson_size( (bson *)&cursor->current ) );
out->finished = 1;
}
mongo_cursor_destroy( cursor );
return MONGO_OK;
} else {
@ -1171,14 +1396,14 @@ MONGO_EXPORT int mongo_create_index( mongo *conn, const char *ns, const bson *ke
strncpy( idxns, ns, 1024-16 );
strcpy( strchr( idxns, '.' ), ".system.indexes" );
mongo_insert( conn, idxns, &b );
mongo_insert( conn, idxns, &b, NULL );
bson_destroy( &b );
*strchr( idxns, '.' ) = '\0'; /* just db not ns */
return mongo_cmd_get_last_error( conn, idxns, out );
}
bson_bool_t mongo_create_simple_index( mongo *conn, const char *ns, const char *field, int options, bson *out ) {
MONGO_EXPORT bson_bool_t mongo_create_simple_index( mongo *conn, const char *ns, const char *field, int options, bson *out ) {
bson b;
bson_bool_t success;
@ -1191,6 +1416,27 @@ bson_bool_t mongo_create_simple_index( mongo *conn, const char *ns, const char *
return success;
}
MONGO_EXPORT int mongo_create_capped_collection( mongo *conn, const char *db,
const char *collection, int size, int max, bson *out ) {
bson b;
int result;
bson_init( &b );
bson_append_string( &b, "create", collection );
bson_append_bool( &b, "capped", 1 );
bson_append_int( &b, "size", size );
if( max > 0 )
bson_append_int( &b, "max", size );
bson_finish( &b );
result = mongo_run_command( conn, db, &b, out );
bson_destroy( &b );
return result;
}
MONGO_EXPORT double mongo_count( mongo *conn, const char *db, const char *ns, const bson *query ) {
bson cmd;
bson out = {NULL, 0};
@ -1404,7 +1650,7 @@ MONGO_EXPORT int mongo_cmd_add_user( mongo *conn, const char *db, const char *us
bson_append_finish_object( &pass_obj );
bson_finish( &pass_obj );
res = mongo_update( conn, ns, &user_obj, &pass_obj, MONGO_UPDATE_UPSERT );
res = mongo_update( conn, ns, &user_obj, &pass_obj, MONGO_UPDATE_UPSERT, NULL );
bson_free( ns );
bson_destroy( &user_obj );

View File

@ -26,8 +26,8 @@
MONGO_EXTERN_C_START
#define MONGO_MAJOR 0
#define MONGO_MINOR 5
#define MONGO_PATCH 2
#define MONGO_MINOR 6
#define MONGO_PATCH 0
#define MONGO_OK 0
#define MONGO_ERROR -1
@ -51,10 +51,12 @@ typedef enum mongo_error_t {
MONGO_SOCKET_ERROR, /**< Other socket error. */
MONGO_READ_SIZE_ERROR, /**< The response is not the expected length. */
MONGO_COMMAND_FAILED, /**< The command returned with 'ok' value of 0. */
MONGO_WRITE_ERROR, /**< Write with given write_concern returned an error. */
MONGO_NS_INVALID, /**< The name for the ns (database or collection) is invalid. */
MONGO_BSON_INVALID, /**< BSON not valid for the specified op. */
MONGO_BSON_NOT_FINISHED, /**< BSON object has not been finished. */
MONGO_BSON_TOO_LARGE /**< BSON object exceeds max BSON size. */
MONGO_BSON_TOO_LARGE, /**< BSON object exceeds max BSON size. */
MONGO_WRITE_CONCERN_INVALID /**< Supplied write concern object is invalid. */
} mongo_error_t;
typedef enum mongo_cursor_error_t {
@ -85,6 +87,10 @@ enum mongo_update_opts {
MONGO_UPDATE_BASIC = 0x4
};
enum mongo_insert_opts {
MONGO_CONTINUE_ON_ERROR = 0x1
};
enum mongo_cursor_opts {
MONGO_TAILABLE = ( 1<<1 ), /**< Create a tailable cursor. */
MONGO_SLAVE_OK = ( 1<<2 ), /**< Allow queries on a non-primary node. */
@ -137,6 +143,16 @@ typedef struct mongo_host_port {
struct mongo_host_port *next;
} mongo_host_port;
typedef struct mongo_write_concern {
int w; /**< Number of nodes this write should be replicated to. */
int wtimeout; /**< Number of milliseconds before replication timeout. */
int j; /**< If non-zero, block until the journal sync. */
int fsync; /**< Same a j with journaling enabled; otherwise, call fsync. */
const char *mode; /**< Either "majority" or a getlasterrormode. Overrides w value. */
bson *cmd; /**< The BSON object representing the getlasterror command. */
} mongo_write_concern;
typedef struct {
mongo_host_port *seeds; /**< List of seeds provided by the user. */
mongo_host_port *hosts; /**< List of host/ports given by the replica set */
@ -153,6 +169,7 @@ typedef struct mongo {
int op_timeout_ms; /**< Read and write timeout in milliseconds. */
int max_bson_size; /**< Largest BSON object allowed on this connection. */
bson_bool_t connected; /**< Connection status. */
mongo_write_concern *write_concern; /**< The default write concern. */
mongo_error_t err; /**< Most recent driver error code. */
int errcode; /**< Most recent errno or WSAGetLastError(). */
@ -176,38 +193,9 @@ typedef struct {
int skip; /**< Bitfield containing cursor options. */
} mongo_cursor;
/* Connection API */
MONGO_EXPORT mongo* mongo_create();
MONGO_EXPORT void mongo_dispose(mongo* conn);
MONGO_EXPORT int mongo_get_err(mongo* conn);
MONGO_EXPORT int mongo_is_connected(mongo* conn);
MONGO_EXPORT int mongo_get_op_timeout(mongo* conn);
MONGO_EXPORT const char* mongo_get_primary(mongo* conn);
MONGO_EXPORT int mongo_get_socket(mongo* conn) ;
MONGO_EXPORT int mongo_get_host_count(mongo* conn);
MONGO_EXPORT const char* mongo_get_host(mongo* conn, int i);
MONGO_EXPORT mongo_cursor* mongo_cursor_create();
MONGO_EXPORT void mongo_cursor_dispose(mongo_cursor* cursor);
MONGO_EXPORT int mongo_get_server_err(mongo* conn);
MONGO_EXPORT const char* mongo_get_server_err_string(mongo* conn);
/**
* Set an error this mongo connection object. Mostly for internal use.
*
* @param conn a mongo connection object.
* @param err a driver error code of mongo_error_t.
* @param errstr a string version of the error.
* @param errorcode Currently errno or WSAGetLastError().
*/
MONGO_EXPORT void __mongo_set_error( mongo *conn, mongo_error_t err,
const char *errstr, int errorcode );
/**
* Clear all errors stored on this mongo connection object.
*
* @param conn a mongo connection object.
*/
MONGO_EXPORT void mongo_clear_errors( mongo *conn );
/*********************************************************************
Connection API
**********************************************************************/
/** Initialize sockets for Windows.
*/
@ -344,61 +332,130 @@ MONGO_EXPORT void mongo_disconnect( mongo *conn );
*/
MONGO_EXPORT void mongo_destroy( mongo *conn );
/**
* Specify the write concern object that this connection should use
* by default for all writes (inserts, updates, and deletes). This value
* can be overridden by passing a write_concern object to any write function.
*
* @param conn a mongo object.
* @param write_concern pointer to a write concern object.
*
*/
MONGO_EXPORT void mongo_set_write_concern( mongo *conn,
mongo_write_concern *write_concern );
/*********************************************************************
CRUD API
**********************************************************************/
/**
* Insert a BSON document into a MongoDB server. This function
* will fail if the supplied BSON struct is not UTF-8 or if
* the keys are invalid for insert (contain '.' or start with '$').
*
* The default write concern set on the conn object will be used.
*
* @param conn a mongo object.
* @param ns the namespace.
* @param data the bson data.
* @param custom_write_concern a write concern object that will
* override any write concern set on the conn object.
*
* @return MONGO_OK or MONGO_ERROR. If the conn->err
* field is MONGO_BSON_INVALID, check the err field
* on the bson struct for the reason.
*/
MONGO_EXPORT int mongo_insert( mongo *conn, const char *ns, const bson *data );
MONGO_EXPORT int mongo_insert( mongo *conn, const char *ns, const bson *data,
mongo_write_concern *custom_write_concern );
/**
* Insert a batch of BSON documents into a MongoDB server. This function
* will fail if any of the documents to be inserted is invalid.
*
* The default write concern set on the conn object will be used.
*
* @param conn a mongo object.
* @param ns the namespace.
* @param data the bson data.
* @param num the number of documents in data.
* @param custom_write_concern a write concern object that will
* override any write concern set on the conn object.
* @param flags flags on this batch insert. Currently, this value
* may be 0 or MONGO_CONTINUE_ON_ERROR, which will cause the
* batch insert to continue even if a given insert in the batch fails.
*
* @return MONGO_OK or MONGO_ERROR.
*
*/
MONGO_EXPORT int mongo_insert_batch( mongo *conn , const char *ns ,
const bson **data , int num );
MONGO_EXPORT int mongo_insert_batch( mongo *conn, const char *ns,
const bson **data, int num, mongo_write_concern *custom_write_concern,
int flags );
/**
* Update a document in a MongoDB server.
*
* The default write concern set on the conn object will be used.
*
* @param conn a mongo object.
* @param ns the namespace.
* @param cond the bson update query.
* @param op the bson update data.
* @param flags flags for the update.
* @param custom_write_concern a write concern object that will
* override any write concern set on the conn object.
*
* @return MONGO_OK or MONGO_ERROR with error stored in conn object.
*
*/
MONGO_EXPORT int mongo_update( mongo *conn, const char *ns, const bson *cond,
const bson *op, int flags );
const bson *op, int flags, mongo_write_concern *custom_write_concern );
/**
* Remove a document from a MongoDB server.
*
* The default write concern set on the conn object will be used.
*
* @param conn a mongo object.
* @param ns the namespace.
* @param cond the bson query.
* @param custom_write_concern a write concern object that will
* override any write concern set on the conn object.
*
* @return MONGO_OK or MONGO_ERROR with error stored in conn object.
*/
MONGO_EXPORT int mongo_remove( mongo *conn, const char *ns, const bson *cond );
MONGO_EXPORT int mongo_remove( mongo *conn, const char *ns, const bson *cond,
mongo_write_concern *custom_write_concern );
/*********************************************************************
Write Concern API
**********************************************************************/
/**
* Initialize a mongo_write_concern object. Effectively zeroes out the struct.
*
*/
MONGO_EXPORT void mongo_write_concern_init( mongo_write_concern *write_concern );
/**
* Finish this write concern object by serializing the literal getlasterror
* command that will be sent to the server.
*
* You must call mongo_write_concern_destroy() to free the serialized BSON.
*
*/
MONGO_EXPORT int mongo_write_concern_finish( mongo_write_concern *write_concern );
/**
* Free the write_concern object (specifically, the BSON that it owns).
*
*/
MONGO_EXPORT void mongo_write_concern_destroy( mongo_write_concern *write_concern );
/*********************************************************************
Cursor API
**********************************************************************/
/**
* Find documents in a MongoDB server.
@ -527,7 +584,10 @@ MONGO_EXPORT int mongo_cursor_destroy( mongo_cursor *cursor );
MONGO_EXPORT int mongo_find_one( mongo *conn, const char *ns, const bson *query,
const bson *fields, bson *out );
/* MongoDB Helper Functions */
/*********************************************************************
Command API and Helpers
**********************************************************************/
/**
* Count the number of documents in a collection matching a query.
@ -544,7 +604,7 @@ MONGO_EXPORT double mongo_count( mongo *conn, const char *db, const char *coll,
const bson *query );
/**
* Create a compouned index.
* Create a compound index.
*
* @param conn a mongo object.
* @param ns the namespace.
@ -556,7 +616,23 @@ MONGO_EXPORT double mongo_count( mongo *conn, const char *db, const char *coll,
*
* @return MONGO_OK if index is created successfully; otherwise, MONGO_ERROR.
*/
MONGO_EXPORT int mongo_create_index( mongo *conn, const char *ns, const bson *key, int options, bson *out );
MONGO_EXPORT int mongo_create_index( mongo *conn, const char *ns,
const bson *key, int options, bson *out );
/**
* Create a capped collection.
*
* @param conn a mongo object.
* @param ns the namespace (e.g., "dbname.collectioname")
* @param size the size of the capped collection in bytes.
* @param max the max number of documents this collection is
* allowed to contain. If zero, this argument will be ignored
* and the server will use the collection's size to age document out.
* If using this option, ensure that the total size can contain this
* number of documents.
*/
MONGO_EXPORT int mongo_create_capped_collection( mongo *conn, const char *db,
const char *collection, int size, int max, bson *out );
/**
* Create an index with a single key.
@ -569,11 +645,8 @@ MONGO_EXPORT int mongo_create_index( mongo *conn, const char *ns, const bson *ke
*
* @return true if the index was created.
*/
bson_bool_t mongo_create_simple_index( mongo *conn, const char *ns, const char *field, int options, bson *out );
/* ----------------------------
COMMANDS
------------------------------ */
MONGO_EXPORT bson_bool_t mongo_create_simple_index( mongo *conn, const char *ns,
const char *field, int options, bson *out );
/**
* Run a command on a MongoDB server.
@ -585,7 +658,8 @@ bson_bool_t mongo_create_simple_index( mongo *conn, const char *ns, const char *
*
* @return MONGO_OK if the command ran without error.
*/
MONGO_EXPORT int mongo_run_command( mongo *conn, const char *db, const bson *command, bson *out );
MONGO_EXPORT int mongo_run_command( mongo *conn, const char *db,
const bson *command, bson *out );
/**
* Run a command that accepts a simple string key and integer value.
@ -614,7 +688,8 @@ MONGO_EXPORT int mongo_simple_int_command( mongo *conn, const char *db,
* @return true if the command ran without error.
*
*/
MONGO_EXPORT int mongo_simple_str_command( mongo *conn, const char *db, const char *cmd, const char *arg, bson *out );
MONGO_EXPORT int mongo_simple_str_command( mongo *conn, const char *db,
const char *cmd, const char *arg, bson *out );
/**
* Drop a database.
@ -636,7 +711,8 @@ MONGO_EXPORT int mongo_cmd_drop_db( mongo *conn, const char *db );
*
* @return true if the collection drop was successful.
*/
MONGO_EXPORT int mongo_cmd_drop_collection( mongo *conn, const char *db, const char *collection, bson *out );
MONGO_EXPORT int mongo_cmd_drop_collection( mongo *conn, const char *db,
const char *collection, bson *out );
/**
* Add a database user.
@ -648,7 +724,8 @@ MONGO_EXPORT int mongo_cmd_drop_collection( mongo *conn, const char *db, const c
*
* @return MONGO_OK or MONGO_ERROR.
*/
MONGO_EXPORT int mongo_cmd_add_user( mongo *conn, const char *db, const char *user, const char *pass );
MONGO_EXPORT int mongo_cmd_add_user( mongo *conn, const char *db,
const char *user, const char *pass );
/**
* Authenticate a user.
@ -660,7 +737,8 @@ MONGO_EXPORT int mongo_cmd_add_user( mongo *conn, const char *db, const char *us
*
* @return MONGO_OK on sucess and MONGO_ERROR on failure.
*/
MONGO_EXPORT int mongo_cmd_authenticate( mongo *conn, const char *db, const char *user, const char *pass );
MONGO_EXPORT int mongo_cmd_authenticate( mongo *conn, const char *db,
const char *user, const char *pass );
/**
* Check if the current server is a master.
@ -706,6 +784,41 @@ MONGO_EXPORT int mongo_cmd_get_prev_error( mongo *conn, const char *db, bson *ou
MONGO_EXPORT void mongo_cmd_reset_error( mongo *conn, const char *db );
/*********************************************************************
Utility API
**********************************************************************/
MONGO_EXPORT mongo* mongo_create();
MONGO_EXPORT void mongo_dispose(mongo* conn);
MONGO_EXPORT int mongo_get_err(mongo* conn);
MONGO_EXPORT int mongo_is_connected(mongo* conn);
MONGO_EXPORT int mongo_get_op_timeout(mongo* conn);
MONGO_EXPORT const char* mongo_get_primary(mongo* conn);
MONGO_EXPORT int mongo_get_socket(mongo* conn) ;
MONGO_EXPORT int mongo_get_host_count(mongo* conn);
MONGO_EXPORT const char* mongo_get_host(mongo* conn, int i);
MONGO_EXPORT mongo_cursor* mongo_cursor_create();
MONGO_EXPORT void mongo_cursor_dispose(mongo_cursor* cursor);
MONGO_EXPORT int mongo_get_server_err(mongo* conn);
MONGO_EXPORT const char* mongo_get_server_err_string(mongo* conn);
/**
* Set an error on a mongo connection object. Mostly for internal use.
*
* @param conn a mongo connection object.
* @param err a driver error code of mongo_error_t.
* @param errstr a string version of the error.
* @param errorcode Currently errno or WSAGetLastError().
*/
MONGO_EXPORT void __mongo_set_error( mongo *conn, mongo_error_t err,
const char *errstr, int errorcode );
/**
* Clear all errors stored on a mongo connection object.
*
* @param conn a mongo connection object.
*/
MONGO_EXPORT void mongo_clear_errors( mongo *conn );
MONGO_EXTERN_C_END
#endif

View File

@ -295,7 +295,7 @@ static switch_status_t my_on_reporting(switch_core_session_t *session)
switch_mutex_lock(globals.mongo_mutex);
if (mongo_insert(globals.mongo_conn, globals.mongo_namespace, &cdr) != MONGO_OK) {
if (mongo_insert(globals.mongo_conn, globals.mongo_namespace, &cdr, NULL) != MONGO_OK) {
if (globals.mongo_conn->err == MONGO_IO_ERROR) {
mongo_error_t db_status;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "MongoDB connection failed; attempting reconnect...\n");
@ -306,7 +306,7 @@ static switch_status_t my_on_reporting(switch_core_session_t *session)
status = SWITCH_STATUS_FALSE;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MongoDB connection re-established.\n");
if (mongo_insert(globals.mongo_conn, globals.mongo_namespace, &cdr) != MONGO_OK) {
if (mongo_insert(globals.mongo_conn, globals.mongo_namespace, &cdr, NULL) != MONGO_OK) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mongo_insert: error code %d\n", globals.mongo_conn->err);
status = SWITCH_STATUS_FALSE;
}