diff --git a/server/core/dcb.c b/server/core/dcb.c index 6717aea41..78b90e7a0 100644 --- a/server/core/dcb.c +++ b/server/core/dcb.c @@ -632,7 +632,18 @@ DCB *dcb; GWPROTOCOL *funcs; int fd; int rc; +char *user; + user = session_getUser(session); + if (NULL != user && strlen(user)) + { + dcb = server_get_persistent(server, user); + if (NULL != dcb) + { + return dcb; + } + } + if ((dcb = dcb_alloc(DCB_ROLE_REQUEST_HANDLER)) == NULL) { return NULL; @@ -1271,6 +1282,13 @@ dcb_close(DCB *dcb) if (rc == 0) { + spinlock_acquire(&dcb->server->persistlock); + dcb->nextpersistent = dcb->server->persistent; + dcb->server->persistent = dcb; + spinlock_release(&dcb->server->persistlock); + atomic_add(&dcb->server->stats.n_persistent, 1); + return; + /** * close protocol and router session */ diff --git a/server/core/server.c b/server/core/server.c index 425089d93..1d57c4a3f 100644 --- a/server/core/server.c +++ b/server/core/server.c @@ -78,6 +78,8 @@ SERVER *server; server->rlag = -2; server->master_id = -1; server->depth = -1; + server->persistent = NULL; + spinlock_init(server->persistlock); spinlock_acquire(&server_spin); server->next = allServers; @@ -128,6 +130,56 @@ SERVER *ptr; return 1; } +/** + * Get a DCB from the persistent connection pool, if possible + * + * @param server The server to set the name on + * @param user The name of the user needing the connection + */ +DCB * +server_get_persistent(SERVER *server, char *user) +{ + DCB *dcb, *previous; + int rc; + + spinlock_acquire(server->persistlock); + dcb = server->persistent; + previous = NULL; + while (dcb) { + /* Test for expired, free and remove from list if it is */ + if (0 == strcmp(dcb->user, user)) + { + if (NULL == previous) + { + server->persistent = dcb->nextpersistent; + } + else + { + previous->nextpersistent = dcb->nextpersistent; + } + rc = poll_add_dcb(dcb); + if (rc == DCBFD_CLOSED) { + dcb_set_state(dcb, DCB_STATE_DISCONNECTED, NULL); + dcb_free(dcb); + } + else + { + spinlock_release(server->persistlock); + atomic_add(&server->stats.n_persistent, -1); + return dcb; + } + } + previous = dcb; + dcb = dcb->nextpersistent; + } + if (NULL != server->persistent) + { + /* Change user, remove DCB from list, release spinlock, return dcb */ + } + spinlock_release(server->persistlock); + return NULL; +} + /** * Set a unique name for the server * diff --git a/server/include/dcb.h b/server/include/dcb.h index 7eedfbec3..c21a91e5d 100644 --- a/server/include/dcb.h +++ b/server/include/dcb.h @@ -249,6 +249,7 @@ typedef struct dcb { DCBSTATS stats; /**< DCB related statistics */ unsigned int dcb_server_status; /*< the server role indicator from SERVER */ struct dcb *next; /**< Next DCB in the chain of allocated DCB's */ + struct dcb *nextpersistent; /**< Next DCB in the persistent pool for SERVER */ struct service *service; /**< The related service */ void *data; /**< Specific client data */ DCBMM memdata; /**< The data related to DCB memory management */ @@ -261,7 +262,7 @@ typedef struct dcb { SPINLOCK polloutlock; int polloutbusy; int writecheck; - unsigned long last_read; /*< Last time the DCB received data */ + unsigned long last_read; /*< Last time the DCB received data */ unsigned int high_water; /**< High water mark */ unsigned int low_water; /**< Low water mark */ struct server *server; /**< The associated backend server */ diff --git a/server/include/server.h b/server/include/server.h index 734f30365..f6ae66902 100644 --- a/server/include/server.h +++ b/server/include/server.h @@ -66,6 +66,7 @@ typedef struct { int n_connections; /**< Number of connections */ int n_current; /**< Current connections */ int n_current_ops; /**< Current active operations */ + int n_persistent; /**< Current persistent pool */ } SERVER_STATS; /** @@ -94,6 +95,8 @@ typedef struct server { int depth; /**< Replication level in the tree */ long *slaves; /**< Slaves of this node */ bool master_err_is_logged; /*< If node failed, this indicates whether it is logged */ + DCB *persistent; /**< List of unused persistent connections to the server */ + SPINLOCK *persistlock; /**< Lock for adjusting the persistent connections list */ } SERVER; /** @@ -189,5 +192,6 @@ extern void serverAddParameter(SERVER *, char *, char *); extern char *serverGetParameter(SERVER *, char *); extern void server_update(SERVER *, char *, char *, char *); extern void server_set_unique_name(SERVER *, char *); +extern DCB *server_get_persistent(SERVER *, char *); extern RESULTSET *serverGetList(); #endif