-
Notifications
You must be signed in to change notification settings - Fork 330
DistributedHashtable
id: DistributedHashtable title: Distributed Hashtable permalink: /docs/manual/DemoApps/DistributedHashtable.html
Hashtable is among the most useful daily-used data structures. A distributed hashtable is a hashtable served by a cluster of machines. It can be accessed through network. We demonstrate how to implement a distributed hashtable on top of GE and how it can be accessed via user-defined interfaces.
A hashtable consists of a set of buckets, each of which is collection of key-value pairs. We use string to represent both the Key and Value in this demo application. In GE, we can use a cell as a hashtable bucket. We define BucketCell in TSL for this purpose:
struct KVPair
{
string Key;
string Value;
}
cell struct BucketCell
{
List<KVPair> KVList;
}
Given an arbitrary Key, we first hash it to a 64-bit cell id. Then we use this id to reference the cell bucket.
Because we are working on a distributed hashtable, we need to define protocols to allow the clients to manipulate the hashtable. Let us first look at the protocol for setting a key-value pair.
The Set protocol is very straightforward: we just need to send a Key (string) and a Value (string) to the hashtable server. Here is the protocol specification:
struct SetMessage
{
string Key;
string Value;
}
protocol Set
{
Type:Syn;
Request:SetMessage;
Response:void;
}
The implementation logic of Set operation is also straightforward:
public override void SetHandler(SetMessageReader request)
{
long cellId = HashHelper.HashString2Int64(request.Key);
using (var cell = Global.LocalStorage.UseBucketCell(cellId, CellAccessOptions.CreateNewOnCellNotFound))
{
int count = cell.KVList.Count;
int index = -1;
for (int i = 0; i < count; i++)
{
if (cell.KVList[i].Key == request.Key)
{
index = i;
break;
}
}
if (index != -1)
{
cell.KVList[index].Value = request.Value;
}
else
cell.KVList.Add(new KVPair(request.Key, request.Value));
}
}
In the cell bucket, we search the key against the key-value pair list. If we find a match, we update the value; otherwise, we add a new value.
Get operation is even simpler. It fetches the value by the user-specified key. This is the protocol specification:
struct GetMessage
{
string Key;
}
struct GetResponse
{
bool IsFound;
string Value;
}
protocol Get
{
Type:Syn;
Request:GetMessage;
Response:GetResponse;
}
This is the implementation logic:
public override void GetHandler(GetMessageReader request, GetResponseWriter response)
{
long cellId = HashHelper.HashString2Int64(request.Key);
response.IsFound = false;
using (var cell = Global.LocalStorage.UseBucketCell(cellId, CellAccessOptions.ReturnNullOnCellNotFound))
{
if (cell == null)
return;
int count = cell.KVList.Count;
for (int i = 0; i < count; i++)
{
if (cell.KVList[i].Key == request.Key)
{
response.IsFound = true;
response.Value = cell.KVList[i].Value;
break;
}
}
}
}
If we do not find a matched bucket, we return immediately. Otherwise, we search the key against the key-value pair list in the matched bucket cell.