aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/c/urweb.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/c/urweb.c')
-rw-r--r--src/c/urweb.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/src/c/urweb.c b/src/c/urweb.c
index d656ae03..cc0eab06 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;
@@ -70,6 +72,9 @@ void uw_buffer_free(uw_buffer *b) {
void uw_buffer_reset(uw_buffer *b) {
b->front = b->start;
+ if (b->front != b->back) {
+ *b->front = 0;
+ }
}
int uw_buffer_check(uw_buffer *b, size_t extra) {
@@ -483,6 +488,10 @@ struct uw_context {
char *output_buffer;
size_t output_buffer_size;
+ // For caching.
+ int numRecording;
+ int recordingOffset;
+
int remoteSock;
};
@@ -567,6 +576,9 @@ uw_context uw_init(int id, uw_loggers *lg) {
ctx->output_buffer = malloc(1);
ctx->output_buffer_size = 1;
+ ctx->numRecording = 0;
+ ctx->recordingOffset = 0;
+
ctx->remoteSock = -1;
return ctx;
@@ -1706,6 +1718,21 @@ void uw_write(uw_context ctx, const char* s) {
*ctx->page.front = 0;
}
+void uw_recordingStart(uw_context ctx) {
+ if (ctx->numRecording++ == 0) {
+ ctx->recordingOffset = ctx->page.front - ctx->page.start;
+ }
+}
+
+char *uw_recordingRead(uw_context ctx) {
+ // Only the outermost recorder can read unless the recording is empty.
+ char *recording = ctx->page.start + ctx->recordingOffset;
+ if (--ctx->numRecording > 0 && recording != ctx->page.front) {
+ return NULL;
+ }
+ return strdup(recording);
+}
+
char *uw_Basis_attrifyInt(uw_context ctx, uw_Basis_int n) {
char *result;
int len;
@@ -4504,3 +4531,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_free(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_free(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_free(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());
+}