This commit is solution to lab4, Caching Locks

git status
 On branch master
 Changed but not updated:
   (use "git add <file>..." to update what will be committed)
   (use "git checkout -- <file>..." to discard changes in working directory)

   modified:   lock_client_cache.cc
   modified:   lock_client_cache.h
   modified:   lock_server.cc
   modified:   lock_server.h
   modified:   lock_server_cache.cc
   modified:   lock_server_cache.h
   modified:   lock_smain.cc
   modified:   rpc/rpc.cc
   modified:   yfs_client.cc
   modified:   yfs_client.h

Design
======
Lock Client Cache
-----------------
clientcacheMap: Stores the state of locks(as per below struct) in a Map.
struct lock_cache_value {
    l_cache_state lock_cache_state; // State of the lock cache
    thread_mutex_t client_lock_mutex; // To protect this structure
    pthread_cond_t client_lock_cv; // CV to be notified of state chang
    pthread_cond_t client_revoke_cv; // CV to be notified if lock is revoked
};
client_cache_mutex: To protect clientcacheMap

It supports acquire, release and listens on revoke and retry.

Releaser, Retryer Threads:
-On init, we spawn two threads, releaser and retryer (mutex and CVs are dedicated for each for synchronization)
-Releaser will listen on a list and release the lock if it is in FREE state or set the state to RELEASING and
wait on client_revoke_cv to be set by the next release request from the client. Once it is released by the client,
it sends release request to server
-Retryer will listen on a list and sends acquire request to server for each lockid. Upon successful response, it notifies
threads that are waiting on client_lock_cv.

Acquire:
The course of action depends on the state of the lockid.
1)NONE: We send acquire to server and set the state to ACQUIRING. On OK response, state is set to LOCKED.
On RETRY response, we wait on client_lock_cv. Upon wakeup, if the state is not FREE, we loop back so that the next course of
action depends on the current state
2)FREE: State is set to LOCKED
3)Otherwise: we wait on client_lock_cv. Upon wakeup, if the state is not FREE, we loop back so that the next course of
action depends on the current state

Release:
If the state of lock is RELEASING, we signal client_revoke_cv. For LOCKED, we signal client_lock_cv.

Lock Server Cache
-----------------
Server is generally designed to be non-blocking and care is taken not to make RPC calls within acquire/release calls.

tLockMap: Stores the state of locks(as per below struct) in a Map.
struct lock_cache_value {
l_state lock_state;
std::string owner_clientid; // used to send revoke
std::string retrying_clientid; // used to match with incoming acquire request
std::list<std::string> waiting_clientids; // need to send retry
};
lmap_mutex: Global lock to synchronize

It supports acquire, release

Releaser, Retryer Threads:
-On init, we spawn two threads, releaser and retryer (mutex and CVs are dedicated for each for synchronization)
-Releaser will listen on a list and will send revoke RPC to client who owns the lock.
-Retryer will listen on a list and will send retry RPC to client who is scheduled to own next

Acquire:
Lock is granted only if current state is
1)LOCKFREE (or) (RETRYING and incoming id matches the retrying_clientid so
that it is granted to the appropriate client. Also, waiting_clientids is probed and if there is any client waiting,
we schedule a revoke request to be sent by Releaser thread to avoid starvation
2) LOCKED
we schedule a revoke request to be sent by Releaser thread and client to added to waiting_clientids list

Release:
State is set to LOCKFREE and if there are clients waiting for this lock, then we schedule a retry request
to be sent to the scheduled owner

Changes to rpc/rpc.cc
---------------------
This is to fix the solution that addresses atmost once delivery of RPC on server side.
Essentially, we respond back with INPROGRESS if cb_present is false.

Validation
==========
It passes all tests from lab3/lab4 scripts with/witout RPC LOSSY