Archived
1
0
Fork 0

proc-cache.c: use hash-table code from hash.c

This commit is contained in:
Henrik Hautakoski 2012-04-12 07:46:28 +02:00
parent 5193e8453c
commit 4f05a5ae4f
2 changed files with 51 additions and 134 deletions

View file

@ -11,7 +11,7 @@ install : $(PROGRAMS)
cp $^ $(HOME)/bin/
dlight : dlight.o buffer.o env.o http.o rss.o lockfile.o filter.o cconf.o \
sha1_io.o proc-cache.o dlhist.o error.o
sha1_io.o proc-cache.o dlhist.o hash.o error.o
dlight-compile : compile.o buffer.o env.o lockfile.o filter.o cconf.o \
sha1_io.o error.o
dlight-read-config : read-config.o buffer.o env.o cconf.o sha1_io.o error.o

View file

@ -28,6 +28,7 @@
#include <fcntl.h>
#include <time.h>
#include "env.h"
#include "hash.h"
#include "lockfile.h"
#include "proc-cache.h"
@ -35,10 +36,6 @@
#define SIGNATURE 0xAF445043
#define STORAGE_FILE "proc-cache"
#define TABLE_MIN_SIZE 128
#define HASH_TABLE_LOAD(c, s) ((double) (c) / ((s) ? (s) : 1))
struct header {
unsigned int signature;
unsigned int version;
@ -54,18 +51,13 @@ union hash {
* NOTE: be sure to change this constant if the struct's size changes.
*/
#define HE_SZ (sizeof(union hash) + sizeof(unsigned))
struct hash_entry {
struct proc_cache_entry {
union hash hash;
unsigned int time;
};
#define he_empty(x) (!(x) || (x)->hash.index == 0)
static struct lockfile lock = LOCKFILE_INIT;
static struct hash_entry *table;
static unsigned int table_size;
static unsigned int table_count;
static struct hash_table table = HASH_TABLE_INIT;
static void hash(union hash *h, const char *s) {
@ -84,110 +76,41 @@ static void hash(union hash *h, const char *s) {
SHA1((unsigned char *)s, n, h->sha1);
}
static struct hash_entry* translate(union hash *he) {
unsigned int offset = he->index % table_size;
/* linear probing */
while(!he_empty(table + offset)) {
if (!memcmp(table[offset].hash.sha1, he->sha1, 20))
break;
offset = (offset + 1) % table_size;
}
return table + offset;
}
static struct hash_entry* lookup(const char *key) {
static struct proc_cache_entry* lookup(const char *key) {
union hash h;
hash(&h, key);
return translate(&h);
return hash_lookup(&table, h.index);
}
static inline void he_set(struct hash_entry *he, const char *key) {
static void he_insert(struct proc_cache_entry *entry) {
if (!he_empty(he))
return;
hash(&he->hash, key);
table_count++;
struct proc_cache_entry *dest;
dest = hash_insert(&table, entry->hash.index, entry);
if (dest) {
memcpy(dest, entry, sizeof(*entry));
free(entry);
}
static int he_insert(struct hash_entry *he) {
struct hash_entry *dest = translate(&he->hash);
if (he_empty(dest)) {
memcpy(dest, he, sizeof(*he));
table_count++;
return 1;
}
return 0;
}
static void he_remove(struct hash_entry *he) {
memset(he, 0, sizeof(*he));
table_count--;
}
static unsigned calculate_size(unsigned count) {
/*
* set size to a load factor that is in the
* middle in the valid range.
*/
unsigned size = count / 0.625;
if (size < TABLE_MIN_SIZE)
size = TABLE_MIN_SIZE;
return size;
}
static void resize_table() {
double load;
unsigned int i, old_size = table_size;
struct hash_entry *old = table;
load = HASH_TABLE_LOAD(table_count, table_size);
/* check if resize should be done */
if ((load < 0.5 && table_size <= TABLE_MIN_SIZE) ||
(load >= 0.5 && load <= 0.75))
return;
table_size = calculate_size(table_count);
table_count = 0;
table = calloc(sizeof(*table), table_size);
for(i=0; i < old_size; i++) {
struct hash_entry *he = old + i;
if (!he_empty(he))
he_insert(he);
}
free(old);
}
static void build_table(const char *buf, size_t entries) {
size_t i, offset = 0;
table_size = calculate_size(entries);
table = calloc(sizeof(*table), table_size);
for(i=0; i < entries; i++) {
struct hash_entry entry;
struct proc_cache_entry *entry = calloc(1, sizeof(*entry));
memcpy(&entry.hash, buf + offset, sizeof(entry.hash));
offset += sizeof(entry.hash);
memcpy(&entry->hash, buf + offset, sizeof(entry->hash));
offset += sizeof(entry->hash);
memcpy(&entry.time, buf + offset, sizeof(entry.time));
offset += sizeof(entry.time);
memcpy(&entry->time, buf + offset, sizeof(entry->time));
offset += sizeof(entry->time);
entry.hash.index = ntohl(entry.hash.index);
entry.time = ntohl(entry.time);
entry->hash.index = ntohl(entry->hash.index);
entry->time = ntohl(entry->time);
he_insert(&entry);
he_insert(entry);
}
}
@ -257,48 +180,41 @@ error:
int proc_cache_lookup(const char *url) {
if (table_size) {
struct hash_entry *he = lookup(url);
return !he_empty(he);
}
return 0;
return lookup(url) != NULL;
}
void proc_cache_update(const char *url) {
struct hash_entry *he;
struct proc_cache_entry *entry = lookup(url);
if (table_size < 1)
return;
/*
* set time and key before resize,
* hash_entry pointer is invalid after that operation.
*/
he = lookup(url);
he->time = time(NULL);
if (he_empty(he)) {
he_set(he, url);
resize_table();
if (!entry) {
entry = calloc(1, sizeof(*entry));
hash(&entry->hash, url);
he_insert(entry);
}
entry->time = time(NULL);
}
void proc_cache_purge(unsigned int timestamp) {
unsigned int i, t = 0, now = time(NULL);
unsigned int i, t, now = time(NULL);
if (now < timestamp)
return;
t = now - timestamp;
for(i=0; i < table_size; i++) {
struct hash_entry *entry = table + i;
for(i=0; i < table.size; i++) {
struct proc_cache_entry *entry = hash_entry(&table, i);
if (!he_empty(entry) && entry->time <= t)
he_remove(entry);
if (!entry)
continue;
if (entry->time <= t) {
entry = hash_remove(&table, entry->hash.index);
if (entry)
free(entry);
}
}
resize_table();
}
void proc_cache_flush() {
@ -307,24 +223,21 @@ void proc_cache_flush() {
struct header hdr;
int fd = lock.fd;
if (table_size < 1)
if (table.size < 1)
return;
ftruncate(fd, 0);
lseek(fd, 0, SEEK_SET);
/* Write header */
hdr.signature = htonl(SIGNATURE);
hdr.version = htonl(1);
hdr.entries = htonl(table_count);
hdr.entries = htonl(table.count);
write(fd, &hdr, sizeof(hdr));
/* Write hash entries */
for(i=0; i < table_size; i++) {
struct hash_entry ondisk, *entry = table + i;
for(i=0; i < table.size; i++) {
struct proc_cache_entry ondisk, *entry = hash_entry(&table, i);
if (he_empty(entry))
if (!entry)
continue;
memcpy(&ondisk.hash, &entry->hash, 20);
@ -341,12 +254,16 @@ void proc_cache_flush() {
void proc_cache_close() {
int i;
proc_cache_flush();
release_lock(&lock);
if (table)
free(table);
table = NULL;
table_count = table_size = 0;
for(i=0; i < table.size; i++) {
struct proc_cache_entry *entry = hash_entry(&table, i);
if (entry)
free(entry);
}
hash_free(&table);
}