Skip to content

PHPC-980: Sessions API #680

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 18, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ if test "$MONGODB" != "no"; then
src/MongoDB/ReadConcern.c \
src/MongoDB/ReadPreference.c \
src/MongoDB/Server.c \
src/MongoDB/Session.c \
src/MongoDB/WriteConcern.c \
src/MongoDB/WriteConcernError.c \
src/MongoDB/WriteError.c \
Expand Down
2 changes: 1 addition & 1 deletion config.w32
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ if (PHP_MONGODB != "no") {
EXTENSION("mongodb", "php_phongo.c phongo_compat.c", null, PHP_MONGODB_CFLAGS);
ADD_SOURCES(configure_module_dirname + "/src", "bson.c bson-encode.c", "mongodb");
ADD_SOURCES(configure_module_dirname + "/src/BSON", "Binary.c BinaryInterface.c DBPointer.c Decimal128.c Decimal128Interface.c Javascript.c JavascriptInterface.c MaxKey.c MaxKeyInterface.c MinKey.c MinKeyInterface.c ObjectId.c ObjectIdInterface.c Persistable.c Regex.c RegexInterface.c Serializable.c Symbol.c Timestamp.c TimestampInterface.c Type.c Undefined.c Unserializable.c UTCDateTime.c UTCDateTimeInterface.c functions.c", "mongodb");
ADD_SOURCES(configure_module_dirname + "/src/MongoDB", "BulkWrite.c Command.c Cursor.c CursorId.c Manager.c Query.c ReadConcern.c ReadPreference.c Server.c WriteConcern.c WriteConcernError.c WriteError.c WriteResult.c", "mongodb");
ADD_SOURCES(configure_module_dirname + "/src/MongoDB", "BulkWrite.c Command.c Cursor.c CursorId.c Manager.c Query.c ReadConcern.c ReadPreference.c Server.c Session.c WriteConcern.c WriteConcernError.c WriteError.c WriteResult.c", "mongodb");
ADD_SOURCES(configure_module_dirname + "/src/MongoDB/Exception", "AuthenticationException.c BulkWriteException.c ConnectionException.c ConnectionTimeoutException.c Exception.c ExecutionTimeoutException.c InvalidArgumentException.c LogicException.c RuntimeException.c SSLConnectionException.c UnexpectedValueException.c WriteException.c", "mongodb");
ADD_SOURCES(configure_module_dirname + "/src/MongoDB/Monitoring", "CommandFailedEvent.c CommandStartedEvent.c CommandSubscriber.c CommandSucceededEvent.c Subscriber.c functions.c", "mongodb");
ADD_SOURCES(configure_module_dirname + "/src/libbson/src/bson", PHP_MONGODB_BSON_SOURCES, "mongodb");
Expand Down
65 changes: 57 additions & 8 deletions php_phongo.c
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,17 @@ void phongo_server_init(zval *return_value, mongoc_client_t *client, int server_
}
/* }}} */

void phongo_session_init(zval *return_value, mongoc_client_session_t *client_session TSRMLS_DC) /* {{{ */
{
php_phongo_session_t *session;

object_init_ex(return_value, php_phongo_session_ce);

session = Z_SESSION_OBJ_P(return_value);
session->client_session = client_session;
}
/* }}} */

void phongo_readconcern_init(zval *return_value, const mongoc_read_concern_t *read_concern TSRMLS_DC) /* {{{ */
{
php_phongo_readconcern_t *intern;
Expand Down Expand Up @@ -527,6 +538,34 @@ static bool process_read_preference(zval *option, bson_t *mongoc_opts, zval **zr
return true;
}

static bool process_session(zval *option, bson_t *mongoc_opts, zval **zsession, mongoc_client_t *client TSRMLS_DC)
{
const mongoc_client_session_t *client_session;

if (Z_TYPE_P(option) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(option), php_phongo_session_ce TSRMLS_CC)) {
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Expected \"session\" option to be %s, %s given", ZSTR_VAL(php_phongo_session_ce->name), PHONGO_ZVAL_CLASS_OR_TYPE_NAME_P(option));
return false;
}

client_session = Z_SESSION_OBJ_P(option)->client_session;

if (client != mongoc_client_session_get_client(client_session)) {
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Cannot use Session started from a different Manager");
return false;
}

if (!mongoc_client_session_append(Z_SESSION_OBJ_P(option)->client_session, mongoc_opts, NULL)) {
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Error appending \"session\" option");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this likely to happen? If so, we should improve our error message to suggest how users can fix it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very unlikely. BSON append for primitive types only fails if the buffer cannot grow or the document length exceeds a 32-bit integer range. Similar to other places where we check for failure (e.g. appending "serverId"), I'm just being a good libmongoc citizen here.

return false;
}

