Here is a simple diagram that shows the flow of data in the code.
Finding the Right Master
The client first has to find the right master to talk to - the master that holds the required data. To do this, RamCloud::read() invokes ObjectFinder::lookup(). It checks client's tabletMap - which is a cache of coordinator's tablet map. If that tablet is recovering or if the object was not found in any tablet, then the cache is refreshed. This is done by refresher(tabletMap) which is hardwired to CoordinatorClient::getTabletMap in the constructor.
Finally, lookup() returns the SessionRef. SessionRef is a reference to a Session object on which we send client RPC requests. RamCloud::read() uses this to create an instance of the right master and invoking read().
Sending RPC Request
MasterClient::read() creates the RPC Request. The structure for all RPCs is defined in Rpc.h. For Read Request, the RPC contains the following fields:
- RpcType type
- uint64_t id
- uint64_t tableId
- uint64_t pad1
- RejectRules rejectRules
Call to sendRecv() sends request over session and later gets response. sendRecv() is defined in Client.h. It creates a AsyncState (called state) which contains:
- pointer to responseBuffer
It sends the requestBuffer and responseBuffer over session by session->clientSend(), and waits for it to return by state.rpc->wait().
When a master is running, it continuously polls for RPCs by:
In Server.h, handleRpc<>() is hardwired to call dispatch() amongst doing other things. Thus, when an rpc is received, the following chain of functions are called in MasterServer.cc:
dispatch() -> callHandler<>() -> read()
MasterServer::read() function looks up the requested object in Hash Table. A segment entry is structured such that the data is at fixed offset from the Segment Entry Handler. Thus the actual length of data can be calculated. This is illustrated in the figure below.
Finally, the response buffer to be returned is formed by appending this obj->data as a Chunk. The Buffer contains:
- Transport Layer Header
- RPC, respHdr (see Rpc.h). For Read Response, the RPC contains:
- length (actual data length, calculated as shown above)
- Data (obj->data from above)
Client Request Processing
The SendRecv() (originally called by MasterClient::read()) resumes from state.rpc->wait() and returns the respHdr RPC to MasterClient.cc. Finally the response is truncated to only contain the actual value (data) as illustrated in the figure below.
This value is returned back to the calling read() function.
EndNode: What? Why? How?
What: A simple introduction to understanding how a "read" works in RAMCloud based on my current understanding.
Why: For me to refer to later on, and hopefully to serve as a good starting point to other new comers to RAMCloud system.
How: Information deduced from reading code, and asking lot of silly questions to Diego, Ryan; and a few to Stephen, Nandu and Christian.