⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cache.c

📁 Win9x下文件系统驱动的例子(EXT2)源代码。
💻 C
📖 第 1 页 / 共 2 页
字号:

		/* 
		 * 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 + -