2
* Copyright (C) 2010 Brian Aker
5
* Use and distribution licensed under the BSD license. See
6
* the COPYING file in the parent directory for full text.
8
* Summary: connects to a host, and makes sure it is alive.
1
/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
5
* Copyright (C) 2011 Data Differential, http://datadifferential.com/
6
* Copyright (C) 2010 Brian Aker All rights reserved.
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions are
12
* * Redistributions of source code must retain the above copyright
13
* notice, this list of conditions and the following disclaimer.
15
* * Redistributions in binary form must reproduce the above
16
* copyright notice, this list of conditions and the following disclaimer
17
* in the documentation and/or other materials provided with the
20
* * The names of its contributors may not be used to endorse or
21
* promote products derived from this software without specific prior
24
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12
/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
13
#include "libmemcached/common.h"
14
#include "libmemcached/memcached_util.h"
39
#include <libmemcached/common.h>
40
#include <libmemcached/memcached_util.h>
17
44
#include <pthread.h>
47
static bool grow_pool(memcached_pool_st* pool);
19
49
struct memcached_pool_st
21
51
pthread_mutex_t mutex;
22
52
pthread_cond_t cond;
23
53
memcached_st *master;
54
memcached_st **server_pool;
27
57
uint32_t current_size;
60
memcached_pool_st(memcached_st *master_arg, size_t max_arg) :
68
pthread_mutex_init(&mutex, NULL);
69
pthread_cond_init(&cond, NULL);
72
bool init(uint32_t initial)
74
server_pool= new (std::nothrow) memcached_st *[size];
79
Try to create the initial size of the pool. An allocation failure at
80
this time is not fatal..
82
for (unsigned int x= 0; x < initial; ++x)
84
if (not grow_pool(this))
93
for (int x= 0; x <= firstfree; ++x)
95
memcached_free(server_pool[x]);
96
server_pool[x] = NULL;
99
pthread_mutex_destroy(&mutex);
100
pthread_cond_destroy(&cond);
101
delete [] server_pool;
104
memcached_free(master);
108
void increment_version()
110
++master->configure.version;
113
bool compare_version(const memcached_st *arg) const
115
return (arg->configure.version == version());
118
int32_t version() const
120
return master->configure.version;
32
124
static memcached_return_t mutex_enter(pthread_mutex_t *mutex)
36
129
ret= pthread_mutex_lock(mutex);
37
while (ret == -1 && errno == EINTR);
130
} while (ret == -1 && errno == EINTR);
39
132
return (ret == -1) ? MEMCACHED_ERRNO : MEMCACHED_SUCCESS;
53
147
* Grow the connection pool by creating a connection structure and clone the
54
148
* original memcached handle.
56
static int grow_pool(memcached_pool_st* pool)
150
static bool grow_pool(memcached_pool_st* pool)
58
memcached_st *obj= calloc(1, sizeof(*obj));
63
if (memcached_clone(obj, pool->master) == NULL)
153
if (not (obj= memcached_clone(NULL, pool->master)))
69
pool->mmc[++pool->firstfree] = obj;
158
pool->server_pool[++pool->firstfree]= obj;
70
159
pool->current_size++;
160
obj->configure.version= pool->version();
75
static inline memcached_pool_st *_pool_create(memcached_st* mmc, uint32_t initial, uint32_t max)
165
static inline memcached_pool_st *_pool_create(memcached_st* master, uint32_t initial, uint32_t max)
77
memcached_pool_st* ret= NULL;
79
167
if (! initial || ! max || initial > max)
85
memcached_pool_st object= { .mutex = PTHREAD_MUTEX_INITIALIZER,
86
.cond= PTHREAD_COND_INITIALIZER,
88
.mmc= calloc(max, sizeof(memcached_st*)),
92
._owns_master= false};
94
if (object.mmc != NULL)
96
ret= (memcached_pool_st*)calloc(1, sizeof(memcached_pool_st));
100
errno= ENOMEM; // Set this for the failed calloc
107
Try to create the initial size of the pool. An allocation failure at
108
this time is not fatal..
110
for (unsigned int ii= 0; ii < initial; ++ii)
112
if (grow_pool(ret) == -1)
173
memcached_pool_st *object= new (std::nothrow) memcached_pool_st(master, max);
176
errno= ENOMEM; // Set this for the failed calloc
181
Try to create the initial size of the pool. An allocation failure at
182
this time is not fatal..
184
if (not object->init(initial))
120
memcached_pool_st *memcached_pool_create(memcached_st* mmc, uint32_t initial, uint32_t max)
193
memcached_pool_st *memcached_pool_create(memcached_st* master, uint32_t initial, uint32_t max)
122
return _pool_create(mmc, initial, max);
195
return _pool_create(master, initial, max);
125
198
memcached_pool_st * memcached_pool(const char *option_string, size_t option_string_length)
200
memcached_st *memc= memcached(option_string, option_string_length);
127
205
memcached_pool_st *self;
128
memcached_st *memc= memcached(option_string, option_string_length);
133
206
self= memcached_pool_create(memc, memc->configure.initial_pool_size, memc->configure.max_pool_size);
136
209
memcached_free(memc);
234
301
if (rc != MEMCACHED_SUCCESS)
237
char* version= memcached_get_user_data(mmc);
238
304
/* Someone updated the behavior on the object.. */
239
if (version != pool->version)
305
if (not pool->compare_version(released))
242
memset(mmc, 0, sizeof(*mmc));
243
if (memcached_clone(mmc, pool->master) == NULL)
307
memcached_free(released);
308
if (not (released= memcached_clone(NULL, pool->master)))
245
310
rc= MEMCACHED_SOME_ERRORS;
249
pool->mmc[++pool->firstfree]= mmc;
314
pool->server_pool[++pool->firstfree]= released;
251
316
if (pool->firstfree == 0 && pool->current_size == pool->size)
285
memcached_set_user_data(pool->master, pool->version);
349
pool->increment_version();
286
350
/* update the clones */
287
351
for (int xx= 0; xx <= pool->firstfree; ++xx)
289
rc= memcached_behavior_set(pool->mmc[xx], flag, data);
353
rc= memcached_behavior_set(pool->server_pool[xx], flag, data);
290
354
if (rc == MEMCACHED_SUCCESS)
292
memcached_set_user_data(pool->mmc[xx], pool->version);
356
pool->server_pool[xx]->configure.version= pool->version();
296
memcached_free(pool->mmc[xx]);
297
memset(pool->mmc[xx], 0, sizeof(*pool->mmc[xx]));
299
if (memcached_clone(pool->mmc[xx], pool->master) == NULL)
360
memcached_free(pool->server_pool[xx]);
361
if (not (pool->server_pool[xx]= memcached_clone(NULL, pool->master)))
301
363
/* I'm not sure what to do in this case.. this would happen
302
364
if we fail to push the server list inside the client..