Buffer Cache

La única manera de terminar el proyecto es empezandolo

Archivos

Deberás crear tus archivos del buffer cache y añadirlos cuando haces un make.

El nombre de los archivos queda a tu discreción pero recuerda que debes de crear un archivo .c y un .h

Un poco de explicación...

Como ya habrás leído, la documentación recomienda empezar por la implementación de un Buffer Cache. ¿No crees sensato hacerles caso? Haremos lo correcto: ¡seguir su recomendación!

A estas alturas ya te habrás dado cuenta que encontrar los errores y arreglarlos requiere una gran inversión de tiempo; y probablemente no dispongas de ese recurso tan valioso cuando llegues aquí.

Ahora sí, comencemos con la implementación del buffer cache.

El buffer cache es simplemente un cache aislado y dedicado a las operaciones del disco. Es decir, este cache sirve cuando se quiere hacer una lectura o escritura al disco duro.

Como asumimos que no se repartieron entre ustedes la fase 3 y fase 4, entonces hallarán muchas cosas en común con la fase 3 y terminarán muy rápido con el cache Aunque, sabemos que algunos se repartieron dichas fases, entonces explicaremos levemente lo que tendrás que hacer.

Para evitar ir a disco cada vez que se necesite leer o escribir un sector, este sector es guardado en el cache y todas las operaciones relacionadas a ese sector se realizan en el cache. Los contenidos del cache se escriben a disco cuando el sector está en dirty y cuando es candidato a reemplazo (*Flashbacks de fase 3*) de lo contrario, no haces nada y reemplazas ese sector.

Este proceso de escribir los contenidos del cache al disco es llamado flush.

Este cache tendrá una capacidad de 64 sectores y recordando un poco, cada sector tiene un tamaño de 512 bytes.

Entonces... ¿qué debemos de hacer? Debemos de realizar lo siguiente:

  1. Crear las estructuras de una entrada del cache (buffer cache entry, resumido a BCE).

  2. Crear la estructura de datos que representará el buffer cache.

  3. Implementar las operaciones del cache.

  4. Implementar una política de reemplazo para las entradas del Buffer Cache.

Objetivos

Implementar un cache relativamente sencillo que será usado para las operaciones de disco.

Implementación

Como te habrás dado cuenta, el buffer cache es muy parecido a la Frame Table que hiciste en la fase 3 del proyecto. Por primera vez me siento muy amable contigo entonces te daré no una mano, si no dos mano y código extra para que te animes y continúes la fase.

Buffer Cache Entry

Entonces, cada "slot" del cache tiene un tamaño de 512 bytes. Como sabes, debemos de almacenar información extra sobre ese "slot" porque no nos sirve guardar información si no sabemos sus detalles.

Como te hice spoiler anteriormente, existe un bit de dirty, ya con eso sabes que existe un vector flag por ahí. También, debemos saber si ese slot ya está en uso o no. Y por último, necesitamos saber qué sector se encuentra en ese "slot" del cache.

Condensando todo en código, tienes lo siguiente:

struct buffer_cache_entry{
    bool used; 
    bool dirty;    
    
    block_sector_t disk_sector;  
    uint8_t buffer[64];
};

¿Ves que también puedo ser misericordioso contigo? Y tú quejándote que no te damos nada de código... en fin, la hipocresía.

Buffer Cache

Te daré una pista: la capacidad del cache es de 64 sectores.

Operaciones del Cache

Las operaciones del cache son 4: allocate, flush, read y write

El allocate lo dejaremos de último.

Flush

Consiste en escribir los contenidos de una entrada del cache al disco duro

void cache_entry_flush (struct buffer_cache_entry * bce) {
	// Tu codiguito aqui :D
}

Read

¡Aquí empieza lo divertido! Cuando el File System quiere extraer la información de un determinado sector, consulta al cache si este sector se encuentra en el cache. Si no se encuentra, debe de esperar a que los contenidos del sector solicitado se encuentren en el cache. De lo contrario, lee los contenidos y operación finalizada.

void cache_read(block_sector_t sector, void * buffer) {
    // tu codiguito aqui :D
}

Write

La misma idea que read, pero ahora estás escribiendo a los contenidos del cache. Recuerda, si no se encuentra el sector solicitado, primero se lee del disco y luego se efectúa la escritura.

void cache_write(block_sector_t sector, void * buffer) {
    // tu codiguito aqui :D
}

Política de Reemplazo

Como bien sugiere la guía, debemos de implementar un algoritmo cuyo performance sea muy similar al Clock Algorithm. Si en la fase 3 hiciste el Clock Algorithm o la variante del Second Chance, es absolutamente copy paste. ¡Qué felicidad! :D

Claro, deberás de modificar la estructura de buffer_cache_entry para que el algoritmo logre funcionar correctamente.

Con la política de reemplazo terminada, lograrás terminar la operación de allocate.

Allocate

Cuando lees un sector del disco y necesitas guardar sus contenidos en alguna entrada del cache, de primero necesitas buscar una entrada del cache que esté libre o escoges un candidato de reemplazo.

De eso se trata la función de allocate: encontrar un BCE libre o si está lleno, escoger un candidato de reemplazo, hacer flush de los contenidos y liberar la entrada asociada.

struct buffer_cache_entry * cache_allocate(void){
    // Tu codiguito aqui :D
}

FAQ

  • ¿El buffer cache es un recurso compartido?

    No lo sé, tu dime.jpg

  • ¿Donde empezaré a usar el buffer cache?

    En la siguiente sección :D

Last updated