=head1 SEE ALSO
-memcached(1) libmemcached_examples(3) libmemcached(1) memcat(1) memcp(1) memflush(1) memrm(1) memslap(1) memstat(1) memcached_fetch(3) memcached_replace(3) memcached_server_list_free(3) libmemcached_examples(3) memcached_clone(3) memcached_free(3) memcached_server_add(3) memcached_server_push(3) memcached_add(3) memcached_get(3) memcached_server_count(3) memcached_servers_parse(3) memcached_create(3) memcached_increment(3) memcached_server_list(3) memcached_set(3) memcached_decrement(3) memcached_mget(3) memcached_server_list_append(3) memcached_strerror(3) memcached_delete(3) memcached_quit(3) memcached_server_list_count(3) memcached_verbosity(3) memcached_server_add_unix_socket(3) memcahed_result_create(3) memcached_result_free(3) memcached_result_key_value(3) memcached_result_key_length(3) memcached_result_value(3) memcached_result_length(3) memcached_result_flags(3) memcached_result_cas(3) memcached_result_st(3) memcached_append(3) memcached_prepend(3) memcached_fetch_result(3) memerror(1) memcached_get_by_key(3) memcached_mget_by_key(3) memcached_delete_by_key(3) memcached_fetch_execute(3) memcached_callback_get(3) memcached_callback_set(3) memcached_version(3) memcached_lib_version(3)
+memcached(1) libmemcached_examples(3) libmemcached(1) memcat(1) memcp(1) memflush(1) memrm(1) memslap(1) memstat(1) memcached_fetch(3) memcached_replace(3) memcached_server_list_free(3) libmemcached_examples(3) memcached_clone(3) memcached_free(3) memcached_server_add(3) memcached_server_push(3) memcached_add(3) memcached_get(3) memcached_server_count(3) memcached_servers_parse(3) memcached_create(3) memcached_increment(3) memcached_server_list(3) memcached_set(3) memcached_decrement(3) memcached_mget(3) memcached_server_list_append(3) memcached_strerror(3) memcached_delete(3) memcached_quit(3) memcached_server_list_count(3) memcached_verbosity(3) memcached_server_add_unix_socket(3) memcahed_result_create(3) memcached_result_free(3) memcached_result_key_value(3) memcached_result_key_length(3) memcached_result_value(3) memcached_result_length(3) memcached_result_flags(3) memcached_result_cas(3) memcached_result_st(3) memcached_append(3) memcached_prepend(3) memcached_fetch_result(3) memerror(1) memcached_get_by_key(3) memcached_mget_by_key(3) memcached_delete_by_key(3) memcached_fetch_execute(3) memcached_callback_get(3) memcached_callback_set(3) memcached_version(3) memcached_lib_version(3) memcached_result_set_value(3)
=cut
memcached_callback_set() changes the function/structure assigned by a
callback flag. No connections are reset.
+You can use MEMCACHED_CALLBACK_USER_DATA to provide custom context if required for any
+of the callbacks
+
=over 4
=item MEMCACHED_CALLBACK_CLEANUP_FUNCTION
void *(*memcached_malloc_function)(memcached_st *ptr, const size_t size);
-You can use MEMCACHED_CALLBACK_USER_DATA to provide custom context if required for malloc.
-
=item MEMCACHED_CALLBACK_REALLOC_FUNCTION,
This alllows yout to pass in a customized version of realloc that will be used instead of the builtin realloc(3) call.
void *(*memcached_realloc_function)(memcached_st *ptr, void *mem, const size_t size);
-You can use MEMCACHED_CALLBACK_USER_DATA to provide custom context if required for realloc.
-
=item MEMCACHED_CALLBACK_FREE_FUNCTION,
This alllows yout to pass in a customized version of realloc that will be used instead of the builtin free(3) call.
typedef void (*memcached_free_function)(memcached_st *ptr, void *mem);
-You can use MEMCACHED_CALLBACK_USER_DATA to provide custom context if required for realloc.
+=item MEMCACHED_CALLBACK_GET_FAILURE,
+
+This function implements the read through cache behavior. On failure of retrieval this callback will be called.
+You are responsible for populating the result object provided. This result object will then be stored in the server and
+returned to the calling process. You must clone the memcached_st in order to
+make use of it. The value will be stored only if you return
+MEMCACHED_SUCCESS or MEMCACHED_BUFFERED. Returning MEMCACHED_BUFFERED will
+cause the object to be buffered and not sent immediatly (if this is the default behavior based on your connection setup this will happen automatically).
+
+The prototype for this is:
+memcached_return (*memcached_trigger_key)(memcached_st *ptr, char *key, size_t key_length, memcached_result_st *result);
=back
uint64_t memcached_result_cas(memcached_result_st *result);
+ memcached_return memcached_result_set_value (memcached_result_st *ptr,
+ char *value, size_t length)
+
+ void memcached_result_set_flags(memcached_result_st *ptr, uint32_t flags)
+
+ void memcached_result_set_expiration(memcached_result_st *ptr, time_t)
+
=head1 DESCRIPTION
libmemcached(3) can optionally return a memcached_result_st which acts as a
current result object. This value will only be available if the server
supports it.
+memcached_result_set_value() takes a byte array and a size and sets
+the result to this value. This function is used for trigger responses.
+
+void memcached_result_set_flags() takes a result structure and stores
+a new value for the flags field.
+
+void memcached_result_set_expiration(A) takes a result structure and stores
+a new value for the expiration field (this is only used by read through
+triggers).
+
=head1 RETURN
new_clone->call_free= ptr->call_free;
new_clone->call_malloc= ptr->call_malloc;
new_clone->call_realloc= ptr->call_realloc;
+ new_clone->get_key_failure= ptr->get_key_failure;
if (ptr->on_clone)
ptr->on_clone(ptr, new_clone);
memcached_free_function call_free;
memcached_malloc_function call_malloc;
memcached_realloc_function call_realloc;
+ memcached_trigger_key get_key_failure;
#ifdef NOT_USED /* Future Use */
uint8_t replicas;
memcached_return warning;
ptr->call_free= func;
break;
}
+ case MEMCACHED_CALLBACK_GET_FAILURE:
+ {
+ memcached_trigger_key func= (memcached_trigger_key)data;
+ ptr->get_key_failure= func;
+ break;
+ }
default:
return MEMCACHED_FAILURE;
}
*error= ptr->call_free ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
return (void *)ptr->call_free;
}
+ case MEMCACHED_CALLBACK_GET_FAILURE:
+ {
+ *error= ptr->get_key_failure ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+ return (void *)ptr->get_key_failure;
+ }
default:
WATCHPOINT_ASSERT(0);
*error= MEMCACHED_FAILURE;
#include "common.h"
#include <poll.h>
+#include <sys/time.h>
static memcached_return set_hostinfo(memcached_server_st *server)
{
MEMCACHED_CALLBACK_MALLOC_FUNCTION,
MEMCACHED_CALLBACK_REALLOC_FUNCTION,
MEMCACHED_CALLBACK_FREE_FUNCTION,
+ MEMCACHED_CALLBACK_GET_FAILURE,
} memcached_callback;
typedef enum {
end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
- result->key_length= 0;
- result->flags= 0;
- memcached_string_reset(&result->value);
+ memcached_result_reset(result);
string_ptr= buffer;
string_ptr+= 6; /* "VALUE " */
{
/* Skip past the \r\n */
string_ptr+= 2;
- result->cas= 0;
}
else
{
*error= MEMCACHED_NOTFOUND;
if (value == NULL)
+ {
+ if (ptr->get_key_failure)
+ {
+ memcached_return rc;
+
+ memcached_result_reset(&ptr->result);
+ rc= ptr->get_key_failure(ptr, key, key_length, &ptr->result);
+
+ /* On all failure drop to returning NULL */
+ if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED)
+ {
+ uint8_t latch; /* We use latch to track the state of the original socket */
+
+ if (rc == MEMCACHED_BUFFERED)
+ {
+ latch= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS);
+ if (latch == 0)
+ memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
+ }
+
+ rc= memcached_set(ptr, key, key_length,
+ memcached_result_value(&ptr->result),
+ memcached_result_length(&ptr->result),
+ 0, memcached_result_flags(&ptr->result));
+
+ if (rc == MEMCACHED_BUFFERED && latch == 0)
+ memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 0);
+
+ if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED)
+ {
+ *error= rc;
+ *value_length= memcached_result_length(&ptr->result);
+ *flags= memcached_result_flags(&ptr->result);
+ return memcached_string_c_copy(&ptr->result.value);
+ }
+ }
+ }
+
return NULL;
+ }
(void)memcached_fetch(ptr, NULL, NULL,
&dummy_length, &dummy_flags,
return ptr;
}
+void memcached_result_reset(memcached_result_st *ptr)
+{
+ ptr->key_length= 0;
+ memcached_string_reset(&ptr->value);
+ ptr->flags= 0;
+ ptr->cas= 0;
+ ptr->expiration= 0;
+}
+
+/*
+ NOTE turn into macro
+*/
+memcached_return memcached_result_set_value(memcached_result_st *ptr, char *value, size_t length)
+{
+ return memcached_string_append(&ptr->value, value, length);
+}
+
void memcached_result_free(memcached_result_st *ptr)
{
if (ptr == NULL)
memcached_string_st value;
uint32_t flags;
uint64_t cas;
+ time_t expiration;
/* Add result callback function */
};
/* Result Struct */
void memcached_result_free(memcached_result_st *result);
+void memcached_result_reset(memcached_result_st *ptr);
memcached_result_st *memcached_result_create(memcached_st *ptr,
memcached_result_st *result);
#define memcached_result_key_value(A) (A)->key
#endif
#define memcached_result_flags(A) (A)->flags
#define memcached_result_cas(A) (A)->cas
+memcached_return memcached_result_set_value(memcached_result_st *ptr, char *value, size_t length);
+void memcached_result_set_flags(A,B) (A)->flags= B
+void memcached_result_set_expiration(A) (A)->expiration
#ifdef __cplusplus
}
typedef void *(*memcached_realloc_function)(memcached_st *ptr, void *mem, const size_t size);
typedef memcached_return (*memcached_execute_function)(memcached_st *ptr, memcached_result_st *result, void *context);
typedef memcached_return (*memcached_server_function)(memcached_st *ptr, memcached_server_st *server, void *context);
+typedef memcached_return (*memcached_trigger_key)(memcached_st *ptr,
+ char *key, size_t key_length,
+ memcached_result_st *result);
#ifdef __cplusplus
}
return 0;
}
+#define READ_THROUGH_VALUE "set for me"
+memcached_return read_through_trigger(memcached_st *memc,
+ char *key, size_t key_length,
+ memcached_result_st *result)
+{
+
+ return memcached_result_set_value(result, READ_THROUGH_VALUE, strlen(READ_THROUGH_VALUE));
+}
+
+uint8_t read_through(memcached_st *memc)
+{
+ memcached_return rc;
+ char *key= "foo";
+ char *string;
+ size_t string_length;
+ uint32_t flags;
+
+ string= memcached_get(memc, key, strlen(key),
+ &string_length, &flags, &rc);
+
+ assert(rc == MEMCACHED_NOTFOUND);
+ assert(string_length == 0);
+ assert(!string);
+
+ rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_GET_FAILURE, read_through_trigger);
+ assert(rc == MEMCACHED_SUCCESS);
+
+ string= memcached_get(memc, key, strlen(key),
+ &string_length, &flags, &rc);
+
+ assert(rc == MEMCACHED_SUCCESS);
+ assert(string_length == strlen(READ_THROUGH_VALUE));
+ assert(!strcmp(READ_THROUGH_VALUE, string));
+
+ string= memcached_get(memc, key, strlen(key),
+ &string_length, &flags, &rc);
+
+ assert(rc == MEMCACHED_SUCCESS);
+ assert(string_length == strlen(READ_THROUGH_VALUE));
+ assert(!strcmp(READ_THROUGH_VALUE, string));
+
+ return 0;
+}
+
uint8_t get_test(memcached_st *memc)
{
memcached_return rc;
{"version_string_test", 0, version_string_test},
{"bad_key", 1, bad_key_test },
{"memcached_server_cursor", 1, memcached_server_cursor_test },
+ {"read_through", 1, read_through },
{0, 0, 0}
};