libmongo-client 0.1.4
src/mongo-sync-pool.c
Go to the documentation of this file.
00001 /* mongo-sync-pool.c - libmongo-client connection pool implementation
00002  * Copyright 2011 Gergely Nagy <algernon@balabit.hu>
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00021 #include <errno.h>
00022 #include <string.h>
00023 #include <glib.h>
00024 #include <mongo.h>
00025 #include "libmongo-private.h"
00026 
00028 struct _mongo_sync_pool
00029 {
00030   gint nmasters; 
00031   gint nslaves; 
00033   GList *masters; 
00034   GList *slaves; 
00035 };
00036 
00037 static mongo_sync_pool_connection *
00038 _mongo_sync_pool_connect (const gchar *host, gint port, gboolean slaveok)
00039 {
00040   mongo_sync_connection *c;
00041   mongo_sync_pool_connection *conn;
00042 
00043   c = mongo_sync_connect (host, port, slaveok);
00044   if (!c)
00045     return NULL;
00046   conn = g_realloc (c, sizeof (mongo_sync_pool_connection));
00047   conn->pool_id = 0;
00048   conn->in_use = FALSE;
00049 
00050   return conn;
00051 }
00052 
00053 mongo_sync_pool *
00054 mongo_sync_pool_new (const gchar *host,
00055                      gint port,
00056                      gint nmasters, gint nslaves)
00057 {
00058   mongo_sync_pool *pool;
00059   mongo_sync_pool_connection *conn;
00060   gint i, j = 0;
00061 
00062   if (!host || port < 0)
00063     {
00064       errno = EINVAL;
00065       return NULL;
00066     }
00067   if (nmasters < 0 || nslaves < 0)
00068     {
00069       errno = ERANGE;
00070       return NULL;
00071     }
00072   if (nmasters + nslaves <= 0)
00073     {
00074       errno = EINVAL;
00075       return NULL;
00076     }
00077 
00078   conn = _mongo_sync_pool_connect (host, port, FALSE);
00079   if (!conn)
00080     return FALSE;
00081 
00082   if (!mongo_sync_cmd_is_master ((mongo_sync_connection *)conn))
00083     {
00084       mongo_sync_disconnect ((mongo_sync_connection *)conn);
00085       errno = EPROTO;
00086       return NULL;
00087     }
00088 
00089   pool = g_new0 (mongo_sync_pool, 1);
00090   pool->nmasters = nmasters;
00091   pool->nslaves = nslaves;
00092 
00093   for (i = 0; i < pool->nmasters; i++)
00094     {
00095       mongo_sync_pool_connection *c;
00096 
00097       c = _mongo_sync_pool_connect (host, port, FALSE);
00098       c->pool_id = i;
00099 
00100       pool->masters = g_list_append (pool->masters, c);
00101     }
00102 
00103   for (i = 0; i < pool->nslaves; i++)
00104     {
00105       mongo_sync_pool_connection *c;
00106       gchar *shost = NULL;
00107       gint sport = 27017;
00108       GList *l;
00109       gboolean found = FALSE;
00110       gboolean need_restart = (j != 0);
00111 
00112       /* Select the next secondary */
00113       l = g_list_nth (conn->super.rs.hosts, j);
00114 
00115       do
00116         {
00117           j++;
00118           if (l && mongo_util_parse_addr ((gchar *)l->data, &shost, &sport))
00119             {
00120               if (sport != port || strcmp (host, shost) != 0)
00121                 {
00122                   found = TRUE;
00123                   break;
00124                 }
00125             }
00126           l = g_list_next (l);
00127           if (!l && need_restart)
00128             {
00129               need_restart = FALSE;
00130               j = 0;
00131               l = g_list_nth (conn->super.rs.hosts, j);
00132             }
00133         }
00134       while (l);
00135 
00136       if (!found)
00137         {
00138           pool->nslaves = i - 1;
00139           break;
00140         }
00141 
00142       /* Connect to it*/
00143       c = _mongo_sync_pool_connect (shost, sport, TRUE);
00144       c->pool_id = pool->nmasters + i + 1;
00145 
00146       pool->slaves = g_list_append (pool->slaves, c);
00147     }
00148 
00149   mongo_sync_disconnect ((mongo_sync_connection *)conn);
00150   return pool;
00151 }
00152 
00153 void
00154 mongo_sync_pool_free (mongo_sync_pool *pool)
00155 {
00156   GList *l;
00157 
00158   if (!pool)
00159     return;
00160 
00161   l = pool->masters;
00162   while (l)
00163     {
00164       mongo_sync_disconnect ((mongo_sync_connection *)l->data);
00165       l = g_list_delete_link (l, l);
00166     }
00167 
00168   l = pool->slaves;
00169   while (l)
00170     {
00171       mongo_sync_disconnect ((mongo_sync_connection *)l->data);
00172       l = g_list_delete_link (l, l);
00173     }
00174 
00175   g_free (pool);
00176 }
00177 
00178 mongo_sync_pool_connection *
00179 mongo_sync_pool_pick (mongo_sync_pool *pool,
00180                       gboolean want_master)
00181 {
00182   GList *l;
00183 
00184   if (!pool)
00185     {
00186       errno = ENOTCONN;
00187       return NULL;
00188     }
00189 
00190   if (!want_master)
00191     {
00192       l = pool->slaves;
00193 
00194       while (l)
00195         {
00196           mongo_sync_pool_connection *c;
00197 
00198           c = (mongo_sync_pool_connection *)l->data;
00199           if (!c->in_use)
00200             {
00201               c->in_use = TRUE;
00202               return c;
00203             }
00204           l = g_list_next (l);
00205         }
00206     }
00207 
00208   l = pool->masters;
00209   while (l)
00210     {
00211       mongo_sync_pool_connection *c;
00212 
00213       c = (mongo_sync_pool_connection *)l->data;
00214       if (!c->in_use)
00215         {
00216           c->in_use = TRUE;
00217           return c;
00218         }
00219       l = g_list_next (l);
00220     }
00221 
00222   errno = EAGAIN;
00223   return NULL;
00224 }
00225 
00226 gboolean
00227 mongo_sync_pool_return (mongo_sync_pool *pool,
00228                         mongo_sync_pool_connection *conn)
00229 {
00230   if (!pool)
00231     {
00232       errno = ENOTCONN;
00233       return FALSE;
00234     }
00235   if (!conn)
00236     {
00237       errno = EINVAL;
00238       return FALSE;
00239     }
00240 
00241   if (conn->pool_id > pool->nmasters)
00242     {
00243       mongo_sync_pool_connection *c;
00244 
00245       if (conn->pool_id - pool->nmasters > pool->nslaves ||
00246           pool->nslaves == 0)
00247         {
00248           errno = ERANGE;
00249           return FALSE;
00250         }
00251 
00252       c = (mongo_sync_pool_connection *)g_list_nth_data
00253         (pool->slaves, conn->pool_id - pool->nmasters - 1);
00254       c->in_use = FALSE;
00255       return TRUE;
00256     }
00257   else
00258     {
00259       mongo_sync_pool_connection *c;
00260 
00261       c = (mongo_sync_pool_connection *)g_list_nth_data (pool->masters,
00262                                                          conn->pool_id);
00263       c->in_use = FALSE;
00264       return TRUE;
00265     }
00266 
00267   errno = ENOENT;
00268   return FALSE;
00269 }
 All Data Structures Files Functions Variables Enumerations Enumerator Defines