sigar/src/sigar_cache.c
Doug MacEachern e472dc9d9a add copyright
2006-07-15 17:46:36 +00:00

182 lines
4.3 KiB
C

/*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of SIGAR.
*
* SIGAR is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program is distributed
* in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
#include "sigar.h"
#include "sigar_private.h"
#include "sigar_util.h"
#include <stdio.h>
/*
* hash table to cache values where key is a unique number
* such as:
* pid -> some process data
* uid -> user name
* gid -> group name
*/
#define ENTRIES_SIZE(n) \
(sizeof(sigar_cache_entry_t *) * (n))
/* wrap free() for use w/ dmalloc */
static void free_value(void *ptr)
{
free(ptr);
}
sigar_cache_t *sigar_cache_new(int size)
{
sigar_cache_t *table = malloc(sizeof(*table));
table->count = 0;
table->size = size;
table->entries = malloc(ENTRIES_SIZE(size));
memset(table->entries, '\0', ENTRIES_SIZE(size));
table->free_value = free_value;
return table;
}
#ifdef DEBUG_CACHE
/* see how well entries are distributed */
static void sigar_cache_dump(sigar_cache_t *table)
{
int i;
sigar_cache_entry_t **entries = table->entries;
for (i=0; i<table->size; i++) {
sigar_cache_entry_t *entry = *entries++;
printf("|");
while (entry) {
printf("%lld", entry->id);
if (entry->next) {
printf(",");
}
entry = entry->next;
}
}
printf("\n");
fflush(stdout);
}
#endif
static void sigar_cache_rehash(sigar_cache_t *table)
{
int i;
unsigned int new_size = table->size * 2 + 1;
sigar_cache_entry_t **entries = table->entries;
sigar_cache_entry_t **new_entries =
malloc(ENTRIES_SIZE(new_size));
memset(new_entries, '\0', ENTRIES_SIZE(new_size));
for (i=0; i<table->size; i++) {
sigar_cache_entry_t *entry = *entries++;
while (entry) {
sigar_cache_entry_t *next = entry->next;
sigar_uint64_t hash = entry->id % new_size;
entry->next = new_entries[hash];
new_entries[hash] = entry;
entry = next;
}
}
free(table->entries);
table->entries = new_entries;
table->size = new_size;
}
#define SIGAR_CACHE_IX(t, k) \
t->entries + (k % t->size)
sigar_cache_entry_t *sigar_cache_find(sigar_cache_t *table,
sigar_uint64_t key)
{
sigar_cache_entry_t *entry, **ptr;
for (ptr = SIGAR_CACHE_IX(table, key), entry = *ptr;
entry;
ptr = &entry->next, entry = *ptr)
{
if (entry->id == key) {
return entry;
}
}
return NULL;
}
/* create entry if it does not exist */
sigar_cache_entry_t *sigar_cache_get(sigar_cache_t *table,
sigar_uint64_t key)
{
sigar_cache_entry_t *entry, **ptr;
for (ptr = SIGAR_CACHE_IX(table, key), entry = *ptr;
entry;
ptr = &entry->next, entry = *ptr)
{
if (entry->id == key) {
return entry;
}
}
if (table->count++ > table->size) {
sigar_cache_rehash(table);
for (ptr = SIGAR_CACHE_IX(table, key), entry = *ptr;
entry;
ptr = &entry->next, entry = *ptr)
{
}
}
*ptr = entry = malloc(sizeof(*entry));
entry->id = key;
entry->value = NULL;
entry->next = NULL;
return entry;
}
void sigar_cache_destroy(sigar_cache_t *table)
{
int i;
sigar_cache_entry_t **entries = table->entries;
#ifdef DEBUG_CACHE
sigar_cache_dump(table);
#endif
for (i=0; i<table->size; i++) {
sigar_cache_entry_t *entry, *ptr;
entry = *entries++;
while (entry) {
if (entry->value) {
table->free_value(entry->value);
}
ptr = entry->next;
free(entry);
entry = ptr;
}
}
free(table->entries);
free(table);
}