Skip to content

Commit

Permalink
Reset context when updating default server list
Browse files Browse the repository at this point in the history
libmemcached does not have a function for removing servers from the current
context so we must recreate the context from scratch when the list of
default servers changes.

The new functionality also makes it possible to implement a
memcache_server_delete() function at some point as requested in [ohmu#4] but
it's not implemented in this commit.
  • Loading branch information
saaros committed May 21, 2014
1 parent 3c79f68 commit ebe9fe5
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 71 deletions.
137 changes: 83 additions & 54 deletions pgmemcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@
PG_MODULE_MAGIC;
#endif

static void pgmemcache_reset_context(void);
static void assign_default_servers_guc(const char *newval, void *extra);
static void assign_default_behavior_guc(const char *newval, void *extra);
static memcached_behavior get_memcached_behavior_flag(const char *flag);
static uint64_t get_memcached_behavior_data(const char *flag, const char *data);
static uint64_t get_memcached_hash_type(const char *data);
static uint64_t get_memcached_distribution_type(const char *data);
static Datum memcache_atomic_op(bool increment, PG_FUNCTION_ARGS);
static Datum memcache_set_cmd(int type, PG_FUNCTION_ARGS);
static memcached_return do_server_add(const char *host_str);
static bool do_memcache_set_cmd(int type, char *key, size_t key_len, char *val, size_t val_len, time_t expire);
static time_t interval_to_time_t(Interval *span);

/* Per-backend global state. */
static struct memcache_global_s
{
Expand All @@ -28,38 +41,12 @@ static struct memcache_global_s

void _PG_init(void)
{
MemoryContext old_ctxt;
int rc;

globals.pg_ctxt = AllocSetContextCreate(TopMemoryContext,
"pgmemcache global context",
ALLOCSET_SMALL_MINSIZE,
ALLOCSET_SMALL_INITSIZE,
ALLOCSET_SMALL_MAXSIZE);

old_ctxt = MemoryContextSwitchTo(globals.pg_ctxt);
globals.mc = memcached_create(NULL);

if (memcached_set_memory_allocators(globals.mc,
(memcached_malloc_fn) pgmemcache_malloc,
(memcached_free_fn) pgmemcache_free,
(memcached_realloc_fn) pgmemcache_realloc,
(memcached_calloc_fn) pgmemcache_calloc,
NULL) != MEMCACHED_SUCCESS) {
elog(ERROR, "pgmemcache: unable to set memory allocators");
}

MemoryContextSwitchTo(old_ctxt);

/* Use memcache binary protocol by default as required for
memcached_(increment|decrement)_with_initial. */
rc = memcached_behavior_set(globals.mc,
MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
1);
if (rc != MEMCACHED_SUCCESS)
elog(WARNING, "pgmemcache: memcached_behavior_set(BINARY_PROTOCOL): %s",
memcached_strerror(globals.mc, rc));

DefineCustomStringVariable("pgmemcache.default_servers",
"Comma-separated list of memcached servers to connect to.",
"Specified as a comma-separated list of host:port (port is optional).",
Expand Down Expand Up @@ -112,23 +99,17 @@ void _PG_init(void)
NULL,
NULL);

#if LIBMEMCACHED_WITH_SASL_SUPPORT
/* XXX: does this work? We should probably add an assign_hook for these
* so that memcache sasl data is updated when the values are changed. */
if (globals.sasl_authentication_username != NULL && strlen(globals.sasl_authentication_username) > 0 &&
globals.sasl_authentication_password != NULL && strlen(globals.sasl_authentication_password) > 0)
{
int rc = memcached_set_sasl_auth_data(globals.mc,
globals.sasl_authentication_username,
globals.sasl_authentication_password);
if (rc != MEMCACHED_SUCCESS)
elog(ERROR, "pgmemcache: memcached_set_sasl_auth_data: %s",
memcached_strerror(globals.mc, rc));
rc = sasl_client_init(NULL);
if (rc != SASL_OK)
elog(ERROR, "pgmemcache: sasl_client_init failed: %d", rc);
}
#endif
pgmemcache_reset_context();
}

/* This is called when we're being unloaded from a process. Note that
* this only happens when we're being replaced by a LOAD (e.g. it
* doesn't happen on process exit), so we can't depend on it being
* called. */
void _PG_fini(void)
{
memcached_free(globals.mc);
MemoryContextDelete(globals.pg_ctxt);
}

static void *pgmemcache_malloc(memcached_st *ptr __attribute__((unused)), const size_t size, void *context)
Expand All @@ -152,10 +133,68 @@ static void *pgmemcache_calloc(memcached_st *ptr __attribute__((unused)), size_t
return MemoryContextAllocZero(globals.pg_ctxt, nelem * size);
}

static void pgmemcache_reset_context(void)
{
int rc;
MemoryContext old_ctxt = MemoryContextSwitchTo(globals.pg_ctxt);

if (globals.mc)
{
memcached_free(globals.mc);
globals.mc = memcached_create(NULL);
}

globals.mc = memcached_create(NULL);

if (memcached_set_memory_allocators(globals.mc,
(memcached_malloc_fn) pgmemcache_malloc,
(memcached_free_fn) pgmemcache_free,
(memcached_realloc_fn) pgmemcache_realloc,
(memcached_calloc_fn) pgmemcache_calloc,
NULL) != MEMCACHED_SUCCESS)
elog(ERROR, "pgmemcache: unable to set memory allocators");

/* Always use the memcache binary protocol as required for
memcached_(increment|decrement)_with_initial. */
rc = memcached_behavior_set(globals.mc,
MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
1);
if (rc != MEMCACHED_SUCCESS)
elog(WARNING, "pgmemcache: memcached_behavior_set(BINARY_PROTOCOL): %s",
memcached_strerror(globals.mc, rc));

assign_default_behavior_guc(globals.default_behavior, NULL);

#if LIBMEMCACHED_WITH_SASL_SUPPORT
/* XXX: does this work? We should probably add an assign_hook for these
* so that memcache sasl data is updated when the values are changed. */
if (globals.sasl_authentication_username != NULL && strlen(globals.sasl_authentication_username) > 0 &&
globals.sasl_authentication_password != NULL && strlen(globals.sasl_authentication_password) > 0)
{
int rc = memcached_set_sasl_auth_data(globals.mc,
globals.sasl_authentication_username,
globals.sasl_authentication_password);
if (rc != MEMCACHED_SUCCESS)
elog(ERROR, "pgmemcache: memcached_set_sasl_auth_data: %s",
memcached_strerror(globals.mc, rc));
rc = sasl_client_init(NULL);
if (rc != SASL_OK)
elog(ERROR, "pgmemcache: sasl_client_init failed: %d", rc);
}
#endif

MemoryContextSwitchTo(old_ctxt);
}

static void assign_default_servers_guc(const char *newval, void *extra)
{
if (newval)
do_server_add(newval);
{
/* there is no way to remove servers from a memcache context, so
* recreate it from scratch when the server list changes */
pgmemcache_reset_context();
do_server_add(newval);
}
}

static void assign_default_behavior_guc(const char *newval, void *extra)
Expand Down Expand Up @@ -224,16 +263,6 @@ static void assign_default_behavior_guc(const char *newval, void *extra)
MemoryContextSwitchTo(old_ctx);
}

/* This is called when we're being unloaded from a process. Note that
* this only happens when we're being replaced by a LOAD (e.g. it
* doesn't happen on process exit), so we can't depend on it being
* called. */
void _PG_fini(void)
{
memcached_free(globals.mc);
MemoryContextDelete(globals.pg_ctxt);
}

Datum memcache_add(PG_FUNCTION_ARGS)
{
return memcache_set_cmd(PG_MEMCACHE_ADD | PG_MEMCACHE_TYPE_INTERVAL, fcinfo);
Expand Down
17 changes: 0 additions & 17 deletions pgmemcache.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,6 @@
void _PG_init(void);
void _PG_fini(void);

/* Custom GUC variable */
static void assign_default_servers_guc(const char *newval, void *extra);
static void assign_default_behavior_guc(const char *newval, void *extra);
static memcached_behavior get_memcached_behavior_flag(const char *flag);
static uint64_t get_memcached_behavior_data(const char *flag, const char *data);
static uint64_t get_memcached_hash_type(const char *data);
static uint64_t get_memcached_distribution_type(const char *data);
static Datum memcache_atomic_op(bool increment, PG_FUNCTION_ARGS);
static Datum memcache_set_cmd(int type, PG_FUNCTION_ARGS);
static memcached_return do_server_add(const char *host_str);
static bool do_memcache_set_cmd(int type, char *key, size_t key_len, char *val, size_t val_len, time_t expire);
static time_t interval_to_time_t(Interval *span);
static void *pgmemcache_malloc(memcached_st *ptr __attribute__((unused)), const size_t, void *context);
static void pgmemcache_free(memcached_st *ptr __attribute__((unused)), void *mem, void *context);
static void *pgmemcache_realloc(memcached_st *ptr __attribute__((unused)), void *, const size_t, void *context);
static void *pgmemcache_calloc(memcached_st *ptr __attribute__((unused)), size_t nelem, const size_t, void *context);

#define PG_MEMCACHE_ADD 0x0001
#define PG_MEMCACHE_REPLACE 0x0002
#define PG_MEMCACHE_SET 0x0004
Expand Down

0 comments on commit ebe9fe5

Please sign in to comment.