if (zsession) {
*zsession = option;
}

return true;
}

static bool process_write_concern(zval *option, bson_t *mongoc_opts, zval **zwriteConcern TSRMLS_DC)
{
if (Z_TYPE_P(option) == IS_OBJECT && instanceof_function(Z_OBJCE_P(option), php_phongo_writeconcern_ce TSRMLS_CC)) {
Expand All @@ -550,7 +589,7 @@ static bool process_write_concern(zval *option, bson_t *mongoc_opts, zval **zwri
return true;
}

static int phongo_execute_parse_options(mongoc_client_t* client, int server_id, zval *driver_options, int type, bson_t *mongoc_opts, zval **zreadPreference, zval **zwriteConcern TSRMLS_DC)
static int phongo_execute_parse_options(mongoc_client_t* client, int server_id, zval *driver_options, int type, bson_t *mongoc_opts, zval **zreadPreference, zval **zwriteConcern, zval **zsession TSRMLS_DC)
{
if (driver_options && Z_TYPE_P(driver_options) == IS_ARRAY) {
HashTable *ht_data = HASH_OF(driver_options);
Expand All @@ -573,6 +612,10 @@ static int phongo_execute_parse_options(mongoc_client_t* client, int server_id,
if (!process_read_preference(driver_option, mongoc_opts, zreadPreference, client, server_id)) {
return false;
}
} else if ((!strcmp(ZSTR_VAL(string_key), "session"))) {
if (!process_session(driver_option, mongoc_opts, zsession, client)) {
return false;
}
} else if ((!strcasecmp(ZSTR_VAL(string_key), "writeConcern")) && (type & PHONGO_COMMAND_WRITE)) {
if (!process_write_concern(driver_option, mongoc_opts, zwriteConcern)) {
return false;
Expand Down Expand Up @@ -606,6 +649,10 @@ static int phongo_execute_parse_options(mongoc_client_t* client, int server_id,
if (!process_read_preference(*driver_option, mongoc_opts, zreadPreference, client, server_id TSRMLS_CC)) {
return false;
}
} else if ((!strcasecmp(ZSTR_VAL(string_key), "session"))) {
if (!process_session(*driver_option, mongoc_opts, zsession, client TSRMLS_CC)) {
return false;
}
} else if ((!strcasecmp(string_key, "writeConcern")) && (type & PHONGO_COMMAND_WRITE)) {
if (!process_write_concern(*driver_option, mongoc_opts, zwriteConcern TSRMLS_CC)) {
return false;
Expand All @@ -628,6 +675,7 @@ bool phongo_execute_bulk_write(mongoc_client_t *client, const char *namespace, p
mongoc_bulk_operation_t *bulk = bulk_write->bulk;
php_phongo_writeresult_t *writeresult;
zval *zwriteConcern = NULL;
zval *zsession = NULL;
const mongoc_write_concern_t *write_concern;
bson_t opts = BSON_INITIALIZER;

Expand All @@ -644,7 +692,7 @@ bool phongo_execute_bulk_write(mongoc_client_t *client, const char *namespace, p
/* FIXME: Legacy way of specifying the writeConcern option into this function */
if (options && Z_TYPE_P(options) == IS_OBJECT && instanceof_function(Z_OBJCE_P(options), php_phongo_writeconcern_ce TSRMLS_CC)) {
zwriteConcern = options;
} else if (!phongo_execute_parse_options(client, server_id, options, PHONGO_COMMAND_WRITE, &opts, NULL, &zwriteConcern TSRMLS_CC)) {
} else if (!phongo_execute_parse_options(client, server_id, options, PHONGO_COMMAND_WRITE, &opts, NULL, &zwriteConcern, &zsession TSRMLS_CC)) {
bson_destroy(&opts);
return false;
}
Expand All @@ -655,6 +703,10 @@ bool phongo_execute_bulk_write(mongoc_client_t *client, const char *namespace, p
mongoc_bulk_operation_set_collection(bulk, bulk_write->collection);
mongoc_bulk_operation_set_client(bulk, client);

if (zsession) {
mongoc_bulk_operation_set_client_session(bulk, Z_SESSION_OBJ_P(zsession)->client_session);
}

/* If a write concern was not specified, libmongoc will use the client's
* write concern; however, we should still fetch it for the write result. */
write_concern = phongo_write_concern_from_zval(zwriteConcern TSRMLS_CC);
Expand Down Expand Up @@ -736,7 +788,6 @@ int phongo_execute_query(mongoc_client_t *client, const char *namespace, zval *z
char *collname;
mongoc_collection_t *collection;
zval *zreadPreference = NULL;
bson_t opts = BSON_INITIALIZER;

if (!phongo_split_namespace(namespace, &dbname, &collname)) {
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "%s: %s", "Invalid namespace provided", namespace);
Expand All @@ -755,13 +806,10 @@ int phongo_execute_query(mongoc_client_t *client, const char *namespace, zval *z
/* FIXME: Legacy way of specifying the readPreference option into this function */
if (options && Z_TYPE_P(options) == IS_OBJECT && instanceof_function(Z_OBJCE_P(options), php_phongo_readpreference_ce TSRMLS_CC)) {
zreadPreference = options;
} else if (!phongo_execute_parse_options(client, server_id, options, PHONGO_COMMAND_READ, &opts, &zreadPreference, NULL TSRMLS_CC)) {
bson_destroy(&opts);
} else if (!phongo_execute_parse_options(client, server_id, options, PHONGO_COMMAND_READ, query->opts, &zreadPreference, NULL, NULL TSRMLS_CC)) {
return false;
}

bson_destroy(&opts);

cursor = mongoc_collection_find_with_opts(collection, query->filter, query->opts, phongo_read_preference_from_zval(zreadPreference TSRMLS_CC));
mongoc_collection_destroy(collection);

Expand Down Expand Up @@ -819,7 +867,7 @@ int phongo_execute_command(mongoc_client_t *client, php_phongo_command_type_t ty
/* FIXME: Legacy way of specifying the readPreference option into this function */
if (options && Z_TYPE_P(options) == IS_OBJECT && instanceof_function(Z_OBJCE_P(options), php_phongo_readpreference_ce TSRMLS_CC)) {
zreadPreference = options;
} else if (!phongo_execute_parse_options(client, server_id, options, type, &opts, &zreadPreference, NULL TSRMLS_CC)) {
} else if (!phongo_execute_parse_options(client, server_id, options, type, &opts, &zreadPreference, NULL, NULL TSRMLS_CC)) {
return false;
}

Expand Down Expand Up @@ -2693,6 +2741,7 @@ PHP_MINIT_FUNCTION(mongodb)
php_phongo_readconcern_init_ce(INIT_FUNC_ARGS_PASSTHRU);
php_phongo_readpreference_init_ce(INIT_FUNC_ARGS_PASSTHRU);
php_phongo_server_init_ce(INIT_FUNC_ARGS_PASSTHRU);
php_phongo_session_init_ce(INIT_FUNC_ARGS_PASSTHRU);
php_phongo_writeconcern_init_ce(INIT_FUNC_ARGS_PASSTHRU);
php_phongo_writeconcernerror_init_ce(INIT_FUNC_ARGS_PASSTHRU);
php_phongo_writeerror_init_ce(INIT_FUNC_ARGS_PASSTHRU);
Expand Down
1 change: 1 addition & 0 deletions php_phongo.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ typedef enum {
zend_object_handlers *phongo_get_std_object_handlers(void);

void phongo_server_init (zval *return_value, mongoc_client_t *client, int server_id TSRMLS_DC);
void phongo_session_init (zval *return_value, mongoc_client_session_t *client_session TSRMLS_DC);
void phongo_readconcern_init (zval *return_value, const mongoc_read_concern_t *read_concern TSRMLS_DC);
void phongo_readpreference_init (zval *return_value, const mongoc_read_prefs_t *read_prefs TSRMLS_DC);
void phongo_writeconcern_init (zval *return_value, const mongoc_write_concern_t *write_concern TSRMLS_DC);
Expand Down
9 changes: 9 additions & 0 deletions php_phongo_classes.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ static inline php_phongo_readpreference_t* php_readpreference_fetch_object(zend_
static inline php_phongo_server_t* php_server_fetch_object(zend_object *obj) {
return (php_phongo_server_t *)((char *)obj - XtOffsetOf(php_phongo_server_t, std));
}
static inline php_phongo_session_t* php_session_fetch_object(zend_object *obj) {
return (php_phongo_session_t *)((char *)obj - XtOffsetOf(php_phongo_session_t, std));
}
static inline php_phongo_writeconcern_t* php_writeconcern_fetch_object(zend_object *obj) {
return (php_phongo_writeconcern_t *)((char *)obj - XtOffsetOf(php_phongo_writeconcern_t, std));
}
Expand Down Expand Up @@ -118,6 +121,7 @@ static inline php_phongo_commandsucceededevent_t* php_commandsucceededevent_fetc
# define Z_READCONCERN_OBJ_P(zv) (php_readconcern_fetch_object(Z_OBJ_P(zv)))
# define Z_READPREFERENCE_OBJ_P(zv) (php_readpreference_fetch_object(Z_OBJ_P(zv)))
# define Z_SERVER_OBJ_P(zv) (php_server_fetch_object(Z_OBJ_P(zv)))
# define Z_SESSION_OBJ_P(zv) (php_session_fetch_object(Z_OBJ_P(zv)))
# define Z_BULKWRITE_OBJ_P(zv) (php_bulkwrite_fetch_object(Z_OBJ_P(zv)))
# define Z_WRITECONCERN_OBJ_P(zv) (php_writeconcern_fetch_object(Z_OBJ_P(zv)))
# define Z_WRITECONCERNERROR_OBJ_P(zv) (php_writeconcernerror_fetch_object(Z_OBJ_P(zv)))
Expand Down Expand Up @@ -147,6 +151,7 @@ static inline php_phongo_commandsucceededevent_t* php_commandsucceededevent_fetc
# define Z_OBJ_READCONCERN(zo) (php_readconcern_fetch_object(zo))
# define Z_OBJ_READPREFERENCE(zo) (php_readpreference_fetch_object(zo))
# define Z_OBJ_SERVER(zo) (php_server_fetch_object(zo))
# define Z_OBJ_SESSION(zo) (php_session_fetch_object(zo))
# define Z_OBJ_BULKWRITE(zo) (php_bulkwrite_fetch_object(zo))
# define Z_OBJ_WRITECONCERN(zo) (php_writeconcern_fetch_object(zo))
# define Z_OBJ_WRITECONCERNERROR(zo) (php_writeconcernerror_fetch_object(zo))
Expand Down Expand Up @@ -178,6 +183,7 @@ static inline php_phongo_commandsucceededevent_t* php_commandsucceededevent_fetc
# define Z_READCONCERN_OBJ_P(zv) ((php_phongo_readconcern_t *)zend_object_store_get_object(zv TSRMLS_CC))
# define Z_READPREFERENCE_OBJ_P(zv) ((php_phongo_readpreference_t *)zend_object_store_get_object(zv TSRMLS_CC))
# define Z_SERVER_OBJ_P(zv) ((php_phongo_server_t *)zend_object_store_get_object(zv TSRMLS_CC))
# define Z_SESSION_OBJ_P(zv) ((php_phongo_session_t *)zend_object_store_get_object(zv TSRMLS_CC))
# define Z_BULKWRITE_OBJ_P(zv) ((php_phongo_bulkwrite_t *)zend_object_store_get_object(zv TSRMLS_CC))
# define Z_WRITECONCERN_OBJ_P(zv) ((php_phongo_writeconcern_t *)zend_object_store_get_object(zv TSRMLS_CC))
# define Z_WRITECONCERNERROR_OBJ_P(zv) ((php_phongo_writeconcernerror_t *)zend_object_store_get_object(zv TSRMLS_CC))
Expand Down Expand Up @@ -207,6 +213,7 @@ static inline php_phongo_commandsucceededevent_t* php_commandsucceededevent_fetc
# define Z_OBJ_READCONCERN(zo) ((php_phongo_readconcern_t *)zo)
# define Z_OBJ_READPREFERENCE(zo) ((php_phongo_readpreference_t *)zo)
# define Z_OBJ_SERVER(zo) ((php_phongo_server_t *)zo)
# define Z_OBJ_SESSION(zo) ((php_phongo_session_t *)zo)
# define Z_OBJ_BULKWRITE(zo) ((php_phongo_bulkwrite_t *)zo)
# define Z_OBJ_WRITECONCERN(zo) ((php_phongo_writeconcern_t *)zo)
# define Z_OBJ_WRITECONCERNERROR(zo) ((php_phongo_writeconcernerror_t *)zo)
Expand Down Expand Up @@ -244,6 +251,7 @@ extern zend_class_entry *php_phongo_query_ce;
extern zend_class_entry *php_phongo_readconcern_ce;
extern zend_class_entry *php_phongo_readpreference_ce;
extern zend_class_entry *php_phongo_server_ce;
extern zend_class_entry *php_phongo_session_ce;
extern zend_class_entry *php_phongo_bulkwrite_ce;
extern zend_class_entry *php_phongo_writeconcern_ce;
extern zend_class_entry *php_phongo_writeconcernerror_ce;
Expand Down Expand Up @@ -332,6 +340,7 @@ extern void php_phongo_query_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_readconcern_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_readpreference_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_server_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_session_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_writeconcern_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_writeconcernerror_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_writeerror_init_ce(INIT_FUNC_ARGS);
Expand Down
6 changes: 6 additions & 0 deletions php_phongo_structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@ typedef struct {
PHONGO_ZEND_OBJECT_POST
} php_phongo_server_t;

typedef struct {
PHONGO_ZEND_OBJECT_PRE
mongoc_client_session_t *client_session;
PHONGO_ZEND_OBJECT_POST
} php_phongo_session_t;

typedef struct {
PHONGO_ZEND_OBJECT_PRE
mongoc_write_concern_t *write_concern;
Expand Down
41 changes: 41 additions & 0 deletions src/MongoDB/Manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,42 @@ static PHP_METHOD(Manager, selectServer)
}
} /* }}} */

/* {{{ proto MongoDB\Driver\Session MongoDB\Driver\Manager::startSession([array $options = null])
Returns a new client session */
static PHP_METHOD(Manager, startSession)
{
php_phongo_manager_t *intern;
zval *options = NULL;
mongoc_session_opt_t *cs_opts = NULL;
mongoc_client_session_t *cs;
bson_error_t error;
SUPPRESS_UNUSED_WARNING(return_value_ptr) SUPPRESS_UNUSED_WARNING(return_value_used)


intern = Z_MANAGER_OBJ_P(getThis());

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &options) == FAILURE) {
return;
}

if (options && php_array_exists(options, "causalConsistency")) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to extract option parsing into its own function like we do for many other options arrays?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can consider that in the future if the options list grows a bit. I believe I modeled this after the ReadPreference constructor, which also parses a single option ("maxStalenessSeconds") at present.

cs_opts = mongoc_session_opts_new();
mongoc_session_opts_set_causal_consistency(cs_opts, php_array_fetchc_bool(options, "causalConsistency"));
}

cs = mongoc_client_start_session(intern->client, cs_opts, &error);

if (cs_opts) {
mongoc_session_opts_destroy(cs_opts);
}

if (cs) {
phongo_session_init(return_value, cs TSRMLS_CC);
} else {
phongo_throw_exception_from_bson_error_t(&error TSRMLS_CC);
}
} /* }}} */

/* {{{ MongoDB\Driver\Manager function entries */
ZEND_BEGIN_ARG_INFO_EX(ai_Manager___construct, 0, 0, 0)
ZEND_ARG_INFO(0, uri)
Expand Down Expand Up @@ -573,6 +609,10 @@ ZEND_BEGIN_ARG_INFO_EX(ai_Manager_selectServer, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, readPreference, MongoDB\\Driver\\ReadPreference, 1)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(ai_Manager_startSession, 0, 0, 0)
ZEND_ARG_ARRAY_INFO(0, options, 1)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(ai_Manager_void, 0, 0, 0)
ZEND_END_ARG_INFO()

Expand All @@ -589,6 +629,7 @@ static zend_function_entry php_phongo_manager_me[] = {
PHP_ME(Manager, getServers, ai_Manager_void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
PHP_ME(Manager, getWriteConcern, ai_Manager_void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
PHP_ME(Manager, selectServer, ai_Manager_selectServer, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
PHP_ME(Manager, startSession, ai_Manager_startSession, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
ZEND_NAMED_ME(__wakeup, PHP_FN(MongoDB_disabled___wakeup), ai_Manager_void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
PHP_FE_END
};
Expand Down
Loading