191 lines
3.5 KiB
C
191 lines
3.5 KiB
C
#include <errno.h>
|
|
#include <pthread.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include "cache.h"
|
|
|
|
#define MAX_RANDOM_ENTRIES 32
|
|
|
|
struct key_record {
|
|
char *key;
|
|
char *value;
|
|
};
|
|
|
|
int generate_random_entry(struct key_record **entry);
|
|
int generate_random_string(char **dst, const size_t len);
|
|
void free_random_entry(void *entry);
|
|
|
|
void *producer(void *arg)
|
|
{
|
|
struct foo_cache *cache = arg;
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_RANDOM_ENTRIES; i++) {
|
|
struct key_record *entry = NULL;
|
|
if (generate_random_entry(&entry)) {
|
|
fprintf(stderr, "generate_random_entry() failed\n");
|
|
continue;
|
|
}
|
|
#if defined(DEBUG)
|
|
printf("Random Entry:\n");
|
|
printf(" key: %s\n", entry->key);
|
|
printf(" Key: %s\n", entry->value);
|
|
#else
|
|
printf("inserted %s (%d)\n", entry->key,
|
|
(int)strlen(entry->key));
|
|
#endif
|
|
if (foo_cache_insert(cache, entry->key, entry)) {
|
|
fprintf(stderr, "foo_cache_insert() failed\n");
|
|
continue;
|
|
}
|
|
}
|
|
|
|
pthread_exit(NULL);
|
|
}
|
|
|
|
void *consumer(void *arg)
|
|
{
|
|
struct foo_cache *cache = arg;
|
|
struct key_record *result = NULL;
|
|
char *buffer = malloc(64);
|
|
char key[33];
|
|
int stop = 0;
|
|
|
|
if (!buffer)
|
|
goto out;
|
|
|
|
/* give producer time to populate the cache */
|
|
sleep(2);
|
|
printf("\n\n");
|
|
|
|
do {
|
|
memset(key, 0, 64);
|
|
result = NULL;
|
|
|
|
printf("Enter key for lookup: ");
|
|
fgets(buffer, sizeof(key), stdin);
|
|
sscanf(buffer, "%s\n", key);
|
|
/* read '\n' from stdin */
|
|
getchar();
|
|
|
|
if (strncmp(key, "exit", 4) == 0) {
|
|
stop = 1;
|
|
continue;
|
|
}
|
|
|
|
printf("Got key %s (%d)\n", key, (int)strlen(key));
|
|
|
|
if (foo_cache_lookup(cache, key, &result)) {
|
|
fprintf(stderr, "Could not retrieve key %s\n", key);
|
|
continue;
|
|
}
|
|
|
|
if (!result) {
|
|
printf("MISS\n");
|
|
continue;
|
|
}
|
|
|
|
printf("HIT\n");
|
|
printf("key: %s\n", result->key);
|
|
printf("key : %s\n", result->value);
|
|
} while (!stop);
|
|
|
|
out:
|
|
if (buffer)
|
|
free(buffer);
|
|
pthread_exit(NULL);
|
|
}
|
|
|
|
int main()
|
|
{
|
|
int rv;
|
|
struct foo_cache *cache = NULL;
|
|
pthread_t workers[2];
|
|
|
|
rv = foo_cache_create(&cache, MAX_RANDOM_ENTRIES / 2,
|
|
free_random_entry);
|
|
if (rv) {
|
|
fprintf(stderr, "Could not create cache\n");
|
|
exit(1);
|
|
}
|
|
|
|
(void)pthread_create(&workers[0], NULL, producer, (void *)cache);
|
|
(void)pthread_create(&workers[1], NULL, consumer, (void *)cache);
|
|
|
|
pthread_join(workers[0], NULL);
|
|
pthread_join(workers[1], NULL);
|
|
|
|
(void)foo_cache_delete(cache, 0);
|
|
return 0;
|
|
}
|
|
|
|
int generate_random_entry(struct key_record **entry)
|
|
{
|
|
struct key_record *new = NULL;
|
|
char *key = NULL;
|
|
char *value = NULL;
|
|
int rv;
|
|
|
|
if (!entry)
|
|
return EINVAL;
|
|
|
|
rv = generate_random_string(&key, 33);
|
|
if (rv)
|
|
return rv;
|
|
|
|
rv = generate_random_string(&value, 129);
|
|
if (rv)
|
|
return rv;
|
|
|
|
if ((new = malloc(sizeof(*new))) == NULL) {
|
|
free(key);
|
|
free(value);
|
|
return ENOMEM;
|
|
}
|
|
|
|
new->key = key;
|
|
new->value = value;
|
|
|
|
*entry = new;
|
|
return 0;
|
|
}
|
|
|
|
int generate_random_string(char **dst, const size_t len)
|
|
{
|
|
static const char alphanum[] =
|
|
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
size_t i;
|
|
char *s;
|
|
|
|
if (!dst || len == 0)
|
|
return EINVAL;
|
|
|
|
if ((s = malloc(len)) == NULL)
|
|
return ENOMEM;
|
|
|
|
for (i = 0; i < len - 1; i++) {
|
|
s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
|
|
}
|
|
|
|
s[len - 1] = '\0';
|
|
*dst = s;
|
|
return 0;
|
|
}
|
|
|
|
void free_random_entry(void *entry)
|
|
{
|
|
#if defined(DEBUG)
|
|
fprintf(stderr, "In %s: entry @ %p\n", __func__, entry);
|
|
#endif
|
|
struct key_record *record = entry;
|
|
if (!record)
|
|
return;
|
|
if (record->key)
|
|
free(record->key);
|
|
if (record->value)
|
|
free(record->value);
|
|
free(record);
|
|
record = NULL;
|
|
}
|