diff options
Diffstat (limited to 'src/c/urweb.c')
-rw-r--r-- | src/c/urweb.c | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/src/c/urweb.c b/src/c/urweb.c index 6d3836f1..66fedfa2 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -22,6 +22,8 @@ #include "types.h" +#include "uthash.h" + uw_unit uw_unit_v = 0; @@ -483,6 +485,9 @@ struct uw_context { char *output_buffer; size_t output_buffer_size; + // For caching. + char *recording; + int remoteSock; }; @@ -567,6 +572,8 @@ uw_context uw_init(int id, uw_loggers *lg) { ctx->output_buffer = malloc(1); ctx->output_buffer_size = 1; + ctx->recording = 0; + ctx->remoteSock = -1; return ctx; @@ -1681,6 +1688,14 @@ void uw_write(uw_context ctx, const char* s) { *ctx->page.front = 0; } +void uw_recordingStart(uw_context ctx) { + ctx->recording = ctx->page.front; +} + +char *uw_recordingRead(uw_context ctx) { + return strdup(ctx->recording); +} + char *uw_Basis_attrifyInt(uw_context ctx, uw_Basis_int n) { char *result; int len; @@ -4479,3 +4494,148 @@ int uw_remoteSock(uw_context ctx) { void uw_set_remoteSock(uw_context ctx, int sock) { ctx->remoteSock = sock; } + + +// Sqlcache + +void uw_sqlcache_listDelete(uw_sqlcache_CacheList *list, uw_sqlcache_CacheEntry *entry) { + if (list->first == entry) { + list->first = entry->next; + } + if (list->last == entry) { + list->last = entry->prev; + } + if (entry->prev) { + entry->prev->next = entry->next; + } + if (entry->next) { + entry->next->prev = entry->prev; + } + entry->prev = NULL; + entry->next = NULL; + --(list->size); +} + +void uw_sqlcache_listAdd(uw_sqlcache_CacheList *list, uw_sqlcache_CacheEntry *entry) { + if (list->last) { + list->last->next = entry; + entry->prev = list->last; + list->last = entry; + } else { + list->first = entry; + list->last = entry; + } + ++(list->size); +} + +void uw_sqlcache_listBump(uw_sqlcache_CacheList *list, uw_sqlcache_CacheEntry *entry) { + uw_sqlcache_listDelete(list, entry); + uw_sqlcache_listAdd(list, entry); +} + +// TODO: deal with time properly. + +time_t uw_sqlcache_getTimeNow() { + return time(NULL); +} + +time_t uw_sqlcache_timeMax(time_t x, time_t y) { + return difftime(x, y) > 0 ? x : y; +} + +void uw_sqlcache_freeuw_sqlcache_CacheValue(uw_sqlcache_CacheValue *value) { + if (value) { + free(value->result); + free(value->output); + free(value); + } +} + +void uw_sqlcache_delete(uw_sqlcache_Cache *cache, uw_sqlcache_CacheEntry* entry) { + //uw_sqlcache_listUw_Sqlcache_Delete(cache->lru, entry); + HASH_DELETE(hh, cache->table, entry); + uw_sqlcache_freeuw_sqlcache_CacheValue(entry->value); + free(entry->key); + free(entry); +} + +uw_sqlcache_CacheValue *uw_sqlcache_checkHelper(uw_sqlcache_Cache *cache, char **keys, int timeInvalid) { + char *key = keys[cache->height]; + uw_sqlcache_CacheEntry *entry; + HASH_FIND(hh, cache->table, key, strlen(key), entry); + timeInvalid = uw_sqlcache_timeMax(timeInvalid, cache->timeInvalid); + if (entry && difftime(entry->timeValid, timeInvalid) > 0) { + if (cache->height == 0) { + // At height 0, entry->value is the desired value. + //uw_sqlcache_listBump(cache->lru, entry); + return entry->value; + } else { + // At height n+1, entry->value is a pointer to a cache at heignt n. + return uw_sqlcache_checkHelper(entry->value, keys, timeInvalid); + } + } else { + return NULL; + } +} + +uw_sqlcache_CacheValue *uw_sqlcache_check(uw_sqlcache_Cache *cache, char **keys) { + return uw_sqlcache_checkHelper(cache, keys, 0); +} + +void uw_sqlcache_storeHelper(uw_sqlcache_Cache *cache, char **keys, uw_sqlcache_CacheValue *value, int timeNow) { + uw_sqlcache_CacheEntry *entry; + char *key = keys[cache->height]; + HASH_FIND(hh, cache->table, key, strlen(key), entry); + if (!entry) { + entry = malloc(sizeof(uw_sqlcache_CacheEntry)); + entry->key = strdup(key); + entry->value = NULL; + HASH_ADD_KEYPTR(hh, cache->table, entry->key, strlen(entry->key), entry); + } + entry->timeValid = timeNow; + if (cache->height == 0) { + //uw_sqlcache_listAdd(cache->lru, entry); + uw_sqlcache_freeuw_sqlcache_CacheValue(entry->value); + entry->value = value; + //if (cache->lru->size > MAX_SIZE) { + //uw_sqlcache_delete(cache, cache->lru->first); + // TODO: return flushed value. + //} + } else { + if (!entry->value) { + uw_sqlcache_Cache *newuw_sqlcache_Cache = malloc(sizeof(uw_sqlcache_Cache)); + newuw_sqlcache_Cache->table = NULL; + newuw_sqlcache_Cache->timeInvalid = timeNow; + newuw_sqlcache_Cache->lru = cache->lru; + newuw_sqlcache_Cache->height = cache->height - 1; + entry->value = newuw_sqlcache_Cache; + } + uw_sqlcache_storeHelper(entry->value, keys, value, timeNow); + } +} + +void uw_sqlcache_store(uw_sqlcache_Cache *cache, char **keys, uw_sqlcache_CacheValue *value) { + uw_sqlcache_storeHelper(cache, keys, value, uw_sqlcache_getTimeNow()); +} + +void uw_sqlcache_flushHelper(uw_sqlcache_Cache *cache, char **keys, int timeNow) { + uw_sqlcache_CacheEntry *entry; + char *key = keys[cache->height]; + if (key) { + HASH_FIND(hh, cache->table, key, strlen(key), entry); + if (entry) { + if (cache->height == 0) { + uw_sqlcache_delete(cache, entry); + } else { + uw_sqlcache_flushHelper(entry->value, keys, timeNow); + } + } + } else { + // Null key means invalidate the entire subtree. + cache->timeInvalid = timeNow; + } +} + +void uw_sqlcache_flush(uw_sqlcache_Cache *cache, char **keys) { + uw_sqlcache_flushHelper(cache, keys, uw_sqlcache_getTimeNow()); +} |