comparison src/c/urweb.c @ 2291:50ad02829abd

Make cache flushes happen immediately instead of at end of transaction.
author Ziv Scully <ziv@mit.edu>
date Tue, 17 Nov 2015 02:44:37 -0500
parents 98f96a976ede
children 5104e480b3e3
comparison
equal deleted inserted replaced
2290:ab6ca12debeb 2291:50ad02829abd
4583 4583
4584 // TODO: pick a number. 4584 // TODO: pick a number.
4585 static unsigned int uw_Sqlcache_maxSize = 1234567890; 4585 static unsigned int uw_Sqlcache_maxSize = 1234567890;
4586 4586
4587 static void uw_Sqlcache_delete(uw_Sqlcache_Cache *cache, uw_Sqlcache_Entry *entry) { 4587 static void uw_Sqlcache_delete(uw_Sqlcache_Cache *cache, uw_Sqlcache_Entry *entry) {
4588 HASH_DEL(cache->table, entry); 4588 if (entry) {
4589 uw_Sqlcache_freeEntry(entry); 4589 HASH_DEL(cache->table, entry);
4590 uw_Sqlcache_freeEntry(entry);
4591 }
4590 } 4592 }
4591 4593
4592 static uw_Sqlcache_Entry *uw_Sqlcache_find(uw_Sqlcache_Cache *cache, char *key, size_t len, int bump) { 4594 static uw_Sqlcache_Entry *uw_Sqlcache_find(uw_Sqlcache_Cache *cache, char *key, size_t len, int bump) {
4593 uw_Sqlcache_Entry *entry = NULL; 4595 uw_Sqlcache_Entry *entry = NULL;
4594 HASH_FIND(hh, cache->table, key, len, entry); 4596 HASH_FIND(hh, cache->table, key, len, entry);
4721 entry->value->timeValid = timeNow; 4723 entry->value->timeValid = timeNow;
4722 pthread_rwlock_unlock(&cache->lockIn); 4724 pthread_rwlock_unlock(&cache->lockIn);
4723 } 4725 }
4724 4726
4725 static void uw_Sqlcache_flushCommitOne(uw_Sqlcache_Cache *cache, char **keys) { 4727 static void uw_Sqlcache_flushCommitOne(uw_Sqlcache_Cache *cache, char **keys) {
4726 pthread_rwlock_wrlock(&cache->lockIn);
4727 size_t numKeys = cache->numKeys;
4728 if (numKeys == 0) {
4729 uw_Sqlcache_Entry *entry = cache->table;
4730 if (entry) {
4731 uw_Sqlcache_freeValue(entry->value);
4732 entry->value = NULL;
4733 }
4734 } else {
4735 char *key = uw_Sqlcache_allocKeyBuffer(keys, numKeys);
4736 char *buf = key;
4737 time_t timeNow = uw_Sqlcache_getTimeNow(cache);
4738 uw_Sqlcache_Entry *entry = NULL;
4739 while (numKeys-- > 0) {
4740 char *k = keys[numKeys];
4741 if (!k) {
4742 if (entry) {
4743 entry->timeInvalid = timeNow;
4744 } else {
4745 // Haven't found an entry yet, so the first key was null.
4746 cache->timeInvalid = timeNow;
4747 }
4748 free(key);
4749 pthread_rwlock_unlock(&cache->lockIn);
4750 return;
4751 }
4752 buf = uw_Sqlcache_keyCopy(buf, k);
4753 size_t len = buf - key;
4754 entry = uw_Sqlcache_find(cache, key, len, 0);
4755 if (!entry) {
4756 // Nothing in the cache to flush.
4757 free(key);
4758 pthread_rwlock_unlock(&cache->lockIn);
4759 return;
4760 }
4761 }
4762 free(key);
4763 // All the keys were non-null and the relevant entry is present, so we delete it.
4764 uw_Sqlcache_delete(cache, entry);
4765 }
4766 pthread_rwlock_unlock(&cache->lockIn);
4767 } 4728 }
4768 4729
4769 static void uw_Sqlcache_commit(void *data) { 4730 static void uw_Sqlcache_commit(void *data) {
4770 uw_context ctx = (uw_context)data; 4731 uw_context ctx = (uw_context)data;
4771 uw_Sqlcache_Update *update = ctx->cacheUpdate; 4732 uw_Sqlcache_Update *update = ctx->cacheUpdate;
4851 } 4812 }
4852 ctx->cacheUpdateTail = update; 4813 ctx->cacheUpdateTail = update;
4853 } 4814 }
4854 4815
4855 void uw_Sqlcache_flush(uw_context ctx, uw_Sqlcache_Cache *cache, char **keys) { 4816 void uw_Sqlcache_flush(uw_context ctx, uw_Sqlcache_Cache *cache, char **keys) {
4856 // A flush is represented in the queue as storing NULL. 4817 // A flush has to happen immediately so that subsequent stores in the same transaction fail.
4857 uw_Sqlcache_store(ctx, cache, keys, NULL); 4818 // This is safe to do because we will always call [uw_Sqlcache_wlock] earlier.
4858 } 4819 // If the transaction fails, the only harm done is a few extra cache misses.
4820 pthread_rwlock_wrlock(&cache->lockIn);
4821 size_t numKeys = cache->numKeys;
4822 if (numKeys == 0) {
4823 uw_Sqlcache_Entry *entry = cache->table;
4824 if (entry) {
4825 uw_Sqlcache_freeValue(entry->value);
4826 entry->value = NULL;
4827 }
4828 } else {
4829 char *key = uw_Sqlcache_allocKeyBuffer(keys, numKeys);
4830 char *buf = key;
4831 time_t timeNow = uw_Sqlcache_getTimeNow(cache);
4832 while (numKeys-- > 0) {
4833 char *k = keys[numKeys];
4834 if (!k) {
4835 size_t len = buf - key;
4836 if (len == 0) {
4837 // The first key was null.
4838 cache->timeInvalid = timeNow;
4839 } else {
4840 uw_Sqlcache_Entry *entry = uw_Sqlcache_find(cache, key, len, 0);
4841 if (entry) {
4842 entry->timeInvalid = timeNow;
4843 }
4844 }
4845 free(key);
4846 pthread_rwlock_unlock(&cache->lockIn);
4847 return;
4848 }
4849 buf = uw_Sqlcache_keyCopy(buf, k);
4850 }
4851 // All the keys were non-null, so we delete the pointed-to entry.
4852 size_t len = buf - key;
4853 uw_Sqlcache_Entry *entry = uw_Sqlcache_find(cache, key, len, 0);
4854 free(key);
4855 uw_Sqlcache_delete(cache, entry);
4856 }
4857 pthread_rwlock_unlock(&cache->lockIn);
4858 }