blob: bfda75af085de49392c910eb146b7aba07b98cd9 [file]
/* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version
* 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* etchrun.c -- runtime data management.
* the runtime cache database is where we cache object vtables etc.
*/
#include <stdio.h>
#include "etch_global.h"
#define ETCH_CACHE_USES_ALPHA_KEY
#define CACHE_DEBUG FALSE
/*
* ETCH_CACHE_USES_ALPHA_KEY switches on alpha cache keys rather than the normal
* 4-byte integer. experiencing a problem with either the hfirst or hnext
* hashtable functionality, this was an attempt to determine if the 4-byte keys
* were causing the problem. it appears not, so we can probably use int keys again.
*/
#ifdef ETCH_CACHE_USES_ALPHA_KEY
#define ETCHCACHEKEYBUFLEN 20
char ckey[ETCHCACHEKEYBUFLEN];
/*
* make_cache_key()
* given 32-bit key constructs alpha key for the cache returning key byte length
*/
int make_cache_key(const unsigned int ikey)
{
char* pkey = ckey;
/* memcpy(pkey+=4,"ca$h",4); */
_itoa_s(ikey, pkey, ETCHCACHEKEYBUFLEN, 10);
return (int)strlen(ckey);
}
/*
* cache_populate_out()
* populate caller's out struct
*/
void cache_populate_out(etch_hashitem* useritem, etch_hashitem* curritem)
{
useritem->key = curritem->key;
useritem->value = curritem->value;
useritem->hash = curritem->hash;
}
/*
* cache_findxl()
*/
void* cache_findxl(char* key, unsigned keylen, void** out)
{
etch_hashitem hashbucket;
etch_hashitem* founditem = &hashbucket;
int result = jenkins_find
(global_cache->realtable, key, keylen, 0, &founditem);
#if CACHE_DEBUG
#pragma warning(disable:4313)
if (result == 0)
printf("cache_found key %s len %d addr %08x\n",
key, keylen, founditem->value);
else printf("cache_notfound key %s len %d\n", key, keylen);
#endif
if (result == -1) return NULL;
if (out)
cache_populate_out(*out, founditem);
return founditem->value;
}
/*
* cache_find()
* locate cached object with specified key, returning it or NULL
*/
void* cache_find(const unsigned int objtype, void** out)
{
unsigned keylen = make_cache_key(objtype);
return cache_findxl(ckey, keylen, out);
}
/*
* cache_findx()
* locate cached object with specified ansi char key, returning it or NULL
*/
void* cache_findx(char* key, void** out)
{
unsigned keylen = (unsigned)strlen(key);
return cache_findxl(key, keylen, out);
}
/*
* cache_find_by_hash()
* locate cached object with specified hashkey, returning it or NULL
*/
void* cache_find_by_hash(const unsigned hash, void** out)
{
int result;
etch_hashitem hashbucket;
etch_hashitem* founditem = &hashbucket;
result = jenkins_findh(global_cache->realtable, hash, 0, &founditem);
if (result == -1) return NULL;
if (out)
cache_populate_out(*out, founditem);
return founditem->value;
}
/*
* cache_current()
* return cached object at current position
*/
etch_hashitem* cache_current()
{
int result;
etch_hashitem hashbucket;
etch_hashitem* founditem = &hashbucket;
result = jenkins_current(global_cache->realtable, 0, &founditem);
return (result == -1)? NULL: founditem;
}
/*
* cache_delxl()
* Remove specified object from cache given ansi char key and length.
* Return pointer to cached object, which is not freed here.
*/
void* cache_delxl (char* key, const unsigned keylen)
{
etch_hashitem hashbucket;
etch_hashitem* founditem = &hashbucket;
int result = jenkins_remove
(global_cache->realtable, ckey, keylen, 0, &founditem);
if (result == -1) return NULL;
free(founditem->key); /* free 4-byte key allocated in cache_add() */
return founditem->value;
}
/*
* cache_del()
* Remove specified object from cache given integer key.
* Return pointer to cached object, which is not freed here.
*/
void* cache_del (const unsigned int objtype)
{
unsigned keylen = make_cache_key(objtype);
return cache_delxl(ckey, keylen);
}
/*
* cache_delx()
* Remove specified object from cache given ansi char key.
* Return pointer to cached object, which is not freed here.
*/
void* cache_delx (char* key)
{
unsigned keylen = (unsigned)strlen(key);
return cache_delxl(key, keylen);
}
/*
* cache_insertxl()
* Add specified object to cache given ansi char key and char length,
* with existence test optional.
* Return hash of supplied key, or zero.
*/
int cache_insertxl (char* key, const unsigned keylen, void* data, const int is_check)
{
int result = 0, keylent = 0;
char* pkey = NULL;
void* pval = NULL;
etch_hashitem hashbucket;
etch_hashitem* inserteditem = &hashbucket;
memset(&hashbucket, 0, sizeof(etch_hashitem));
if (is_check)
{ pval = cache_findxl(key, keylen, &inserteditem);
if (pval) return inserteditem->hash; /* entry exists */
}
keylent = keylen + 1;/* add new entry */
pkey = malloc(keylent);
strcpy_s(pkey, keylent, key);
#if CACHE_DEBUG
#pragma warning(disable:4313)
printf("cache_insertxl key %s len %d addr %08x\n", pkey, keylen, data);
#endif
result = jenkins_insert
(global_cache->realtable, pkey, keylen, data, 0, 0, &inserteditem);
/* cache_dump(); */
return inserteditem->hash;
}
/*
* cache_insert()
* Add specified object to cache with existence test optional.
* Return inserted item hash, or zero.
*/
int cache_insert (const unsigned int key, void* data, const int is_check)
{
int keylen = 0;
void* pval = NULL;
keylen = make_cache_key(key);
return cache_insertxl(ckey, keylen, data, is_check);
}
/*
* cache_insertx()
* Add specified object to cache with existence test optional.
* Return inserted item hash, or zero.
*/
int cache_insertx (char* key, void* data, const int is_check)
{
unsigned keylen = (unsigned)strlen(key);
return cache_insertxl(key, keylen, data, is_check);
}
/*
* cache_add()
* Add specified object to cache given integer key.
* Return 0 or -1.
*/
int cache_add (const unsigned int objtype, void* data)
{
return cache_insert (objtype, data, TRUE);
}
/*
* cache_addx()
* Add specified object to cache.
* Return 0 or -1.
*/
int cache_addx(char* key, void* data)
{
return cache_insertx(key, data, TRUE);
}
#else // #ifdef ETCH_CACHE_USES_ALPHA_KEY
/*
* cache_find()
* locate cached object with specified key, returning it or NULL
*/
void* cache_find(const unsigned int objtype)
{
etch_hashitem hashbucket;
etch_hashitem* founditem = &hashbucket;
int result = jenkins_find
(global_cache->realtable, (char*)&objtype, sizeof(int), 0, &founditem);
return result == -1? NULL: founditem->value;
}
/*
* cache_del()
* Remove specified object from cache.
* Return pointer to cached object, which is not freed here.
*/
void* cache_del (const unsigned int objtype)
{
etch_hashitem hashbucket;
etch_hashitem* founditem = &hashbucket;
int result = jenkins_remove
(global_cache->realtable, (char*)&objtype, sizeof(int), 0, &founditem);
if (result == -1) return NULL;
free(founditem->key); /* free 4-byte key allocated in cache_add() */
return founditem->value;
}
*
* cache_add()
* Add specified object to cache.
* Return pointer to item's data entry, which is not freed here.
*/
int cache_add (const unsigned int objtype, void* data)
{
int result = 0;
char* pkey = 0;
void* pval = cache_find(objtype);
if (pval) return 0; /* entry exists */
pkey = malloc(sizeof(int)); /* add new entry */
memcpy(pkey, &objtype, sizeof(int));
result = jenkins_insert
(global_cache->realtable, pkey, sizeof(int), data, 0, 0, 0);
return result;
}
#endif // #ifdef ETCH_CACHE_USES_ALPHA_KEY
/*
* cache_create()
* create the global cache as an untracked hashtable
*/
etch_hashtable* cache_create()
{
global_cache = new_systemhashtable(INITIAL_CACHE_SIZE_ITEMS);
return global_cache;
}
/*
* cache_clear()
* remove all objects from the runtime list, freeing both key memory and
* data object memory for each. Returns the count of buckets so cleared.
*/
int cache_clear()
{
int result = jenkins_clear(global_cache->realtable, TRUE, TRUE, 0, 0);
return result;
}
/*
* cache_destroy()
* clear the cache and destroy the cache object
*/
int cache_destroy()
{
int result = cache_clear();
result = jenkins_destroy(global_cache->realtable, 0, 0);
return result;
}
/*
* cache_count()
* return number of items in the runtime cache
*/
int cache_count()
{
return jenkins_count(global_cache->realtable, 0, 0);
}
#pragma warning(disable:4311)
/*
* cache_dump()
* debug console display of pointers to each entry in the cache
*/
int cache_dump()
{
etch_hashitem hashbucket;
etch_hashitem* myentry = &hashbucket;
const int count = jenkins_count(global_cache->realtable, 0, 0);
printf("\n%d entries in cache\n",count);
if (count == 0) return 0;
if (0 == jenkins_first(global_cache->realtable, NULL, &myentry))
printf("%08x: %08x\n", *(unsigned*)myentry->key, (unsigned)myentry->value);
else printf("cache.first() failed\n");
while(0 == jenkins_next(global_cache->realtable, NULL, &myentry))
printf("%08x: %08x\n", *(unsigned*)myentry->key, (unsigned)myentry->value);
return count;
}
/*
* - - - - - old list cache code from here on - - - - -
*/
#ifdef ETCH_CACHE_USES_LINKEDLIST
objrec* cache_find(const unsigned int objtype)
{
return objrec_find(objtype);
}
void* cache_get (const unsigned int objtype)
{
return objrec_get(objtype);
}
void* cache_del (const unsigned int objtype)
{
return objrec_del(objtype);
}
objrec* cache_add (const unsigned int objtype, void* data)
{
return objrec_add(objtype, data);
}
int cache_clear()
{
return objtable_clear();
}
int cache_count()
{
return objtable_count();
}
/*
* objrec_find
* look up an object in the runtable
*/
objrec* objrec_find(const unsigned int objtype)
{
objrec* p = runtable;
for(; p; p = p->next)
if (p->obj_type == objtype)
break;
return p;
}
/*
* objrec_get
* look up an object in the runtable, returning its data, or null.
*/
void* objrec_get(const unsigned int objtype)
{
objrec* p = objrec_find(objtype);
return p? p->obj_impl: NULL;
}
#pragma warning (disable:4311) // todo debug stmts
/*
* objrec_add
* if obj rec exists, return it, otherwise add a new obj rec and return it.
*/
objrec* objrec_add(const unsigned int objtype, void* data)
{
objrec* p = objrec_find(objtype);
if (p) return p;
/* we do not track allocations for the tracking hashtable
* since the tracking table does of course not yet exist. */
p = is_memtable_instance?
malloc(sizeof(objrec)):
malloc(sizeof(objrec)); /* we are currently not tracking the cache at all */
/* malloc(sizeof(objrec), ETCHTYPEA_CACHEREC); */
p->obj_type = objtype; p->obj_impl = data; p->next = NULL;
if (runtable == NULL) /* first entry? */
runtable = runtable_tail = p;
else /* chain entry */
{ assert(runtable_tail);
runtable_tail->next = p;
runtable_tail = p; /* added to end - new entry is new tail */
}
/* printf("cache: add %08x\n",(unsigned)p); */
return p;
}
/*
* objrec_del
* Remove specified object record from list and free its bucket memory.
* Return pointer to item's data entry, which is not freed here.
*/
void* objrec_del(const unsigned int objtype)
{
void* data = NULL;
objrec* p = runtable, *prior = NULL;
for(; p; p = p->next)
{
if (p->obj_type != objtype)
{ prior = p; /* not found yet */
continue;
}
if (prior) /* found: chain around this entry */
prior->next = p->next;
/* if last entry, adjust tail ptr */
if (runtable_tail == p)
runtable_tail = prior;
/* if first entry, adjust head ptr */
if (runtable == p)
runtable = prior;
/* save off data, free the bucket */
data = p->obj_impl;
free(p);
/* printf("cache: del %08x\n",(unsigned)p); */
break;
}
return data;
}
/*
* objtable_count
* returns the current count of cache buckets.
*/
int objtable_count()
{
objrec *p = NULL;
int count = 0;
for(p = runtable; p; p = p->next, count++);
return count;
}
/*
* objtable_clear
* remove all objects from the runtime list, freeing bucket memory and
* data memory for each. Returns the count of buckets so cleared.
*/
int objtable_clear()
{
objrec *p = NULL, *nextp = NULL;
int count = 0;
for(p = runtable; p; p = nextp, count++)
{
/* note that we must be careful to not clear the cache before we
are done accessing object vtables */
free(p->obj_impl); /* free data memory */
nextp = p->next;
/* printf("cache: del %08x\n",(unsigned)p); */
free(p); /* free bucket memory */
}
/* printf("cache: %d items cleared\n",count); */
runtable = runtable_tail = NULL;
return count;
}
#endif // #ifdef ETCH_CACHE_USES_LINKEDLIST