Commit 2011b7f2 authored by NILANJAN DAW's avatar NILANJAN DAW

Added support for data replication on Follower nodes.

Added Storage model
Added IO handler wrapper class
parent 34204c32
......@@ -7,11 +7,13 @@ import hpdos.grpc.HeartbeatRequest;
import hpdos.grpc.HeartbeatResponse;
import hpdos.grpc.HeartbeatServiceGrpc;
import hpdos.handler.HeartbeatHandler;
import hpdos.handler.IOHandler;
import hpdos.handler.NetworkHandler;
import hpdos.handler.ReplicateHandler;
import hpdos.lib.MasterFollower;
import hpdos.lib.MemoryStorage;
import hpdos.lib.StorageService;
import hpdos.messageformat.MessageConstants;
import hpdos.message.MessageConstants;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Server;
......@@ -30,7 +32,7 @@ public class MetadataServer {
private boolean isMaster = false;
private int port;
private final String host;
private StorageService storageService;
private IOHandler ioHandler;
public MetadataServer() {
this.followers = new HashMap<>();
......@@ -43,13 +45,13 @@ public class MetadataServer {
return "Hello World!";
}
public boolean startServer() {
server = ServerBuilder.forPort(ConfigConstants.PORT)
.addService(new NetworkHandler())
public boolean startMasterServices() {
this.server = ServerBuilder.forPort(ConfigConstants.PORT)
.addService(new NetworkHandler(this.ioHandler))
.addService(new HeartbeatHandler(followers, serverID))
.build();
try {
server.start();
this.server.start();
} catch (IOException e) {
e.printStackTrace();
return false;
......@@ -57,7 +59,22 @@ public class MetadataServer {
return true;
}
public void blockForIO() {
public boolean startFollowerServices() {
// In case of followers NetworkHandler will only serve read requests for private metadata
// Other network handler services will fail
this.server = ServerBuilder.forPort(ConfigConstants.PORT)
.addService(new NetworkHandler(this.ioHandler))
.addService(new ReplicateHandler(this.ioHandler))
.build();
try {
this.server.start();
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
public void blockForIO(Server server) {
if (server == null)
return;
try {
......@@ -87,7 +104,6 @@ public class MetadataServer {
this.port = ConfigConstants.PORT;
}
channel.shutdown();
}
private void startHeartbeatService() {
......@@ -100,15 +116,18 @@ public class MetadataServer {
}, ConfigConstants.HEARTBEAT_INTERVAL, ConfigConstants.HEARTBEAT_INTERVAL);
}
private boolean initStorage(int backend) {
private IOHandler initStorage(int backend) {
StorageService storageService;
switch (backend) {
case ConfigConstants.BACKEND_IN_MEMORY:
this.storageService = new MemoryStorage();
return true;
storageService = new MemoryStorage();
break;
case ConfigConstants.BINARY_TREE_BACKEND:
case ConfigConstants.LSM_BACKEND:
default: return false;
default: return null;
}
IOHandler ioHandler = new IOHandler(storageService);
return ioHandler;
}
public static void main(String[] args) {
......@@ -117,25 +136,35 @@ public class MetadataServer {
System.out.println(metaDataServer.getGreeting());
System.out.println("Starting Metadata service");
System.out.println("Initialising storage service");
boolean status = metaDataServer.initStorage(ConfigConstants.BACKEND_IN_MEMORY);
if (!status) {
// Check ConfigConstants for available storage options
metaDataServer.ioHandler = metaDataServer.initStorage(ConfigConstants.BACKEND_IN_MEMORY);
if (metaDataServer.ioHandler == null) {
System.out.println("Storage server initialisation error");
return;
}
System.out.println("Searching for MetadataMaster");
metaDataServer.announceToMaster();
if (metaDataServer.isMaster) {
status = metaDataServer.startServer();
boolean status = metaDataServer.startMasterServices();
System.out.println("Master ID: " + metaDataServer.serverID);
if (status) {
System.out.println("Starting RPC server at: " + ConfigConstants.PORT);
metaDataServer.blockForIO();
System.out.println("Starting Master MetadataServer at: " + ConfigConstants.PORT);
metaDataServer.blockForIO(metaDataServer.server);
}
else
System.out.println("Failed to create server");
} else {
System.out.println("Master Node detected.\nStarting heartbeat service");
metaDataServer.startHeartbeatService();
System.out.println("Starting replication service");
boolean status = metaDataServer.startFollowerServices();
if (status) {
System.out.println("Starting Follower MetadataServer at: " + metaDataServer.port);
metaDataServer.blockForIO(metaDataServer.server);
}
else
System.out.println("Failed to create server");
}
}
......
......@@ -4,14 +4,10 @@ import hpdos.grpc.HeartbeatRequest;
import hpdos.grpc.HeartbeatResponse;
import hpdos.grpc.HeartbeatServiceGrpc;
import hpdos.lib.MasterFollower;
import hpdos.messageformat.MessageConstants;
import hpdos.message.MessageConstants;
import io.grpc.stub.StreamObserver;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.Timestamp;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
public class HeartbeatHandler extends HeartbeatServiceGrpc.HeartbeatServiceImplBase {
......
package hpdos.handler;
import hpdos.grpc.Ack;
import hpdos.grpc.Nack;
import hpdos.grpc.Request;
import hpdos.grpc.Response;
import hpdos.lib.StorageModel;
import hpdos.lib.StorageService;
import hpdos.message.MessageConstants;
import hpdos.message.ResponseBuilder;
public class IOHandler {
StorageService storageService;
public IOHandler(StorageService storageService) {
this.storageService = storageService;
}
public Response create(Request request) {
Ack ack = null; Nack nack = null;
StorageModel blob = new StorageModel(
MessageConstants.INIT_VERSION,
request.getDataSize(),
request.getKey(),
request.getAccessType(),
request.getClientID(),
request.getValue());
boolean status = storageService.create(request.getKey(), blob);
if (status) {
ack = ResponseBuilder.buildAck(MessageConstants.INIT_VERSION,
blob.getDataSize(),
blob.getKey(),
blob.getCrc(),
blob.getValue());
}
else {
nack = ResponseBuilder.buildNack(MessageConstants.INVALID_VERSION,
MessageConstants.STATUS_REPLICATE_FAILED,
request.getKey());
}
return ResponseBuilder.buildResponsePacket(
MessageConstants.METADATA_CREATE,
ack, nack);
}
public Response update(Request request) {
return null;
}
public Response delete(Request request) {
return null;
}
}
package hpdos.handler;
import hpdos.grpc.*;
import hpdos.messageformat.*;
import hpdos.message.*;
import io.grpc.stub.StreamObserver;
import java.util.ArrayList;
public class NetworkHandler extends NetworkServiceGrpc.NetworkServiceImplBase {
private IOHandler ioHandler;
public NetworkHandler(IOHandler ioHandler) {
this.ioHandler = ioHandler;
}
@Override
public void getMetadata(Packet request,
public void readMetadata(Packet request,
StreamObserver<Packet> responseObserver) {
System.out.println("Data received" + request.toString());
String key = "dummy";
......@@ -18,11 +22,25 @@ public class NetworkHandler extends NetworkServiceGrpc.NetworkServiceImplBase {
ArrayList<Response> responses = new ArrayList<>();
responses.add(ResponseBuilder.
buildResponsePacket(MessageConstants.METADATA_LOOKUP_RESPONSE, acks, null));
buildResponsePacket(MessageConstants.METADATA_READ, acks, null));
Packet packet = ResponseBuilder.buildPacket(responses);
System.out.println(packet);
responseObserver.onNext(packet);
responseObserver.onCompleted();
}
@Override
public void createMetadata(Packet request, StreamObserver<Packet> responseObserver) {
super.createMetadata(request, responseObserver);
}
@Override
public void updateMetadata(Packet request, StreamObserver<Packet> responseObserver) {
super.updateMetadata(request, responseObserver);
}
@Override
public void deleteMetadata(Packet request, StreamObserver<Packet> responseObserver) {
super.deleteMetadata(request, responseObserver);
}
}
package hpdos.handler;
import hpdos.grpc.*;
import hpdos.message.MessageConstants;
import hpdos.message.ResponseBuilder;
import io.grpc.stub.StreamObserver;
public class ReplicateHandler extends ReplicationServiceGrpc.ReplicationServiceImplBase {
private final IOHandler ioHandler;
public ReplicateHandler(IOHandler ioHandler) {
this.ioHandler = ioHandler;
}
@Override
public void replicateMetadata(ReplicationRequest replicationRequest, StreamObserver<ReplicationResponse> responseObserver) {
ReplicationResponse responsePacket = null;
System.out.println("Replication request " + replicationRequest);
if (replicationRequest.getPacketType() == MessageConstants.PACKET_METADATA_REQUEST) {
for (Request request: replicationRequest.getRequestList()) {
if (request.getOperationType() == MessageConstants.METADATA_CREATE) {
Response response = ioHandler.create(request);
responsePacket = ResponseBuilder.buildReplicationResponse(response);
} else if (request.getOperationType() == MessageConstants.METADATA_UPDATE) {
Response response = ioHandler.update(request);
responsePacket = ResponseBuilder.buildReplicationResponse(response);
} else if (request.getOperationType() == MessageConstants.METADATA_DELETE) {
Response response = ioHandler.delete(request);
responsePacket = ResponseBuilder.buildReplicationResponse(response);
}
responseObserver.onNext(responsePacket);
}
}
}
}
......@@ -3,21 +3,42 @@ package hpdos.lib;
import java.util.HashMap;
public class MemoryStorage implements StorageService{
private final HashMap<String, String> memoryKVStore;
private final HashMap<String, StorageModel> memoryKVStore;
public MemoryStorage() {
this.memoryKVStore = new HashMap<>();
}
@Override
public String put(String key, String value) {
public boolean create(String key, StorageModel value) {
try {
return memoryKVStore.put(key, value);
if (memoryKVStore.containsKey(key))
return false;
memoryKVStore.put(key, value);
} catch (Exception e) {
return null;
return false;
}
return true;
}
@Override
public String getByKey(String key) {
public StorageModel readByKey(String key) {
return memoryKVStore.get(key);
}
@Override
public boolean update(String key, StorageModel value) {
if (!memoryKVStore.containsKey(key))
return false;
memoryKVStore.put(key, value);
return true;
}
@Override
public boolean delete(String key) {
try {
memoryKVStore.remove(key);
} catch (Exception e) {
return false;
}
return true;
}
}
package hpdos.lib;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
public class StorageModel {
private int version;
private int dataSize;
private String key;
private long crc;
private int accessType;
private String value;
private String owner;
public StorageModel(int version, int dataSize, String key, int accessType, String owner, String value) {
this.version = version;
this.dataSize = dataSize;
this.key = key;
this.accessType = accessType;
this.value = value;
this.owner = owner;
// calculate CRC32 based on the value field
byte[] bytes = value.getBytes();
Checksum checksum = new CRC32();
checksum.update(bytes, 0, bytes.length);
this.crc = checksum.getValue();
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public int getDataSize() {
return dataSize;
}
public void setDataSize(int dataSize) {
this.dataSize = dataSize;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public long getCrc() {
return crc;
}
public void setCrc(long crc) {
this.crc = crc;
}
public int getAccessType() {
return accessType;
}
public void setAccessType(int accessType) {
this.accessType = accessType;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
}
package hpdos.lib;
public interface StorageService {
String put(String key, String value);
String getByKey(String key);
boolean create(String key, StorageModel value);
StorageModel readByKey(String key);
boolean update(String key, StorageModel value);
boolean delete(String key);
}
package hpdos.messageformat;
package hpdos.message;
public class MessageConstants {
public static final int INIT_VERSION = 0;
public static final int INVALID_VERSION = -1;
// 00 to 99 - Client Server Interaction operations
public static final int PACKET_METADATA_REQUEST = 0;
public static final int PACKET_METADATA_RESPONSE = 1;
// Distinguishing ACK and NACK packets (might be redundant)
public static final boolean STATUS_OK = true;
public static final boolean STATUS_FAIL = false;
// Distinguishing ACK and NACK packets
public static final int STATUS_OK = 200;
public static final int STATUS_OWNER_MISMATCH = 401;
public static final int STATUS_REPLICATE_FAILED = 402;
// 100 to 199 - HPDOS System internal operations
public static final int MASTER_HEARTBEAT = 100;
public static final int METADATA_LOOKUP_REQUEST = 101;
public static final int METADATA_LOOKUP_RESPONSE = 102;
public static final int METADATA_CREATE = 101;
public static final int METADATA_READ = 102;
public static final int METADATA_UPDATE = 103;
public static final int METADATA_DELETE = 104;
}
package hpdos.messageformat;
package hpdos.message;
import hpdos.grpc.Packet;
import hpdos.grpc.PacketFormatProto;
import hpdos.grpc.Request;
import java.util.ArrayList;
......
package hpdos.messageformat;
import java.util.ArrayList;
package hpdos.message;
import hpdos.grpc.*;
import java.util.ArrayList;
public class ResponseBuilder {
public static Ack buildAck(int version, int dataSize, String key, int crc, String value) {
public static Ack buildAck(int version, int dataSize, String key, long crc, String value) {
Ack.Builder ack = Ack.newBuilder();
ack.setStatus(MessageConstants.STATUS_OK);
ack.setKey(key);
......@@ -16,18 +16,17 @@ public class ResponseBuilder {
return ack.build();
}
public static Nack buildNack(int version, int reason, String key) {
public static Nack buildNack(int version, int status, String key) {
Nack.Builder nack = Nack.newBuilder();
nack.setStatus(MessageConstants.STATUS_FAIL);
nack.setStatus(status);
nack.setKey(key);
nack.setVersion(version);
nack.setReason(reason);
return nack.build();
}
public static Response buildResponsePacket(int operationType,
ArrayList<Ack> acks,
ArrayList<Nack> nacks) {
ArrayList<Ack> acks,
ArrayList<Nack> nacks) {
Response.Builder response = Response.newBuilder();
response.setOperationType(operationType);
if (acks != null)
......@@ -41,10 +40,40 @@ public class ResponseBuilder {
return response.build();
}
public static Response buildResponsePacket(int operationType,
Ack ack,
Nack nack) {
Response.Builder response = Response.newBuilder();
response.setOperationType(operationType);
if (ack != null)
response.addAck(ack);
else
response.clearAck();
if (nack != null)
response.addNack(nack);
else
response.clearNack();
return response.build();
}
public static Packet buildPacket(ArrayList<Response> responses) {
Packet.Builder packet = Packet.newBuilder();
packet.setPacketType(MessageConstants.PACKET_METADATA_RESPONSE);
packet.addAllResponse(responses);
return packet.build();
}
public static Packet buildPacket(Response response) {
Packet.Builder packet = Packet.newBuilder();
packet.setPacketType(MessageConstants.PACKET_METADATA_RESPONSE);
packet.addResponse(response);
return packet.build();
}
public static ReplicationResponse buildReplicationResponse(Response response) {
ReplicationResponse.Builder packet = ReplicationResponse.newBuilder();
packet.setPacketType(MessageConstants.PACKET_METADATA_RESPONSE);
packet.addResponse(response);
return packet.build();
}
}
......@@ -10,7 +10,10 @@ service NetworkService {
/**
Receive Packet from client
*/
rpc getMetadata(Packet) returns (Packet) {}
rpc readMetadata(Packet) returns (Packet) {}
rpc createMetadata(Packet) returns (Packet) {}
rpc updateMetadata(Packet) returns (Packet) {}
rpc deleteMetadata(Packet) returns (Packet) {}
}
......@@ -25,8 +28,10 @@ message Request {
int32 version = 2;
int32 dataSize = 3;
string key = 4;
int32 crc = 5;
string value = 6;
int64 crc = 5;
int32 accessType = 6;
string clientID = 7;
string value = 8;
}
message Response {
......@@ -36,17 +41,16 @@ message Response {
}
message Ack {
bool status = 1;
int32 status = 1;
int32 version = 2;
int32 dataSize = 3;
string key = 4;
int32 crc = 5;
int64 crc = 5;
string value = 6;
}
message Nack {
bool status = 1;
int32 reason = 2;
string key = 3;
int32 version = 4;
int32 status = 1;
string key = 2;
int32 version = 3;
}
\ No newline at end of file
syntax = "proto3";
package hpdos.grpc;
import "PacketFormat.proto";
option java_multiple_files = true;
option java_package = "hpdos.grpc";
option java_outer_classname = "Replicate";
service ReplicationService {
/**
Receive Packet from client
*/
rpc replicateMetadata(ReplicationRequest) returns (ReplicationResponse) {}
}
message ReplicationRequest {
int32 packetType = 1;
repeated Request request = 2;
}
message ReplicationResponse {
int32 packetType = 1;
repeated Response response = 2;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment