/* Inserts the given KEY, VALUE pair into this server's store and cache. Access * to the cache should be concurrent if the keys are in different cache sets. * Returns 0 if successful, else a negative error code. */ int kvserver_put(kvserver_t *server, char *key, char *value) { // OUR CODE HERE int success; pthread_rwlock_t *lock = kvcache_getlock(&server->cache, key); if (lock == NULL) return ERRKEYLEN; pthread_rwlock_wrlock(lock); if ((success = kvcache_put(&server->cache, key, value)) < 0) { pthread_rwlock_unlock(lock); return success; } pthread_rwlock_unlock(lock); return kvstore_put(&server->store, key, value); }
int tpcmaster_get_cached(void) { int ret; pthread_rwlock_t *cachelock = kvcache_getlock(&testmaster.cache, "KEY"); pthread_rwlock_wrlock(cachelock); ret = kvcache_put(&testmaster.cache, "KEY", "VAL"); pthread_rwlock_unlock(cachelock); ASSERT_EQUAL(ret, 0); reqmsg.key = "KEY"; tpcmaster_handle_get(&testmaster, &reqmsg, &respmsg); ASSERT_EQUAL(respmsg.type, GETRESP); ASSERT_STRING_EQUAL(respmsg.key, "KEY"); ASSERT_STRING_EQUAL(respmsg.value, "VAL"); return 1; }
/* Removes the given KEY from this server's store and cache. Access to the * cache should be concurrent if the keys are in different cache sets. Returns * 0 if successful, else a negative error code. */ int kvserver_del(kvserver_t *server, char *key) { // OUR CODE HERE int ret; pthread_rwlock_t *lock = kvcache_getlock(&server->cache, key); if (lock == NULL) return ERRKEYLEN; pthread_rwlock_wrlock(lock); if ((ret = kvstore_del(&server->store, key)) < 0) { pthread_rwlock_unlock(lock); return ret; } pthread_rwlock_unlock(lock); kvcache_del(&server->cache, key); // if not in server's cache, that's okay return 0; }
/* Attempts to get KEY from SERVER. Returns 0 if successful, else a negative * error code. If successful, VALUE will point to a string which should later * be free()d. If the KEY is in cache, take the value from there. Otherwise, * go to the store and update the value in the cache. */ int kvserver_get(kvserver_t *server, char *key, char **value) { // OUR CODE HERE int ret; pthread_rwlock_t *lock = kvcache_getlock(&server->cache, key); if (lock == NULL) return ERRKEYLEN; pthread_rwlock_rdlock(lock); if (kvcache_get(&server->cache, key, value) == 0) { pthread_rwlock_unlock(lock); return 0; } pthread_rwlock_unlock(lock); if ((ret = kvstore_get(&server->store, key, value)) < 0) return ret; pthread_rwlock_wrlock(lock); ret = kvcache_put(&server->cache, key, *value); // what happens if this is unsuccessful? pthread_rwlock_unlock(lock); return ret; }
int kvserver_cache_concurrent_gets_rdlock(void) { pthread_rwlock_t *cachelock; pthread_t thread; reqmsg.type = PUTREQ; reqmsg.key = "MYKEY"; reqmsg.value = "MYVALUE"; kvserver_handle_no_tpc(&testserver, &reqmsg, &respmsg); ASSERT_EQUAL(respmsg.type, RESP); ASSERT_STRING_EQUAL(respmsg.message, MSG_SUCCESS); synch = 0; reqmsg.type = GETREQ; cachelock = kvcache_getlock(&testserver.cache, "MYKEY"); pthread_rwlock_rdlock(cachelock); pthread_create(&thread, NULL, kvserver_concurrent_helper, NULL); usleep(1000 * SLEEP_TIME); /* Give the get request a chance to run. */ ASSERT_EQUAL(synch, 1); /* Ensure the get request was able to complete already. */ pthread_rwlock_unlock(cachelock); pthread_join(thread, NULL); return 1; }
int kvserver_cache_concurrent_get_cache_writes(void) { pthread_rwlock_t *cachelock; pthread_t thread; kvserver_init(&testserver, KVSERVER_DIRNAME, 1, 2, 1, KVSERVER_HOSTNAME, KVSERVER_PORT, false); reqmsg.type = PUTREQ; reqmsg.key = "MYKEY1"; reqmsg.value = "MYVALUE1"; kvserver_handle_no_tpc(&testserver, &reqmsg, &respmsg); ASSERT_EQUAL(respmsg.type, RESP); ASSERT_STRING_EQUAL(respmsg.message, MSG_SUCCESS); /* Clear MYKEY1 from the cache */ reqmsg.key = "MYKEY2"; reqmsg.value = "MYVALUE2"; kvserver_handle_no_tpc(&testserver, &reqmsg, &respmsg); ASSERT_EQUAL(respmsg.type, RESP); ASSERT_STRING_EQUAL(respmsg.message, MSG_SUCCESS); reqmsg.key = "MYKEY3"; reqmsg.value = "MYVALUE3"; kvserver_handle_no_tpc(&testserver, &reqmsg, &respmsg); ASSERT_EQUAL(respmsg.type, RESP); ASSERT_STRING_EQUAL(respmsg.message, MSG_SUCCESS); synch = 0; reqmsg.type = GETREQ; reqmsg.key = "MYKEY1"; cachelock = kvcache_getlock(&testserver.cache, "MYKEY1"); pthread_rwlock_rdlock(cachelock); pthread_create(&thread, NULL, kvserver_concurrent_helper, NULL); usleep(1000 * SLEEP_TIME); /* Give the get request a chance to run. */ ASSERT_EQUAL(synch, 0); /* Ensure the get request didn't complete yet. */ pthread_rwlock_unlock(cachelock); pthread_join(thread, NULL); ASSERT_EQUAL(synch, 1); /* Ensure that the get request was able to run after the lock was released. */ return 1; }