libmongo-client 0.1.4
|
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 }