1 /* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2 #include "libmemcached/common.h"
3 #include "libmemcached/pool.h"
8 struct memcached_pool_st
10 pthread_mutex_t mutex
;
16 uint32_t current_size
;
20 static memcached_return_t
mutex_enter(pthread_mutex_t
*mutex
)
24 ret
= pthread_mutex_lock(mutex
);
25 while (ret
== -1 && errno
== EINTR
);
27 return (ret
== -1) ? MEMCACHED_ERRNO
: MEMCACHED_SUCCESS
;
30 static memcached_return_t
mutex_exit(pthread_mutex_t
*mutex
)
34 ret
= pthread_mutex_unlock(mutex
);
35 while (ret
== -1 && errno
== EINTR
);
37 return (ret
== -1) ? MEMCACHED_ERRNO
: MEMCACHED_SUCCESS
;
41 * Grow the connection pool by creating a connection structure and clone the
42 * original memcached handle.
44 static int grow_pool(memcached_pool_st
* pool
)
46 memcached_st
*obj
= calloc(1, sizeof(*obj
));
51 if (memcached_clone(obj
, pool
->master
) == NULL
)
57 pool
->mmc
[++pool
->firstfree
] = obj
;
63 memcached_pool_st
*memcached_pool_create(memcached_st
* mmc
,
64 uint32_t initial
, uint32_t max
)
66 memcached_pool_st
* ret
= NULL
;
67 memcached_pool_st object
= { .mutex
= PTHREAD_MUTEX_INITIALIZER
,
68 .cond
= PTHREAD_COND_INITIALIZER
,
70 .mmc
= calloc(max
, sizeof(memcached_st
*)),
75 if (object
.mmc
!= NULL
)
77 ret
= calloc(1, sizeof(*ret
));
87 Try to create the initial size of the pool. An allocation failure at
88 this time is not fatal..
90 for (unsigned int ii
= 0; ii
< initial
; ++ii
)
92 if (grow_pool(ret
) == -1)
100 memcached_st
* memcached_pool_destroy(memcached_pool_st
* pool
)
102 memcached_st
*ret
= pool
->master
;
104 for (int xx
= 0; xx
<= pool
->firstfree
; ++xx
)
106 memcached_free(pool
->mmc
[xx
]);
108 pool
->mmc
[xx
] = NULL
;
111 pthread_mutex_destroy(&pool
->mutex
);
112 pthread_cond_destroy(&pool
->cond
);
119 memcached_st
* memcached_pool_pop(memcached_pool_st
* pool
,
121 memcached_return_t
*rc
)
123 memcached_st
*ret
= NULL
;
124 if ((*rc
= mutex_enter(&pool
->mutex
)) != MEMCACHED_SUCCESS
)
129 if (pool
->firstfree
> -1)
130 ret
= pool
->mmc
[pool
->firstfree
--];
131 else if (pool
->current_size
== pool
->size
)
135 *rc
= mutex_exit(&pool
->mutex
);
139 if (pthread_cond_wait(&pool
->cond
, &pool
->mutex
) == -1)
142 mutex_exit(&pool
->mutex
);
144 *rc
= MEMCACHED_ERRNO
;
148 else if (grow_pool(pool
) == -1)
150 *rc
= mutex_exit(&pool
->mutex
);
156 *rc
= mutex_exit(&pool
->mutex
);
161 memcached_return_t
memcached_pool_push(memcached_pool_st
* pool
,
164 memcached_return_t rc
= mutex_enter(&pool
->mutex
);
166 if (rc
!= MEMCACHED_SUCCESS
)
169 char* version
= memcached_get_user_data(mmc
);
170 /* Someone updated the behavior on the object.. */
171 if (version
!= pool
->version
)
174 memset(mmc
, 0, sizeof(*mmc
));
175 if (memcached_clone(mmc
, pool
->master
) == NULL
)
177 rc
= MEMCACHED_SOME_ERRORS
;
181 pool
->mmc
[++pool
->firstfree
]= mmc
;
183 if (pool
->firstfree
== 0 && pool
->current_size
== pool
->size
)
185 /* we might have people waiting for a connection.. wake them up :-) */
186 pthread_cond_broadcast(&pool
->cond
);
189 memcached_return_t rval
= mutex_exit(&pool
->mutex
);
190 if (rc
== MEMCACHED_SOME_ERRORS
)
197 memcached_return_t
memcached_pool_behavior_set(memcached_pool_st
*pool
,
198 memcached_behavior_t flag
,
202 memcached_return_t rc
= mutex_enter(&pool
->mutex
);
203 if (rc
!= MEMCACHED_SUCCESS
)
206 /* update the master */
207 rc
= memcached_behavior_set(pool
->master
, flag
, data
);
208 if (rc
!= MEMCACHED_SUCCESS
)
210 mutex_exit(&pool
->mutex
);
215 memcached_set_user_data(pool
->master
, pool
->version
);
216 /* update the clones */
217 for (int xx
= 0; xx
<= pool
->firstfree
; ++xx
)
219 rc
= memcached_behavior_set(pool
->mmc
[xx
], flag
, data
);
220 if (rc
== MEMCACHED_SUCCESS
)
221 memcached_set_user_data(pool
->mmc
[xx
], pool
->version
);
224 memcached_free(pool
->mmc
[xx
]);
225 memset(pool
->mmc
[xx
], 0, sizeof(*pool
->mmc
[xx
]));
226 if (memcached_clone(pool
->mmc
[xx
], pool
->master
) == NULL
)
228 /* I'm not sure what to do in this case.. this would happen
229 if we fail to push the server list inside the client..
230 I should add a testcase for this, but I believe the following
231 would work, except that you would add a hole in the pool list..
232 in theory you could end up with an empty pool....
240 return mutex_exit(&pool
->mutex
);
243 memcached_return_t
memcached_pool_behavior_get(memcached_pool_st
*pool
,
244 memcached_behavior_t flag
,
247 memcached_return_t rc
= mutex_enter(&pool
->mutex
);
249 if (rc
!= MEMCACHED_SUCCESS
)
254 *value
= memcached_behavior_get(pool
->master
, flag
);
256 return mutex_exit(&pool
->mutex
);