A Simple LRU Cache Implementation

LRU Cache is a caching strategy where we use Least Recently Used (LRU) eviction policy when the cache is full and we want to add more new data to the cache. LRU cache is used in many caching applications. For example memcached uses LRU cache.

I have implemented a simple LRU Cache. The code is far from production use. First of all it is not thread safe and I have not used template programming to make it generic. The code is just to illustrate one of the possible ways of implementing an LRU Cache.

The implementation is inspired from Sun Java LinkedHashMap implementation. For serious production use one should use the LinkedHashMap implementation. The code here is just to illustrate the data structure used.

I have used a doubly-linked list and a hashmap. All the key-value pairs are saved in a node of doubly-linked list and these nodes are hashed on the key in the hashmap. This allows for O(1) time access. The node corresponding to the most recently used key-value pair is always at the head of the linked list and the node corresponding to the least recently used key-value pair is always at the tail of the linked list. Time complexity for ‘get’ and ‘put’ operation is O(1) and the space complexity is O(n), where n is the maximum capacity of cache.

Here goes the code -


public class Node {

  public Node prev;
  public Node next;
  public String key;
  public String data;

  public Node()
  {
  }

  public Node(String key, String data)
  {
    this.key = key;
    this.data = data;
  }
}
import java.util.*;

public class LRUCache {

  private Node head;
  private Node tail;
  private int maxSize;
  private HashMap<String, Node> m = new HashMap<String, Node>();

  // Constructor - maxSize is the maximum capacity of the cache
  public LRUCache(int maxSize)
  {
    this.maxSize = maxSize;
    head = new Node(null, null);
    tail = new Node(null, null);
    head.next = tail;
    tail.prev = head;
  }

  private void addElementToListAtHead(Node node)
  {
    node.next = head.next;
    node.prev = head;
    head.next.prev = node;
    head.next = node;
  }

  private void removeElementFromList(Node node)
  {
    node.prev.next = node.next;
    node.next.prev = node.prev;
  }

  // Function to access data from the cache
  public String get(String key)
  {
    Node node = m.get(key);
    if(node == null)
      return null;

    if(m.size() == 1)
      return node.data;

    removeElementFromList(node);
    addElementToListAtHead(node);
    return node.data;
  }

  // Function to add new data or modify existing data in the cache
  public void put (String key, String data)
  {
    if(maxSize <= 0)
      return;

    Node node = m.get(key);
    if (node != null)
    {
      removeElementFromList(node);
      addElementToListAtHead(node);
      node.data = data;
    } else {
      node = new Node(key, data);
      m.put(key, node);
      addElementToListAtHead(node);
      if(m.size() > maxSize)
      {
        m.remove(tail.prev.key);
        removeElementFromList(tail.prev);
      }
    }
    return;
  }
}

Please point out the obvious/non-obvious bugs in the code. And also provide suggestions for better implementation.

Posted in Algorithm, Caching Algorithm, Data Structure, Linked HashMap | Tagged , , , , | Leave a comment

Perplexing Probability – Things are not always obvious

Note: Below mentioned story is a purely hypothetical one. Think of it as just another probability problem. Don’t get into the complexities of real world. Everything you need to ponder upon is already mentioned in the story.

After the recent India-SA test series, the big question is which is the better test team. Obviously, if we go by test rankings India is currently the number 1 test team and the mighty SA the second in the list. But ICC decided to organize a three match series between the two sides to decide the ultimate team. They propose to Indian cricket team – if they can win at least two consecutive matches they will be declared the number 1 team of all times. The three matches will be played alternatively in India and South Africa. The Indian team can decide the order, either they can choose to play in India-SA-India or SA-India-SA. The ICC also lifted up the 5 day constraint – which means each match will end up with a result for sure, no draw. For quite obvious reasons the probability of India winning a match in India is more than India winning a match in SA.

Now the question in front of BCCI is to select the order of venues to maximize the probability of India becoming the best test team of all times.

