This repository has been archived by the owner on Dec 8, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
34 changed files
with
2,076 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
# Logs | ||
logs | ||
*.log | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
lerna-debug.log* | ||
|
||
# Diagnostic reports (https://nodejs.org/api/report.html) | ||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json | ||
|
||
# Runtime data | ||
pids | ||
*.pid | ||
*.seed | ||
*.pid.lock | ||
|
||
# Directory for instrumented libs generated by jscoverage/JSCover | ||
lib-cov | ||
|
||
# Coverage directory used by tools like istanbul | ||
coverage | ||
*.lcov | ||
|
||
# nyc test coverage | ||
.nyc_output | ||
|
||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) | ||
.grunt | ||
|
||
# Bower dependency directory (https://bower.io/) | ||
bower_components | ||
|
||
# node-waf configuration | ||
.lock-wscript | ||
|
||
# Compiled binary addons (https://nodejs.org/api/addons.html) | ||
build/Release | ||
|
||
# Dependency directories | ||
node_modules/ | ||
jspm_packages/ | ||
|
||
# TypeScript v1 declaration files | ||
typings/ | ||
|
||
# TypeScript cache | ||
*.tsbuildinfo | ||
|
||
# Optional npm cache directory | ||
.npm | ||
|
||
# Optional eslint cache | ||
.eslintcache | ||
|
||
# Microbundle cache | ||
.rpt2_cache/ | ||
.rts2_cache_cjs/ | ||
.rts2_cache_es/ | ||
.rts2_cache_umd/ | ||
|
||
# Optional REPL history | ||
.node_repl_history | ||
|
||
# Output of 'npm pack' | ||
*.tgz | ||
|
||
# Yarn Integrity file | ||
.yarn-integrity | ||
|
||
# dotenv environment variables file | ||
.env | ||
.env.test | ||
|
||
# parcel-bundler cache (https://parceljs.org/) | ||
.cache | ||
|
||
# Next.js build output | ||
.next | ||
|
||
# Nuxt.js build / generate output | ||
.nuxt | ||
dist | ||
|
||
# Gatsby files | ||
.cache/ | ||
# Comment in the public line in if your project uses Gatsby and *not* Next.js | ||
# https://nextjs.org/blog/next-9-1#public-directory-support | ||
# public | ||
|
||
# vuepress build output | ||
.vuepress/dist | ||
|
||
# Serverless directories | ||
.serverless/ | ||
|
||
# FuseBox cache | ||
.fusebox/ | ||
|
||
# DynamoDB Local files | ||
.dynamodb/ | ||
|
||
# TernJS port file | ||
.tern-port | ||
|
||
# Gradle | ||
|
||
.gradle | ||
/build/ | ||
!gradle/wrapper/gradle-wrapper.jar | ||
|
||
### IntelliJ IDEA ### | ||
/target/ | ||
*/target/** | ||
.idea | ||
*.iws | ||
*.iml | ||
*.ipr | ||
**/out | ||
**/bin | ||
**/build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Project Configurations | ||
|
||
The main directory of the project is divided into 3 other directories, each with its own responsibilities: | ||
|
||
- `Client`: This directory corresponds to the client-side library that allows clients to connect and access the service, namely, invoke operations. | ||
- `Replica`: This directory contains the Raft algorithm implementation. | ||
- `ReplicaContract`: This directory represents the contract where all the necessary objects and operations for communication are defined. | ||
|
||
To run the project, start by installing the `ReplicaContract`. Next, start up the `Replicas`, and finally, execute the `Client` to invoke operations. | ||
|
||
### Replica | ||
To run each replica, first **obtain its JAR** through Maven, and then execute the following command to start it up. Since the config file has only 5 IPs, if you don't change it, there can be a maximum of 5 replicas (0 <= `id` <= 4). The config file allows the client and the replicas to know the IP addresses of the other replicas. The log file corresponds to the mechanism of log replication. In case the replica goes down, it can easily recover its state and update its log. | ||
|
||
```bash | ||
java -jar Replica-1.0-jar-with-dependencies.jar <id(>= 0)> <configFile(absolute path)> <logFile(absolute path)> | ||
``` | ||
|
||
### Client | ||
To run the client, start by obtaining its JAR the same way as before, and then execute the following command after inserting the absolute path for the desired config file. | ||
|
||
```bash | ||
java -jar Client.jar <configFile(absolute path)> | ||
``` | ||
|
||
The text has been revised for clarity, consistency, and correctness. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<groupId>org.example</groupId> | ||
<artifactId>Client</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
|
||
<properties> | ||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
<java.version>11</java.version> | ||
<maven.compiler.source>${java.version}</maven.compiler.source> | ||
<maven.compiler.target>${java.version}</maven.compiler.target> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>io.grpc</groupId> | ||
<artifactId>grpc-netty-shaded</artifactId> | ||
<version>1.45.1</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>io.grpc</groupId> | ||
<artifactId>grpc-protobuf</artifactId> | ||
<version>1.45.1</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>io.grpc</groupId> | ||
<artifactId>grpc-stub</artifactId> | ||
<version>1.45.1</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.google.code.gson</groupId> | ||
<artifactId>gson</artifactId> | ||
<version>2.10</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>fcul.tfd</groupId> | ||
<artifactId>ReplicaContract</artifactId> | ||
<version>1.0</version> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-assembly-plugin</artifactId> | ||
<version>3.1.1</version> | ||
<configuration> | ||
<descriptorRefs> | ||
<descriptorRef>jar-with-dependencies</descriptorRef> | ||
</descriptorRefs> | ||
<archive> | ||
<manifest> | ||
<mainClass>Client</mainClass> | ||
</manifest> | ||
</archive> | ||
</configuration> | ||
<executions> | ||
<execution> | ||
<id>assemble-all</id> | ||
<phase>package</phase> | ||
<goals> | ||
<goal>single</goal> | ||
</goals> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
|
||
|
||
</project> |
136 changes: 136 additions & 0 deletions
136
TFD-Project/code/Client/src/main/java/org/example/Client.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
package org.example; | ||
|
||
import com.google.protobuf.ByteString; | ||
import com.google.protobuf.Timestamp; | ||
import io.grpc.ManagedChannel; | ||
import io.grpc.ManagedChannelBuilder; | ||
import replica.Request; | ||
import replica.Result; | ||
import replica.ServerGrpc; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.FileReader; | ||
import java.io.IOException; | ||
import java.nio.ByteBuffer; | ||
import java.time.Instant; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Random; | ||
|
||
public class Client { | ||
private static final int MINIMUM = 1; | ||
private static final int MAXIMUM = 6; | ||
private static final int INT_SIZE = 4; | ||
public static final int CLIENT_ID = -1; | ||
public static final int WAITING_TIME = 5000; | ||
private static final String INCREASE_LABEL = "increaseBy"; | ||
|
||
private static int current_leader = 2; | ||
|
||
private static final List<Pair<ReplicaAddress, ServerGrpc.ServerBlockingStub>> replicas = new ArrayList<>(); | ||
|
||
public static void main(String[] args) { | ||
|
||
if (args.length < 1) { | ||
System.out.println("Usage: java -jar Client.jar <configFile(absolute path)>"); | ||
System.exit(-1); | ||
} | ||
|
||
try { | ||
initClient(args[0]); | ||
sendCommands(); | ||
} catch (Exception e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
private static void sendCommands() { | ||
Request request = createRequestMessage(); | ||
boolean reset = false; | ||
while (true) { | ||
try { | ||
System.out.println("Sending command to replica " + current_leader); | ||
Result response = replicas.get(current_leader).getSecond().request(request); | ||
|
||
System.out.println("Response arrived: " + response.getResultMessage()); | ||
|
||
if (response.getId() == -1) { | ||
return; | ||
} | ||
if (response.getId() != current_leader) { | ||
current_leader = response.getId(); | ||
System.out.println("Switched leader to: " + current_leader); | ||
} else { | ||
Thread.sleep(WAITING_TIME); | ||
request = createRequestMessage(); | ||
} | ||
} catch (Exception e){ | ||
if(current_leader > 0 && !reset) { | ||
current_leader = 0; | ||
reset = true; | ||
} else { | ||
current_leader++; | ||
if (current_leader == replicas.size()) { | ||
System.out.println("No available replicas to be found, exiting.."); | ||
System.exit(-1); | ||
} | ||
} | ||
System.out.println("No reply from replica or crash occurred, attempting communication with other known replica (" + current_leader + ")"); | ||
} | ||
|
||
} | ||
} | ||
|
||
private static Request createRequestMessage() { | ||
System.out.println("Create request message called"); | ||
Random rand = new Random(); | ||
int value = rand.nextInt(MAXIMUM - MINIMUM) + MINIMUM; | ||
System.out.println("Random value generated: "+ value); | ||
byte[] data = ByteBuffer.allocate(INT_SIZE).putInt(value).array(); | ||
return Request.newBuilder() | ||
.setId(CLIENT_ID) | ||
.setLabel(INCREASE_LABEL) | ||
.setData(ByteString.copyFrom(data)) | ||
.setTimestamp(getInstantTimestamp()) | ||
.build(); | ||
} | ||
|
||
private static Timestamp getInstantTimestamp() { | ||
var timestamp = java.sql.Timestamp.from(Instant.now()); | ||
return Timestamp.newBuilder().setSeconds(timestamp.getTime()).setNanos(timestamp.getNanos()).build(); | ||
} | ||
|
||
private static void initClient(String configFilePath) throws IOException { | ||
readConfigFile(configFilePath); | ||
} | ||
|
||
/** | ||
* Reads each line from the file provided and stores for each line the ReplicaAddress and the stub channel in a pair | ||
* of the list replicas | ||
* | ||
* @param configFilePath absolute path to the configuration text file with the replicas' addresses | ||
* @throws IOException in case an I/O error occurs | ||
*/ | ||
private static void readConfigFile(String configFilePath) throws IOException { | ||
try (BufferedReader br = new BufferedReader(new FileReader(configFilePath))) { | ||
String address; | ||
ReplicaAddress replicaAddress; | ||
while ((address = br.readLine()) != null) { | ||
replicaAddress = new ReplicaAddress(address); | ||
replicas.add(new Pair<>(replicaAddress, initStub(replicaAddress)) // To not initiate a client stub to itself | ||
); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Initializes the client communication channel | ||
* | ||
* @param replicaAddress address of the replica to establish the connection | ||
* @return the stub created | ||
*/ | ||
private static ServerGrpc.ServerBlockingStub initStub(ReplicaAddress replicaAddress) { | ||
ManagedChannel channel = ManagedChannelBuilder.forAddress(replicaAddress.getIp(), replicaAddress.getPort()).usePlaintext().build(); | ||
return ServerGrpc.newBlockingStub(channel); | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
TFD-Project/code/Client/src/main/java/org/example/Pair.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package org.example; | ||
public class Pair<K, V> { | ||
private final K first; | ||
private final V second; | ||
|
||
public Pair(K first, V second) { | ||
this.first = first; | ||
this.second = second; | ||
} | ||
|
||
public K getFirst() { | ||
return first; | ||
} | ||
|
||
public V getSecond() { | ||
return second; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "(" + first + ", " + second + ")"; | ||
} | ||
} |
Oops, something went wrong.