📄 cache.c
字号:
/*-------------------------------------------------------------------*/
/* Set the LRU head to first and LRU tail to last entry in pool. */
/*-------------------------------------------------------------------*/
C->lru_head = &C->pool[0];
C->lru_tail = &C->pool[C->pool_size - 1];
}
/***********************************************************************/
/* DestroyCache: Deallocate all the memory taken by cache C */
/* */
/* Input: C = cache to be deleted */
/* */
/***********************************************************************/
void DestroyCache(Cache *C)
{
/*-------------------------------------------------------------------*/
/* Write back all the dirty sectors. */
/*-------------------------------------------------------------------*/
FlushSectors(C);
/*-------------------------------------------------------------------*/
/* Deallocate the memory for the pool and the hash table. */
/*-------------------------------------------------------------------*/
free(C->pool[0].sector);
free(C->pool);
free(C->hash_tbl);
/*-------------------------------------------------------------------*/
/* Null out the LRU head and tail. */
/*-------------------------------------------------------------------*/
C->lru_head = C->lru_tail = NULL;
}
/***********************************************************************/
/* GetSector: Return pointer to cache entry containing the specified */
/* sector number, bringing the sector into the cache if */
/* not already there. */
/* */
/* Inputs: C = cache pointer */
/* sector_number = sector to return pointer to */
/* skip_read = if TRUE, don't read new sector from media */
/* file_ptr = pointer to file control information */
/* entry_ptr = cache entry with new sector */
/* */
/* Returns: GET_OK on success, GET_WRITE_ERROR on write error, */
/* GET_READ_ERROR on read error */
/* */
/***********************************************************************/
int GetSector(Cache *C, int sector_number, int skip_read, void *file_ptr,
CacheEntry **entry_ptr)
{
int index, r_val = GET_OK;
CacheEntry *entry;
/*-------------------------------------------------------------------*/
/* Remember the current sector being chached and get the head of the */
/* list in which the corresponding entry would be in the cache. */
/*-------------------------------------------------------------------*/
C->sector_number = sector_number;
entry = C->hash_tbl[hash(C->sector_number, C->pool_size)];
/*-------------------------------------------------------------------*/
/* Look first if sector is already in the cache. */
/*-------------------------------------------------------------------*/
for (; entry; entry = entry->next_hash)
if (entry->sect_num == C->sector_number)
{
/*---------------------------------------------------------------*/
/* If entry is on replacer list, take it out. */
/*---------------------------------------------------------------*/
if (entry->pin_cnt++ == 0)
remove_from_replacer(entry, C);
*entry_ptr = entry;
return r_val;
}
/*-------------------------------------------------------------------*/
/* The sector is not in the cache. Choose one to replace with LRU */
/* replacement policy. */
/*-------------------------------------------------------------------*/
entry = C->lru_head;
remove_from_replacer(C->lru_head, C);
/*-------------------------------------------------------------------*/
/* There should always be an available sector. */
/*-------------------------------------------------------------------*/
PfAssert(entry);
/*-------------------------------------------------------------------*/
/* If dirty sector, write it back to its medium. */
/*-------------------------------------------------------------------*/
if (entry->dirty != CLEAN && C->write(entry, FALSE))
{
entry->dirty = CLEAN;
put_into_tail(entry, C);
*entry_ptr = NULL;
return GET_WRITE_ERROR;
}
/*-------------------------------------------------------------------*/
/* If the entry is in the hash table, remove it from there. */
/*-------------------------------------------------------------------*/
if (entry->hash_loc)
{
/*-----------------------------------------------------------------*/
/* If entry is not first, update previous one, else update head. */
/*-----------------------------------------------------------------*/
if (entry->prev_hash)
entry->prev_hash->next_hash = entry->next_hash;
else
*(entry->hash_loc) = entry->next_hash;
/*-----------------------------------------------------------------*/
/* If next entry needs to be updated, update it. */
/*-----------------------------------------------------------------*/
if (entry->next_hash)
entry->next_hash->prev_hash = entry->prev_hash;
}
/*-------------------------------------------------------------------*/
/* Read new sector into the cache if skip_read is not set. */
/*-------------------------------------------------------------------*/
if (skip_read == FALSE &&
C->read(entry->sector, (ui32)C->sector_number))
{
set_errno(EIO);
r_val = GET_READ_ERROR;
}
/*-------------------------------------------------------------------*/
/* Set entry for new sector. */
/*-------------------------------------------------------------------*/
entry->sect_num = C->sector_number;
entry->dirty = CLEAN;
entry->pin_cnt = 1;
entry->file_ptr = file_ptr;
/*-------------------------------------------------------------------*/
/* Add new entry into the hash table. */
/*-------------------------------------------------------------------*/
index = hash(C->sector_number, C->pool_size);
entry->prev_hash = NULL;
if (C->hash_tbl[index])
{
entry->next_hash = C->hash_tbl[index];
C->hash_tbl[index]->prev_hash = entry;
}
else
entry->next_hash = NULL;
C->hash_tbl[index] = entry;
entry->hash_loc = &C->hash_tbl[index];
/*-------------------------------------------------------------------*/
/* No need to remember the sector being cached any longer. */
/*-------------------------------------------------------------------*/
C->sector_number = -1;
*entry_ptr = entry;
return r_val;
}
/***********************************************************************/
/* FlushFileSectors: Flush all sectors belonging to a file */
/* */
/* Inputs: C = cache for which flush is to be performed */
/* file_ptr = pointer to file */
/* */
/* Returns: NULL on success, (void)-1 on failure */
/* */
/***********************************************************************/
void *FlushFileSectors(Cache *C, const void *file_ptr)
{
int i;
void *r_val = NULL;
/*-------------------------------------------------------------------*/
/* If no dirty sectors, return success. */
/*-------------------------------------------------------------------*/
if (!C->dirty_old && !C->dirty_new)
return NULL;
/*-------------------------------------------------------------------*/
/* Loop over cache entries, flushing each one. */
/*-------------------------------------------------------------------*/
C->dirty_old = C->dirty_new = FALSE;
for (i = 0; i < C->pool_size; ++i)
{
/*-----------------------------------------------------------------*/
/* If sector is not clean, either it belongs to the file or have */
/* to set the dirty flag. */
/*-----------------------------------------------------------------*/
if (C->pool[i].dirty != CLEAN)
{
/*---------------------------------------------------------------*/
/* If it belongs to the file, write it and mark it clear. */
/*---------------------------------------------------------------*/
if (C->pool[i].file_ptr == file_ptr)
{
if (C->write(&C->pool[i], TRUE))
r_val = (void *)-1;
C->pool[i].dirty = CLEAN;
}
/*---------------------------------------------------------------*/
/* Else, mark the appropriate flag. */
/*---------------------------------------------------------------*/
else if (C->pool[i].dirty == DIRTY_NEW)
C->dirty_new = TRUE;
else
C->dirty_old = TRUE;
}
}
return r_val;
}
/***********************************************************************/
/* FlushSectors: Go through cache and flush all dirty sectors */
/* */
/* Input: C = cache for which flush is to be performed */
/* */
/* Returns: -1 on failure, 0 if no sectors written, 1 otherwise */
/* */
/***********************************************************************/
int FlushSectors(Cache *C)
{
int i, r_val = 0, written;
/*-------------------------------------------------------------------*/
/* If no dirty sectors, return. */
/*-------------------------------------------------------------------*/
if (!C->dirty_old && !C->dirty_new)
return 0;
/*-------------------------------------------------------------------*/
/* Loop over cache entries, flushing each one. */
/*-------------------------------------------------------------------*/
for (i = 0, written = FALSE; i < C->pool_size; ++i)
{
/*-----------------------------------------------------------------*/
/* If sector is not clean, write it and then mark it clean. */
/*-----------------------------------------------------------------*/
if (C->pool[i].dirty != CLEAN)
{
written = TRUE;
if (C->write(&C->pool[i], TRUE))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -