📄 cache.c
字号:
/*
* Alloc cache object
*/
if (! (Cache=(TCache *) calloc(1, sizeof(TCache))))
{
VxdDebugPrint(D_ERROR, "CacheCreate: could not alloc cache");
goto error_init_cache_1;
}
/*
* Initialise field members
*/
Cache->nrObjects = NrObjects;
Cache->ObjectDataSize = ObjectDataSize;
strncpy(Cache->Name, CacheName, MAX_CACHE_NAME-1);
Cache->Name[MAX_CACHE_NAME-1] = 0;
/*
* For dir. entry caches, allocate space
* to store the data belonging to the objects
*/
if (ObjectDataSize)
{
if ( !(Cache->ObjectDataSpace = malloc(ObjectDataSize * NrObjects)))
{
VxdDebugPrint(D_ERROR, "CacheCreate: could not alloc space for dir. entry cache ");
goto error_init_cache_2;
}
}
/*
* Allocate the cache object list
*/
if ( !(Cache->CacheObjectList = (TCacheObject*) calloc(NrObjects, sizeof(TCacheObject))))
{
VxdDebugPrint(D_ERROR, "CacheCreate: could not alloc cache entries");
goto error_init_cache_3;
}
/*
* For dir. entry cache we have two levels.
* For disk block reference we only have one level
*/
if (ObjectDataSize)
{
/*
* Setup the two LRU heads
*/
Cache->LruHead[0] = Cache->CacheObjectList;
HalfWay = NrObjects / 2;
Cache->LruHead[1] = Cache->LruHead[0] + HalfWay;
/*
* Setup the level 1 cache
*/
CacheObject = Cache->LruHead[0];
for (i=0; i<HalfWay ; i++, CacheObject++)
{
CacheObject->HashNext = CacheObject->HashPrev = 0;
CacheObject->LruNext = CacheObject+1;
CacheObject->LruPrev = CacheObject-1;
CacheObject->Level = LEVEL1;
CacheObject->HashIndex = 0xFFFFu;
CacheObject->ObjectData = ((char *) Cache->ObjectDataSpace) + ObjectDataSize * i;
}
/*
* Fix first+last entries to create circular list
*/
Cache->LruHead[0]->LruPrev = Cache->LruHead[1]-1;
Cache->CacheObjectList[HalfWay - 1].LruNext = Cache->LruHead[0];
/*
* Setup the level 2 cache (dir. entry cache only)
*/
CacheObject = Cache->LruHead[1];
for(i=HalfWay ; i<NrObjects ; i++, CacheObject++)
{
CacheObject->HashNext = CacheObject->HashPrev = 0;
CacheObject->LruNext = CacheObject+1;
CacheObject->LruPrev = CacheObject-1;
CacheObject->Level = LEVEL2;
CacheObject->HashIndex = 0xFFFFu;
CacheObject->ObjectData = ((char *) Cache->ObjectDataSpace) + ObjectDataSize * i;
}
/*
* Fix first+last entries to create circular list
*/
Cache->LruHead[1]->LruPrev = &Cache->CacheObjectList[NrObjects -1];
Cache->CacheObjectList[NrObjects -1].LruNext = Cache->LruHead[1];
}
else
{
/*
* Setup the level 1 cache only
*/
Cache->LruHead[0] = Cache->CacheObjectList;
Cache->LruHead[1] = 0;
CacheObject = Cache->LruHead[0];
for (i=0; i<NrObjects ; i++,CacheObject++)
{
CacheObject->HashNext = CacheObject->HashPrev = 0;
CacheObject->LruNext = CacheObject+1;
CacheObject->LruPrev = CacheObject-1;
CacheObject->Level = LEVEL1;
CacheObject->HashIndex = 0xFFFFu;
}
/*
* Fix first+last entries to create circular list
*/
Cache->LruHead[0]->LruPrev = &Cache->CacheObjectList[NrObjects -1];
Cache->CacheObjectList[NrObjects -1].LruNext = Cache->LruHead[0];
}
/*
* alloc HashQueue, initialised with 0 pointers
*/
Cache->HashSize = NrObjects/HASH_QUEUE_SIZE;
if ( !(Cache->HashQueue = (TCacheObject **) calloc(Cache->HashSize, sizeof(TCacheObject*))))
{
VxdDebugPrint(D_ERROR, "CacheCreate: could not alloc hash_queue");
goto error_init_cache_4;
}
/*
* Create the Mutex, needed to provide for exclusive access
* when updating the cache internal datastructures
* There is no boost needed as we specify the MUTEX_MUST_COMPLETE
* flag. Since we typically run for short moments, it is
* not smart to let the thread preempted when the Mutex is
* claimed
*/
Cache->Mutex = CreateMutex(0, MUTEX_MUST_COMPLETE);
VxdDebugPrint(D_SYSTEM, "CacheCreate: done");
return Cache;
error_init_cache_4:
free(Cache->CacheObjectList);
error_init_cache_3:
if (Cache->ObjectDataSpace)
free(Cache->ObjectDataSpace);
error_init_cache_2:
free(Cache);
error_init_cache_1:
VxdDebugPrint(D_SYSTEM, "CacheCreate: done");
return (TCache*) 0;
}
/*
* Destroys a TCache object
*
* PRE CONDITIONS:
* There must be no more clients that use the TCache object
*
* POST CONDITIONS:
* Cache object and internal data structures are destroyed
*
* IN:
* Cache : pointer to a previously created TCache object
*
* OUT:
* <none>
*
* RETURNS
* <none>
*/
void CacheDestroy(TCache *Cache)
{
TCacheObject *CacheObject;
unsigned i;
VxdDebugPrint(D_SYSTEM, "CacheDestroy: cache=%s, lookups: %lu, hits:%lu",Cache->Name, Cache->nrLookups, Cache->nrHits);
EnterMutex(Cache->Mutex, BLOCK_THREAD_IDLE);
/*
* Free the data belonging to each cache object.
* For dir. entry caches, the cache holds the
* buffer space for all these objects itself.
* For diskblock caches, the DestroyOnFlush
* flag specifies if the cache should delete the
* objects or not. If so, we traverse the objectlist
* and delete each dataobject individually
*/
if (Cache->ObjectDataSpace)
free (Cache->ObjectDataSpace);
else
{
for (i=0, CacheObject=Cache->CacheObjectList; i<Cache->nrObjects ; i++,CacheObject++)
{
if (CacheObject->ObjectData)
free (CacheObject->ObjectData);
}
}
free(Cache->CacheObjectList);
free(Cache->HashQueue);
/*
* First, leave the Mutex (and destroy it) before
* deleting the TCache object itself
*/
LeaveMutex(Cache->Mutex);
DestroyMutex(Cache->Mutex);
free(Cache);
VxdDebugPrint(D_SYSTEM, "CacheDestroy: done");
}
/*
* Lookup an cache object by Id
*
* PRE CONDITIONS:
* Cache object should be valid.
* ObjectData should be point to a buffer large enough to hold
* either the the data belonging to the cache object
* (dir. entry cache) or the pointer to the data
* (diskblock cache)
*
* POST CONDITIONS:
* Dir entry cache:
* If the object being looked up for is in the cache, it is
* lifted to level 2 (if not already there). The found cache
* object is marked as the most recently used object. The data
* belonging to the found cache item is copied to the caller's
* buffer space pointed to by Data.
* Diskblock caches:
* If the object being lookup for is in the cache, it is removed
* from the cache and the _pointer_ to the object's data is
* copied to the buffer Data is pointing to.
*
* IN:
* Cache: pointer to valid TCache object
* MediumId: Id of the medium on which the objects reside
* ObjectId: id of the object
*
* OUT:
* ObjectData: pointer to caller's buffer space
*
* RETURNS:
* TRUE: when the object is found
* FALSE: otherwise
*
*/
BOOL CacheLookupById(TCache *Cache, unsigned long MediumId, unsigned long ObjectId, void *ObjectData)
{
BOOL Rval;
EnterMutex(Cache->Mutex, BLOCK_THREAD_IDLE);
Rval = CacheLookupByNameOrId(Cache, MediumId, ObjectId, 0, 0, ObjectData);
LeaveMutex(Cache->Mutex);
return Rval;
}
/*
* Lookup an cache object by Id and by Name
*
* PRE CONDITIONS:
* Cache object should be valid.
* ObjectData should be point to a buffer large enough to hold
* either the the data belonging to the cache object
* (dir. entry cache) or the pointer to the data
* (diskblock cache)
*
* POST CONDITIONS:
* Dir entry cache:
* If the object being looked up for is in the cache, it is
* lifted to level 2 (if not already there). The found cache
* object is marked as the most recently used object. The data
* belonging to the found cache item is copied to the caller's
* buffer space pointed to by Data.
* Diskblock caches:
* If the object being lookup for is in the cache, it is removed
* from the cache and the _pointer_ to the object's data is
* copied to the buffer Data is pointing to.
*
* If NameLen > 16, CacheLookupByName returns FALSE
*
* IN:
* Cache: pointer to valid TCache object
* MediumId: Id of the medium on which the objects reside
* ObjectId: id of the object
* ObjectName: Name of the object (need not be zero-terminated)
* NameLen: Length of the object's name
*
* OUT:
* ObjectData: pointer to caller's buffer space
*
* RETURNS:
* TRUE: when the object is found
* FALSE: otherwise
*
*/
BOOL CacheLookupByName(TCache *Cache, unsigned long MediumId, unsigned long ObjectId, const char *ObjectName, unsigned NameLen, void *ObjectData)
{
BOOL Rval;
/*
* Long ObjectNames were just not cached :-)
*/
if (NameLen > MAX_OBJECT_NAME)
return FALSE;
/*
* Synchronised access to the Cache
*/
EnterMutex(Cache->Mutex, BLOCK_THREAD_IDLE);
Rval = CacheLookupByNameOrId(Cache, MediumId, ObjectId, ObjectName, NameLen, ObjectData);
LeaveMutex(Cache->Mutex);
return Rval;
}
/*
* Add an object to the cache
*
* PRE CONDITIONS:
* Cache object should be valid.
* dir. entry caches:
* ObjectData should point to a buffer with at least the same
* size of the Cache's objectsize
* diskblock caches:
* ObjectData should point to a valid block of memory that can
* be freed by the Cache if the object need to be flushed
*
* POST CONDITIONS:
* dir. entry caches:
* The object is copied to the cache and marked most recently
* used. It does not matter if a previous copy of the object is
* still in the cache. Eventhough a previous copy will not be
* overwritten by this copy, it is garantueed that subsequent
* lookups on this object will return the last added copy.
* If the cache is full, the least recently used object is
* released from the cache.
* Diskblock caches:
* The pointer is copied in the cache and marked as most recently
* used. If the cache was full, the least recently used object
* is destroyed, that is, the memory is freed.
* It _does_ matter if a previously copy is still in the
* cache, as both point to the same memory. The oldest pointer
* may be flushed, resulting in the second pointer pointing
* to invalid memeory.
*
* If NameLen > 16, CacheAddById ignored the object and don't
* caches it.
*
* IN:
* Cache: pointer to valid TCache object
* MediumId: Id of the medium on which the objects reside
* ObjectId: id of the object
* ObjectData: pointer to caller's buffer space
*
* OUT:
* <none>
*
* RETURNS:
* <none>
*
*/
void CacheAddById(TCache *Cache, unsigned long MediumId, unsigned long ObjectId, void *ObjectData)
{
/*
* Synchronised access to the Cache
*/
EnterMutex(Cache->Mutex, BLOCK_THREAD_IDLE);
CacheAddByNameOrId(Cache, MediumId, ObjectId, 0, 0, ObjectData);
LeaveMutex(Cache->Mutex);
}
/*
* Add an object to the cache
*
* PRE CONDITIONS:
* Cache object should be valid.
* dir. entry caches:
* ObjectData should point to a buffer with at least the same
* size of the Cache's objectsize
* diskblock caches:
* ObjectData should point to a valid block of memory that can
* be freed by the Cache if the object need to be flushed
*
* POST CONDITIONS:
* dir. entry caches:
* The object is copied to the cache and marked most recently
* used. It does not matter if a previous copy of the object is
* still in the cache. Eventhough a previous copy will not be
* overwritten by this copy, it is garantueed that subsequent
* lookups on this object will return the last added copy.
* If the cache is full, the least recently used object is
* released from the cache.
* Diskblock caches:
* The pointer is copied in the cache and marked as most recently
* used. If the cache was full, the least recently used object
* is destroyed, that is, the memory is freed.
* It _does_ matter if a previously copy is still in the
* cache, as both point to the same memory. The oldest pointer
* may be flushed, resulting in the second pointer pointing
* to invalid memeory.
*
* If NameLen > 16, CacheAddByName ignored the object and don't
* caches it.
*
* IN:
* Cache: pointer to valid TCache object
* MediumId: Id of the medium on which the objects reside
* ObjectId: id of the object
* ObjectData: pointer to caller's buffer space
* ObjectName: Name of the object
* ObjectLen: Length of the object's name
*
* OUT:
* <none>
*
* RETURNS:
* <none>
*
*/
void CacheAddByName(TCache *Cache, unsigned long MediumId, unsigned long ObjectId, char *ObjectName, unsigned NameLen, void *ObjectData)
{
/*
* Synchronised access to the Cache
*/
/*
* Long ObjectNames were just not cached :-)
*/
if (NameLen > MAX_OBJECT_NAME)
return;
EnterMutex(Cache->Mutex, BLOCK_THREAD_IDLE);
CacheAddByNameOrId(Cache, MediumId, ObjectId, ObjectName, NameLen, ObjectData);
LeaveMutex(Cache->Mutex);
}
/*
* Returns the statistics for a cache object
*
* PRE CONDITIONS:
* Cache object should be valid. Both pointers should point
* to memory large enough to store a long
*
* POST CONDITIONS:
* The number of lookups and hits on the cache are returned
*
* IN:
* Cache: pointer to valid TCache object
*
* OUT:
* Lookup: Pointer to unsigned long in which the number of
* lookups on the cache is returned
* Hits: Pointer to unsigned long in which the number of
* hits on the cache is returned
*
* RETURNS:
* <none>
*
*/
void CacheGetStats(TCache *Cache, unsigned long *Lookups, unsigned long *Hits)
{
*Lookups = Cache->nrLookups;
*Hits = Cache->nrHits;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -