Saturday, October 31, 2015

Least Recently Used Cache working example implementation in C

/* program to implement Least Recently Used (LRU) Cache */

#include<stdio.h>
#include<stdlib.h>
// define node for doubly linked list holds pageNumber
typedef struct QNode
{
    struct QNode *prev, *next;
    unsigned int pageNumber;
} QNode;

// Queue - collection of QNodes
typedef struct Queue
{
    unsigned count;
    unsigned numberofFrames;
    QNode *front, *rear;
} Queue;

// hash as collection of pointers to Qnodes and size
typedef struct Hash
{
    int capacity;
    QNode* *array;
}Hash;

QNode* createQNode(int pageNumber)
{
    QNode* qNode = (QNode*) malloc (sizeof(QNode));
    qNode->pageNumber = pageNumber;
    qNode->prev = qNode->next = NULL;
    return qNode;
}

Queue* createQueue(int numberofFrames)
{
    Queue* queue = (Queue*) malloc (sizeof(Queue));
    queue->count = 0;
    queue->front = queue->rear = NULL;
    queue->numberofFrames = numberofFrames;
    return queue;
}

Hash* createHash(int capacity)
{
    Hash *hash = (Hash*) malloc (sizeof(Hash));
    hash->capacity = capacity;

    hash->array = (QNode**) malloc( hash->capacity * sizeof(QNode*));
    int i;
    for(i =0; i< hash->capacity;++i)
    hash->array[i] = NULL;
    return hash;
}

void deQueue (Queue* queue) {
    if (queue->count == 0)
        return ;
    if (queue->front == queue->rear)
        queue->front = queue->rear = NULL;
    QNode* temp = queue->rear;
    queue->rear = queue->rear->prev;

    if(queue->rear)
       queue->rear->next = NULL;

    free(temp);
    if (queue->count > 0)
    queue->count--;
}

void Enqueue (Queue* queue, Hash* hash, unsigned pageNumber)
{
    if (queue->count == queue->numberofFrames) {
        hash->array[queue->rear->pageNumber] = NULL;
        deQueue(queue);
    }

    QNode* temp = createQNode(pageNumber);
    temp->next = queue->front;

    if (queue->count == 0) {
        queue->rear = queue->front = temp;
    } else {
        queue->front->prev = temp;
        queue->front = temp;
    }

    hash->array[pageNumber] = temp;
    queue->count++;
}
// when a page with pageNumber is referenced from cache:
// 1) frame is not present in memory,which needs to be added
//in memory (add at front of queue)
// 2) if page is present with given page number then needs to
// be moved to the front of queue.
void ReferencePage(Queue* queue, Hash* hash, unsigned pageNumber)
{
    QNode* reqPage = hash->array[pageNumber];
    // page is not in cache, add to the queue
    if (reqPage == NULL)
        Enqueue( queue, hash, pageNumber);
    // page is there and not at front, need to move to front
    else if (reqPage != queue->front) {
        reqPage->prev->next = reqPage->next;
        if (reqPage->next)
            reqPage->next->prev =  reqPage->prev;
        if(reqPage == queue->rear)
         {
             queue->rear = reqPage->prev;
             queue->rear->next = NULL;
         }

         reqPage->next = queue->front;
         reqPage->prev = NULL;

         reqPage->next->prev = reqPage;
         queue->front = reqPage;
     }
}


int main()
{
    // create a queue for number of pages to be hold by cache
    Queue* q = createQueue(4);  // 4 pages

    // create hash to reference pages
    Hash* hash = createHash(10);

    ReferencePage( q, hash, 1);
    ReferencePage( q, hash, 2);
    ReferencePage( q, hash, 3);
    ReferencePage (q, hash, 1);
    ReferencePage (q, hash, 4);
    ReferencePage (q, hash, 5);

    // print the cache page frames after the referencing
    printf ("%d", q->front->pageNumber);
    printf("%d", q->front->next->pageNumber);
    printf("%d", q->front->next->next->pageNumber);
    printf("%d\n", q->front->next->next->next->pageNumber);

    return 0;
}

No comments:

Post a Comment