LRU Cache Design🛠
Tags: design, architecture
Published: 2019-11-26 14:39:57

## What is Cache?
A cache is a hardware or software component that stores data so that future requests for that data can be served faster; the data stored in a cache might be the result of an earlier computation or a copy of data stored elsewhere.

## What Is An LRU Cache?
So a Least Recently Used (LRU) Cache is a storage of items so that future access to those items can be serviced quickly and an LRU policy is used for cache eviction.

## Why do we need Caches? 
Basically, computers are processing operations on data which is stored in main memory, for example hard disks. Unfortunately, reading and writing data directly from/to disks is not efficient, so we need to predict, what are the blocks of data which is more likely to be processed by the processor to put in the cache.

Now you can guess that cache is the nearest/fastest place for the processor to get the data (if found) from. So why don't we just use caches for all the data processing? There are two main reasons, firstly caches store the data temporarily, when there is no electric power all the data disappears. Secondly caches are expensive and have limited __capacity__.

So we need to define the method by which we would choose the data blocks that will be into our cache, in order to minimize the possibility of reading/writing from the disk. This method depends on the principle of **Locality of reference**.


## Locality of reference 

Since size of cache memory is less as compared to main memory. So to check which part of main memory should be given priority and loaded in cache is decided based on locality of reference.

### Types of Locality of reference

#### Spatial Locality of reference

This says that there is a chance that element will be present in the close proximity to the reference point and next time if again searched then more close proximity to the point of reference.

#### Temporal Locality of reference

In this Least recently used algorithm will be used. Whenever there is page fault occurs within a word will not only load word in main memory but complete page fault will be loaded because spatial locality of reference rule says that if you are referring any word next word will be referred in its register that’s why we load complete page table so the complete block will be loaded.


## Removal policies

At some point, cache size will hit it maximum capacity. It must replace some blocks to receive new ones. There are multiple applies policies.

- First in first out (FIFO)
- Last in first out (LIFO)
- Least recently used (LRU)
- Most recently used (MRU)
- Least-frequently used (LFU)

I will pick the LRU policy to design a LRU Cache.

## LRU Cache example 

Let's assume that there is a cache of capacity 3.
The cache contains { 5 , 4 ,1 } and there is a operation to be done which is put(6)

<a href="https://ibb.co/nBJWjJY"><img src="https://i.ibb.co/9h5MW51/1.jpg" alt="1" border="0"></a>
<a href="https://ibb.co/9YgYBwj"><img src="https://i.ibb.co/q1j1h0w/2.jpg" alt="2" border="0"></a>
<a href="https://ibb.co/H4pCK3r"><img src="https://i.ibb.co/DWgY1T7/3.jpg" alt="3" border="0"></a>
<a href="https://ibb.co/X7xgJq0"><img src="https://i.ibb.co/CbKZ0fC/4.jpg" alt="4" border="0"></a>
<a href="https://ibb.co/dGnwtWC"><img src="https://i.ibb.co/qkb3Cyq/5.jpg" alt="5" border="0"></a>


## Design LRU Cache

### Requirements 

Least Recently Used (LRU) cache should support the following operations: 

- get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.

- put(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.

Constrains: 
- Cache capacity: initialized with a positive capacity.
- Key: positive number.
- Lookup of cache items must be O(1)
- Addition to the cache must be O(1)
- The cache should evict items using the LRU policy

### Data Structures 
Thinking about the data structures that will be used in designing is the most important step. To make it easier, let's analyze the requirements.

- Get(key): Fast look up in O(1) time complexity.
- Put(key , value): Look up O(1) and if the size hits the capacity evict LRU in O(1).

So let's think about data structures that might help to achieve this two functionalities in O(1) time complexity. 
A **Hash table** is what we look for most of the times when we need O(1) look ups, but how would if help us in knowing the LRU element? there must be another helpful data structure.
Most of the answers might be dynamic arrays, trees or linked lists, all of these data structures will face a time complexity problem while deleting (like arrays) or while inserting (like linked lists).
A helpful data structure which can delete in O(1) is **Doubly linked list** . So YES we have got the data structures that can achieve the requirements.

- Doubly linked list for fast removal.
    *  A node contains key and value.
- The Doubly linked list is supported by a Hash table for fast access.
    * The key is the input key and the value is a pointer to the corresponding node in the doubly linked list.

#### Let's dive into an example of a LRU Cache of size 3 

* put(1,5)
* put(2,17) 
* put(3,99) 
* put(4,1) 
* get(2)

<a href="https://ibb.co/q7tMqG5"><img src="https://i.ibb.co/8NWDv3c/6.jpg" alt="6" border="0"></a>
<a href="https://ibb.co/C7P2XDL"><img src="https://i.ibb.co/7Wk4TLh/7.png" alt="7" border="0"></a>
<a href="https://ibb.co/02bbgJW"><img src="https://i.ibb.co/ZXDDnTw/8.jpg" alt="8" border="0"></a>
<a href="https://ibb.co/2FfsWn6"><img src="https://i.ibb.co/qDPW7yn/9.jpg" alt="9" border="0"></a>
<a href="https://ibb.co/xYX3f10"><img src="https://i.ibb.co/sCbt6KG/10.jpg" alt="10" border="0"></a>
<a href="https://ibb.co/q59xfC8"><img src="https://i.ibb.co/xHG30Yb/11.jpg" alt="11" border="0"></a>
<a href="https://ibb.co/QpGnvzR"><img src="https://i.ibb.co/HBQYT1s/12.jpg" alt="12" border="0"></a>
<a href="https://ibb.co/r3WBqkt"><img src="https://i.ibb.co/nBWX4r0/13.jpg" alt="13" border="0"></a>

## Is LRU policy the best choice?
Definitely, every policy has pros and cons, one could perfectly work in some conditions but other conditions no. So choosing the suitable policy is affected by the type of your business.

#### Helpful references 

[Implement An LRU Cache - The LRU Cache Eviction Policy ("LRU Cache" on LeetCode)](https://www.youtube.com/watch?v=S6IfqDXWa10)
[Leetcode problem](https://leetcode.com/problems/lru-cache/)
[Geeksforgeeks](https://www.geeksforgeeks.org/cache-memory-in-computer-organization/)

#### You can also find me on 

[Linkedin](https://www.linkedin.com/in/amrable/)
[Github](https://github.com/amrable)
[Twitter](https://twitter.com/amrable)