BCCI first came up with the order – India-SA-India, which also sounds obvious. But, when they later realized that India has to win at least two consecutive matches to prove their supremacy, they changed the order to SA-India-SA which is not so obvious but of course the correct strategy (at least probabilistically).

Do some calculations yourself to appreciate the BCCI’s final decision.

Posted in Probability | Tagged | 3 Comments

What’s wrong with binary search!

There’s a bug in the code of “Binary Search” as most of us write it. When asked most of us code binary search as -

int binary_search(int *a, int len, int key)
{
int low = 0;
int high = len-1;

while (low <= high)
{
int mid = (low+high)/2;
int val = a[mid];

if (val < key)
{
low = mid + 1;
} else if (val > key)
{
high = mid - 1;
} else
{
return mid;
}
}
return -1;
}

Now, try to find the bug in the above code. The bug surfaces if the array is too large. If the length of the array is too large, line number 8 in the above code would cause the variable “mid” to overflow and hence will have a negative number and the code breaks. A very simple solution would be to replace line 8 in the above code with -

mid = low + (high-low)/2;

So, you see how bugs could creep in your code. To see more detailed discussion on how the bug was discovered and a couple of more elegant, efficient solutions check out this Google Research blog – http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html

Posted in Algorithm, Binary Search, Google | Tagged , , , , | 7 Comments

What’s been keeping me busy these days?

Of late, I have not been adding new pages to my blog. A lot has changed since I last blogged. From an undergrad student at IIT Guwahati to a Software Developer at Adobe India now. Transitioning from one role to another took a lot of time. Now, when I think, I am probably comfortable in the new role, I have started exploring new stuffs. I will enumerate few of the interesting stuffs I have been looking into since last one month or so.

  • Page Replacement Algorithms – I have been digging into various page/memory replacement algorithms. For the uninitiated ones here is the wikipedia page which explains various of those algorithms in short – http://en.wikipedia.org/wiki/Page_replacement_algorithm . I explored the memcached cache replacement policy and its implementation. I will write more about my reading on this subject in my later posts. I will also try to attach implementations of few of the algorithms.
  • OpenStackOpenstack is anĀ IaaS Cloud Computing open source project started by Rackspace and NASA. There are basically two sub projects of Openstack – Nova and Swift. I have read the overview of both the sub projects and I am trying to dig more into Nova. I would love to contribute to this awesome project and will start off soon by accomplishing some low hanging fruits of Nova. Will write more about my experience and technical insights I gain in my later posts.
  • Art of Trading – I have been looking into various articles related to algorithmic trading. I started off with Optimal Stopping Theorem. Depth first search of the wikipedia article led me to Search Theory, Odds Algorithm, the interesting The Marriage Problem. But things start getting mathematically complex once I start digging into Automated Trading Algorithms. ATQs use techniques from signal processing, game theory, gambling Kelly Criterion and time series analysis. Miles to go. Phew!

And yeah, I have also been listening to two songs continuously (read frequently) these days – Madno Re from Lamhaa (2010) and Naam Adaa Likhna from Yahaan (2005).

Posted in Life, Memory Management Algorithms, Nova, OpenStack, Page Replacement Algorithms, Swift, Trading Algorithm | Tagged , , , , , , , , | 2 Comments

IITG Webmail Extension – Auto Login Feature

Note: This post is only for currently enrolled IITG students.

Today I added a new feature to the “IITG webmail chrome extension” – Auto Login feature. Now you can save your username and password in the options page of the extension and enable auto-login. After enabling auto-login feature, whenever you open http://webmail.iitg.ernet.in, the extension will automatically redirect you to your inbox.

Check out the screenshots at the extension page: https://chrome.google.com/extensions/detail/ljfkohgffehmmfnmghdlbceidmddgdob?hl=en-us

All those who are already using this extension can update it by clicking “Update extensions now” button in chrome://extensions page. New users can directly install the extension at: https://chrome.google.com/extensions/detail/ljfkohgffehmmfnmghdlbceidmddgdob?hl=en-us

Keep pouring in your feedback by posting comments.

Posted in Chrome, IITG, IITG webmail | Tagged , , , | Leave a comment