#define PS_MM_PATH "/tmp/session_mm"
+/* For php_uint32 */
+#include "ext/standard/basic_functions.h"
+
/*
* this list holds all data associated with one session
*/
typedef struct ps_sd {
- struct ps_sd *next, *prev;
- time_t ctime;
+ struct ps_sd *next;
+ php_uint32 hv; /* hash value of key */
+ time_t ctime; /* time of last change */
char *key;
void *data;
- size_t datalen;
+ size_t datalen; /* amount of valid data */
+ size_t alloclen; /* amount of allocated memory for data */
} ps_sd;
typedef struct {
#define HASH_SIZE 577
#if 0
-#define ps_mm_debug(a...) fprintf(stderr, a)
+#define ps_mm_debug(a) printf a
#else
-#define ps_mm_debug
+#define ps_mm_debug(a)
#endif
-/* For php_uint32 */
-#include "ext/standard/basic_functions.h"
-
-static php_uint32 ps_sd_hash(const char *data)
+static inline php_uint32 ps_sd_hash(const char *data)
{
php_uint32 h;
char c;
- for (h = 2166136261; (c = *data++); ) {
+ for (h = 2166136261U; (c = *data++); ) {
h *= 16777619;
h ^= c;
}
static ps_sd *ps_sd_new(ps_mm *data, const char *key, const void *sdata, size_t sdatalen)
{
- php_uint32 h;
+ php_uint32 hv, slot;
ps_sd *sd;
- h = ps_sd_hash(key) % HASH_SIZE;
+ hv = ps_sd_hash(key);
+ slot = hv % HASH_SIZE;
sd = mm_malloc(data->mm, sizeof(*sd));
if (!sd)
return NULL;
sd->ctime = 0;
+ sd->hv = hv;
sd->data = mm_malloc(data->mm, sdatalen);
if (!sd->data) {
return NULL;
}
- sd->datalen = sdatalen;
+ sd->alloclen = sd->datalen = sdatalen;
sd->key = mm_strdup(data->mm, key);
if (!sd->key) {
memcpy(sd->data, sdata, sdatalen);
- if ((sd->next = data->hash[h]))
- sd->next->prev = sd;
- sd->prev = NULL;
-
- ps_mm_debug("inserting %s(%p) into %d\n", key, sd, h);
+ sd->next = data->hash[slot];
+ data->hash[slot] = sd;
- data->hash[h] = sd;
+ ps_mm_debug(("inserting %s(%p) into slot %d\n", key, sd, slot));
return sd;
}
static void ps_sd_destroy(ps_mm *data, ps_sd *sd)
{
- unsigned int h;
+ php_uint32 slot;
- h = ps_sd_hash(sd->key) % HASH_SIZE;
-
- if (sd->next)
- sd->next->prev = sd->prev;
- if (sd->prev)
- sd->prev->next = sd->next;
-
- if (data->hash[h] == sd)
- data->hash[h] = sd->next;
+ slot = ps_sd_hash(sd->key) % HASH_SIZE;
+
+ if (data->hash[slot] == sd)
+ data->hash[slot] = sd->next;
+ else {
+ ps_sd *prev;
+
+ /* There must be some entry before the one we want to delete */
+ for (prev = data->hash[slot]; prev->next != sd; prev = prev->next);
+ prev->next = sd->next;
+ }
mm_free(data->mm, sd->key);
if (sd->data)
static ps_sd *ps_sd_lookup(ps_mm *data, const char *key, int rw)
{
- unsigned int h;
+ php_uint32 hv, slot;
ps_sd *ret;
- h = ps_sd_hash(key) % HASH_SIZE;
-
- for (ret = data->hash[h]; ret; ret = ret->next)
- if (!strcmp(ret->key, key))
+ hv = ps_sd_hash(key);
+ slot = hv % HASH_SIZE;
+
+ for (ret = data->hash[slot]; ret; ret = ret->next)
+ if (ret->hv == hv && !strcmp(ret->key, key))
break;
- if (ret && rw && ret != data->hash[h]) {
- data->hash[h]->prev = ret;
- ret->next = data->hash[h];
- data->hash[h] = ret;
- ps_mm_debug("optimizing\n");
+ if (ret && rw && ret != data->hash[slot]) {
+ /* Move the entry to the top of the linked list */
+
+ ret->next = data->hash[slot];
+ data->hash[slot] = ret;
}
- ps_mm_debug("lookup(%s): ret=%p,h=%d\n", key, ret, h);
+ ps_mm_debug(("lookup(%s): ret=%p,hv=%u,slot=%d\n", key, ret, hv, slot));
return ret;
}
PS_OPEN_FUNC(mm)
{
- ps_mm_debug("open: ps_mm_instance=%p\n", ps_mm_instance);
+ ps_mm_debug(("open: ps_mm_instance=%p\n", ps_mm_instance));
if (!ps_mm_instance)
return FAILURE;
sd = ps_sd_lookup(data, key, 0);
if (sd) {
*vallen = sd->datalen;
- *val = emalloc(sd->datalen);
+ *val = emalloc(sd->datalen + 1);
memcpy(*val, sd->data, sd->datalen);
+ (*val)[sd->datalen] = '\0';
ret = SUCCESS;
}
PS_MM_DATA;
ps_sd *sd;
- if (vallen == 0) return SUCCESS;
-
mm_lock(data->mm, MM_LOCK_RW);
sd = ps_sd_lookup(data, key, 1);
if (!sd) {
sd = ps_sd_new(data, key, val, vallen);
- ps_mm_debug("new one for %s\n", key);
+ ps_mm_debug(("new entry for %s\n", key));
} else {
- ps_mm_debug("found existing one for %s\n", key);
- mm_free(data->mm, sd->data);
- sd->datalen = vallen;
- sd->data = mm_malloc(data->mm, vallen);
- if (!sd->data) {
- ps_sd_destroy(data, sd);
- sd = NULL;
- } else
+ ps_mm_debug(("found existing entry for %s\n", key));
+
+ if (vallen >= sd->alloclen) {
+ mm_free(data->mm, sd->data);
+ sd->alloclen = vallen + 1;
+ sd->data = mm_malloc(data->mm, sd->alloclen);
+
+ if (!sd->data) {
+ ps_sd_destroy(data, sd);
+ sd = NULL;
+ }
+ }
+ if (sd) {
+ sd->datalen = vallen;
memcpy(sd->data, val, vallen);
+ }
}
if (sd)
{
PS_MM_DATA;
int h;
- time_t now;
+ time_t limit;
ps_sd *sd, *next;
*nrdels = 0;
- ps_mm_debug("gc\n");
-
+ ps_mm_debug(("gc\n"));
+
+ time(&limit);
+
+ limit -= maxlifetime;
+
mm_lock(data->mm, MM_LOCK_RW);
-
- time(&now);
for (h = 0; h < HASH_SIZE; h++)
for (sd = data->hash[h]; sd; sd = next) {
next = sd->next;
- ps_mm_debug("looking at %s\n", sd->key);
- if ((now - sd->ctime) > maxlifetime) {
+ if (sd->ctime < limit) {
+ ps_mm_debug(("purging %s\n", sd->key));
ps_sd_destroy(data, sd);
- *nrdels++;
+ (*nrdels)++;
}
}