Commit b4722ef3 authored by Shah Rinku's avatar Shah Rinku

restructured git

parent 8f618288
File added
File added
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="libraries-with-intellij-classes">
<option name="intellijApiContainingLibraries">
<list>
<LibraryCoordinatesState>
<option name="artifactId" value="ideaIU" />
<option name="groupId" value="com.jetbrains.intellij.idea" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="ideaIU" />
<option name="groupId" value="com.jetbrains" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="ideaIC" />
<option name="groupId" value="com.jetbrains.intellij.idea" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="ideaIC" />
<option name="groupId" value="com.jetbrains" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="pycharmPY" />
<option name="groupId" value="com.jetbrains.intellij.pycharm" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="pycharmPY" />
<option name="groupId" value="com.jetbrains" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="pycharmPC" />
<option name="groupId" value="com.jetbrains.intellij.pycharm" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="pycharmPC" />
<option name="groupId" value="com.jetbrains" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="clion" />
<option name="groupId" value="com.jetbrains.intellij.clion" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="clion" />
<option name="groupId" value="com.jetbrains" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="riderRD" />
<option name="groupId" value="com.jetbrains.intellij.rider" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="riderRD" />
<option name="groupId" value="com.jetbrains" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="goland" />
<option name="groupId" value="com.jetbrains.intellij.goland" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="goland" />
<option name="groupId" value="com.jetbrains" />
</LibraryCoordinatesState>
</list>
</option>
</component>
</project>
\ No newline at end of file
app.name="HPDOS-Client"
app.version="0.1.4"
app.concurrency=5
app.runtime=10
app.data_size=10
app.data_conversion_factor=B
app.private_ratio=0.8
app.cycle_create=1
app.cycle_read=4
app.cycle_update=3
app.cycle_delete=1
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package HpdosClient;
import HpdosClient.MessageFormat.MessageConstants;
import HpdosClient.lib.StorageModel;
import HpdosClient.lib.StorageService;
import com.google.common.base.Stopwatch;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import hpdos.grpc.*;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.netty.shaded.io.netty.util.concurrent.FutureListener;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.*;
public class ClientRunner {
public static int concurrency;
public static int runtime;
private final String clientID;
public static String propertiesFile;
private int cCreate, cRead, cUpdate, cDelete;
public boolean experimentEnded = false;
private List<Follower> replicaSet;
private Queue<Long> createTime, updateTime, readTime, deleteTime;
private final Properties properties;
private final List<StorageModel> generatedPacket;
private Semaphore limiter = null;
private final int cpuCount;
public ClientRunner() {
clientID = UUID.randomUUID().toString();
generatedPacket = Collections.synchronizedList(new ArrayList<>());
properties = new Properties();
cpuCount = Runtime.getRuntime().availableProcessors();
try {
InputStream inputStream = new FileInputStream(propertiesFile);
this.properties.load(inputStream);
System.out.println((String) properties.get("app.concurrency"));
concurrency = Integer.parseInt((String) properties.get("app.concurrency"));
this.limiter = new Semaphore(concurrency / cpuCount);
runtime = Integer.parseInt((String) properties.get("app.runtime"));
this.cCreate = Integer.parseInt((String) properties.get("app.cycle_create"));
this.cRead = Integer.parseInt((String) properties.get("app.cycle_read"));
this.cUpdate = Integer.parseInt((String) properties.get("app.cycle_update"));
this.cDelete = Integer.parseInt((String) properties.get("app.cycle_delete"));
this.createTime = new ConcurrentLinkedQueue<>();
this.updateTime = new ConcurrentLinkedQueue<>();
this.readTime = new ConcurrentLinkedQueue<>();
this.deleteTime = new ConcurrentLinkedQueue<>();
} catch (IOException e) {
e.printStackTrace();
}
}
public String getGreeting() {
return "Hello World!";
}
private String createString() {
double dataSize = Double.parseDouble((String) properties.get("app.data_size"));
dataSize /= 2.0; // Java strings are 2B long
String conversionFactor = (String) properties.get("app.data_conversion_factor");
int multiplier = 1;
switch (conversionFactor) {
case "G": multiplier *= 1000;
case "M": multiplier *= 1000;
case "K": multiplier *= 1000;
}
char[] data = new char[(int)(dataSize * multiplier)];
return new String(data);
}
private void seedServer(StorageService storageService, String value) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
String key = Integer.toString((int) (Math.random() * Integer.MAX_VALUE));
ListenableFuture<Packet> res = storageService.create(key, value, MessageConstants.METADATA_ACCESS_PRIVATE);
StorageModel model = new StorageModel(0, value.length(), key,
MessageConstants.METADATA_ACCESS_PRIVATE, clientID, 0, value);
res.addListener(() -> {
try {
Packet packet = res.get();
for (Response response: packet.getResponseList()) {
// System.out.println("seed: " + response);
if (response.getStatus() == MessageConstants.STATUS_OK) {
model.updateData(response.getAck());
generatedPacket.add(model);
}
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
latch.countDown();
}, MoreExecutors.directExecutor());
}
latch.await();
}
public double runExperiment(StorageService storageService) throws InterruptedException {
String value = createString(), updatedValue = createString();
double totalBracket = this.cCreate + this.cRead + this.cUpdate + this.cDelete;
double createBracket, readBracket, updateBracket, deleteBracket;
createBracket = this.cCreate * 1.0 / totalBracket;
readBracket = createBracket + this.cRead / totalBracket;
updateBracket = readBracket + this.cUpdate / totalBracket;
deleteBracket = updateBracket + this.cDelete / totalBracket;
System.out.println("Starting experiment");
do {
limiter.acquire();
double toss = Math.random();
if (toss < createBracket) {
// System.out.println("create");
String key = Integer.toString((int) (Math.random() * Integer.MAX_VALUE));
StorageModel model = new StorageModel(0, value.length(), key,
MessageConstants.METADATA_ACCESS_PRIVATE, clientID, 0, value);
final long createStart = System.currentTimeMillis();
ListenableFuture<Packet> res = storageService.create(model.getKey(), model.getValue(), model.getAccessType());
res.addListener(() -> {
try {
Packet packet = res.get();
// System.out.println("packet " + packet);
for (Response response: packet.getResponseList()) {
if (response.getStatus() == MessageConstants.STATUS_OK) {
model.updateData(response.getAck());
generatedPacket.add(model);
}
// else
// System.out.println("error packet " + response);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
this.createTime.add(System.currentTimeMillis() - createStart);
limiter.release();
}, MoreExecutors.directExecutor());
} else if (toss < readBracket) {
// System.out.println("read");
int index = (int) (Math.random() * generatedPacket.size());
StorageModel sendPacket = this.generatedPacket.get(index);
final long readStart = System.currentTimeMillis();
ListenableFuture<Packet> res = storageService.read(sendPacket.getKey());
res.addListener(() -> {
try {
Packet packet = res.get();
// System.out.println("packet " + packet);
for (Response response: packet.getResponseList()) {
if (response.getStatus() == MessageConstants.STATUS_OK)
if (sendPacket.getKey().equals(response.getAck().getKey())) {
synchronized (sendPacket) {
sendPacket.updateData(response.getAck());
}
}
// else
// System.out.println("error packet " + response);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
readTime.add(System.currentTimeMillis() - readStart);
limiter.release();
}, MoreExecutors.directExecutor());
} else if (toss < updateBracket) {
// System.out.println("update");
int index = (int) (Math.random() * generatedPacket.size());
StorageModel sendPacket = this.generatedPacket.get(index);
final long updateStart = System.currentTimeMillis();
ListenableFuture<Packet> res = storageService.update(sendPacket.getKey(), updatedValue,
sendPacket.getVersion());
res.addListener(() -> {
try {
Packet packet = res.get();
// System.out.println("packet " + packet);
for (Response response: packet.getResponseList()) {
if (response.getStatus() == MessageConstants.STATUS_OK)
if (sendPacket.getKey().equals(response.getAck().getKey())) {
synchronized (sendPacket) {
sendPacket.updateData(response.getAck());
}
}
// else
// System.out.println("error packet " + response);
}
updateTime.add(System.currentTimeMillis() - updateStart);
limiter.release();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}, MoreExecutors.directExecutor());
} else {
// System.out.println("delete");
int index = (int) (Math.random() * generatedPacket.size());
StorageModel sendPacket = this.generatedPacket.get(index);
final long deleteStart = System.currentTimeMillis();
ListenableFuture<Packet> res = storageService.delete(sendPacket.getKey(), sendPacket.getVersion());
res.addListener(() -> {
try {
Packet packet = res.get();
// System.out.println("packet " + packet);
for (Response response: packet.getResponseList()) {
if (response.getStatus() == MessageConstants.STATUS_OK)
if (sendPacket.getKey().equals(response.getAck().getKey())) {
synchronized (sendPacket) {
generatedPacket.remove(sendPacket);
}
}
// else
// System.out.println("error packet " + response);
}
deleteTime.add(System.currentTimeMillis() - deleteStart);
limiter.release();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}, MoreExecutors.directExecutor());
// deleteTime.add(System.currentTimeMillis() - timestampDeleteStart);
}
} while (!this.experimentEnded);
// System.out.println(id + "runtime " + (System.currentTimeMillis() - startTime) +
// "ms qps " + qps);
return 0;
}
private void timerService() {
Stopwatch stopwatch = Stopwatch.createUnstarted();
stopwatch.start();
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if (experimentEnded) {
timer.cancel();
timer.purge();
}
System.out.println("Experiment ran: " + stopwatch);
}
}, 5000, 5000);
}
private void printStatistics(double totalRuntime) {
long readQps = 0, createQps = 0, updateQps = 0, deleteQps = 0;
double avgRead = 0, avgCreate = 0, avgUpdate = 0, avgDelete = 0;
for (Long time: this.readTime) {
readQps++;
avgRead += time;
}
avgRead /= readQps * 1.0;
for (Long time: this.createTime) {
createQps++;
avgCreate += time;
}
avgCreate /= createQps * 1.0;
for (Long time: this.updateTime) {
updateQps++;
avgUpdate += time;
}
avgUpdate /= updateQps * 1.0;
for (Long time: this.deleteTime) {
deleteQps++;
avgDelete += time;
}
avgDelete /= deleteQps * 1.0;
double totalQps = readQps + createQps + updateQps + deleteQps;
System.out.println("Total runtime: " + totalRuntime);
System.out.println("Read: " + readQps + " Create: " + createQps
+ " Update: " + updateQps + " Delete: " + deleteQps + " Total: " + totalQps);
totalRuntime /= 1000;
System.out.println("Total QPS: " + totalQps / totalRuntime + " avg query time: " +
(totalQps * concurrency / (totalRuntime)));
System.out.println("Read QPS: " + readQps / totalRuntime + " avg query time: " + avgRead);
System.out.println("Create QPS: " + createQps / totalRuntime + " avg query time: " + avgCreate);
System.out.println("Update QPS: " + updateQps / totalRuntime + " avg query time: " + avgUpdate);
System.out.println("Delete QPS: " + deleteQps / totalRuntime + " avg query time: " + avgDelete);
}
private void cleanupExperiment(StorageService storageService) throws InterruptedException {
System.out.println("Cleaning up remnants");
CountDownLatch latch = new CountDownLatch(generatedPacket.size());
for (StorageModel data: generatedPacket) {
ListenableFuture<Packet> res = storageService.delete(data.getKey(), data.getVersion());
res.addListener(latch::countDown, MoreExecutors.directExecutor());
}
latch.await();
storageService.cleanup();
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
propertiesFile = args[0];
ClientRunner clientRunner = new ClientRunner();
System.out.println(clientRunner.getGreeting());
StorageService storageService = new StorageService(clientRunner.clientID);
storageService.initStorage();
System.out.println("storage initialised");
clientRunner.seedServer(storageService, clientRunner.createString());
System.out.println("server seeded" + clientRunner.generatedPacket);
final long startTime = System.currentTimeMillis();
clientRunner.timerService();
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(() -> {
try {
Thread.sleep(runtime * 1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
clientRunner.experimentEnded = true;
System.out.println("Experiment ended");
});
ExecutorService experimentExecutors = Executors.newFixedThreadPool(clientRunner.cpuCount);
Set<Callable<Double>> callables = new HashSet<>();
for (int i = 0; i < clientRunner.cpuCount; i++) {
callables.add(() -> clientRunner.runExperiment(storageService));
}
List<Future<Double>> futures = experimentExecutors.invokeAll(callables);
for (Future<Double> future: futures) {
future.get();
}
long endTime = System.currentTimeMillis();
System.out.println("Waiting for system to settle down");
Thread.sleep(2000);
double totalRuntime = endTime - startTime;
clientRunner.printStatistics(totalRuntime);
clientRunner.cleanupExperiment(storageService);
executorService.shutdown();
boolean status = executorService.awaitTermination(1000, TimeUnit.MICROSECONDS);
if (!status)
executorService.shutdownNow();
}
}
package HpdosClient.MessageFormat;
public class MessageConstants {
public static final int INIT_VERSION = 0;
public static final int INVALID_VERSION = -1;
public static final int METADATA_ACCESS_PRIVATE = 700;
public static final int METADATA_ACCESS_SHARED = 777;
// 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
public static final int STATUS_OK = 200;
public static final int STATUS_UNAUTHORIZED_PRIVATE_KEY_ACCESS = 401;
public static final int STATUS_REPLICATION_FAILED = 402;
public static final int STATUS_SERVER_NOT_MASTER = 403;
public static final int STATUS_KEY_NOT_FOUND = 404;
public static final int STATUS_REPLICATION_TIMEOUT = 405;
public static final int STATUS_IO_WRITE_FAILED = 406;
public static final int STATUS_KEY_EXISTS = 407;
public static final int STATUS_UPDATE_VERSION_MISMATCH = 408;
// 100 to 199 - HPDOS System internal operations
public static final int MASTER_HEARTBEAT = 100;
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 HpdosClient.lib;
import hpdos.grpc.Ack;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
public class StorageModel {
private int version;
private int dataSize;
private final String key; // key is immutable
private long crc;
private int accessType;
private String value;
private final String owner; // ownership is immutable
public StorageModel(int version, int dataSize, String key, int accessType, String owner, long crc, 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
this.crc = crc;
}
public void updateData(Ack ack) {
this.version = ack.getVersion();
this.dataSize = ack.getDataSize();
this.value = ack.getValue();
this.crc = ack.getCrc();
}
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 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;
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (obj.getClass() != this.getClass())
return false;
StorageModel model = (StorageModel) obj;
return this.getKey().equals(model.getKey());
}
@Override
public String toString() {
return "key: " + this.key + "\n" +
"dataSize: " + this.dataSize + "\n" +
"version: " + this.version + "\n" +
"owner: " + this.owner + "\n" +
"accessType: " + this.accessType + "\n" +
"crc: " + this.crc + "\n" +
"value: " + this.value;
}
}
package HpdosClient.lib;
import HpdosClient.ConfigConstants;
import HpdosClient.MessageFormat.MessageConstants;
import HpdosClient.MessageFormat.RequestBuilder;
import com.google.common.util.concurrent.ListenableFuture;
import hpdos.grpc.*;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import java.util.*;
public class StorageService {
private final String clientID;
private ManagedChannel masterChannel;
private ArrayList<ManagedChannel> channels;
private NetworkServiceGrpc.NetworkServiceFutureStub masterStub;
private final ArrayList<NetworkServiceGrpc.NetworkServiceFutureStub> stubs;
private List<Follower> replicaSet;
public StorageService(String clientID) {
this.clientID = clientID;
this.stubs = new ArrayList<>();
}
public void retrieveFollowerList() {
NetworkServiceGrpc.NetworkServiceBlockingStub stub = NetworkServiceGrpc.newBlockingStub(this.masterChannel);
ResponseList responseList = stub.getReadReplicaList(null);
this.replicaSet = responseList.getFollowerList();
// for (Follower follower: this.replicaSet) {
// System.out.println(follower);
// }
}
public void cleanup() {
for (ManagedChannel channel: this.channels)
channel.shutdown();
}
public void initStorage() {
masterChannel = ManagedChannelBuilder.
forAddress(ConfigConstants.HOST, ConfigConstants.PORT)
.usePlaintext()
.build();
channels = new ArrayList<>();
channels.add(masterChannel);
masterStub = NetworkServiceGrpc.newFutureStub(this.masterChannel);
retrieveFollowerList();
for (Follower follower: replicaSet) {
ManagedChannel channel = ManagedChannelBuilder.
forAddress(follower.getIp(), follower.getPort())
.usePlaintext()
.build();
channels.add(channel);
NetworkServiceGrpc.NetworkServiceFutureStub stub = NetworkServiceGrpc.newFutureStub(channel);
stubs.add(stub);
}
}
public ListenableFuture<Packet> create(String key, String value, int accessType) {
ArrayList<Request> request = new ArrayList<>();
request.add(RequestBuilder.buildRequest(MessageConstants.METADATA_CREATE,
0, value.length(), key,
0, accessType, this.clientID, value));
Packet packet = RequestBuilder.buildPacket(request);
return this.masterStub.createMetadata(packet);
}
public ListenableFuture<Packet> read(String key) {
int rnd = new Random().nextInt(this.stubs.size());
NetworkServiceGrpc.NetworkServiceFutureStub stub = this.stubs.get(rnd);
ArrayList<Request> request = new ArrayList<>();
request.add(RequestBuilder.buildRequest(MessageConstants.METADATA_READ,
0, 0, key, 0, MessageConstants.METADATA_ACCESS_PRIVATE, this.clientID, ""));
Packet packet = RequestBuilder.buildPacket(request);
return stub.readMetadata(packet);
}
public ListenableFuture<Packet> update(String key, String value, int version) {
ArrayList<Request> request = new ArrayList<>();
request.add(RequestBuilder.buildRequest(MessageConstants.METADATA_UPDATE,
version, value.length(), key,
0, MessageConstants.METADATA_ACCESS_PRIVATE, this.clientID, value));
Packet packet = RequestBuilder.buildPacket(request);
return this.masterStub.updateMetadata(packet);
}
public ListenableFuture<Packet> delete(String key, int version) {
ArrayList<Request> request = new ArrayList<>();
request.add(RequestBuilder.buildRequest(MessageConstants.METADATA_DELETE,
version, 0, key,
0, MessageConstants.METADATA_ACCESS_PRIVATE, this.clientID, ""));
Packet packet = RequestBuilder.buildPacket(request);
return this.masterStub.deleteMetadata(packet);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#JAVA_HOME" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="libraries-with-intellij-classes">
<option name="intellijApiContainingLibraries">
<list>
<LibraryCoordinatesState>
<option name="artifactId" value="ideaIU" />
<option name="groupId" value="com.jetbrains.intellij.idea" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="ideaIU" />
<option name="groupId" value="com.jetbrains" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="ideaIC" />
<option name="groupId" value="com.jetbrains.intellij.idea" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="ideaIC" />
<option name="groupId" value="com.jetbrains" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="pycharmPY" />
<option name="groupId" value="com.jetbrains.intellij.pycharm" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="pycharmPY" />
<option name="groupId" value="com.jetbrains" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="pycharmPC" />
<option name="groupId" value="com.jetbrains.intellij.pycharm" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="pycharmPC" />
<option name="groupId" value="com.jetbrains" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="clion" />
<option name="groupId" value="com.jetbrains.intellij.clion" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="clion" />
<option name="groupId" value="com.jetbrains" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="riderRD" />
<option name="groupId" value="com.jetbrains.intellij.rider" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="riderRD" />
<option name="groupId" value="com.jetbrains" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="goland" />
<option name="groupId" value="com.jetbrains.intellij.goland" />
</LibraryCoordinatesState>
<LibraryCoordinatesState>
<option name="artifactId" value="goland" />
<option name="groupId" value="com.jetbrains" />
</LibraryCoordinatesState>
</list>
</option>
</component>
</project>
\ No newline at end of file
app.name=HPDOS-Server
app.version=0.1.6
app.REPLICATION_TYPE=async
app.REPLICATOR_THREAD_POOL_SIZE=140
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java application project to get you started.
* For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle
* User Manual available at https://docs.gradle.org/6.8.3/userguide/building_java_projects.html
*/
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
id 'application'
id "com.google.protobuf" version "0.8.15"
id "java"
}
repositories {
// Use JCenter for resolving dependencies.
jcenter()
mavenCentral()
}
dependencies {
// Use JUnit test framework.
testImplementation 'junit:junit:4.13'
// This dependency is used by the application.
implementation 'com.google.guava:guava:29.0-jre'
implementation group: 'com.google.protobuf', name: 'protobuf-java', version: '3.15.6'
implementation 'io.grpc:grpc-netty-shaded:1.36.0'
implementation 'io.grpc:grpc-protobuf:1.36.0'
implementation 'io.grpc:grpc-stub:1.36.0'
compileOnly 'org.apache.tomcat:annotations-api:6.0.53' // necessary for Java 9+
}
application {
// Define the main class for the application.
mainClass = 'hpdos.MetadataServer'
}
sourceSets {
src {
main {
java {
srcDirs 'build/generated/source/proto/main/grpc'
srcDirs 'build/generated/source/proto/main/java'
}
}
}
}
protobuf {
protoc {
artifact = 'com.google.protobuf:protoc:3.15.6'
}
plugins {
grpc {
artifact = "io.grpc:protoc-gen-grpc-java:1.36.0"
}
}
generateProtoTasks {
all()*.plugins {
grpc {}
}
}
}
\ No newline at end of file
package hpdos;
public class ConfigConstants {
public static final String HOST = "localhost";
public static final int PORT = 8080;
public static final int HEARTBEAT_INTERVAL = 500;
public static final int REPLICATION_TIMEOUT = 5000;
public static final String replicationAsync = "async";
// Backend types 300-399
public static final int BACKEND_IN_MEMORY = 300;
public static final int LSM_BACKEND = 301;
public static final int BINARY_TREE_BACKEND = 302;
public static final int REPLICATOR_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2;
}
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package hpdos;
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.*;
import hpdos.message.MessageConstants;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
public class MetadataServer {
private Server server;
private final HashMap<String, MasterFollower> followers;
private final String serverID;
private boolean isMaster = false;
private int port;
private final String host;
private IOHandler ioHandler;
private ReplicationService replicationService;
private final Properties properties;
public MetadataServer(String propertiesFile) throws IOException {
this.followers = new HashMap<>();
this.serverID = UUID.randomUUID().toString();
this.port = 10000 + (int)(Math.random() * 40000);
this.host = "localhost";
this.replicationService = null;
this.properties = new Properties();
InputStream inputStream = new FileInputStream(propertiesFile);
properties.load(inputStream);
}
public String getGreeting() {
return "Hello World!";
}
public boolean startMasterServices() {
this.server = ServerBuilder.forPort(ConfigConstants.PORT)
.addService(new NetworkHandler(this.ioHandler, this.replicationService))
.addService(new HeartbeatHandler(followers, serverID))
.build();
try {
this.server.start();
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
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(port)
.addService(new NetworkHandler(this.ioHandler, this.replicationService))
.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 {
server.awaitTermination();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void announceToMaster() {
final ManagedChannel channel = ManagedChannelBuilder.
forAddress(ConfigConstants.HOST, ConfigConstants.PORT)
.usePlaintext()
.build();
HeartbeatServiceGrpc.HeartbeatServiceBlockingStub stub = HeartbeatServiceGrpc.newBlockingStub(channel);
HeartbeatRequest.Builder heartbeat = HeartbeatRequest.newBuilder();
heartbeat.setPacketType(MessageConstants.PACKET_METADATA_REQUEST);
heartbeat.setOperationType(MessageConstants.MASTER_HEARTBEAT);
heartbeat.setFollowerID(this.serverID);
heartbeat.setIp(this.host);
heartbeat.setPort(this.port);
try {
HeartbeatResponse response = stub.heartbeat(heartbeat.build());
} catch (Exception e) {
System.out.println("Metadata Master not found, electing self as master");
this.isMaster = true;
this.port = ConfigConstants.PORT;
}
channel.shutdown();
}
private void startHeartbeatService() {
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
announceToMaster();
}
}, ConfigConstants.HEARTBEAT_INTERVAL, ConfigConstants.HEARTBEAT_INTERVAL);
}
private IOHandler initStorage(int backend) {
StorageService storageService;
switch (backend) {
case ConfigConstants.BACKEND_IN_MEMORY:
storageService = new MemoryStorageService();
break;
case ConfigConstants.BINARY_TREE_BACKEND:
case ConfigConstants.LSM_BACKEND:
default: return null;
}
return new IOHandler(storageService, this.isMaster);
}
private void cleanup () {
if (this.replicationService != null) {
try {
this.replicationService.cleanup();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
MetadataServer metaDataServer = null;
try {
metaDataServer = new MetadataServer(args[0]);
} catch (IOException e) {
System.out.println("Config file missing or unreadable");
System.exit(-1);
}
System.out.println(metaDataServer.getGreeting());
System.out.println("Starting Metadata service");
System.out.println("Initialising storage service");
// 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) {
metaDataServer.replicationService = new InlineReplicationService(
metaDataServer.followers, metaDataServer.properties);
System.out.println("Started master replication module");
boolean status = metaDataServer.startMasterServices();
System.out.println("Master ID: " + metaDataServer.serverID);
if (status) {
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");
}
// Adding a shutdown hook
Runtime current = Runtime.getRuntime();
current.addShutdownHook(new Thread(metaDataServer::cleanup));
}
}
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.lib.StoredModel;
import hpdos.message.MessageConstants;
import hpdos.message.ResponseBuilder;
public class IOHandler {
StorageService storageService;
private final boolean isMaster;
public IOHandler(StorageService storageService, boolean isMaster) {
this.storageService = storageService;
this.isMaster = isMaster;
}
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());
StoredModel storedData = storageService.create(request.getKey(), blob);
if (storedData.getStatus() == MessageConstants.STATUS_OK) {
ack = ResponseBuilder.buildAck(storedData.getData().getVersion(),
storedData.getData().getDataSize(),
storedData.getData().getKey(),
storedData.getData().getCrc(),
storedData.getData().getValue());
return ResponseBuilder.buildResponsePacket(
MessageConstants.METADATA_CREATE, MessageConstants.STATUS_OK,
ack, null);
}
else {
nack = ResponseBuilder.buildNack(MessageConstants.INVALID_VERSION,
request.getKey());
return ResponseBuilder.buildResponsePacket(
MessageConstants.METADATA_CREATE, storedData.getStatus(),
null, nack);
}
}
public Response update(Request request) {
Ack ack = null; Nack nack = null;
StorageModel blob = new StorageModel(
request.getVersion(),
request.getDataSize(),
request.getKey(),
request.getAccessType(),
request.getClientID(),
request.getValue());
StoredModel storedData = storageService.update(request.getKey(), blob);
if (storedData.getStatus() == MessageConstants.STATUS_OK) {
ack = ResponseBuilder.buildAck(storedData.getData().getVersion(),
storedData.getData().getDataSize(),
storedData.getData().getKey(),
storedData.getData().getCrc(),
storedData.getData().getValue());
return ResponseBuilder.buildResponsePacket(
MessageConstants.METADATA_UPDATE, MessageConstants.STATUS_OK,
ack, null);
}
else {
int version = (storedData.getStatus() == MessageConstants.STATUS_UPDATE_VERSION_MISMATCH)?
storedData.getData().getVersion(): MessageConstants.INVALID_VERSION;
nack = ResponseBuilder.buildNack(version, request.getKey());
return ResponseBuilder.buildResponsePacket(
MessageConstants.METADATA_UPDATE, storedData.getStatus(),
null, nack);
}
}
/**
* Removes the object from the KV store if the request version matches with the current version of data
* @param request Models to be deleted. Only the key, clientID and version needs to be valid
* @return previous value if successful else null with status
*/
public Response delete(Request request) {
Ack ack = null; Nack nack = null;
StorageModel blob = new StorageModel(
request.getVersion(),
request.getDataSize(),
request.getKey(),
request.getAccessType(),
request.getClientID(),
request.getValue());
StoredModel storedData = storageService.delete(request.getKey(), blob);
if (storedData.getStatus() == MessageConstants.STATUS_OK) {
ack = ResponseBuilder.buildAck(storedData.getData().getVersion(),
storedData.getData().getDataSize(),
storedData.getData().getKey(),
storedData.getData().getCrc(),
storedData.getData().getValue());
return ResponseBuilder.buildResponsePacket(
MessageConstants.METADATA_DELETE, MessageConstants.STATUS_OK,
ack, null);
}
else {
int version = (storedData.getStatus() == MessageConstants.STATUS_UPDATE_VERSION_MISMATCH)?
storedData.getData().getVersion(): MessageConstants.INVALID_VERSION;
nack = ResponseBuilder.buildNack(version, request.getKey());
return ResponseBuilder.buildResponsePacket(
MessageConstants.METADATA_DELETE, storedData.getStatus(),
null, nack);
}
}
public Response read(Request request) {
Ack ack = null; Nack nack = null;
int status;
// Only Metadata Master can serve shared object lookup requests
if (!isMaster && request.getAccessType() == MessageConstants.METADATA_ACCESS_SHARED) {
status = MessageConstants.STATUS_SERVER_NOT_MASTER;
nack = ResponseBuilder.buildNack(MessageConstants.INVALID_VERSION,
request.getKey());
} else {
StoredModel readData = storageService.readByKey(request.getKey());
if (readData.getStatus() == MessageConstants.STATUS_KEY_NOT_FOUND) {
status = MessageConstants.STATUS_KEY_NOT_FOUND;
nack = ResponseBuilder.buildNack(MessageConstants.INVALID_VERSION,
request.getKey());
} else if (readData.getData() != null &&
readData.getData().getAccessType() == MessageConstants.METADATA_ACCESS_PRIVATE &&
!request.getClientID().equals(readData.getData().getOwner())) {
status = MessageConstants.STATUS_UNAUTHORIZED_PRIVATE_KEY_ACCESS;
nack = ResponseBuilder.buildNack(MessageConstants.INVALID_VERSION,
request.getKey());
} else {
status = MessageConstants.STATUS_OK;
ack = ResponseBuilder.buildAck(readData.getData().getVersion(),
readData.getData().getDataSize(),
readData.getData().getKey(),
readData.getData().getCrc(),
readData.getData().getValue());
}
}
return ResponseBuilder.buildResponsePacket(
MessageConstants.METADATA_READ, status,
ack, nack);
}
}
package hpdos.handler;
import com.google.common.base.Stopwatch;
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);
Stopwatch stopwatch = Stopwatch.createUnstarted();
stopwatch.start();
if (replicationRequest.getPacketType() == MessageConstants.PACKET_METADATA_REQUEST) {
if (replicationRequest.getRequestList().size() > 1)
System.out.println("REQUEST BATCHING");
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);
}
// System.out.println(responsePacket);
responseObserver.onNext(responsePacket);
}
responseObserver.onCompleted();
}
stopwatch.stop();
// System.out.println("Replicate Handler " + stopwatch);
}
}
package hpdos.lib;
import com.google.common.base.Stopwatch;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import hpdos.ConfigConstants;
import hpdos.grpc.ReplicationRequest;
import hpdos.grpc.ReplicationResponse;
import hpdos.grpc.ReplicationServiceGrpc;
import hpdos.grpc.Response;
import hpdos.message.MessageConstants;
import hpdos.message.ResponseBuilder;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import javax.annotation.Nonnull;
import java.util.*;
import java.util.concurrent.*;
public class InlineReplicationService implements ReplicationService {
private final HashMap<String, MasterFollower> followers;
private final HashMap<String, ManagedChannel> channels;
private ExecutorService executorService;
private final boolean isReplicationAsync;
public InlineReplicationService(HashMap<String, MasterFollower> followers, Properties properties) {
this.followers = followers;
this.channels = new HashMap<>();
String replicationType = (String) properties.get("app.REPLICATION_TYPE");
this.isReplicationAsync = replicationType.equals(ConfigConstants.replicationAsync);
if (!this.isReplicationAsync) {
int replicationThreadPoolSize;
if (properties.containsKey("app.REPLICATOR_THREAD_POOL_SIZE")) {
replicationThreadPoolSize = Integer.parseInt((String)
properties.get("app.REPLICATOR_THREAD_POOL_SIZE"));
} else {
replicationThreadPoolSize = ConfigConstants.REPLICATOR_THREAD_POOL_SIZE;
}
this.executorService = Executors.newFixedThreadPool(replicationThreadPoolSize);
System.out.println("Creating synchronous replication pool. Pool size: " + replicationThreadPoolSize);
} else {
System.out.println("Replication to be handled using asynchronous handlers");
}
}
@Override
public void cleanup() throws InterruptedException {
for (ManagedChannel channel: channels.values())
channel.shutdown();
if (this.executorService != null) {
executorService.shutdown();
boolean status = executorService.
awaitTermination(MessageConstants.STATUS_REPLICATION_TIMEOUT, TimeUnit.MILLISECONDS);
if (!status)
executorService.shutdownNow();
}
}
private void establishChannels() {
for (String followerID: followers.keySet()) {
if (!channels.containsKey(followerID)) {
MasterFollower follower = followers.get(followerID);
ManagedChannel channel = ManagedChannelBuilder
.forAddress(follower.getIp(), follower.getPort())
.usePlaintext()
.build();
channels.put(follower.getFollowerID(), channel);
}
}
}
@Override
public ReplicationResponse replicateMetadata(ReplicationRequest replicationRequest) throws ExecutionException, InterruptedException {
if (this.isReplicationAsync) {
return replicateMetadataAsync(replicationRequest);
} else {
return replicateMetadataSync(replicationRequest);
}
}
public ReplicationResponse replicateMetadataSync(ReplicationRequest replicationRequest)
throws InterruptedException, ExecutionException {
Set<Callable<ReplicationResponse>> callables = new HashSet<>();
// new followers have joined or left.
// TODO: Handle follower leaving scenario
// FIXME: fix edge case where equal number of followers leaving and joining won't trigger connection reestablishment
if (channels.size() != followers.size()) {
establishChannels();
}
for (ManagedChannel channel: channels.values()) {
callables.add(() -> {
ReplicationServiceGrpc.ReplicationServiceBlockingStub stub =
ReplicationServiceGrpc.newBlockingStub(channel);
return stub.replicateMetadata(replicationRequest);
});
}
List<Future<ReplicationResponse>> futures = executorService.invokeAll(callables);
HashMap<String, Response> responseHashMap = new HashMap<>();
Stopwatch stopwatch = Stopwatch.createUnstarted();
stopwatch.start();
for (Future<ReplicationResponse> future: futures) {
ReplicationResponse replicationResponse;
replicationResponse = future.get(); //TODO: Add and handle get timeout. Timeout related constants already added
for (Response receivedResponse: replicationResponse.getResponseList()) {
int status = receivedResponse.getStatus();
if (status == MessageConstants.STATUS_OK) {
if (!responseHashMap.containsKey(receivedResponse.getAck().getKey()))
responseHashMap.put(receivedResponse.getAck().getKey(), receivedResponse);
} else {
responseHashMap.put(receivedResponse.getNack().getKey(), receivedResponse);
}
}
}
stopwatch.stop();
// System.out.println("replicateMetadata ReplicationService " + stopwatch);
return ResponseBuilder.
buildReplicationResponse(new ArrayList<>(responseHashMap.values()));
}
/**
* Incomplete implementation do not use
* @param replicationRequest replication request sent
* @return replication response
*/
public ReplicationResponse replicateMetadataAsync(ReplicationRequest replicationRequest) throws InterruptedException {
CountDownLatch replicationWaiter = new CountDownLatch(this.followers.size());
HashMap<String, Response> responseHashMap = new HashMap<>();
if (channels.size() != followers.size()) {
establishChannels();
}
for (ManagedChannel channel: channels.values()) {
ReplicationServiceGrpc.ReplicationServiceFutureStub stub =
ReplicationServiceGrpc.newFutureStub(channel);
ListenableFuture<ReplicationResponse> res = stub.replicateMetadata(replicationRequest);
Futures.addCallback(res, new FutureCallback<>() {
@Override
public void onSuccess(ReplicationResponse result) {
for (Response receivedResponse: result.getResponseList()) {
int status = receivedResponse.getStatus();
if (status == MessageConstants.STATUS_OK) {
if (!responseHashMap.containsKey(receivedResponse.getAck().getKey()))
responseHashMap.put(receivedResponse.getAck().getKey(), receivedResponse);
} else {
responseHashMap.put(receivedResponse.getNack().getKey(), receivedResponse);
}
}
replicationWaiter.countDown();
}
@Override
public void onFailure(@Nonnull Throwable t) {
replicationWaiter.countDown();
}
}, MoreExecutors.directExecutor());
}
Stopwatch stopwatch = Stopwatch.createUnstarted();
stopwatch.start();
replicationWaiter.await();
stopwatch.stop();
// System.out.println("replication latency" + stopwatch);
return ResponseBuilder.
buildReplicationResponse(new ArrayList<>(responseHashMap.values()));
}
@Override
public HashMap<String, MasterFollower> getFollowers() {
return followers;
}
}
package hpdos.lib;
import hpdos.message.MessageConstants;
import java.util.concurrent.ConcurrentHashMap;
public class MemoryStorageService implements StorageService {
private final ConcurrentHashMap<String, StorageModel> memoryKVStore;
public MemoryStorageService() {
this.memoryKVStore = new ConcurrentHashMap<>();
}
@Override
public StoredModel create(String key, StorageModel value) {
try {
if (memoryKVStore.putIfAbsent(key, value) != null)
return new StoredModel(null, MessageConstants.STATUS_KEY_EXISTS);
return new StoredModel(value, MessageConstants.STATUS_OK);
} catch (Exception e) {
return null;
}
}
@Override
public StoredModel readByKey(String key) {
if (!memoryKVStore.containsKey(key))
return new StoredModel(null, MessageConstants.STATUS_KEY_NOT_FOUND);
return new StoredModel(memoryKVStore.get(key), MessageConstants.STATUS_OK);
}
@Override
public StoredModel update(String key, StorageModel value) {
StorageModel previousValue = memoryKVStore.get(key);
if (previousValue == null)
return new StoredModel(null, MessageConstants.STATUS_KEY_NOT_FOUND);
else if (previousValue.getAccessType() == MessageConstants.METADATA_ACCESS_PRIVATE
&& !previousValue.getOwner().equals(value.getOwner()))
return new StoredModel(null, MessageConstants.STATUS_UNAUTHORIZED_PRIVATE_KEY_ACCESS);
// the request will have the old version number of the data to be inserted, we only update the data
// with a new version number if at the time of update the two versions match
// else we reject the update
StorageModel newValue = value.createVersionUpdatedModel();
boolean status = memoryKVStore.replace(key, value, newValue); // the equals method is overridden in Storage model
// to equate two objects based on their version numbers
if (status)
return new StoredModel(newValue, MessageConstants.STATUS_OK);
else
return new StoredModel(previousValue, MessageConstants.STATUS_UPDATE_VERSION_MISMATCH);
}
@Override
public StoredModel delete(String key, StorageModel value) {
StorageModel previousValue = memoryKVStore.get(key);
if (previousValue == null)
return new StoredModel(null, MessageConstants.STATUS_KEY_NOT_FOUND);
else if (previousValue.getAccessType() == MessageConstants.METADATA_ACCESS_PRIVATE
&& !previousValue.getOwner().equals(value.getOwner()))
return new StoredModel(null, MessageConstants.STATUS_UNAUTHORIZED_PRIVATE_KEY_ACCESS);
boolean status = memoryKVStore.remove(key, value);
if (status)
return new StoredModel(previousValue, MessageConstants.STATUS_OK);
else
return new StoredModel(previousValue, MessageConstants.STATUS_UPDATE_VERSION_MISMATCH);
}
}
package hpdos.lib;
import hpdos.grpc.ReplicationRequest;
import hpdos.grpc.ReplicationResponse;
import java.util.HashMap;
import java.util.concurrent.ExecutionException;
public interface ReplicationService {
abstract ReplicationResponse replicateMetadata(ReplicationRequest replicationRequest) throws InterruptedException, ExecutionException;
abstract void cleanup() throws InterruptedException;
abstract HashMap<String, MasterFollower> getFollowers();
}
package hpdos.lib;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
public class StorageModel {
private int version;
private int dataSize;
private final String key; // key is immutable
private long crc;
private int accessType;
private String value;
private final String owner; // ownership is immutable
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 StorageModel createVersionUpdatedModel() {
int updatedVersion = (this.getVersion() + 1) % Integer.MAX_VALUE; // version wraps around
return new StorageModel(updatedVersion, this.getDataSize(),
this.getKey(), this.getAccessType(), this.getOwner(), this.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 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;
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (obj.getClass() != this.getClass())
return false;
StorageModel model = (StorageModel) obj;
return this.getVersion() == model.getVersion();
}
}
package hpdos.message;
public class MessageConstants {
public static final int INIT_VERSION = 1;
public static final int INVALID_VERSION = -1;
public static final int METADATA_ACCESS_PRIVATE = 700;
public static final int METADATA_ACCESS_SHARED = 777;
// 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
public static final int STATUS_OK = 200;
public static final int STATUS_UNAUTHORIZED_PRIVATE_KEY_ACCESS = 401;
public static final int STATUS_REPLICATION_FAILED = 402;
public static final int STATUS_SERVER_NOT_MASTER = 403;
public static final int STATUS_KEY_NOT_FOUND = 404;
public static final int STATUS_REPLICATION_TIMEOUT = 405;
public static final int STATUS_IO_WRITE_FAILED = 406;
public static final int STATUS_KEY_EXISTS = 407;
public static final int STATUS_UPDATE_VERSION_MISMATCH = 408;
// 100 to 199 - HPDOS System internal operations
public static final int MASTER_HEARTBEAT = 100;
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.message;
import hpdos.grpc.*;
import java.util.ArrayList;
public class ResponseBuilder {
public static Ack buildAck(int version, int dataSize, String key, long crc, String value) {
Ack.Builder ack = Ack.newBuilder();
ack.setKey(key);
ack.setVersion(version);
ack.setDataSize(dataSize);
ack.setCrc(crc);
ack.setValue(value);
return ack.build();
}
public static Nack buildNack(int version, String key) {
Nack.Builder nack = Nack.newBuilder();
nack.setKey(key);
nack.setVersion(version);
return nack.build();
}
public static Response buildResponsePacket(int operationType, int status,
Ack ack,
Nack nack) {
Response.Builder response = Response.newBuilder();
response.setOperationType(operationType);
response.setStatus(status);
if (ack != null)
response.setAck(ack);
else
response.clearAck();
if (nack != null)
response.setNack(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();
}
public static ReplicationResponse buildReplicationResponse(ArrayList<Response> response) {
ReplicationResponse.Builder packet = ReplicationResponse.newBuilder();
packet.setPacketType(MessageConstants.PACKET_METADATA_RESPONSE);
if (response.size() > 1)
System.out.println("RESPONSE BATCHING" + response.size());
try {
for (Response subResponse: response)
if (subResponse != null)
packet.addResponse(subResponse);
} catch (Exception e) {
System.out.println(response);
System.exit(0);
}
return packet.build();
}
}
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package hpdos;
import org.junit.Test;
import java.io.IOException;
import static org.junit.Assert.*;
public class AppTest {
@Test public void testAppHasAGreeting() throws IOException {
MetadataServer classUnderTest = new MetadataServer("dummypath");
assertNotNull("app should have a greeting", classUnderTest.getGreeting());
}
}
#### Metadata server with kernel stack and LSM-tree backend
- Install gradle version
https://linuxize.com/post/how-to-install-gradle-on-ubuntu-20-04/
- Steps to compile/run metadata application
-- Server
--- ./gradlew build
--- ./gradlew installDist
--- ./app/build/install/app/bin/app
-- Client
--- ./gradlew build
--- ./gradlew installDist
--- ./app/build/install/app/bin/app <absolute-path>/app.config
#
# https://help.github.com/articles/dealing-with-line-endings/
#
# These are explicitly windows files and should use crlf
*.bat text eol=crlf
# Ignore Gradle project-specific cache directory
.gradle
# Ignore Gradle build output directory
build
# Default ignored files
/shelf/
/workspace.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="14" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="MavenRepo" />
<option name="name" value="MavenRepo" />
<option name="url" value="https://repo.maven.apache.org/maven2/" />
</remote-repository>
<remote-repository>
<option name="id" value="BintrayJCenter" />
<option name="name" value="BintrayJCenter" />
<option name="url" value="https://jcenter.bintray.com/" />
</remote-repository>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_14" default="true" project-jdk-name="14" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
</component>
</project>
\ No newline at end of file
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java application project to get you started.
* For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle
* User Manual available at https://docs.gradle.org/6.8.3/userguide/building_java_projects.html
*/
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
id 'application'
id "com.google.protobuf" version "0.8.15"
id "java"
}
repositories {
// Use JCenter for resolving dependencies.
jcenter()
mavenCentral()
}
dependencies {
// Use JUnit test framework.
testImplementation 'junit:junit:4.13'
// This dependency is used by the application.
implementation 'com.google.guava:guava:29.0-jre'
implementation group: 'com.google.protobuf', name: 'protobuf-java', version: '3.15.6'
implementation 'io.grpc:grpc-netty-shaded:1.36.0'
implementation 'io.grpc:grpc-protobuf:1.36.0'
implementation 'io.grpc:grpc-stub:1.36.0'
compileOnly 'org.apache.tomcat:annotations-api:6.0.53' // necessary for Java 9+
}
application {
// Define the main class for the application.
mainClass = 'HpdosClient.ClientRunner'
}
sourceSets {
src {
main {
java {
srcDirs 'build/generated/source/proto/main/grpc'
srcDirs 'build/generated/source/proto/main/java'
}
}
}
}
protobuf {
protoc {
artifact = 'com.google.protobuf:protoc:3.15.6'
}
plugins {
grpc {
artifact = "io.grpc:protoc-gen-grpc-java:1.36.0"
}
}
generateProtoTasks {
all()*.plugins {
grpc {}
}
}
}
package HpdosClient;
public class ConfigConstants {
public static final String HOST = "localhost";
public static final int PORT = 8080;
public static final String URL = HOST + ":" + PORT;
}
package HpdosClient.MessageFormat;
import hpdos.grpc.Packet;
import hpdos.grpc.Request;
import java.util.ArrayList;
public class RequestBuilder {
public static Request buildRequest(int operationType, int version,
int dataSize, String key, int crc,
int accessType, String clientID, String value) {
Request.Builder request = Request.newBuilder();
request.setOperationType(operationType);
request.setVersion(version);
request.setDataSize(dataSize);
request.setKey(key);
request.setCrc(crc);
request.setAccessType(accessType);
request.setClientID(clientID);
request.setValue(value);
return request.build();
}
public static Packet buildPacket(ArrayList<Request> requests) {
Packet.Builder packet = Packet.newBuilder();
packet.setPacketType(MessageConstants.PACKET_METADATA_REQUEST);
packet.addAllRequest(requests);
return packet.build();
}
}
package HpdosClient.MessageFormat;
import hpdos.grpc.*;
import java.util.ArrayList;
public class ResponseBuilder {
public static Ack buildAck(int version, int dataSize, String key, long crc, String value) {
Ack.Builder ack = Ack.newBuilder();
ack.setKey(key);
ack.setVersion(version);
ack.setDataSize(dataSize);
ack.setCrc(crc);
ack.setValue(value);
return ack.build();
}
public static Nack buildNack(int version, String key) {
Nack.Builder nack = Nack.newBuilder();
nack.setKey(key);
nack.setVersion(version);
return nack.build();
}
public static Response buildResponsePacket(int operationType, int status,
Ack ack,
Nack nack) {
Response.Builder response = Response.newBuilder();
response.setOperationType(operationType);
response.setStatus(status);
if (ack != null)
response.setAck(ack);
else
response.clearAck();
if (nack != null)
response.setNack(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();
}
}
syntax = "proto3";
package hpdos.grpc;
option java_multiple_files = true;
option java_package = "hpdos.grpc";
option java_outer_classname = "PacketFormatProto";
service NetworkService {
/**
Receive Packet from client
*/
rpc readMetadata(Packet) returns (Packet) {}
rpc createMetadata(Packet) returns (Packet) {}
rpc updateMetadata(Packet) returns (Packet) {}
rpc deleteMetadata(Packet) returns (Packet) {}
rpc getReadReplicaList(RequestList) returns (ResponseList) {}
}
message Packet {
int32 packetType = 1;
repeated Request request = 2;
repeated Response response = 3;
}
message Request {
int32 operationType = 1;
int32 version = 2;
int32 dataSize = 3;
string key = 4;
int64 crc = 5;
int32 accessType = 6;
string clientID = 7;
string value = 8;
}
message Response {
int32 operationType = 1;
int32 status = 2;
Ack ack = 3;
Nack nack = 4;
}
message Ack {
int32 version = 2;
int32 dataSize = 3;
string key = 4;
int64 crc = 5;
string value = 6;
}
message Nack {
string key = 2;
int32 version = 3;
}
message RequestList {}
message ResponseList {
int32 operationType = 1;
int32 status = 2;
repeated Follower follower = 3;
}
message Follower {
string ip = 1;
int32 port = 2;
string followerID = 3;
int64 lastSeen = 4;
}
\ No newline at end of file
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package HpdosClient;
import org.junit.Test;
import static org.junit.Assert.*;
public class AppTest {
@Test public void testAppHasAGreeting() {
ClientRunner classUnderTest = new ClientRunner();
assertNotNull("app should have a greeting", classUnderTest.getGreeting());
}
}
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
/*
* This file was generated by the Gradle 'init' task.
*
* The settings file is used to specify which projects to include in your build.
*
* Detailed information about configuring a multi-project build in Gradle can be found
* in the user manual at https://docs.gradle.org/6.8.3/userguide/multi_project_builds.html
*/
rootProject.name = 'HpdosClient'
include('app')
# Default ignored files
/shelf/
/workspace.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="14" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="MavenRepo" />
<option name="name" value="MavenRepo" />
<option name="url" value="https://repo.maven.apache.org/maven2/" />
</remote-repository>
<remote-repository>
<option name="id" value="BintrayJCenter" />
<option name="name" value="BintrayJCenter" />
<option name="url" value="https://jcenter.bintray.com/" />
</remote-repository>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_14" default="true" project-jdk-name="14" project-jdk-type="JavaSDK" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="bin/main" path="src/main/java">
<attributes>
<attribute name="gradle_scope" value="main"/>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/main" path="src/main/resources">
<attributes>
<attribute name="gradle_scope" value="main"/>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/test" path="src/test/java">
<attributes>
<attribute name="gradle_scope" value="test"/>
<attribute name="gradle_used_by_scope" value="test"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/test" path="src/test/resources">
<attributes>
<attribute name="gradle_scope" value="test"/>
<attribute name="gradle_used_by_scope" value="test"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/main" path="build/generated/source/proto/main/java">
<attributes>
<attribute name="gradle_scope" value="main"/>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-14/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>app</name>
<comment>Project app created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
<filteredResources>
<filter>
<id>1617116007477</id>
<name></name>
<type>30</type>
<matcher>
<id>org.eclipse.core.resources.regexFilterMatcher</id>
<arguments>node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
</matcher>
</filter>
</filteredResources>
</projectDescription>
package hpdos.handler;
import hpdos.grpc.HeartbeatRequest;
import hpdos.grpc.HeartbeatResponse;
import hpdos.grpc.HeartbeatServiceGrpc;
import hpdos.lib.MasterFollower;
import hpdos.message.MessageConstants;
import io.grpc.stub.StreamObserver;
import java.time.Instant;
import java.util.HashMap;
public class HeartbeatHandler extends HeartbeatServiceGrpc.HeartbeatServiceImplBase {
private final HashMap<String, MasterFollower> followers;
private final String serverID;
public HeartbeatHandler(HashMap<String, MasterFollower> followers, String serverID) {
this.followers = followers;
this.serverID = serverID;
}
@Override
public void heartbeat(HeartbeatRequest request, StreamObserver<HeartbeatResponse> heartbeatResponseStreamObserver) {
if (!followers.containsKey(request.getFollowerID())) {
System.out.println("New follower autodiscovery. Added to system " + request);
followers.put(request.getFollowerID(), new MasterFollower(request.getIp(),
request.getPort(), request.getFollowerID()));
} else {
MasterFollower follower = followers.get(request.getFollowerID());
follower.setLastSeen(Instant.now().getEpochSecond());
}
HeartbeatResponse.Builder response = HeartbeatResponse.newBuilder();
response.setPacketType(MessageConstants.PACKET_METADATA_RESPONSE);
response.setOperationType(MessageConstants.MASTER_HEARTBEAT);
response.setMasterID(this.serverID);
heartbeatResponseStreamObserver.onNext(response.build());
heartbeatResponseStreamObserver.onCompleted();
}
}
package hpdos.handler;
import com.google.common.base.Stopwatch;
import hpdos.grpc.*;
import hpdos.lib.MasterFollower;
import hpdos.lib.ReplicationService;
import hpdos.message.RequestBuilder;
import hpdos.message.ResponseBuilder;
import io.grpc.stub.StreamObserver;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.ExecutionException;
public class NetworkHandler extends NetworkServiceGrpc.NetworkServiceImplBase {
private final IOHandler ioHandler;
private final ReplicationService replicationService;
public NetworkHandler(IOHandler ioHandler, ReplicationService replicationService) {
this.ioHandler = ioHandler;
this.replicationService = replicationService;
}
@Override
public void readMetadata(Packet requestPacket,
StreamObserver<Packet> responseObserver) {
// System.out.println("Data received" + requestPacket.toString());
for (Request request: requestPacket.getRequestList()) {
Response response = ioHandler.read(request);
Packet packet = ResponseBuilder.buildPacket(response);
// System.out.println(packet);
responseObserver.onNext(packet);
}
responseObserver.onCompleted();
}
@Override
public void createMetadata(Packet requestPacket, StreamObserver<Packet> responseObserver) {
Stopwatch stopwatch = Stopwatch.createUnstarted();
stopwatch.start();
for (Request request: requestPacket.getRequestList()) {
ioHandler.create(request);
}
stopwatch.stop();
// System.out.println("Added to local memory " + stopwatch);
stopwatch.reset();
stopwatch.start();
Packet packet = replicate(requestPacket);
stopwatch.stop();
// System.out.println("Replication time " + stopwatch);
responseObserver.onNext(packet);
responseObserver.onCompleted();
}
@Override
public void updateMetadata(Packet requestPacket, StreamObserver<Packet> responseObserver) {
// System.out.println("new create request " + requestPacket);
for (Request request: requestPacket.getRequestList()) {
ioHandler.update(request);
}
// System.out.println("Added to local memory");
Packet packet = replicate(requestPacket);
responseObserver.onNext(packet);
responseObserver.onCompleted();
}
@Override
public void deleteMetadata(Packet requestPacket, StreamObserver<Packet> responseObserver) {
// System.out.println("new create request " + requestPacket);
for (Request request: requestPacket.getRequestList()) {
ioHandler.delete(request);
}
// System.out.println("Added to local memory");
Packet packet = replicate(requestPacket);
responseObserver.onNext(packet);
responseObserver.onCompleted();
}
@Override
public void getReadReplicaList(RequestList requestList,
StreamObserver<ResponseList> responseListStreamObserver) {
HashMap<String, MasterFollower> followers = replicationService.getFollowers();
ResponseList.Builder responseList = ResponseList.newBuilder();
for (MasterFollower follower: followers.values()) {
Follower.Builder replica = Follower.newBuilder();
replica.setIp(follower.getIp());
replica.setPort(follower.getPort());
replica.setFollowerID(follower.getFollowerID());
replica.setLastSeen(follower.getLastSeen());
replica.build();
responseList.addFollower(replica);
}
responseListStreamObserver.onNext(responseList.build());
responseListStreamObserver.onCompleted();
}
private Packet replicate(Packet requestPacket) {
ReplicationRequest replicationRequest = RequestBuilder.
buildReplicationRequest(new ArrayList<>(requestPacket.getRequestList()));
ReplicationResponse replicationResponse = null;
try {
// System.out.println("starting replication");
Stopwatch stopwatch = Stopwatch.createUnstarted();
stopwatch.start();
replicationResponse = replicationService.replicateMetadata(replicationRequest);
stopwatch.stop();
// System.out.println("Network handler replicate" + stopwatch);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
// System.out.println("replication complete");
Packet packet = ResponseBuilder.buildPacket(new ArrayList<>(replicationResponse.getResponseList()));
// System.out.println(packet);
return packet;
}
}
package hpdos.lib;
import java.time.Instant;
public class MasterFollower {
private String ip;
private int port;
private final String followerID;
private long lastSeen;
public MasterFollower(String ip, int port, String followerID) {
this.ip = ip;
this.port = port;
this.followerID = followerID;
this.lastSeen = Instant.now().getEpochSecond();
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getFollowerID() {
return followerID;
}
public long getLastSeen() {
return lastSeen;
}
public void setLastSeen(long lastSeen) {
this.lastSeen = lastSeen;
}
@Override
public String toString() {
return "MasterFollower {" +
"ip='" + ip + '\'' +
", port=" + port +
", followerID='" + followerID + '\'' +
'}';
}
}
package hpdos.lib;
public interface StorageService {
StoredModel create(String key, StorageModel value);
StoredModel readByKey(String key);
StoredModel update(String key, StorageModel value);
StoredModel delete(String key, StorageModel version);
}
package hpdos.lib;
public class StoredModel {
private StorageModel data;
private int status;
public StoredModel(StorageModel data, int status) {
this.data = data;
this.status = status;
}
public StorageModel getData() {
return data;
}
public void setData(StorageModel data) {
this.data = data;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
}
package hpdos.message;
import hpdos.grpc.Packet;
import hpdos.grpc.ReplicationRequest;
import hpdos.grpc.Request;
import java.util.ArrayList;
public class RequestBuilder {
public static Request buildRequest(int operationType, int version,
int dataSize, String key, int crc, String value) {
Request.Builder request = Request.newBuilder();
request.setOperationType(operationType);
request.setVersion(version);
request.setDataSize(dataSize);
request.setKey(key);
request.setCrc(crc);
request.setValue(value);
return request.build();
}
public static Packet buildPacket(ArrayList<Request> requests) {
Packet.Builder packet = Packet.newBuilder();
packet.setPacketType(MessageConstants.PACKET_METADATA_REQUEST);
packet.addAllRequest(requests);
return packet.build();
}
public static ReplicationRequest buildReplicationRequest(ArrayList<Request> requests) {
ReplicationRequest.Builder builder = ReplicationRequest.newBuilder();
builder.setPacketType(MessageConstants.PACKET_METADATA_REQUEST);
builder.addAllRequest(requests);
return builder.build();
}
}
syntax = "proto3";
package hpdos.grpc;
option java_multiple_files = true;
option java_package = "hpdos.grpc";
option java_outer_classname = "Heartbeat";
service HeartbeatService {
/**
Exchange heartbeat
*/
rpc heartbeat(HeartbeatRequest) returns (HeartbeatResponse) {}
}
message HeartbeatRequest {
int32 packetType = 1;
int32 operationType = 2;
string ip = 3;
int32 port = 4;
string followerID = 5;
}
message HeartbeatResponse {
int32 packetType = 1;
int32 operationType = 2;
bool status = 3;
string masterID = 4;
}
syntax = "proto3";
package hpdos.grpc;
option java_multiple_files = true;
option java_package = "hpdos.grpc";
option java_outer_classname = "PacketFormatProto";
service NetworkService {
/**
Receive Packet from client
*/
rpc readMetadata(Packet) returns (Packet) {}
rpc createMetadata(Packet) returns (Packet) {}
rpc updateMetadata(Packet) returns (Packet) {}
rpc deleteMetadata(Packet) returns (Packet) {}
rpc getReadReplicaList(RequestList) returns (ResponseList) {}
}
message Packet {
int32 packetType = 1;
repeated Request request = 2;
repeated Response response = 3;
}
message Request {
int32 operationType = 1;
int32 version = 2;
int32 dataSize = 3;
string key = 4;
int64 crc = 5;
int32 accessType = 6;
string clientID = 7;
string value = 8;
}
message Response {
int32 operationType = 1;
int32 status = 2;
Ack ack = 3;
Nack nack = 4;
}
message Ack {
int32 version = 2;
int32 dataSize = 3;
string key = 4;
int64 crc = 5;
string value = 6;
}
message Nack {
string key = 2;
int32 version = 3;
}
message RequestList {}
message ResponseList {
int32 operationType = 1;
int32 status = 2;
repeated Follower follower = 3;
}
message Follower {
string ip = 1;
int32 port = 2;
string followerID = 3;
int64 lastSeen = 4;
}
\ 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;
}
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
/*
* This file was generated by the Gradle 'init' task.
*
* The settings file is used to specify which projects to include in your build.
*
* Detailed information about configuring a multi-project build in Gradle can be found
* in the user manual at https://docs.gradle.org/6.8.3/userguide/multi_project_builds.html
*/
rootProject.name = 'hpdos'
include('app')
================================================= 0 Introduction ==================================================
In this repository, I implemented a simple NetCache with standard P4 language and designed an experiemnt with behavior model to show the efficiency of NetCache.
I create a network with mininet, containing 1 switch and 3 hosts. One host is the server, which handles READ queries. One host is the client, which sends READ queries. The last host is to simulate the controller of the programmable switch, because the behavior model does not provide such an interface.
The experiemnts runs in the following steps. First, the switch starts. Some table entries are added. Second, the server starts. The server loads pre-generated key-value items. Third, the controller starts. The controller sends some UPDATE queries to the server to get values of some pre-determined hot items, and insert them to the switch. Finally, the client starts. The client sends READ queries to the server and receives replies. If a query hits the cache in the switch, the switch would directly reply this query without routing it to the server.
If some uncached items are detected to be hot by the heavy-hitter, the switch would send a HOT_READ to the controller.
================================================= 1 Obtaining required software ==================================================
It is recommended to do the following things in the directory "NetCache/".
Firstly, you need to get the p4 compiler from Github, and install required dependencies.
git clone https://github.com/p4lang/p4c-bm.git p4c-bmv2
cd p4c-bmv2
sudo pip install -r requirements.txt
Secondly, you need to get the behavior model of p4 from github, install dependencies and compile the behavior model.
git clone https://github.com/p4lang/behavioral-model.git bmv2
cd bmv2
install_deps.sh
./autogen.sh
./configure
make
Finally, you need to install some other tools which are used in this simulation.
sudo apt-get install mininet python-ipaddr
sudo pip install scapy thrift networkx
If you do not do the above things in "NetCache/", you need to modify the path to p4c-bmv2 and bmv2 in NetCache/mininet/run_demo.sh.
================================================= 2 Content ==================================================
NetCache/generator: Python programs, which generates key-value items and queries.
NetCache/client: Two Python programs for the client. "send.py" can read queries from the "query.txt" file and send queries to the server. "receive.py" can receive replies from the server and the switch. In addition, both of these programs can print current READ throughput to the screen.
NetCache/server: One Python program for the server. "server.py" can read key-value items from the "kv.txt" file, and reply UPDATE queries from the controller and READ queries from the client. In addition, this program can print current READ throughput to the screen.
NetCache/p4src: Codes for the NetCache in standard P4 language.
NetCache/controller: One Python program for the controller. "controller.py" can read hot keys from the "hot.txt" file, and send UPDATE requests to the server. Then the switch would insert values to the cache when detect UDPATE replies from the server. After updating the cache of the switch, the controller would wait for "HOT_READ" packets, which shows that a key is detected as hot. In addition, this program can print HOT_READ reports with heavy hitter information to the screen.
NetCache/mininet: Scripts to run the experiments.
================================================= 3 Run Simulation ==================================================
Experiment configuration: IP address "10.0.0.1" is for the client. IP address "10.0.0.2" is for the server. IP address "10.0.0.3" is for the controller. There are 1000 key-value items in total, following zipf-0.90 distribution. Items whose keys are 1, 3, 5, ..., 99 will be inserted to the cache of the switch, and items whose keys are 2, 4, ..., 100 will be detected as hot items and reported to the controller after running for several seconds. If an uncached item is accessed for 128 times, it would be reported to the controller, and this parameter can be changed in "NetCache/p4src/heavy_hitter.p4".
Before the experiment starts, you need to generate some files. Run "python gen_kv.py" in "NetCache/generator", and you will get "kv.txt" and "hot.txt". Copy "kv.txt" to "NetCache/server" and copy "hot.txt" to "NetCache/controller". Then run "python gen_query_zipf.py" in "NetCache/generator", and you will get "query.txt". It takes several minutes. Then copy "query.txt" to "NetCache/client".
To initialize the environment, open a terminal in "NetCache/mininet", and run "./run_demo.sh". After you can see "Ready! Starting CLI: mininet>", you can begin to run the experiment. In the following description, I will call this terminal "mininet terminal".
Firstly, in the mininet terminal, run "xterm h2" to open a terminal for the server. In the new terminal, enter "NetCache/server" by running "cd ../server" and run "python server.py". Then the server starts. You can see two numbers, which are the number of READ queries in one second and the total number of READ queries in the past time.
Secondly, in the mininet terminal, run "xterm h3" to open a terminal for the controller. In the new terminal, enter "NetCache/controller" by running "cd ../controller" and run "python controller.py". Then the controller starts. When the controller receives a HOT_READ report, the detected key and values of the heavy hitter will be displayed.
Thidly, in the mininet terminal, run "xterm h1" to open a terminal for "receive.py" of the client. In the new terminal, enter "NetCache/client" by running "cd ../client" and run "python receive.py". Then you can see the number of READ replies received per second and the total number of READ replies in the past time.
Finally, in the mininet terminal, run "xterm h1" to open a terminal for "send.py" of the client. In the new terminal, enter "NetCache/client" by running "cd ../client" and run "python send.py". THen you can the number of READ replies received per second and the total number of READ replies in the past time. At the same time, the displayed numbers of the server and the "receive.py" will change with the "send.py", and after several seconds the controller will show the detected hot keys.
In addition, READ replies received by the "receive.py" is more than READ requests handled by the server. This is because some queries are handled by the switch.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--------------------------------------------------------------------------------
Code in python/ray/rllib/{evolution_strategies, dqn} adapted from
https://github.com/openai (MIT License)
Copyright (c) 2016 OpenAI (http://openai.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
# Literature Survey
## Dynamo DB
- [Paper](https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf)
- [Notes](https://docs.google.com/document/d/1t9gIIUqNdnGTld-TE52pYzz_lENuKXM-xFNmtg9s1h4/edit?usp=sharing)
## RAMCloud
- [Paper](https://dl.acm.org/doi/pdf/10.1145/2806887)
- [Notes](https://docs.google.com/document/d/1Ogl3dJpH-dqiWOTHoslz80-I2jGXv64LZlIOZexCu58/edit?usp=sharing)
## Orion
## NOVA
# Meeting Minutes
## Aug 7
---
### Action Items
1. Study prevalent distributed FS and Techniques:
- Dynamo
- Chord/Pastry Partitioning/Routing protocols
- Raft consensus protocol
- Redis
- Memcache
- List of all possible actions that can be done on the smartNICs?
2. Map these actions to a distributed FS
- For eg. Raft protocol - can some parts of Raft be done by a smartNICs?
3. State management required in a tiered storage?
4. What tiered storage should be used? What all can the smartNIC directly interact with? NVMe over fabric, RDMA?
## Aug 13
---
Building a KV store for Metadata
Metadata is stored in a KV store:
Metadata is required for caching
1. Metadata properties:
- Parts of the metadata change very quickly (timestamp), 
- Always consistent
2. Do we need RDMA to send the metadata response? Profiling?
3. Change 'Central Server' to a 'Logical repository'
4. We can't use something like 'consistent hashing' for actual files, because load
5. p4 and micro-C
6. LSM trees on smartNICs
7. Do we have a tiered storage setup?
### Action Items
1. [Saksham, Nilanjan] ~~Study other partitioning algorithms used by systems like RAMCloud/Redis~~: **Done**
- Routing cost is not critical in a closed HPC system
- Summarize the paper in a report
2. [Saksham, Nilanjan] Understand basics of P4/microC, and how to build for the netronome smartNIC - **In Progress**
3. [Prof. Kulkarni] Setup another machine with a smartNIC - **In Progress**
4. [Prof. Bellur] Update regarding virtual lab from Huawei - **In Progress**
5. [Pramod] ~~Read and document NVMM literature like Orion and Octopus~~ **Done**
## Aug 21
---
1. Should we test RAMCloud on a local cluster? Should focus on the following aspects:
- What parts of the design can be delegated to the smartNIC?
- Can our intended workload fit entirely in memory?
- Can NVMMs be leveraged in the design?
- Can we further optimize aspects corresponding to the specifics of our workload?
- For eg. assuming file system metadata as the usecase
### Action Items
1. [Saksham, Nilanjan, Pramod] Prepare a document to categorize different potential dist. stores based on the literature already studied
- Find survey papers on this
- Dynamo, RAMCloud, Chord/Pastry routing, Consistency protocols, Octopus/Orion/Nova
2. [Prof. Kulkarni, Prof. Bellur] Meeting with Huawei:
- Understand their requirements better/ establish a PoC from their end
- Virtual Lab to test systems
3. [Prof. Kulkarni] Establish a git repo to collect literature survey documents + other experiments
## Aug 28
---
### Action Items
1. Formalize the RAMCloud document [Saksham]
2. DFS Comparison Chart [All]
3. Points of Optimizations in RAMCloud:
- Understand Design thoroughly?
- Concrete Ideas using:
- SmartNICs [Pramod, Saksham, Nilanjan]
- Where do NVMM fits??? Persistence, closer to DRAM? ---maybe later
4. Virtual Labs: Will take 2-3weeks
5. PoC:
- Literature documentation
- Exploratory Optimizations (?)/ What are their requirements?
- Workloads
6. Setup related issues
7. FS vs Object Stores vs Key Value stores
## Sep 11
### Discussion
1. Huawei PoC:
- No clear requirements, its a whiteboard for us to experiment
- Virtual Lab is taking some time
2. SmartNIC:
- Different memories
3. Design a Distributed KV store which leverages smartNICs:
- What functionality does the smartNIC offers? (TODO)
- 'Early' processing
- What functions of the KV store can be offloaded to the smartNIC?
- What parts of get/put are handled by the smartNIC?
- basic communication: heartbeats
- advanced processing: consensus protocols?
- Take a concrete KV Store, add smartNIC functionality
- RAMCloud + smartNIC
# High Performance Distributed Object Store
A Distributed Object Store built to take advantage of recent advances in storage and networking hardware for high throughput low latency object storage.
\ No newline at end of file
NC_READ_REQUEST = 0
NC_READ_REPLY = 1
NC_HOT_READ_REQUEST = 2
NC_WRITE_REQUEST = 4
NC_WRITE_REPLY = 5
NC_UPDATE_REQUEST = 8
NC_UPDATE_REPLY = 9
This source diff could not be displayed because it is too large. You can view the blob instead.
import socket
import struct
import time
import thread
from nc_config import *
NC_PORT = 8888
CLIENT_IP = "10.0.0.1"
SERVER_IP = "10.0.0.2"
CONTROLLER_IP = "10.0.0.3"
path_reply = "reply.txt"
len_key = 16
counter = 0
def counting():
last_counter = 0
while True:
print (counter - last_counter), counter
last_counter = counter
time.sleep(1)
thread.start_new_thread(counting, ())
#f = open(path_reply, "w")
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((CLIENT_IP, NC_PORT))
while True:
packet, addr = s.recvfrom(1024)
counter = counter + 1
#op = struct.unpack("B", packet[0])
#key_header = struct.unpack(">I", packet[1:5])[0]
#f.write(str(op) + ' ')
#f.write(str(key_header) + '\n')
#f.flush()
#print counter
#f.close()
import socket
import struct
import time
import thread
from nc_config import *
NC_PORT = 8889
CLIENT_IP = "10.0.0.1"
SERVER_IP = "10.0.0.2"
CONTROLLER_IP = "10.0.0.3"
path_query = "query.txt"
query_rate = 1000
len_key = 16
print NC_PORT
counter = 0
def counting():
last_counter = 0
while True:
print (counter - last_counter), counter
last_counter = counter
time.sleep(1)
thread.start_new_thread(counting, ())
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
f = open(path_query, "r")
interval = 1.0 / (query_rate + 1)
for line in f.readlines():
line = line.split()
op = line[0]
key_header = int(line[1])
key_body = line[2:]
op_field = struct.pack("B", 0)
key_field = struct.pack(">I", key_header)
for i in range(len(key_body)):
key_field += struct.pack("B", int(key_body[i], 16))
packet = op_field + key_field
s.sendto(packet, (SERVER_IP, NC_PORT))
counter = counter + 1
time.sleep(interval)
# break
f.close()
import socket
import struct
import time
import thread
import argparse
from nc_config import *
NC_PORT = 8888
parser = argparse.ArgumentParser(description='Mininet demo')
parser.add_argument('--server-ip', help='IP of server',
type=str, action="store", required=True)
parser.add_argument('--controller-ip', help='IP of controller',
type=str, action="store", required=True)
args = parser.parse_args()
CLIENT_IP = "10.0.0.1"
SERVER_IP = args.server_ip
CONTROLLER_IP = args.controller_ip
path_hot = "hot.txt"
path_log = "controller_log.txt"
len_key = 16
len_val = 128
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((CONTROLLER_IP, NC_PORT))
# Initiate the switch
op = NC_UPDATE_REQUEST
op_field = struct.pack("B", op)
f = open(path_hot, "r")
for line in f.readlines():
line = line.split()
key_header = line[0]
key_body = line[1:]
key_header = int(key_header)
for i in range(len(key_body)):
key_body[i] = int(key_body[i], 16)
key_field = ""
key_field += struct.pack(">I", key_header)
for i in range(len(key_body)):
key_field += struct.pack("B", key_body[i])
packet = op_field + key_field
s.sendto(packet, (SERVER_IP, NC_PORT))
time.sleep(0.001)
f.close()
# Listen hot report
f = open(path_log, "w")
counter = 0
while True:
packet, addr = s.recvfrom(2048)
# print(packet, addr)
op_field = packet[0]
key_field = packet[1:len_key + 1]
load_field = packet[len_key + 1:]
op = struct.unpack("B", op_field)[0]
if (op != NC_HOT_READ_REQUEST):
continue
key_header = struct.unpack(">I", key_field[:4])[0]
print(op_field, key_header)
load = struct.unpack(">IIII", load_field)
counter = counter + 1
print "\tHot Item:", key_header, load
f.write(str(key_header) + ' ')
f.write(str(load) + ' ')
f.write("\n")
f.flush()
f.close()
NC_READ_REQUEST = 0
NC_READ_REPLY = 1
NC_HOT_READ_REQUEST = 2
NC_WRITE_REQUEST = 4
NC_WRITE_REPLY = 5
NC_UPDATE_REQUEST = 8
NC_UPDATE_REPLY = 9
import random
path_kv = "kv.txt" #The path to save generated keys and values
path_hot = "hot.txt" #The path to save the hot keys
len_key = 16 #The number of bytes in the key
len_val = 128 #The number of bytes in the value
max_key = 1000 #The number of keys
max_hot = 100 #The number of hot keys
f = open(path_kv, "w")
f_hot = open(path_hot, "w")
f.write(str(max_key) + "\n\n")
for i in range(1, max_key + 1):
## Generate a key-value item
#Select a key
key_header = i
key_body = [0] * (len_key - 4)
#Select a value
val = [1] * len_val #The value
###################################################################################################
## Output the key and the value to the file
f.write(str(key_header) + " ")
for i in range(len(key_body)):
f.write(hex(key_body[i]) + " ")
f.write("\n")
for i in range(len(val)):
f.write(hex(val[i]) + " ")
f.write("\n\n")
###################################################################################################
##Output the hot key to the file
if (key_header <= max_hot and key_header % 2 == 1):
f_hot.write(str(key_header) + " ")
for i in range(len(key_body)):
f_hot.write(hex(key_body[i]) + " ")
f_hot.write("\n")
###################################################################################################
f.flush()
f.close()
f_hot.flush()
f_hot.close()
import random
path_query = "query.txt"
num_query = 1000000
len_key = 16
len_val = 128
max_key = 1000
f = open(path_query, "w")
for i in range(num_query):
#Randomly select a key
key_header = random.randint(1, max_key)
key_body = [0] * (len_key - 4)
#Save the generated query to the file
f.write("get ")
f.write(str(key_header) + ' ')
for i in range(len(key_body)):
f.write(hex(key_body[i]) + ' ')
f.write('\n')
f.flush()
f.close()
import random
import math
path_query = "query.txt"
num_query = 1000000
zipf = 0.99
len_key = 16
len_val = 128
max_key = 1000
#Zipf
zeta = [0.0]
for i in range(1, max_key + 1):
zeta.append(zeta[i - 1] + 1 / pow(i, zipf))
field = [0] * (num_query + 1)
k = 1
for i in range(1, num_query + 1):
if (i > num_query * zeta[k] / zeta[max_key]):
k = k + 1
field[i] = k
#Generate queries
f = open(path_query, "w")
for i in range(num_query):
#Randomly select a key in zipf distribution
r = random.randint(1, num_query)
key_header = field[r]
key_body = [0] * (len_key - 4)
#Save the generated query to the file
f.write("get ")
f.write(str(key_header) + ' ')
for i in range(len_key - 4):
f.write(hex(key_body[i]) + ' ')
f.write('\n')
f.flush()
f.close()
table_set_default check_cache_valid check_cache_valid_act
table_set_default set_cache_valid set_cache_valid_act
table_add ipv4_route set_egress 10.0.0.1 => 1
table_add ipv4_route set_egress 10.0.0.2 => 2
table_add ipv4_route set_egress 10.0.0.3 => 3
table_add ethernet_set_mac ethernet_set_mac_act 1 => aa:bb:cc:dd:ee:11 aa:bb:cc:dd:ee:01
table_add ethernet_set_mac ethernet_set_mac_act 2 => aa:bb:cc:dd:ee:12 aa:bb:cc:dd:ee:02
table_add ethernet_set_mac ethernet_set_mac_act 3 => aa:bb:cc:dd:ee:13 aa:bb:cc:dd:ee:03
table_set_default calculate_router_hash calculate_router_hash_act
table_set_default _resubmit _resubmit_act
table_add update_dst update_dst_act 0 => 10.0.0.2
table_set_default hh_load_1_count hh_load_1_count_act
table_set_default hh_load_2_count hh_load_2_count_act
table_set_default hh_load_3_count hh_load_3_count_act
table_set_default hh_load_4_count hh_load_4_count_act
table_set_default hh_bf_1 hh_bf_1_act
table_set_default hh_bf_2 hh_bf_2_act
table_set_default hh_bf_3 hh_bf_3_act
table_set_default clone_to_controller clone_to_controller_act
table_set_default report_hot report_hot_act
mirroring_add 1 1
mirroring_add 2 2
mirroring_add 3 3
table_set_default reply_read_hit_before reply_read_hit_before_act
table_set_default reply_read_hit_after reply_read_hit_after_act
table_set_default read_value_1_1 read_value_1_1_act
table_set_default add_value_header_1 add_value_header_1_act
table_set_default write_value_1_1 write_value_1_1_act
table_set_default remove_value_header_1 remove_value_header_1_act
table_set_default read_value_1_2 read_value_1_2_act
table_set_default add_value_header_1 add_value_header_1_act
table_set_default write_value_1_2 write_value_1_2_act
table_set_default remove_value_header_1 remove_value_header_1_act
table_set_default read_value_1_3 read_value_1_3_act
table_set_default add_value_header_1 add_value_header_1_act
table_set_default write_value_1_3 write_value_1_3_act
table_set_default remove_value_header_1 remove_value_header_1_act
table_set_default read_value_1_4 read_value_1_4_act
table_set_default add_value_header_1 add_value_header_1_act
table_set_default write_value_1_4 write_value_1_4_act
table_set_default remove_value_header_1 remove_value_header_1_act
table_set_default read_value_2_1 read_value_2_1_act
table_set_default add_value_header_2 add_value_header_2_act
table_set_default write_value_2_1 write_value_2_1_act
table_set_default remove_value_header_2 remove_value_header_2_act
table_set_default read_value_2_2 read_value_2_2_act
table_set_default add_value_header_2 add_value_header_2_act
table_set_default write_value_2_2 write_value_2_2_act
table_set_default remove_value_header_2 remove_value_header_2_act
table_set_default read_value_2_3 read_value_2_3_act
table_set_default add_value_header_2 add_value_header_2_act
table_set_default write_value_2_3 write_value_2_3_act
table_set_default remove_value_header_2 remove_value_header_2_act
table_set_default read_value_2_4 read_value_2_4_act
table_set_default add_value_header_2 add_value_header_2_act
table_set_default write_value_2_4 write_value_2_4_act
table_set_default remove_value_header_2 remove_value_header_2_act
table_set_default read_value_3_1 read_value_3_1_act
table_set_default add_value_header_3 add_value_header_3_act
table_set_default write_value_3_1 write_value_3_1_act
table_set_default remove_value_header_3 remove_value_header_3_act
table_set_default read_value_3_2 read_value_3_2_act
table_set_default add_value_header_3 add_value_header_3_act
table_set_default write_value_3_2 write_value_3_2_act
table_set_default remove_value_header_3 remove_value_header_3_act
table_set_default read_value_3_3 read_value_3_3_act
table_set_default add_value_header_3 add_value_header_3_act
table_set_default write_value_3_3 write_value_3_3_act
table_set_default remove_value_header_3 remove_value_header_3_act
table_set_default read_value_3_4 read_value_3_4_act
table_set_default add_value_header_3 add_value_header_3_act
table_set_default write_value_3_4 write_value_3_4_act
table_set_default remove_value_header_3 remove_value_header_3_act
table_set_default read_value_4_1 read_value_4_1_act
table_set_default add_value_header_4 add_value_header_4_act
table_set_default write_value_4_1 write_value_4_1_act
table_set_default remove_value_header_4 remove_value_header_4_act
table_set_default read_value_4_2 read_value_4_2_act
table_set_default add_value_header_4 add_value_header_4_act
table_set_default write_value_4_2 write_value_4_2_act
table_set_default remove_value_header_4 remove_value_header_4_act
table_set_default read_value_4_3 read_value_4_3_act
table_set_default add_value_header_4 add_value_header_4_act
table_set_default write_value_4_3 write_value_4_3_act
table_set_default remove_value_header_4 remove_value_header_4_act
table_set_default read_value_4_4 read_value_4_4_act
table_set_default add_value_header_4 add_value_header_4_act
table_set_default write_value_4_4 write_value_4_4_act
table_set_default remove_value_header_4 remove_value_header_4_act
table_set_default read_value_5_1 read_value_5_1_act
table_set_default add_value_header_5 add_value_header_5_act
table_set_default write_value_5_1 write_value_5_1_act
table_set_default remove_value_header_5 remove_value_header_5_act
table_set_default read_value_5_2 read_value_5_2_act
table_set_default add_value_header_5 add_value_header_5_act
table_set_default write_value_5_2 write_value_5_2_act
table_set_default remove_value_header_5 remove_value_header_5_act
table_set_default read_value_5_3 read_value_5_3_act
table_set_default add_value_header_5 add_value_header_5_act
table_set_default write_value_5_3 write_value_5_3_act
table_set_default remove_value_header_5 remove_value_header_5_act
table_set_default read_value_5_4 read_value_5_4_act
table_set_default add_value_header_5 add_value_header_5_act
table_set_default write_value_5_4 write_value_5_4_act
table_set_default remove_value_header_5 remove_value_header_5_act
table_set_default read_value_6_1 read_value_6_1_act
table_set_default add_value_header_6 add_value_header_6_act
table_set_default write_value_6_1 write_value_6_1_act
table_set_default remove_value_header_6 remove_value_header_6_act
table_set_default read_value_6_2 read_value_6_2_act
table_set_default add_value_header_6 add_value_header_6_act
table_set_default write_value_6_2 write_value_6_2_act
table_set_default remove_value_header_6 remove_value_header_6_act
table_set_default read_value_6_3 read_value_6_3_act
table_set_default add_value_header_6 add_value_header_6_act
table_set_default write_value_6_3 write_value_6_3_act
table_set_default remove_value_header_6 remove_value_header_6_act
table_set_default read_value_6_4 read_value_6_4_act
table_set_default add_value_header_6 add_value_header_6_act
table_set_default write_value_6_4 write_value_6_4_act
table_set_default remove_value_header_6 remove_value_header_6_act
table_set_default read_value_7_1 read_value_7_1_act
table_set_default add_value_header_7 add_value_header_7_act
table_set_default write_value_7_1 write_value_7_1_act
table_set_default remove_value_header_7 remove_value_header_7_act
table_set_default read_value_7_2 read_value_7_2_act
table_set_default add_value_header_7 add_value_header_7_act
table_set_default write_value_7_2 write_value_7_2_act
table_set_default remove_value_header_7 remove_value_header_7_act
table_set_default read_value_7_3 read_value_7_3_act
table_set_default add_value_header_7 add_value_header_7_act
table_set_default write_value_7_3 write_value_7_3_act
table_set_default remove_value_header_7 remove_value_header_7_act
table_set_default read_value_7_4 read_value_7_4_act
table_set_default add_value_header_7 add_value_header_7_act
table_set_default write_value_7_4 write_value_7_4_act
table_set_default remove_value_header_7 remove_value_header_7_act
table_set_default read_value_8_1 read_value_8_1_act
table_set_default add_value_header_8 add_value_header_8_act
table_set_default write_value_8_1 write_value_8_1_act
table_set_default remove_value_header_8 remove_value_header_8_act
table_set_default read_value_8_2 read_value_8_2_act
table_set_default add_value_header_8 add_value_header_8_act
table_set_default write_value_8_2 write_value_8_2_act
table_set_default remove_value_header_8 remove_value_header_8_act
table_set_default read_value_8_3 read_value_8_3_act
table_set_default add_value_header_8 add_value_header_8_act
table_set_default write_value_8_3 write_value_8_3_act
table_set_default remove_value_header_8 remove_value_header_8_act
table_set_default read_value_8_4 read_value_8_4_act
table_set_default add_value_header_8 add_value_header_8_act
table_set_default write_value_8_4 write_value_8_4_act
table_set_default remove_value_header_8 remove_value_header_8_act
table_add check_cache_exist check_cache_exist_act 79228162514264337593543950336 => 1
table_add check_cache_exist check_cache_exist_act 237684487542793012780631851008 => 3
table_add check_cache_exist check_cache_exist_act 396140812571321687967719751680 => 5
table_add check_cache_exist check_cache_exist_act 554597137599850363154807652352 => 7
table_add check_cache_exist check_cache_exist_act 713053462628379038341895553024 => 9
table_add check_cache_exist check_cache_exist_act 871509787656907713528983453696 => 11
table_add check_cache_exist check_cache_exist_act 1029966112685436388716071354368 => 13
table_add check_cache_exist check_cache_exist_act 1188422437713965063903159255040 => 15
table_add check_cache_exist check_cache_exist_act 1346878762742493739090247155712 => 17
table_add check_cache_exist check_cache_exist_act 1505335087771022414277335056384 => 19
table_add check_cache_exist check_cache_exist_act 1663791412799551089464422957056 => 21
table_add check_cache_exist check_cache_exist_act 1822247737828079764651510857728 => 23
table_add check_cache_exist check_cache_exist_act 1980704062856608439838598758400 => 25
table_add check_cache_exist check_cache_exist_act 2139160387885137115025686659072 => 27
table_add check_cache_exist check_cache_exist_act 2297616712913665790212774559744 => 29
table_add check_cache_exist check_cache_exist_act 2456073037942194465399862460416 => 31
table_add check_cache_exist check_cache_exist_act 2614529362970723140586950361088 => 33
table_add check_cache_exist check_cache_exist_act 2772985687999251815774038261760 => 35
table_add check_cache_exist check_cache_exist_act 2931442013027780490961126162432 => 37
table_add check_cache_exist check_cache_exist_act 3089898338056309166148214063104 => 39
table_add check_cache_exist check_cache_exist_act 3248354663084837841335301963776 => 41
table_add check_cache_exist check_cache_exist_act 3406810988113366516522389864448 => 43
table_add check_cache_exist check_cache_exist_act 3565267313141895191709477765120 => 45
table_add check_cache_exist check_cache_exist_act 3723723638170423866896565665792 => 47
table_add check_cache_exist check_cache_exist_act 3882179963198952542083653566464 => 49
table_add check_cache_exist check_cache_exist_act 4040636288227481217270741467136 => 51
table_add check_cache_exist check_cache_exist_act 4199092613256009892457829367808 => 53
table_add check_cache_exist check_cache_exist_act 4357548938284538567644917268480 => 55
table_add check_cache_exist check_cache_exist_act 4516005263313067242832005169152 => 57
table_add check_cache_exist check_cache_exist_act 4674461588341595918019093069824 => 59
table_add check_cache_exist check_cache_exist_act 4832917913370124593206180970496 => 61
table_add check_cache_exist check_cache_exist_act 4991374238398653268393268871168 => 63
table_add check_cache_exist check_cache_exist_act 5149830563427181943580356771840 => 65
table_add check_cache_exist check_cache_exist_act 5308286888455710618767444672512 => 67
table_add check_cache_exist check_cache_exist_act 5466743213484239293954532573184 => 69
table_add check_cache_exist check_cache_exist_act 5625199538512767969141620473856 => 71
table_add check_cache_exist check_cache_exist_act 5783655863541296644328708374528 => 73
table_add check_cache_exist check_cache_exist_act 5942112188569825319515796275200 => 75
table_add check_cache_exist check_cache_exist_act 6100568513598353994702884175872 => 77
table_add check_cache_exist check_cache_exist_act 6259024838626882669889972076544 => 79
table_add check_cache_exist check_cache_exist_act 6417481163655411345077059977216 => 81
table_add check_cache_exist check_cache_exist_act 6575937488683940020264147877888 => 83
table_add check_cache_exist check_cache_exist_act 6734393813712468695451235778560 => 85
table_add check_cache_exist check_cache_exist_act 6892850138740997370638323679232 => 87
table_add check_cache_exist check_cache_exist_act 7051306463769526045825411579904 => 89
table_add check_cache_exist check_cache_exist_act 7209762788798054721012499480576 => 91
table_add check_cache_exist check_cache_exist_act 7368219113826583396199587381248 => 93
table_add check_cache_exist check_cache_exist_act 7526675438855112071386675281920 => 95
table_add check_cache_exist check_cache_exist_act 7685131763883640746573763182592 => 97
table_add check_cache_exist check_cache_exist_act 7843588088912169421760851083264 => 99
\ No newline at end of file
table_set_default check_cache_valid check_cache_valid_act
table_set_default set_cache_valid set_cache_valid_act
table_add ipv4_route set_egress 10.0.0.1 => 1
table_add ipv4_route set_egress 10.0.0.2 => 2
table_add ipv4_route set_egress 10.0.0.3 => 2
table_add ipv4_route set_egress 10.0.0.4 => 3
table_add ipv4_route set_egress 10.0.0.5 => 3
table_add ethernet_set_mac ethernet_set_mac_act 1 => aa:bb:cc:dd:ee:11 aa:bb:cc:dd:ee:01
table_add ethernet_set_mac ethernet_set_mac_act 2 => aa:bb:cc:dd:ee:12 aa:bb:cc:dd:ee:14
table_add ethernet_set_mac ethernet_set_mac_act 3 => aa:bb:cc:dd:ee:13 aa:bb:cc:dd:ee:17
table_set_default calculate_router_hash calculate_router_hash_act
table_set_default _resubmit _resubmit_act
table_add update_dst update_dst_act 0 => 10.0.0.2
table_add update_dst update_dst_act 1 => 10.0.0.4
table_set_default hh_load_1_count hh_load_1_count_act
table_set_default hh_load_2_count hh_load_2_count_act
table_set_default hh_load_3_count hh_load_3_count_act
table_set_default hh_load_4_count hh_load_4_count_act
table_set_default hh_bf_1 hh_bf_1_act
table_set_default hh_bf_2 hh_bf_2_act
table_set_default hh_bf_3 hh_bf_3_act
table_set_default clone_to_controller clone_to_controller_act
table_set_default report_hot report_hot_act
table_add report_hot report_hot_act 10.0.0.2 => 10.0.0.3
table_add report_hot report_hot_act 10.0.0.4 => 10.0.0.5
mirroring_add 1 1
mirroring_add 2 2
mirroring_add 3 3
mirroring_add 4 4
mirroring_add 5 5
table_set_default reply_read_hit_before reply_read_hit_before_act
table_set_default reply_read_hit_after reply_read_hit_after_act
table_set_default read_value_1_1 read_value_1_1_act
table_set_default add_value_header_1 add_value_header_1_act
table_set_default write_value_1_1 write_value_1_1_act
table_set_default remove_value_header_1 remove_value_header_1_act
table_set_default read_value_1_2 read_value_1_2_act
table_set_default add_value_header_1 add_value_header_1_act
table_set_default write_value_1_2 write_value_1_2_act
table_set_default remove_value_header_1 remove_value_header_1_act
table_set_default read_value_1_3 read_value_1_3_act
table_set_default add_value_header_1 add_value_header_1_act
table_set_default write_value_1_3 write_value_1_3_act
table_set_default remove_value_header_1 remove_value_header_1_act
table_set_default read_value_1_4 read_value_1_4_act
table_set_default add_value_header_1 add_value_header_1_act
table_set_default write_value_1_4 write_value_1_4_act
table_set_default remove_value_header_1 remove_value_header_1_act
table_set_default read_value_2_1 read_value_2_1_act
table_set_default add_value_header_2 add_value_header_2_act
table_set_default write_value_2_1 write_value_2_1_act
table_set_default remove_value_header_2 remove_value_header_2_act
table_set_default read_value_2_2 read_value_2_2_act
table_set_default add_value_header_2 add_value_header_2_act
table_set_default write_value_2_2 write_value_2_2_act
table_set_default remove_value_header_2 remove_value_header_2_act
table_set_default read_value_2_3 read_value_2_3_act
table_set_default add_value_header_2 add_value_header_2_act
table_set_default write_value_2_3 write_value_2_3_act
table_set_default remove_value_header_2 remove_value_header_2_act
table_set_default read_value_2_4 read_value_2_4_act
table_set_default add_value_header_2 add_value_header_2_act
table_set_default write_value_2_4 write_value_2_4_act
table_set_default remove_value_header_2 remove_value_header_2_act
table_set_default read_value_3_1 read_value_3_1_act
table_set_default add_value_header_3 add_value_header_3_act
table_set_default write_value_3_1 write_value_3_1_act
table_set_default remove_value_header_3 remove_value_header_3_act
table_set_default read_value_3_2 read_value_3_2_act
table_set_default add_value_header_3 add_value_header_3_act
table_set_default write_value_3_2 write_value_3_2_act
table_set_default remove_value_header_3 remove_value_header_3_act
table_set_default read_value_3_3 read_value_3_3_act
table_set_default add_value_header_3 add_value_header_3_act
table_set_default write_value_3_3 write_value_3_3_act
table_set_default remove_value_header_3 remove_value_header_3_act
table_set_default read_value_3_4 read_value_3_4_act
table_set_default add_value_header_3 add_value_header_3_act
table_set_default write_value_3_4 write_value_3_4_act
table_set_default remove_value_header_3 remove_value_header_3_act
table_set_default read_value_4_1 read_value_4_1_act
table_set_default add_value_header_4 add_value_header_4_act
table_set_default write_value_4_1 write_value_4_1_act
table_set_default remove_value_header_4 remove_value_header_4_act
table_set_default read_value_4_2 read_value_4_2_act
table_set_default add_value_header_4 add_value_header_4_act
table_set_default write_value_4_2 write_value_4_2_act
table_set_default remove_value_header_4 remove_value_header_4_act
table_set_default read_value_4_3 read_value_4_3_act
table_set_default add_value_header_4 add_value_header_4_act
table_set_default write_value_4_3 write_value_4_3_act
table_set_default remove_value_header_4 remove_value_header_4_act
table_set_default read_value_4_4 read_value_4_4_act
table_set_default add_value_header_4 add_value_header_4_act
table_set_default write_value_4_4 write_value_4_4_act
table_set_default remove_value_header_4 remove_value_header_4_act
table_set_default read_value_5_1 read_value_5_1_act
table_set_default add_value_header_5 add_value_header_5_act
table_set_default write_value_5_1 write_value_5_1_act
table_set_default remove_value_header_5 remove_value_header_5_act
table_set_default read_value_5_2 read_value_5_2_act
table_set_default add_value_header_5 add_value_header_5_act
table_set_default write_value_5_2 write_value_5_2_act
table_set_default remove_value_header_5 remove_value_header_5_act
table_set_default read_value_5_3 read_value_5_3_act
table_set_default add_value_header_5 add_value_header_5_act
table_set_default write_value_5_3 write_value_5_3_act
table_set_default remove_value_header_5 remove_value_header_5_act
table_set_default read_value_5_4 read_value_5_4_act
table_set_default add_value_header_5 add_value_header_5_act
table_set_default write_value_5_4 write_value_5_4_act
table_set_default remove_value_header_5 remove_value_header_5_act
table_set_default read_value_6_1 read_value_6_1_act
table_set_default add_value_header_6 add_value_header_6_act
table_set_default write_value_6_1 write_value_6_1_act
table_set_default remove_value_header_6 remove_value_header_6_act
table_set_default read_value_6_2 read_value_6_2_act
table_set_default add_value_header_6 add_value_header_6_act
table_set_default write_value_6_2 write_value_6_2_act
table_set_default remove_value_header_6 remove_value_header_6_act
table_set_default read_value_6_3 read_value_6_3_act
table_set_default add_value_header_6 add_value_header_6_act
table_set_default write_value_6_3 write_value_6_3_act
table_set_default remove_value_header_6 remove_value_header_6_act
table_set_default read_value_6_4 read_value_6_4_act
table_set_default add_value_header_6 add_value_header_6_act
table_set_default write_value_6_4 write_value_6_4_act
table_set_default remove_value_header_6 remove_value_header_6_act
table_set_default read_value_7_1 read_value_7_1_act
table_set_default add_value_header_7 add_value_header_7_act
table_set_default write_value_7_1 write_value_7_1_act
table_set_default remove_value_header_7 remove_value_header_7_act
table_set_default read_value_7_2 read_value_7_2_act
table_set_default add_value_header_7 add_value_header_7_act
table_set_default write_value_7_2 write_value_7_2_act
table_set_default remove_value_header_7 remove_value_header_7_act
table_set_default read_value_7_3 read_value_7_3_act
table_set_default add_value_header_7 add_value_header_7_act
table_set_default write_value_7_3 write_value_7_3_act
table_set_default remove_value_header_7 remove_value_header_7_act
table_set_default read_value_7_4 read_value_7_4_act
table_set_default add_value_header_7 add_value_header_7_act
table_set_default write_value_7_4 write_value_7_4_act
table_set_default remove_value_header_7 remove_value_header_7_act
table_set_default read_value_8_1 read_value_8_1_act
table_set_default add_value_header_8 add_value_header_8_act
table_set_default write_value_8_1 write_value_8_1_act
table_set_default remove_value_header_8 remove_value_header_8_act
table_set_default read_value_8_2 read_value_8_2_act
table_set_default add_value_header_8 add_value_header_8_act
table_set_default write_value_8_2 write_value_8_2_act
table_set_default remove_value_header_8 remove_value_header_8_act
table_set_default read_value_8_3 read_value_8_3_act
table_set_default add_value_header_8 add_value_header_8_act
table_set_default write_value_8_3 write_value_8_3_act
table_set_default remove_value_header_8 remove_value_header_8_act
table_set_default read_value_8_4 read_value_8_4_act
table_set_default add_value_header_8 add_value_header_8_act
table_set_default write_value_8_4 write_value_8_4_act
table_set_default remove_value_header_8 remove_value_header_8_act
table_add check_cache_exist check_cache_exist_act 79228162514264337593543950336 => 1
table_add check_cache_exist check_cache_exist_act 237684487542793012780631851008 => 3
table_add check_cache_exist check_cache_exist_act 396140812571321687967719751680 => 5
table_add check_cache_exist check_cache_exist_act 554597137599850363154807652352 => 7
table_add check_cache_exist check_cache_exist_act 713053462628379038341895553024 => 9
table_add check_cache_exist check_cache_exist_act 871509787656907713528983453696 => 11
table_add check_cache_exist check_cache_exist_act 1029966112685436388716071354368 => 13
table_add check_cache_exist check_cache_exist_act 1188422437713965063903159255040 => 15
table_add check_cache_exist check_cache_exist_act 1346878762742493739090247155712 => 17
table_add check_cache_exist check_cache_exist_act 1505335087771022414277335056384 => 19
table_add check_cache_exist check_cache_exist_act 1663791412799551089464422957056 => 21
table_add check_cache_exist check_cache_exist_act 1822247737828079764651510857728 => 23
table_add check_cache_exist check_cache_exist_act 1980704062856608439838598758400 => 25
table_add check_cache_exist check_cache_exist_act 2139160387885137115025686659072 => 27
table_add check_cache_exist check_cache_exist_act 2297616712913665790212774559744 => 29
table_add check_cache_exist check_cache_exist_act 2456073037942194465399862460416 => 31
table_add check_cache_exist check_cache_exist_act 2614529362970723140586950361088 => 33
table_add check_cache_exist check_cache_exist_act 2772985687999251815774038261760 => 35
table_add check_cache_exist check_cache_exist_act 2931442013027780490961126162432 => 37
table_add check_cache_exist check_cache_exist_act 3089898338056309166148214063104 => 39
table_add check_cache_exist check_cache_exist_act 3248354663084837841335301963776 => 41
table_add check_cache_exist check_cache_exist_act 3406810988113366516522389864448 => 43
table_add check_cache_exist check_cache_exist_act 3565267313141895191709477765120 => 45
table_add check_cache_exist check_cache_exist_act 3723723638170423866896565665792 => 47
table_add check_cache_exist check_cache_exist_act 3882179963198952542083653566464 => 49
table_add check_cache_exist check_cache_exist_act 4040636288227481217270741467136 => 51
table_add check_cache_exist check_cache_exist_act 4199092613256009892457829367808 => 53
table_add check_cache_exist check_cache_exist_act 4357548938284538567644917268480 => 55
table_add check_cache_exist check_cache_exist_act 4516005263313067242832005169152 => 57
table_add check_cache_exist check_cache_exist_act 4674461588341595918019093069824 => 59
table_add check_cache_exist check_cache_exist_act 4832917913370124593206180970496 => 61
table_add check_cache_exist check_cache_exist_act 4991374238398653268393268871168 => 63
table_add check_cache_exist check_cache_exist_act 5149830563427181943580356771840 => 65
table_add check_cache_exist check_cache_exist_act 5308286888455710618767444672512 => 67
table_add check_cache_exist check_cache_exist_act 5466743213484239293954532573184 => 69
table_add check_cache_exist check_cache_exist_act 5625199538512767969141620473856 => 71
table_add check_cache_exist check_cache_exist_act 5783655863541296644328708374528 => 73
table_add check_cache_exist check_cache_exist_act 5942112188569825319515796275200 => 75
table_add check_cache_exist check_cache_exist_act 6100568513598353994702884175872 => 77
table_add check_cache_exist check_cache_exist_act 6259024838626882669889972076544 => 79
table_add check_cache_exist check_cache_exist_act 6417481163655411345077059977216 => 81
table_add check_cache_exist check_cache_exist_act 6575937488683940020264147877888 => 83
table_add check_cache_exist check_cache_exist_act 6734393813712468695451235778560 => 85
table_add check_cache_exist check_cache_exist_act 6892850138740997370638323679232 => 87
table_add check_cache_exist check_cache_exist_act 7051306463769526045825411579904 => 89
table_add check_cache_exist check_cache_exist_act 7209762788798054721012499480576 => 91
table_add check_cache_exist check_cache_exist_act 7368219113826583396199587381248 => 93
table_add check_cache_exist check_cache_exist_act 7526675438855112071386675281920 => 95
table_add check_cache_exist check_cache_exist_act 7685131763883640746573763182592 => 97
table_add check_cache_exist check_cache_exist_act 7843588088912169421760851083264 => 99
\ No newline at end of file
table_set_default check_cache_valid check_cache_valid_act
table_set_default set_cache_valid set_cache_valid_act
table_add ipv4_route set_egress 10.0.0.1 => 1
table_add ipv4_route set_egress 10.0.0.4 => 1
table_add ipv4_route set_egress 10.0.0.5 => 1
table_add ipv4_route set_egress 10.0.0.2 => 2
table_add ipv4_route set_egress 10.0.0.3 => 3
table_add ethernet_set_mac ethernet_set_mac_act 1 => aa:bb:cc:dd:ee:14 aa:bb:cc:dd:ee:12
table_add ethernet_set_mac ethernet_set_mac_act 2 => aa:bb:cc:dd:ee:15 aa:bb:cc:dd:ee:02
table_add ethernet_set_mac ethernet_set_mac_act 3 => aa:bb:cc:dd:ee:16 aa:bb:cc:dd:ee:03
table_set_default calculate_router_hash calculate_router_hash_act
table_set_default _resubmit _resubmit_act
table_add update_dst update_dst_act 0 => 10.0.0.2
table_set_default hh_load_1_count hh_load_1_count_act
table_set_default hh_load_2_count hh_load_2_count_act
table_set_default hh_load_3_count hh_load_3_count_act
table_set_default hh_load_4_count hh_load_4_count_act
table_set_default hh_bf_1 hh_bf_1_act
table_set_default hh_bf_2 hh_bf_2_act
table_set_default hh_bf_3 hh_bf_3_act
table_set_default clone_to_controller clone_to_controller_act
table_add report_hot report_hot_act 10.0.0.2 => 10.0.0.3
table_add report_hot report_hot_act 10.0.0.4 => 10.0.0.5
mirroring_add 1 1
mirroring_add 2 2
mirroring_add 3 3
table_set_default reply_read_hit_before reply_read_hit_before_act
table_set_default reply_read_hit_after reply_read_hit_after_act
table_set_default read_value_1_1 read_value_1_1_act
table_set_default add_value_header_1 add_value_header_1_act
table_set_default write_value_1_1 write_value_1_1_act
table_set_default remove_value_header_1 remove_value_header_1_act
table_set_default read_value_1_2 read_value_1_2_act
table_set_default add_value_header_1 add_value_header_1_act
table_set_default write_value_1_2 write_value_1_2_act
table_set_default remove_value_header_1 remove_value_header_1_act
table_set_default read_value_1_3 read_value_1_3_act
table_set_default add_value_header_1 add_value_header_1_act
table_set_default write_value_1_3 write_value_1_3_act
table_set_default remove_value_header_1 remove_value_header_1_act
table_set_default read_value_1_4 read_value_1_4_act
table_set_default add_value_header_1 add_value_header_1_act
table_set_default write_value_1_4 write_value_1_4_act
table_set_default remove_value_header_1 remove_value_header_1_act
table_set_default read_value_2_1 read_value_2_1_act
table_set_default add_value_header_2 add_value_header_2_act
table_set_default write_value_2_1 write_value_2_1_act
table_set_default remove_value_header_2 remove_value_header_2_act
table_set_default read_value_2_2 read_value_2_2_act
table_set_default add_value_header_2 add_value_header_2_act
table_set_default write_value_2_2 write_value_2_2_act
table_set_default remove_value_header_2 remove_value_header_2_act
table_set_default read_value_2_3 read_value_2_3_act
table_set_default add_value_header_2 add_value_header_2_act
table_set_default write_value_2_3 write_value_2_3_act
table_set_default remove_value_header_2 remove_value_header_2_act
table_set_default read_value_2_4 read_value_2_4_act
table_set_default add_value_header_2 add_value_header_2_act
table_set_default write_value_2_4 write_value_2_4_act
table_set_default remove_value_header_2 remove_value_header_2_act
table_set_default read_value_3_1 read_value_3_1_act
table_set_default add_value_header_3 add_value_header_3_act
table_set_default write_value_3_1 write_value_3_1_act
table_set_default remove_value_header_3 remove_value_header_3_act
table_set_default read_value_3_2 read_value_3_2_act
table_set_default add_value_header_3 add_value_header_3_act
table_set_default write_value_3_2 write_value_3_2_act
table_set_default remove_value_header_3 remove_value_header_3_act
table_set_default read_value_3_3 read_value_3_3_act
table_set_default add_value_header_3 add_value_header_3_act
table_set_default write_value_3_3 write_value_3_3_act
table_set_default remove_value_header_3 remove_value_header_3_act
table_set_default read_value_3_4 read_value_3_4_act
table_set_default add_value_header_3 add_value_header_3_act
table_set_default write_value_3_4 write_value_3_4_act
table_set_default remove_value_header_3 remove_value_header_3_act
table_set_default read_value_4_1 read_value_4_1_act
table_set_default add_value_header_4 add_value_header_4_act
table_set_default write_value_4_1 write_value_4_1_act
table_set_default remove_value_header_4 remove_value_header_4_act
table_set_default read_value_4_2 read_value_4_2_act
table_set_default add_value_header_4 add_value_header_4_act
table_set_default write_value_4_2 write_value_4_2_act
table_set_default remove_value_header_4 remove_value_header_4_act
table_set_default read_value_4_3 read_value_4_3_act
table_set_default add_value_header_4 add_value_header_4_act
table_set_default write_value_4_3 write_value_4_3_act
table_set_default remove_value_header_4 remove_value_header_4_act
table_set_default read_value_4_4 read_value_4_4_act
table_set_default add_value_header_4 add_value_header_4_act
table_set_default write_value_4_4 write_value_4_4_act
table_set_default remove_value_header_4 remove_value_header_4_act
table_set_default read_value_5_1 read_value_5_1_act
table_set_default add_value_header_5 add_value_header_5_act
table_set_default write_value_5_1 write_value_5_1_act
table_set_default remove_value_header_5 remove_value_header_5_act
table_set_default read_value_5_2 read_value_5_2_act
table_set_default add_value_header_5 add_value_header_5_act
table_set_default write_value_5_2 write_value_5_2_act
table_set_default remove_value_header_5 remove_value_header_5_act
table_set_default read_value_5_3 read_value_5_3_act
table_set_default add_value_header_5 add_value_header_5_act
table_set_default write_value_5_3 write_value_5_3_act
table_set_default remove_value_header_5 remove_value_header_5_act
table_set_default read_value_5_4 read_value_5_4_act
table_set_default add_value_header_5 add_value_header_5_act
table_set_default write_value_5_4 write_value_5_4_act
table_set_default remove_value_header_5 remove_value_header_5_act
table_set_default read_value_6_1 read_value_6_1_act
table_set_default add_value_header_6 add_value_header_6_act
table_set_default write_value_6_1 write_value_6_1_act
table_set_default remove_value_header_6 remove_value_header_6_act
table_set_default read_value_6_2 read_value_6_2_act
table_set_default add_value_header_6 add_value_header_6_act
table_set_default write_value_6_2 write_value_6_2_act
table_set_default remove_value_header_6 remove_value_header_6_act
table_set_default read_value_6_3 read_value_6_3_act
table_set_default add_value_header_6 add_value_header_6_act
table_set_default write_value_6_3 write_value_6_3_act
table_set_default remove_value_header_6 remove_value_header_6_act
table_set_default read_value_6_4 read_value_6_4_act
table_set_default add_value_header_6 add_value_header_6_act
table_set_default write_value_6_4 write_value_6_4_act
table_set_default remove_value_header_6 remove_value_header_6_act
table_set_default read_value_7_1 read_value_7_1_act
table_set_default add_value_header_7 add_value_header_7_act
table_set_default write_value_7_1 write_value_7_1_act
table_set_default remove_value_header_7 remove_value_header_7_act
table_set_default read_value_7_2 read_value_7_2_act
table_set_default add_value_header_7 add_value_header_7_act
table_set_default write_value_7_2 write_value_7_2_act
table_set_default remove_value_header_7 remove_value_header_7_act
table_set_default read_value_7_3 read_value_7_3_act
table_set_default add_value_header_7 add_value_header_7_act
table_set_default write_value_7_3 write_value_7_3_act
table_set_default remove_value_header_7 remove_value_header_7_act
table_set_default read_value_7_4 read_value_7_4_act
table_set_default add_value_header_7 add_value_header_7_act
table_set_default write_value_7_4 write_value_7_4_act
table_set_default remove_value_header_7 remove_value_header_7_act
table_set_default read_value_8_1 read_value_8_1_act
table_set_default add_value_header_8 add_value_header_8_act
table_set_default write_value_8_1 write_value_8_1_act
table_set_default remove_value_header_8 remove_value_header_8_act
table_set_default read_value_8_2 read_value_8_2_act
table_set_default add_value_header_8 add_value_header_8_act
table_set_default write_value_8_2 write_value_8_2_act
table_set_default remove_value_header_8 remove_value_header_8_act
table_set_default read_value_8_3 read_value_8_3_act
table_set_default add_value_header_8 add_value_header_8_act
table_set_default write_value_8_3 write_value_8_3_act
table_set_default remove_value_header_8 remove_value_header_8_act
table_set_default read_value_8_4 read_value_8_4_act
table_set_default add_value_header_8 add_value_header_8_act
table_set_default write_value_8_4 write_value_8_4_act
table_set_default remove_value_header_8 remove_value_header_8_act
table_add check_cache_exist check_cache_exist_act 79228162514264337593543950336 => 1
table_add check_cache_exist check_cache_exist_act 237684487542793012780631851008 => 3
table_add check_cache_exist check_cache_exist_act 396140812571321687967719751680 => 5
table_add check_cache_exist check_cache_exist_act 554597137599850363154807652352 => 7
table_add check_cache_exist check_cache_exist_act 713053462628379038341895553024 => 9
table_add check_cache_exist check_cache_exist_act 871509787656907713528983453696 => 11
table_add check_cache_exist check_cache_exist_act 1029966112685436388716071354368 => 13
table_add check_cache_exist check_cache_exist_act 1188422437713965063903159255040 => 15
table_add check_cache_exist check_cache_exist_act 1346878762742493739090247155712 => 17
table_add check_cache_exist check_cache_exist_act 1505335087771022414277335056384 => 19
table_add check_cache_exist check_cache_exist_act 1663791412799551089464422957056 => 21
table_add check_cache_exist check_cache_exist_act 1822247737828079764651510857728 => 23
table_add check_cache_exist check_cache_exist_act 1980704062856608439838598758400 => 25
table_add check_cache_exist check_cache_exist_act 2139160387885137115025686659072 => 27
table_add check_cache_exist check_cache_exist_act 2297616712913665790212774559744 => 29
table_add check_cache_exist check_cache_exist_act 2456073037942194465399862460416 => 31
table_add check_cache_exist check_cache_exist_act 2614529362970723140586950361088 => 33
table_add check_cache_exist check_cache_exist_act 2772985687999251815774038261760 => 35
table_add check_cache_exist check_cache_exist_act 2931442013027780490961126162432 => 37
table_add check_cache_exist check_cache_exist_act 3089898338056309166148214063104 => 39
table_add check_cache_exist check_cache_exist_act 3248354663084837841335301963776 => 41
table_add check_cache_exist check_cache_exist_act 3406810988113366516522389864448 => 43
table_add check_cache_exist check_cache_exist_act 3565267313141895191709477765120 => 45
table_add check_cache_exist check_cache_exist_act 3723723638170423866896565665792 => 47
table_add check_cache_exist check_cache_exist_act 3882179963198952542083653566464 => 49
table_add check_cache_exist check_cache_exist_act 4040636288227481217270741467136 => 51
table_add check_cache_exist check_cache_exist_act 4199092613256009892457829367808 => 53
table_add check_cache_exist check_cache_exist_act 4357548938284538567644917268480 => 55
table_add check_cache_exist check_cache_exist_act 4516005263313067242832005169152 => 57
table_add check_cache_exist check_cache_exist_act 4674461588341595918019093069824 => 59
table_add check_cache_exist check_cache_exist_act 4832917913370124593206180970496 => 61
table_add check_cache_exist check_cache_exist_act 4991374238398653268393268871168 => 63
table_add check_cache_exist check_cache_exist_act 5149830563427181943580356771840 => 65
table_add check_cache_exist check_cache_exist_act 5308286888455710618767444672512 => 67
table_add check_cache_exist check_cache_exist_act 5466743213484239293954532573184 => 69
table_add check_cache_exist check_cache_exist_act 5625199538512767969141620473856 => 71
table_add check_cache_exist check_cache_exist_act 5783655863541296644328708374528 => 73
table_add check_cache_exist check_cache_exist_act 5942112188569825319515796275200 => 75
table_add check_cache_exist check_cache_exist_act 6100568513598353994702884175872 => 77
table_add check_cache_exist check_cache_exist_act 6259024838626882669889972076544 => 79
table_add check_cache_exist check_cache_exist_act 6417481163655411345077059977216 => 81
table_add check_cache_exist check_cache_exist_act 6575937488683940020264147877888 => 83
table_add check_cache_exist check_cache_exist_act 6734393813712468695451235778560 => 85
table_add check_cache_exist check_cache_exist_act 6892850138740997370638323679232 => 87
table_add check_cache_exist check_cache_exist_act 7051306463769526045825411579904 => 89
table_add check_cache_exist check_cache_exist_act 7209762788798054721012499480576 => 91
table_add check_cache_exist check_cache_exist_act 7368219113826583396199587381248 => 93
table_add check_cache_exist check_cache_exist_act 7526675438855112071386675281920 => 95
table_add check_cache_exist check_cache_exist_act 7685131763883640746573763182592 => 97
table_add check_cache_exist check_cache_exist_act 7843588088912169421760851083264 => 99
\ No newline at end of file
table_set_default check_cache_valid check_cache_valid_act
table_set_default set_cache_valid set_cache_valid_act
table_add ipv4_route set_egress 10.0.0.1 => 1
table_add ipv4_route set_egress 10.0.0.2 => 1
table_add ipv4_route set_egress 10.0.0.3 => 1
table_add ipv4_route set_egress 10.0.0.4 => 2
table_add ipv4_route set_egress 10.0.0.5 => 3
table_add ethernet_set_mac ethernet_set_mac_act 1 => aa:bb:cc:dd:ee:17 aa:bb:cc:dd:ee:13
table_add ethernet_set_mac ethernet_set_mac_act 2 => aa:bb:cc:dd:ee:18 aa:bb:cc:dd:ee:04
table_add ethernet_set_mac ethernet_set_mac_act 3 => aa:bb:cc:dd:ee:19 aa:bb:cc:dd:ee:05
table_set_default calculate_router_hash calculate_router_hash_act
table_set_default _resubmit _resubmit_act
table_add update_dst update_dst_act 0 => 10.0.0.2
table_set_default hh_load_1_count hh_load_1_count_act
table_set_default hh_load_2_count hh_load_2_count_act
table_set_default hh_load_3_count hh_load_3_count_act
table_set_default hh_load_4_count hh_load_4_count_act
table_set_default hh_bf_1 hh_bf_1_act
table_set_default hh_bf_2 hh_bf_2_act
table_set_default hh_bf_3 hh_bf_3_act
table_set_default clone_to_controller clone_to_controller_act
table_add report_hot report_hot_act 10.0.0.2 => 10.0.0.3
table_add report_hot report_hot_act 10.0.0.4 => 10.0.0.5
mirroring_add 1 1
mirroring_add 2 2
mirroring_add 3 3
table_set_default reply_read_hit_before reply_read_hit_before_act
table_set_default reply_read_hit_after reply_read_hit_after_act
table_set_default read_value_1_1 read_value_1_1_act
table_set_default add_value_header_1 add_value_header_1_act
table_set_default write_value_1_1 write_value_1_1_act
table_set_default remove_value_header_1 remove_value_header_1_act
table_set_default read_value_1_2 read_value_1_2_act
table_set_default add_value_header_1 add_value_header_1_act
table_set_default write_value_1_2 write_value_1_2_act
table_set_default remove_value_header_1 remove_value_header_1_act
table_set_default read_value_1_3 read_value_1_3_act
table_set_default add_value_header_1 add_value_header_1_act
table_set_default write_value_1_3 write_value_1_3_act
table_set_default remove_value_header_1 remove_value_header_1_act
table_set_default read_value_1_4 read_value_1_4_act
table_set_default add_value_header_1 add_value_header_1_act
table_set_default write_value_1_4 write_value_1_4_act
table_set_default remove_value_header_1 remove_value_header_1_act
table_set_default read_value_2_1 read_value_2_1_act
table_set_default add_value_header_2 add_value_header_2_act
table_set_default write_value_2_1 write_value_2_1_act
table_set_default remove_value_header_2 remove_value_header_2_act
table_set_default read_value_2_2 read_value_2_2_act
table_set_default add_value_header_2 add_value_header_2_act
table_set_default write_value_2_2 write_value_2_2_act
table_set_default remove_value_header_2 remove_value_header_2_act
table_set_default read_value_2_3 read_value_2_3_act
table_set_default add_value_header_2 add_value_header_2_act
table_set_default write_value_2_3 write_value_2_3_act
table_set_default remove_value_header_2 remove_value_header_2_act
table_set_default read_value_2_4 read_value_2_4_act
table_set_default add_value_header_2 add_value_header_2_act
table_set_default write_value_2_4 write_value_2_4_act
table_set_default remove_value_header_2 remove_value_header_2_act
table_set_default read_value_3_1 read_value_3_1_act
table_set_default add_value_header_3 add_value_header_3_act
table_set_default write_value_3_1 write_value_3_1_act
table_set_default remove_value_header_3 remove_value_header_3_act
table_set_default read_value_3_2 read_value_3_2_act
table_set_default add_value_header_3 add_value_header_3_act
table_set_default write_value_3_2 write_value_3_2_act
table_set_default remove_value_header_3 remove_value_header_3_act
table_set_default read_value_3_3 read_value_3_3_act
table_set_default add_value_header_3 add_value_header_3_act
table_set_default write_value_3_3 write_value_3_3_act
table_set_default remove_value_header_3 remove_value_header_3_act
table_set_default read_value_3_4 read_value_3_4_act
table_set_default add_value_header_3 add_value_header_3_act
table_set_default write_value_3_4 write_value_3_4_act
table_set_default remove_value_header_3 remove_value_header_3_act
table_set_default read_value_4_1 read_value_4_1_act
table_set_default add_value_header_4 add_value_header_4_act
table_set_default write_value_4_1 write_value_4_1_act
table_set_default remove_value_header_4 remove_value_header_4_act
table_set_default read_value_4_2 read_value_4_2_act
table_set_default add_value_header_4 add_value_header_4_act
table_set_default write_value_4_2 write_value_4_2_act
table_set_default remove_value_header_4 remove_value_header_4_act
table_set_default read_value_4_3 read_value_4_3_act
table_set_default add_value_header_4 add_value_header_4_act
table_set_default write_value_4_3 write_value_4_3_act
table_set_default remove_value_header_4 remove_value_header_4_act
table_set_default read_value_4_4 read_value_4_4_act
table_set_default add_value_header_4 add_value_header_4_act
table_set_default write_value_4_4 write_value_4_4_act
table_set_default remove_value_header_4 remove_value_header_4_act
table_set_default read_value_5_1 read_value_5_1_act
table_set_default add_value_header_5 add_value_header_5_act
table_set_default write_value_5_1 write_value_5_1_act
table_set_default remove_value_header_5 remove_value_header_5_act
table_set_default read_value_5_2 read_value_5_2_act
table_set_default add_value_header_5 add_value_header_5_act
table_set_default write_value_5_2 write_value_5_2_act
table_set_default remove_value_header_5 remove_value_header_5_act
table_set_default read_value_5_3 read_value_5_3_act
table_set_default add_value_header_5 add_value_header_5_act
table_set_default write_value_5_3 write_value_5_3_act
table_set_default remove_value_header_5 remove_value_header_5_act
table_set_default read_value_5_4 read_value_5_4_act
table_set_default add_value_header_5 add_value_header_5_act
table_set_default write_value_5_4 write_value_5_4_act
table_set_default remove_value_header_5 remove_value_header_5_act
table_set_default read_value_6_1 read_value_6_1_act
table_set_default add_value_header_6 add_value_header_6_act
table_set_default write_value_6_1 write_value_6_1_act
table_set_default remove_value_header_6 remove_value_header_6_act
table_set_default read_value_6_2 read_value_6_2_act
table_set_default add_value_header_6 add_value_header_6_act
table_set_default write_value_6_2 write_value_6_2_act
table_set_default remove_value_header_6 remove_value_header_6_act
table_set_default read_value_6_3 read_value_6_3_act
table_set_default add_value_header_6 add_value_header_6_act
table_set_default write_value_6_3 write_value_6_3_act
table_set_default remove_value_header_6 remove_value_header_6_act
table_set_default read_value_6_4 read_value_6_4_act
table_set_default add_value_header_6 add_value_header_6_act
table_set_default write_value_6_4 write_value_6_4_act
table_set_default remove_value_header_6 remove_value_header_6_act
table_set_default read_value_7_1 read_value_7_1_act
table_set_default add_value_header_7 add_value_header_7_act
table_set_default write_value_7_1 write_value_7_1_act
table_set_default remove_value_header_7 remove_value_header_7_act
table_set_default read_value_7_2 read_value_7_2_act
table_set_default add_value_header_7 add_value_header_7_act
table_set_default write_value_7_2 write_value_7_2_act
table_set_default remove_value_header_7 remove_value_header_7_act
table_set_default read_value_7_3 read_value_7_3_act
table_set_default add_value_header_7 add_value_header_7_act
table_set_default write_value_7_3 write_value_7_3_act
table_set_default remove_value_header_7 remove_value_header_7_act
table_set_default read_value_7_4 read_value_7_4_act
table_set_default add_value_header_7 add_value_header_7_act
table_set_default write_value_7_4 write_value_7_4_act
table_set_default remove_value_header_7 remove_value_header_7_act
table_set_default read_value_8_1 read_value_8_1_act
table_set_default add_value_header_8 add_value_header_8_act
table_set_default write_value_8_1 write_value_8_1_act
table_set_default remove_value_header_8 remove_value_header_8_act
table_set_default read_value_8_2 read_value_8_2_act
table_set_default add_value_header_8 add_value_header_8_act
table_set_default write_value_8_2 write_value_8_2_act
table_set_default remove_value_header_8 remove_value_header_8_act
table_set_default read_value_8_3 read_value_8_3_act
table_set_default add_value_header_8 add_value_header_8_act
table_set_default write_value_8_3 write_value_8_3_act
table_set_default remove_value_header_8 remove_value_header_8_act
table_set_default read_value_8_4 read_value_8_4_act
table_set_default add_value_header_8 add_value_header_8_act
table_set_default write_value_8_4 write_value_8_4_act
table_set_default remove_value_header_8 remove_value_header_8_act
table_add check_cache_exist check_cache_exist_act 79228162514264337593543950336 => 1
table_add check_cache_exist check_cache_exist_act 237684487542793012780631851008 => 3
table_add check_cache_exist check_cache_exist_act 396140812571321687967719751680 => 5
table_add check_cache_exist check_cache_exist_act 554597137599850363154807652352 => 7
table_add check_cache_exist check_cache_exist_act 713053462628379038341895553024 => 9
table_add check_cache_exist check_cache_exist_act 871509787656907713528983453696 => 11
table_add check_cache_exist check_cache_exist_act 1029966112685436388716071354368 => 13
table_add check_cache_exist check_cache_exist_act 1188422437713965063903159255040 => 15
table_add check_cache_exist check_cache_exist_act 1346878762742493739090247155712 => 17
table_add check_cache_exist check_cache_exist_act 1505335087771022414277335056384 => 19
table_add check_cache_exist check_cache_exist_act 1663791412799551089464422957056 => 21
table_add check_cache_exist check_cache_exist_act 1822247737828079764651510857728 => 23
table_add check_cache_exist check_cache_exist_act 1980704062856608439838598758400 => 25
table_add check_cache_exist check_cache_exist_act 2139160387885137115025686659072 => 27
table_add check_cache_exist check_cache_exist_act 2297616712913665790212774559744 => 29
table_add check_cache_exist check_cache_exist_act 2456073037942194465399862460416 => 31
table_add check_cache_exist check_cache_exist_act 2614529362970723140586950361088 => 33
table_add check_cache_exist check_cache_exist_act 2772985687999251815774038261760 => 35
table_add check_cache_exist check_cache_exist_act 2931442013027780490961126162432 => 37
table_add check_cache_exist check_cache_exist_act 3089898338056309166148214063104 => 39
table_add check_cache_exist check_cache_exist_act 3248354663084837841335301963776 => 41
table_add check_cache_exist check_cache_exist_act 3406810988113366516522389864448 => 43
table_add check_cache_exist check_cache_exist_act 3565267313141895191709477765120 => 45
table_add check_cache_exist check_cache_exist_act 3723723638170423866896565665792 => 47
table_add check_cache_exist check_cache_exist_act 3882179963198952542083653566464 => 49
table_add check_cache_exist check_cache_exist_act 4040636288227481217270741467136 => 51
table_add check_cache_exist check_cache_exist_act 4199092613256009892457829367808 => 53
table_add check_cache_exist check_cache_exist_act 4357548938284538567644917268480 => 55
table_add check_cache_exist check_cache_exist_act 4516005263313067242832005169152 => 57
table_add check_cache_exist check_cache_exist_act 4674461588341595918019093069824 => 59
table_add check_cache_exist check_cache_exist_act 4832917913370124593206180970496 => 61
table_add check_cache_exist check_cache_exist_act 4991374238398653268393268871168 => 63
table_add check_cache_exist check_cache_exist_act 5149830563427181943580356771840 => 65
table_add check_cache_exist check_cache_exist_act 5308286888455710618767444672512 => 67
table_add check_cache_exist check_cache_exist_act 5466743213484239293954532573184 => 69
table_add check_cache_exist check_cache_exist_act 5625199538512767969141620473856 => 71
table_add check_cache_exist check_cache_exist_act 5783655863541296644328708374528 => 73
table_add check_cache_exist check_cache_exist_act 5942112188569825319515796275200 => 75
table_add check_cache_exist check_cache_exist_act 6100568513598353994702884175872 => 77
table_add check_cache_exist check_cache_exist_act 6259024838626882669889972076544 => 79
table_add check_cache_exist check_cache_exist_act 6417481163655411345077059977216 => 81
table_add check_cache_exist check_cache_exist_act 6575937488683940020264147877888 => 83
table_add check_cache_exist check_cache_exist_act 6734393813712468695451235778560 => 85
table_add check_cache_exist check_cache_exist_act 6892850138740997370638323679232 => 87
table_add check_cache_exist check_cache_exist_act 7051306463769526045825411579904 => 89
table_add check_cache_exist check_cache_exist_act 7209762788798054721012499480576 => 91
table_add check_cache_exist check_cache_exist_act 7368219113826583396199587381248 => 93
table_add check_cache_exist check_cache_exist_act 7526675438855112071386675281920 => 95
table_add check_cache_exist check_cache_exist_act 7685131763883640746573763182592 => 97
table_add check_cache_exist check_cache_exist_act 7843588088912169421760851083264 => 99
\ No newline at end of file
path_to_cmd = "commands_cache.txt"
max_hot = 100
len_key = 16
f = open(path_to_cmd, "w")
for i in range(1, max_hot + 1, 2):
x = i << ((len_key - 4) * 8)
f.write("table_add check_cache_exist check_cache_exist_act %d => %d\n" % (x, i))
f.flush()
f.close()
path_to_cmd = "commands_value.txt"
f = open(path_to_cmd, "w")
for i in range(1, 9):
for j in range(1, 5):
f.write("table_set_default read_value_%d_%d read_value_%d_%d_act\n" % (i, j, i, j))
f.write("table_set_default add_value_header_%d add_value_header_%d_act\n" % (i, i))
f.write("table_set_default write_value_%d_%d write_value_%d_%d_act\n" % (i, j, i, j))
f.write("table_set_default remove_value_header_%d remove_value_header_%d_act\n" % (i, i))
f.flush()
f.close()
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"__meta__": {
"version": [
2,
5
],
"compiler": "https://github.com/p4lang/p4c-bm"
},
"header_types": [
{
"name": "standard_metadata_t",
"id": 0,
"fields": [
[
"ingress_port",
9
],
[
"packet_length",
32
],
[
"egress_spec",
9
],
[
"egress_port",
9
],
[
"egress_instance",
32
],
[
"instance_type",
32
],
[
"clone_spec",
32
],
[
"_padding",
5
]
],
"length_exp": null,
"max_length": null
},
{
"name": "ethernet_t",
"id": 1,
"fields": [
[
"dstAddr",
48
],
[
"srcAddr",
48
],
[
"etherType",
16
]
],
"length_exp": null,
"max_length": null
},
{
"name": "ipv4_t",
"id": 2,
"fields": [
[
"version",
4
],
[
"ihl",
4
],
[
"diffserv",
8
],
[
"totalLen",
16
],
[
"identification",
16
],
[
"flags",
3
],
[
"fragOffset",
13
],
[
"ttl",
8
],
[
"protocol",
8
],
[
"hdrChecksum",
16
],
[
"srcAddr",
32
],
[
"dstAddr",
32
]
],
"length_exp": null,
"max_length": null
},
{
"name": "tcp_t",
"id": 3,
"fields": [
[
"srcPort",
16
],
[
"dstPort",
16
],
[
"seqNo",
32
],
[
"ackNo",
32
],
[
"dataOffset",
4
],
[
"res",
3
],
[
"ecn",
3
],
[
"ctrl",
6
],
[
"window",
16
],
[
"checksum",
16
],
[
"urgentPtr",
16
]
],
"length_exp": null,
"max_length": null
},
{
"name": "udp_t",
"id": 4,
"fields": [
[
"srcPort",
16
],
[
"dstPort",
16
],
[
"len",
16
],
[
"checksum",
16
]
],
"length_exp": null,
"max_length": null
}
],
"headers": [
{
"name": "standard_metadata",
"id": 0,
"header_type": "standard_metadata_t",
"metadata": true
},
{
"name": "ethernet",
"id": 1,
"header_type": "ethernet_t",
"metadata": false
},
{
"name": "ipv4",
"id": 2,
"header_type": "ipv4_t",
"metadata": false
},
{
"name": "tcp",
"id": 3,
"header_type": "tcp_t",
"metadata": false
},
{
"name": "udp",
"id": 4,
"header_type": "udp_t",
"metadata": false
}
],
"header_stacks": [],
"parsers": [
{
"name": "parser",
"id": 0,
"init_state": "start",
"parse_states": [
{
"name": "start",
"id": 0,
"parser_ops": [],
"transition_key": [],
"transitions": [
{
"type": "default",
"value": null,
"mask": null,
"next_state": "parse_ethernet"
}
]
},
{
"name": "parse_ethernet",
"id": 1,
"parser_ops": [
{
"op": "extract",
"parameters": [
{
"type": "regular",
"value": "ethernet"
}
]
}
],
"transition_key": [
{
"type": "field",
"value": [
"ethernet",
"etherType"
]
}
],
"transitions": [
{
"type": "hexstr",
"value": "0x0800",
"mask": null,
"next_state": "parse_ipv4"
},
{
"type": "default",
"value": null,
"mask": null,
"next_state": null
}
]
},
{
"name": "parse_ipv4",
"id": 2,
"parser_ops": [
{
"op": "extract",
"parameters": [
{
"type": "regular",
"value": "ipv4"
}
]
}
],
"transition_key": [
{
"type": "field",
"value": [
"ipv4",
"protocol"
]
}
],
"transitions": [
{
"type": "hexstr",
"value": "0x06",
"mask": null,
"next_state": "parse_tcp"
},
{
"type": "hexstr",
"value": "0x11",
"mask": null,
"next_state": "parse_udp"
},
{
"type": "default",
"value": null,
"mask": null,
"next_state": null
}
]
},
{
"name": "parse_tcp",
"id": 3,
"parser_ops": [
{
"op": "extract",
"parameters": [
{
"type": "regular",
"value": "tcp"
}
]
}
],
"transition_key": [],
"transitions": [
{
"type": "default",
"value": null,
"mask": null,
"next_state": null
}
]
},
{
"name": "parse_udp",
"id": 4,
"parser_ops": [
{
"op": "extract",
"parameters": [
{
"type": "regular",
"value": "udp"
}
]
}
],
"transition_key": [
{
"type": "field",
"value": [
"udp",
"dstPort"
]
}
],
"transitions": [
{
"type": "hexstr",
"value": "0x1f99",
"mask": null,
"next_state": null
},
{
"type": "default",
"value": null,
"mask": null,
"next_state": null
}
]
}
]
}
],
"parse_vsets": [],
"deparsers": [
{
"name": "deparser",
"id": 0,
"order": [
"ethernet",
"ipv4",
"tcp",
"udp"
]
}
],
"meter_arrays": [],
"actions": [
{
"name": "update_dst_act",
"id": 0,
"runtime_data": [],
"primitives": [
{
"op": "modify_field",
"parameters": [
{
"type": "field",
"value": [
"ipv4",
"dstAddr"
]
},
{
"type": "hexstr",
"value": "0xa000003"
}
]
}
]
}
],
"pipelines": [
{
"name": "ingress",
"id": 0,
"init_table": "_condition_0",
"tables": [
{
"name": "update_dst",
"id": 0,
"match_type": "exact",
"type": "simple",
"max_size": 16384,
"with_counters": false,
"direct_meters": null,
"support_timeout": false,
"key": [],
"actions": [
"update_dst_act"
],
"next_tables": {
"update_dst_act": null
},
"base_default_next": null
}
],
"action_profiles": [],
"conditionals": [
{
"name": "_condition_0",
"id": 0,
"expression": {
"type": "expression",
"value": {
"op": "==",
"left": {
"type": "field",
"value": [
"udp",
"dstPort"
]
},
"right": {
"type": "hexstr",
"value": "0x1f99"
}
}
},
"true_next": "update_dst",
"false_next": null
}
]
},
{
"name": "egress",
"id": 1,
"init_table": null,
"tables": [],
"action_profiles": [],
"conditionals": []
}
],
"calculations": [
{
"name": "ipv4_chksum_calc",
"id": 0,
"input": [
{
"type": "field",
"value": [
"ipv4",
"version"
]
},
{
"type": "field",
"value": [
"ipv4",
"ihl"
]
},
{
"type": "field",
"value": [
"ipv4",
"diffserv"
]
},
{
"type": "field",
"value": [
"ipv4",
"totalLen"
]
},
{
"type": "field",
"value": [
"ipv4",
"identification"
]
},
{
"type": "field",
"value": [
"ipv4",
"flags"
]
},
{
"type": "field",
"value": [
"ipv4",
"fragOffset"
]
},
{
"type": "field",
"value": [
"ipv4",
"ttl"
]
},
{
"type": "field",
"value": [
"ipv4",
"protocol"
]
},
{
"type": "field",
"value": [
"ipv4",
"srcAddr"
]
},
{
"type": "field",
"value": [
"ipv4",
"dstAddr"
]
}
],
"algo": "csum16"
},
{
"name": "udp_checksum",
"id": 1,
"input": [
{
"type": "field",
"value": [
"ipv4",
"srcAddr"
]
},
{
"type": "field",
"value": [
"ipv4",
"dstAddr"
]
},
{
"type": "hexstr",
"value": "0x00",
"bitwidth": 8
},
{
"type": "field",
"value": [
"ipv4",
"protocol"
]
},
{
"type": "field",
"value": [
"udp",
"len"
]
},
{
"type": "field",
"value": [
"udp",
"srcPort"
]
},
{
"type": "field",
"value": [
"udp",
"dstPort"
]
},
{
"type": "field",
"value": [
"udp",
"len"
]
},
{
"type": "header",
"value": "tcp"
},
{
"type": "payload"
}
],
"algo": "csum16"
}
],
"checksums": [
{
"name": "ipv4.hdrChecksum|ipv4_chksum_calc",
"id": 0,
"target": [
"ipv4",
"hdrChecksum"
],
"type": "generic",
"calculation": "ipv4_chksum_calc",
"if_cond": null
},
{
"name": "udp.checksum|udp_checksum",
"id": 1,
"target": [
"udp",
"checksum"
],
"type": "generic",
"calculation": "udp_checksum",
"if_cond": null
}
],
"learn_lists": [],
"field_lists": [],
"counter_arrays": [],
"register_arrays": [],
"force_arith": [
[
"standard_metadata",
"ingress_port"
],
[
"standard_metadata",
"packet_length"
],
[
"standard_metadata",
"egress_spec"
],
[
"standard_metadata",
"egress_port"
],
[
"standard_metadata",
"egress_instance"
],
[
"standard_metadata",
"instance_type"
],
[
"standard_metadata",
"clone_spec"
],
[
"standard_metadata",
"_padding"
]
]
}
\ No newline at end of file
# Copyright 2013-present Barefoot Networks, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from mininet.net import Mininet
from mininet.node import Switch, Host
from mininet.log import setLogLevel, info, error, debug
from mininet.moduledeps import pathCheck
from sys import exit
import os
import tempfile
import socket
class P4Host(Host):
def config(self, **params):
r = super(Host, self).config(**params)
self.defaultIntf().rename("eth0")
for off in ["rx", "tx", "sg"]:
cmd = "/sbin/ethtool --offload eth0 %s off" % off
self.cmd(cmd)
# disable IPv6
self.cmd("sysctl -w net.ipv6.conf.all.disable_ipv6=1")
self.cmd("sysctl -w net.ipv6.conf.default.disable_ipv6=1")
self.cmd("sysctl -w net.ipv6.conf.lo.disable_ipv6=1")
return r
def describe(self):
print "**********"
print self.name
print "default interface: %s\t%s\t%s" %(
self.defaultIntf().name,
self.defaultIntf().IP(),
self.defaultIntf().MAC()
)
print "**********"
class P4Switch(Switch):
"""P4 virtual switch"""
device_id = 0
def __init__(self, name, sw_path = None, json_path = None,
thrift_port = None,
pcap_dump = False,
log_console = False,
verbose = False,
device_id = None,
enable_debugger = False,
**kwargs):
Switch.__init__(self, name, **kwargs)
assert(sw_path)
assert(json_path)
# make sure that the provided sw_path is valid
pathCheck(sw_path)
# make sure that the provided JSON file exists
if not os.path.isfile(json_path):
error("Invalid JSON file.\n")
exit(1)
self.sw_path = sw_path
self.json_path = json_path
self.verbose = verbose
logfile = "/tmp/p4s.{}.log".format(self.name)
self.output = open(logfile, 'w')
self.thrift_port = thrift_port
self.pcap_dump = pcap_dump
self.enable_debugger = enable_debugger
self.log_console = log_console
if device_id is not None:
self.device_id = device_id
P4Switch.device_id = max(P4Switch.device_id, device_id)
else:
self.device_id = P4Switch.device_id
P4Switch.device_id += 1
self.nanomsg = "ipc:///tmp/bm-{}-log.ipc".format(self.device_id)
@classmethod
def setup(cls):
pass
def check_switch_started(self, pid):
"""While the process is running (pid exists), we check if the Thrift
server has been started. If the Thrift server is ready, we assume that
the switch was started successfully. This is only reliable if the Thrift
server is started at the end of the init process"""
while True:
if not os.path.exists(os.path.join("/proc", str(pid))):
return False
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(0.5)
result = sock.connect_ex(("localhost", self.thrift_port))
if result == 0:
return True
def start(self, controllers):
"Start up a new P4 switch"
info("Starting P4 switch {}.\n".format(self.name))
args = [self.sw_path]
for port, intf in self.intfs.items():
if not intf.IP():
args.extend(['-i', str(port) + "@" + intf.name])
if self.pcap_dump:
args.append("--pcap")
# args.append("--useFiles")
if self.thrift_port:
args.extend(['--thrift-port', str(self.thrift_port)])
if self.nanomsg:
args.extend(['--nanolog', self.nanomsg])
args.extend(['--device-id', str(self.device_id)])
P4Switch.device_id += 1
args.append(self.json_path)
if self.enable_debugger:
args.append("--debugger")
if self.log_console:
args.append("--log-console")
logfile = "/tmp/p4s.{}.log".format(self.name)
info(' '.join(args) + "\n")
pid = None
with tempfile.NamedTemporaryFile() as f:
# self.cmd(' '.join(args) + ' > /dev/null 2>&1 &')
self.cmd(' '.join(args) + ' >' + logfile + ' 2>&1 & echo $! >> ' + f.name)
pid = int(f.read())
debug("P4 switch {} PID is {}.\n".format(self.name, pid))
if not self.check_switch_started(pid):
error("P4 switch {} did not start correctly.\n".format(self.name))
exit(1)
info("P4 switch {} has been started.\n".format(self.name))
def stop(self):
"Terminate P4 switch."
self.output.flush()
self.cmd('kill %' + self.sw_path)
self.cmd('wait')
self.deleteIntfs()
def attach(self, intf):
"Connect a data port"
assert(0)
def detach(self, intf):
"Disconnect a data port"
assert(0)
#!/bin/bash
# Copyright 2013-present Barefoot Networks, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
BMV2_PATH=../bmv2
P4C_BM_PATH=../p4c-bmv2
P4C_BM_SCRIPT=$P4C_BM_PATH/p4c_bm/__main__.py
SWITCH_PATH=$BMV2_PATH/targets/simple_switch/simple_switch
#CLI_PATH=$BMV2_PATH/tools/runtime_CLI.py
CLI_PATH=$BMV2_PATH/targets/simple_switch/sswitch_CLI
$P4C_BM_SCRIPT ../p4src/hpdos.p4 --json hpdos.json
# This gives libtool the opportunity to "warm-up"
# sudo $SWITCH_PATH >/dev/null 2>&1
sudo PYTHONPATH=$PYTHONPATH:$BMV2_PATH/mininet/ python topo.py \
--behavioral-exe $SWITCH_PATH \
--json hpdos.json \
--cli $CLI_PATH
#!/usr/bin/python
# Copyright 2013-present Barefoot Networks, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from mininet.net import Mininet
from mininet.topo import Topo
from mininet.log import setLogLevel, info
from mininet.cli import CLI
from mininet.link import TCLink
from p4_mininet import P4Switch, P4Host
import argparse
from time import sleep
import os
import subprocess
_THIS_DIR = os.path.dirname(os.path.realpath(__file__))
_THRIFT_BASE_PORT = 22222
parser = argparse.ArgumentParser(description='Mininet demo')
parser.add_argument('--behavioral-exe', help='Path to behavioral executable',
type=str, action="store", required=True)
parser.add_argument('--json', help='Path to JSON config file',
type=str, action="store", required=True)
parser.add_argument('--cli', help='Path to BM CLI',
type=str, action="store", required=True)
args = parser.parse_args()
class MyTopo(Topo):
def __init__(self, sw_path, json_path, nb_hosts, nb_switches, links, **opts):
# Initialize topology and default options
Topo.__init__(self, **opts)
for i in xrange(nb_switches):
switch = self.addSwitch('s%d' % (i + 1),
sw_path = sw_path,
json_path = json_path,
thrift_port = _THRIFT_BASE_PORT + i,
pcap_dump = True,
device_id = i)
for h in xrange(nb_hosts):
host = self.addHost('h%d' % (h + 1))
for a, b in links:
self.addLink(a, b)
def read_topo():
nb_hosts = 0
nb_switches = 0
links = []
with open("topo.txt", "r") as f:
line = f.readline()[:-1]
w, nb_switches = line.split()
assert(w == "switches")
line = f.readline()[:-1]
w, nb_hosts = line.split()
assert(w == "hosts")
for line in f:
if not f: break
a, b = line.split()
links.append( (a, b) )
return int(nb_hosts), int(nb_switches), links
def main():
nb_hosts, nb_switches, links = read_topo()
topo = MyTopo(args.behavioral_exe,
args.json,
nb_hosts, nb_switches, links)
net = Mininet(topo = topo,
host = P4Host,
switch = P4Switch,
controller = None,
autoStaticArp=True )
net.start()
for n in range(nb_hosts):
h = net.get('h%d' % (n + 1))
for off in ["rx", "tx", "sg"]:
cmd = "/sbin/ethtool --offload eth0 %s off" % off
print cmd
h.cmd(cmd)
print "disable ipv6"
h.cmd("sysctl -w net.ipv6.conf.all.disable_ipv6=1")
h.cmd("sysctl -w net.ipv6.conf.default.disable_ipv6=1")
h.cmd("sysctl -w net.ipv6.conf.lo.disable_ipv6=1")
h.cmd("sysctl -w net.ipv4.tcp_congestion_control=reno")
h.cmd("iptables -I OUTPUT -p icmp --icmp-type destination-unreachable -j DROP")
h.setIP("10.0.0.%d" % (n + 1))
h.setMAC("aa:bb:cc:dd:ee:0%d" % (n + 1))
for i in range(nb_hosts):
if (i != n):
print("setting", "10.0.0.%d" % (i + 1), "aa:bb:cc:dd:ee:0%d" % (i + 1))
h.setARP("10.0.0.%d" % (i + 1), "aa:bb:cc:dd:ee:0%d" % (i + 1))
ctr = 1
for i in range(3):
for j in range(3):
# if (n + 1) == 1:
print("setting s%d" % (i + 1), "aa:bb:cc:dd:ee:1%d" % (ctr), "s%d-eth%d" % (i + 1, j + 1))
net.get('s%d' % (i + 1)).setMAC("aa:bb:cc:dd:ee:1%d" % (ctr), "s%d-eth%d" % (i + 1, j + 1))
# elif (n + 1) < 4:
# print("setting s2", "aa:bb:cc:dd:ee:1%d" % (n + 1), "s2-eth%d" % (n + 1))
# net.get('s2').setMAC("aa:bb:cc:dd:ee:1%d" % (n + 1), "s2-eth%d" % (n + 1))
# else:
# print("setting s3", "aa:bb:cc:dd:ee:1%d" % (n + 1), "s3-eth%d" % (n + 1 - 2))
# net.get('s3').setMAC("aa:bb:cc:dd:ee:1%d" % (n + 1), "s3-eth%d" % (n + 1 - 2))
ctr += 1
sleep(1)
for i in range(nb_switches):
#cmd = [args.cli, "--json", args.json, "--thrift-port", str(_THRIFT_BASE_PORT + i)]
cmd = [args.cli, args.json, str(_THRIFT_BASE_PORT + i)]
with open("c%d.txt" % (i + 1), "r") as f:
print " ".join(cmd)
try:
output = subprocess.check_output(cmd, stdin = f)
print output
except subprocess.CalledProcessError as e:
print e
print e.output
sleep(1)
print "Ready !"
CLI( net )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
main()
switches 3
hosts 5
h1 s1
s2 s1
s3 s1
h2 s2
h3 s2
h4 s3
h5 s3
NC_READ_REQUEST = 0
NC_READ_REPLY = 1
NC_HOT_READ_REQUEST = 2
NC_WRITE_REQUEST = 4
NC_WRITE_REPLY = 5
NC_UPDATE_REQUEST = 8
NC_UPDATE_REPLY = 9
header_type nc_cache_md_t {
fields {
cache_exist: 1;
cache_index: 14;
cache_valid: 1;
}
}
metadata nc_cache_md_t nc_cache_md;
action check_cache_exist_act(index) {
modify_field (nc_cache_md.cache_exist, 1);
modify_field (nc_cache_md.cache_index, index);
}
table check_cache_exist {
reads {
nc_hdr.key: exact;
}
actions {
check_cache_exist_act;
}
size: NUM_CACHE;
}
register cache_valid_reg {
width: 1;
instance_count: NUM_CACHE;
}
action check_cache_valid_act() {
register_read(nc_cache_md.cache_valid, cache_valid_reg, nc_cache_md.cache_index);
}
table check_cache_valid {
actions {
check_cache_valid_act;
}
//default_action: check_cache_valid_act;
}
action set_cache_valid_act() {
register_write(cache_valid_reg, nc_cache_md.cache_index, 1);
}
table set_cache_valid {
actions {
set_cache_valid_act;
}
//default_action: set_cache_valid_act;
}
control process_cache {
apply (check_cache_exist);
if (nc_cache_md.cache_exist == 1) {
if (nc_hdr.op == NC_READ_REQUEST) {
apply (check_cache_valid);
}
else if (nc_hdr.op == NC_UPDATE_REPLY) {
apply (set_cache_valid);
}
}
}
action ethernet_set_mac_act (smac, dmac) {
modify_field (ethernet.srcAddr, smac);
modify_field (ethernet.dstAddr, dmac);
}
table ethernet_set_mac {
reads {
standard_metadata.egress_port: exact;
}
actions {
ethernet_set_mac_act;
}
}
#define HH_LOAD_WIDTH 32
#define HH_LOAD_NUM 256
#define HH_LOAD_HASH_WIDTH 8
#define HH_THRESHOLD 128
#define HH_BF_NUM 512
#define HH_BF_HASH_WIDTH 9
header_type nc_load_md_t {
fields {
index_1: 16;
index_2: 16;
index_3: 16;
index_4: 16;
load_1: 32;
load_2: 32;
load_3: 32;
load_4: 32;
}
}
metadata nc_load_md_t nc_load_md;
field_list hh_hash_fields {
nc_hdr.key;
}
register hh_load_1_reg {
width: HH_LOAD_WIDTH;
instance_count: HH_LOAD_NUM;
}
field_list_calculation hh_load_1_hash {
input {
hh_hash_fields;
}
algorithm : crc32;
output_width : HH_LOAD_HASH_WIDTH;
}
action hh_load_1_count_act() {
modify_field_with_hash_based_offset(nc_load_md.index_1, 0, hh_load_1_hash, HH_LOAD_NUM);
register_read(nc_load_md.load_1, hh_load_1_reg, nc_load_md.index_1);
register_write(hh_load_1_reg, nc_load_md.index_1, nc_load_md.load_1 + 1);
}
table hh_load_1_count {
actions {
hh_load_1_count_act;
}
}
register hh_load_2_reg {
width: HH_LOAD_WIDTH;
instance_count: HH_LOAD_NUM;
}
field_list_calculation hh_load_2_hash {
input {
hh_hash_fields;
}
algorithm : csum16;
output_width : HH_LOAD_HASH_WIDTH;
}
action hh_load_2_count_act() {
modify_field_with_hash_based_offset(nc_load_md.index_2, 0, hh_load_2_hash, HH_LOAD_NUM);
register_read(nc_load_md.load_2, hh_load_2_reg, nc_load_md.index_2);
register_write(hh_load_2_reg, nc_load_md.index_2, nc_load_md.load_2 + 1);
}
table hh_load_2_count {
actions {
hh_load_2_count_act;
}
}
register hh_load_3_reg {
width: HH_LOAD_WIDTH;
instance_count: HH_LOAD_NUM;
}
field_list_calculation hh_load_3_hash {
input {
hh_hash_fields;
}
algorithm : crc16;
output_width : HH_LOAD_HASH_WIDTH;
}
action hh_load_3_count_act() {
modify_field_with_hash_based_offset(nc_load_md.index_3, 0, hh_load_3_hash, HH_LOAD_NUM);
register_read(nc_load_md.load_3, hh_load_3_reg, nc_load_md.index_3);
register_write(hh_load_3_reg, nc_load_md.index_3, nc_load_md.load_3 + 1);
}
table hh_load_3_count {
actions {
hh_load_3_count_act;
}
}
register hh_load_4_reg {
width: HH_LOAD_WIDTH;
instance_count: HH_LOAD_NUM;
}
field_list_calculation hh_load_4_hash {
input {
hh_hash_fields;
}
algorithm : crc32;
output_width : HH_LOAD_HASH_WIDTH;
}
action hh_load_4_count_act() {
modify_field_with_hash_based_offset(nc_load_md.index_4, 0, hh_load_4_hash, HH_LOAD_NUM);
register_read(nc_load_md.load_4, hh_load_4_reg, nc_load_md.index_4);
register_write(hh_load_4_reg, nc_load_md.index_4, nc_load_md.load_4 + 1);
}
table hh_load_4_count {
actions {
hh_load_4_count_act;
}
}
control count_min {
apply (hh_load_1_count);
apply (hh_load_2_count);
apply (hh_load_3_count);
apply (hh_load_4_count);
}
header_type hh_bf_md_t {
fields {
index_1: 16;
index_2: 16;
index_3: 16;
bf_1: 1;
bf_2: 1;
bf_3: 1;
}
}
metadata hh_bf_md_t hh_bf_md;
register hh_bf_1_reg {
width: 1;
instance_count: HH_BF_NUM;
}
field_list_calculation hh_bf_1_hash {
input {
hh_hash_fields;
}
algorithm : crc32;
output_width : HH_BF_HASH_WIDTH;
}
action hh_bf_1_act() {
modify_field_with_hash_based_offset(hh_bf_md.index_1, 0, hh_bf_1_hash, HH_BF_NUM);
register_read(hh_bf_md.bf_1, hh_bf_1_reg, hh_bf_md.index_1);
register_write(hh_bf_1_reg, hh_bf_md.index_1, 1);
}
table hh_bf_1 {
actions {
hh_bf_1_act;
}
}
register hh_bf_2_reg {
width: 1;
instance_count: HH_BF_NUM;
}
field_list_calculation hh_bf_2_hash {
input {
hh_hash_fields;
}
algorithm : csum16;
output_width : HH_BF_HASH_WIDTH;
}
action hh_bf_2_act() {
modify_field_with_hash_based_offset(hh_bf_md.index_2, 0, hh_bf_2_hash, HH_BF_NUM);
register_read(hh_bf_md.bf_2, hh_bf_2_reg, hh_bf_md.index_2);
register_write(hh_bf_2_reg, hh_bf_md.index_2, 1);
}
table hh_bf_2 {
actions {
hh_bf_2_act;
}
}
register hh_bf_3_reg {
width: 1;
instance_count: HH_BF_NUM;
}
field_list_calculation hh_bf_3_hash {
input {
hh_hash_fields;
}
algorithm : crc16;
output_width : HH_BF_HASH_WIDTH;
}
action hh_bf_3_act() {
modify_field_with_hash_based_offset(hh_bf_md.index_3, 0, hh_bf_3_hash, HH_BF_NUM);
register_read(hh_bf_md.bf_3, hh_bf_3_reg, hh_bf_md.index_3);
register_write(hh_bf_3_reg, hh_bf_md.index_3, 1);
}
table hh_bf_3 {
actions {
hh_bf_3_act;
}
}
control bloom_filter {
apply (hh_bf_1);
apply (hh_bf_2);
apply (hh_bf_3);
}
field_list mirror_list {
nc_load_md.load_1;
nc_load_md.load_2;
nc_load_md.load_3;
nc_load_md.load_4;
}
#define CONTROLLER_MIRROR_DSET 3
action clone_to_controller_act() {
clone_egress_pkt_to_egress(CONTROLLER_MIRROR_DSET, mirror_list);
}
table clone_to_controller {
actions {
clone_to_controller_act;
}
}
control report_hot_step_1 {
apply (clone_to_controller);
}
#define CONTROLLER_IP 0x0a000003
action report_hot_act(controller_ip) {
modify_field (nc_hdr.op, NC_HOT_READ_REQUEST);
add_header (nc_load);
add_to_field(ipv4.totalLen, 16);
add_to_field(udp.len, 16);
modify_field (nc_load.load_1, nc_load_md.load_1);
modify_field (nc_load.load_2, nc_load_md.load_2);
modify_field (nc_load.load_3, nc_load_md.load_3);
modify_field (nc_load.load_4, nc_load_md.load_4);
modify_field (ipv4.dstAddr, controller_ip);
}
table report_hot {
reads {
ipv4.dstAddr: exact;
}
actions {
report_hot_act;
}
}
control report_hot_step_2 {
apply (report_hot);
}
control heavy_hitter {
if (standard_metadata.instance_type == 0) {
count_min();
if (nc_load_md.load_1 > HH_THRESHOLD) {
if (nc_load_md.load_2 > HH_THRESHOLD) {
if (nc_load_md.load_3 > HH_THRESHOLD) {
if (nc_load_md.load_4 > HH_THRESHOLD) {
bloom_filter();
if (hh_bf_md.bf_1 == 0 or hh_bf_md.bf_2 == 0 or hh_bf_md.bf_3 == 0){
report_hot_step_1();
}
}
}
}
}
}
else {
report_hot_step_2();
}
}
#include "includes/defines.p4"
#include "includes/headers.p4"
#include "includes/parsers.p4"
#include "includes/checksum.p4"
#include "ethernet.p4"
#include "ipv4.p4"
#include "mds.p4"
#include "cache.p4"
#include "heavy_hitter.p4"
#include "value.p4"
#define PKT_INSTANCE_TYPE_NORMAL 0
#define PKT_INSTANCE_TYPE_INGRESS_CLONE 1
#define PKT_INSTANCE_TYPE_EGRESS_CLONE 2
#define PKT_INSTANCE_TYPE_COALESCED 3
#define PKT_INSTANCE_TYPE_INGRESS_RECIRC 4
#define PKT_INSTANCE_TYPE_REPLICATION 5
#define PKT_INSTANCE_TYPE_RESUBMIT 6
header_type resubmit_meta_t {
fields {
resubmit_key: 8;
}
}
metadata resubmit_meta_t resubmit_meta;
field_list resubmit_metadata {
resubmit_meta.resubmit_key;
}
action _resubmit_act() {
resubmit(resubmit_metadata);
}
table _resubmit{
actions {
_resubmit_act;
}
}
control ingress {
if (udp.dstPort == MDS_PORT) {
routePacket();
} else if (standard_metadata.instance_type == PKT_INSTANCE_TYPE_NORMAL) {
apply(_resubmit);
} else {
process_cache();
process_value();
}
apply(ipv4_route);
}
control egress {
if (nc_hdr.op == NC_READ_REQUEST and nc_cache_md.cache_exist != 1) {
heavy_hitter();
}
apply(ethernet_set_mac);
}
\ No newline at end of file
field_list ipv4_field_list {
ipv4.version;
ipv4.ihl;
ipv4.diffserv;
ipv4.totalLen;
ipv4.identification;
ipv4.flags;
ipv4.fragOffset;
ipv4.ttl;
ipv4.protocol;
ipv4.srcAddr;
ipv4.dstAddr;
}
field_list_calculation ipv4_chksum_calc {
input {
ipv4_field_list;
}
algorithm : csum16;
output_width: 16;
}
calculated_field ipv4.hdrChecksum {
update ipv4_chksum_calc;
}
field_list udp_checksum_list {
// IPv4 Pseudo Header Format. Must modify for IPv6 support.
ipv4.srcAddr;
ipv4.dstAddr;
8'0;
ipv4.protocol;
udp.len;
udp.srcPort;
udp.dstPort;
udp.len;
// udp.checksum;
payload;
}
field_list_calculation udp_checksum {
input {
udp_checksum_list;
}
algorithm : csum16;
output_width : 16;
}
calculated_field udp.checksum {
update udp_checksum;
}
#define NC_PORT 8888
#define MDS_PORT 8889
#define NUM_CACHE 128
#define CLUSTER_COUNT 2
#define NC_READ_REQUEST 0
#define NC_READ_REPLY 1
#define NC_HOT_READ_REQUEST 2
#define NC_WRITE_REQUEST 4
#define NC_WRITE_REPLY 5
#define NC_UPDATE_REQUEST 8
#define NC_UPDATE_REPLY 9
header_type ethernet_t {
fields {
dstAddr : 48;
srcAddr : 48;
etherType : 16;
}
}
header ethernet_t ethernet;
header_type ipv4_t {
fields {
version : 4;
ihl : 4;
diffserv : 8;
totalLen : 16;
identification : 16;
flags : 3;
fragOffset : 13;
ttl : 8;
protocol : 8;
hdrChecksum : 16;
srcAddr : 32;
dstAddr: 32;
}
}
header ipv4_t ipv4;
header_type tcp_t {
fields {
srcPort : 16;
dstPort : 16;
seqNo : 32;
ackNo : 32;
dataOffset : 4;
res : 3;
ecn : 3;
ctrl : 6;
window : 16;
checksum : 16;
urgentPtr : 16;
}
}
header tcp_t tcp;
header_type udp_t {
fields {
srcPort : 16;
dstPort : 16;
len : 16;
checksum : 16;
}
}
header udp_t udp;
header_type router_hdr_t {
fields {
op: 8;
key: 32;
}
}
header router_hdr_t router_hdr;
header_type nc_hdr_t {
fields {
op: 8;
key: 128;
}
}
header nc_hdr_t nc_hdr;
header_type nc_load_t {
fields {
load_1: 32;
load_2: 32;
load_3: 32;
load_4: 32;
}
}
header nc_load_t nc_load;
/*
The headers for value are defined in value.p4
k = 1, 2, ..., 8
header_type nc_value_{k}_t {
fields {
value_{k}_1: 32;
value_{k}_2: 32;
value_{k}_3: 32;
value_{k}_4: 32;
}
}
*/
parser start {
return parse_ethernet;
}
#define ETHER_TYPE_IPV4 0x0800
parser parse_ethernet {
extract (ethernet);
return select (latest.etherType) {
ETHER_TYPE_IPV4: parse_ipv4;
default: ingress;
}
}
#define IPV4_PROTOCOL_TCP 6
#define IPV4_PROTOCOL_UDP 17
parser parse_ipv4 {
extract(ipv4);
return select (latest.protocol) {
IPV4_PROTOCOL_TCP: parse_tcp;
IPV4_PROTOCOL_UDP: parse_udp;
default: ingress;
}
}
parser parse_tcp {
extract (tcp);
return ingress;
}
parser parse_udp {
extract (udp);
return select (latest.dstPort) {
NC_PORT: parse_nc_hdr;
MDS_PORT: parse_router_hdr;
default: ingress;
}
}
parser parse_router_hdr {
extract (router_hdr);
return ingress;
}
parser parse_nc_hdr {
extract (nc_hdr);
return select(latest.op) {
NC_READ_REQUEST: ingress;
NC_READ_REPLY: parse_value;
NC_HOT_READ_REQUEST: parse_nc_load;
NC_UPDATE_REQUEST: ingress;
NC_UPDATE_REPLY: parse_value;
default: ingress;
}
}
parser parse_nc_load {
extract (nc_load);
return ingress;
}
parser parse_value {
return parse_nc_value_1;
}
/*
The parsers for value headers are defined in value.p4
k = 1, 2, ..., 8
parser parse_value_{k} {
extract (nc_value_{k});
return select(k) {
8: ingress;
default: parse_value_{k + 1};
}
}
*/
action set_egress(egress_spec) {
modify_field(standard_metadata.egress_spec, egress_spec);
add_to_field(ipv4.ttl, -1);
}
@pragma stage 11
table ipv4_route {
reads {
ipv4.dstAddr : exact;
}
actions {
set_egress;
}
size : 8192;
}
#define ROUTER_HASH_WIDTH 8
header_type router_t {
fields {
router_index: 8;
}
}
metadata router_t router;
action update_dst_act(dstAddr) {
modify_field (ipv4.dstAddr, dstAddr);
modify_field (udp.dstPort, NC_PORT);
}
table update_dst {
reads {
router.router_index: exact;
}
actions {
update_dst_act;
}
}
field_list router_hash_fields {
router_hdr.key;
}
field_list_calculation router_hash {
input {
router_hash_fields;
}
algorithm : crc32;
output_width : ROUTER_HASH_WIDTH;
}
action calculate_router_hash_act() {
modify_field_with_hash_based_offset(router.router_index, 0, router_hash, CLUSTER_COUNT);
}
table calculate_router_hash {
actions {
calculate_router_hash_act;
}
}
control routePacket {
apply(calculate_router_hash);
apply(update_dst);
}
#include "includes/defines.p4"
#include "includes/headers.p4"
#include "includes/parsers.p4"
#include "includes/checksum.p4"
#include "cache.p4"
#include "heavy_hitter.p4"
#include "value.p4"
#include "ipv4.p4"
#include "ethernet.p4"
control ingress {
process_cache();
process_value();
apply (ipv4_route);
}
control egress {
if (nc_hdr.op == NC_READ_REQUEST and nc_cache_md.cache_exist != 1) {
heavy_hitter();
}
apply (ethernet_set_mac);
}
#define HEADER_VALUE(i) \
header_type nc_value_##i##_t { \
fields { \
value_##i##_1: 32; \
value_##i##_2: 32; \
value_##i##_3: 32; \
value_##i##_4: 32; \
} \
} \
header nc_value_##i##_t nc_value_##i;
#define PARSER_VALUE(i, ip1) \
parser parse_nc_value_##i { \
extract (nc_value_##i); \
return parse_nc_value_##ip1; \
}
#define REGISTER_VALUE_SLICE(i, j) \
register value_##i##_##j##_reg { \
width: 32; \
instance_count: NUM_CACHE; \
}
#define REGISTER_VALUE(i) \
REGISTER_VALUE_SLICE(i, 1) \
REGISTER_VALUE_SLICE(i, 2) \
REGISTER_VALUE_SLICE(i, 3) \
REGISTER_VALUE_SLICE(i, 4)
#define ACTION_READ_VALUE_SLICE(i, j) \
action read_value_##i##_##j##_act() { \
register_read(nc_value_##i.value_##i##_##j, value_##i##_##j##_reg, nc_cache_md.cache_index); \
}
#define ACTION_READ_VALUE(i) \
ACTION_READ_VALUE_SLICE(i, 1) \
ACTION_READ_VALUE_SLICE(i, 2) \
ACTION_READ_VALUE_SLICE(i, 3) \
ACTION_READ_VALUE_SLICE(i, 4)
#define TABLE_READ_VALUE_SLICE(i, j) \
table read_value_##i##_##j { \
actions { \
read_value_##i##_##j##_act; \
} \
}
#define TABLE_READ_VALUE(i) \
TABLE_READ_VALUE_SLICE(i, 1) \
TABLE_READ_VALUE_SLICE(i, 2) \
TABLE_READ_VALUE_SLICE(i, 3) \
TABLE_READ_VALUE_SLICE(i, 4)
#define ACTION_ADD_VALUE_HEADER(i) \
action add_value_header_##i##_act() { \
add_to_field(ipv4.totalLen, 16);\
add_to_field(udp.len, 16);\
add_header(nc_value_##i); \
}
#define TABLE_ADD_VALUE_HEADER(i) \
table add_value_header_##i { \
actions { \
add_value_header_##i##_act; \
} \
}
#define ACTION_WRITE_VALUE_SLICE(i, j) \
action write_value_##i##_##j##_act() { \
register_write(value_##i##_##j##_reg, nc_cache_md.cache_index, nc_value_##i.value_##i##_##j); \
}
#define ACTION_WRITE_VALUE(i) \
ACTION_WRITE_VALUE_SLICE(i, 1) \
ACTION_WRITE_VALUE_SLICE(i, 2) \
ACTION_WRITE_VALUE_SLICE(i, 3) \
ACTION_WRITE_VALUE_SLICE(i, 4)
#define TABLE_WRITE_VALUE_SLICE(i, j) \
table write_value_##i##_##j { \
actions { \
write_value_##i##_##j##_act; \
} \
}
#define TABLE_WRITE_VALUE(i) \
TABLE_WRITE_VALUE_SLICE(i, 1) \
TABLE_WRITE_VALUE_SLICE(i, 2) \
TABLE_WRITE_VALUE_SLICE(i, 3) \
TABLE_WRITE_VALUE_SLICE(i, 4)
#define ACTION_REMOVE_VALUE_HEADER(i) \
action remove_value_header_##i##_act() { \
subtract_from_field(ipv4.totalLen, 16);\
subtract_from_field(udp.len, 16);\
remove_header(nc_value_##i); \
}
#define TABLE_REMOVE_VALUE_HEADER(i) \
table remove_value_header_##i { \
actions { \
remove_value_header_##i##_act; \
} \
}
#define CONTROL_PROCESS_VALUE(i) \
control process_value_##i { \
if (nc_hdr.op == NC_READ_REQUEST and nc_cache_md.cache_valid == 1) { \
apply (add_value_header_##i); \
apply (read_value_##i##_1); \
apply (read_value_##i##_2); \
apply (read_value_##i##_3); \
apply (read_value_##i##_4); \
} \
else if (nc_hdr.op == NC_UPDATE_REPLY and nc_cache_md.cache_exist == 1) { \
apply (write_value_##i##_1); \
apply (write_value_##i##_2); \
apply (write_value_##i##_3); \
apply (write_value_##i##_4); \
apply (remove_value_header_##i); \
} \
}
#define HANDLE_VALUE(i, ip1) \
HEADER_VALUE(i) \
PARSER_VALUE(i, ip1) \
REGISTER_VALUE(i) \
ACTION_READ_VALUE(i) \
TABLE_READ_VALUE(i) \
ACTION_ADD_VALUE_HEADER(i) \
TABLE_ADD_VALUE_HEADER(i) \
ACTION_WRITE_VALUE(i) \
TABLE_WRITE_VALUE(i) \
ACTION_REMOVE_VALUE_HEADER(i) \
TABLE_REMOVE_VALUE_HEADER(i) \
CONTROL_PROCESS_VALUE(i)
#define FINAL_PARSER(i) \
parser parse_nc_value_##i { \
return ingress; \
}
HANDLE_VALUE(1, 2)
HANDLE_VALUE(2, 3)
HANDLE_VALUE(3, 4)
HANDLE_VALUE(4, 5)
HANDLE_VALUE(5, 6)
HANDLE_VALUE(6, 7)
HANDLE_VALUE(7, 8)
HANDLE_VALUE(8, 9)
FINAL_PARSER(9)
header_type reply_read_hit_info_md_t {
fields {
ipv4_srcAddr: 32;
ipv4_dstAddr: 32;
}
}
metadata reply_read_hit_info_md_t reply_read_hit_info_md;
action reply_read_hit_before_act() {
modify_field (reply_read_hit_info_md.ipv4_srcAddr, ipv4.srcAddr);
modify_field (reply_read_hit_info_md.ipv4_dstAddr, ipv4.dstAddr);
}
table reply_read_hit_before {
actions {
reply_read_hit_before_act;
}
}
action reply_read_hit_after_act() {
modify_field (ipv4.srcAddr, reply_read_hit_info_md.ipv4_dstAddr);
modify_field (ipv4.dstAddr, reply_read_hit_info_md.ipv4_srcAddr);
modify_field (nc_hdr.op, NC_READ_REPLY);
}
table reply_read_hit_after {
actions {
reply_read_hit_after_act;
}
}
control process_value {
if (nc_hdr.op == NC_READ_REQUEST and nc_cache_md.cache_valid == 1) {
apply (reply_read_hit_before);
}
process_value_1();
process_value_2();
process_value_3();
process_value_4();
process_value_5();
process_value_6();
process_value_7();
process_value_8();
if (nc_hdr.op == NC_READ_REQUEST and nc_cache_md.cache_valid == 1) {
apply (reply_read_hit_after);
}
}
NC_READ_REQUEST = 0
NC_READ_REPLY = 1
NC_HOT_READ_REQUEST = 2
NC_WRITE_REQUEST = 4
NC_WRITE_REPLY = 5
NC_UPDATE_REQUEST = 8
NC_UPDATE_REPLY = 9
import socket
import struct
import time
import thread
import argparse
from nc_config import *
parser = argparse.ArgumentParser(description='Mininet demo')
parser.add_argument('--server-ip', help='IP of server',
type=str, action="store", required=True)
parser.add_argument('--controller-ip', help='IP of controller',
type=str, action="store", required=True)
args = parser.parse_args()
NC_PORT = 8888
CLIENT_IP = "10.0.0.1"
SERVER_IP = args.server_ip
CONTROLLER_IP = args.controller_ip
path_kv = "kv.txt"
path_log = "server_log.txt"
len_key = 16
len_val = 128
f = open(path_kv, "r")
lines = f.readlines()
f.close()
kv = {}
for i in range(2, 3002, 3):
line = lines[i].split()
key_header = line[0]
key_body = line[1:]
val = lines[i + 1].split()
key_header = int(key_header)
for i in range(len(key_body)):
key_body[i] = int(key_body[i], 16)
for i in range(len(val)):
val[i] = int(val[i], 16)
key_field = ""
key_field += struct.pack(">I", key_header)
for i in range(len(key_body)):
key_field += struct.pack("B", key_body[i])
val_field = ""
for i in range(len(val)):
val_field += struct.pack("B", val[i])
kv[key_header] = (key_field, val_field)
f.close()
counter = 0
def counting():
last_counter = 0
while True:
# print (counter - last_counter), counter
last_counter = counter
time.sleep(1)
thread.start_new_thread(counting, ())
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((SERVER_IP, NC_PORT))
f = open(path_log, "w")
while True:
packet, addr = s.recvfrom(2048)
op_field = packet[0]
key_field = packet[1:]
op = struct.unpack("B", op_field)[0]
key_header = struct.unpack(">I", key_field[:4])[0]
print(op, key_header)
if (op == NC_READ_REQUEST or op == NC_HOT_READ_REQUEST):
# print("in")
op = NC_READ_REPLY
op_field = struct.pack("B", op)
key_field, val_field = kv[key_header]
packet = op_field + key_field + val_field
s.sendto(packet, (CLIENT_IP, NC_PORT))
counter = counter + 1
elif (op == NC_UPDATE_REQUEST):
op = NC_UPDATE_REPLY
op_field = struct.pack("B", op)
key_field, val_field = kv[key_header]
packet = op_field + key_field + val_field
s.sendto(packet, (CONTROLLER_IP, NC_PORT))
f.write(str(op) + ' ')
f.write(str(key_header) + '\n')
f.flush()
print counter
f.close()
<mxfile host="Electron" modified="2020-10-11T20:56:28.266Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.3.9 Chrome/83.0.4103.119 Electron/9.0.5 Safari/537.36" etag="CST4uzL3w92j-Lz-AeRa" version="13.3.9" type="device"><diagram id="dVNmU7IUbBy7O8nTNUCA" name="Page-1">7Vpbc5s6EP41foxHIC7yoy91O52kzYzPnPY8KkbF6gByhZzY+fWVQEBAJPEZx1btxg8GrS5I+2m/XS0M4DTdfuR4vbphEUkGLoi2AzgbuC6CnvxXgl0p8IEWxJxGpchpBAv6SLQQaOmGRiRvNRSMJYKu28IlyzKyFC0Z5pw9tJv9YEn7qWscE0OwWOLElH6jkVhpaeB7TcUnQuOVfrQLYVDWpLhqrZeSr3DEHp6I4IcBnHLGRHmXbqckUcqrFFP2mz9TW8+Mk0zs02ESfFn/M0lns0cWg4+zz5v47vEq1LO9x8lGL1nPVuwqHZBIqkQXM5bJy4SzTRYRNTCQJcbFisUsw8k1Y2spdKTwJxFipwHFG8GkaCXSRNeWD1EjP7saLcrZhi/JS0tAel9gHhPxQkMU1lqX25WwlAi+kx05SbCg9+2ZYL1x4rpdo1p5o7X7fzQd/kWadmxq2oHAjqpzqRgxVqzTDFrI5lStoBiWZFHVYpngPKfLUqibqGF+sExMWcJ4MVM4n0P5s4Sk446sGg0ykJzi5YpmsQGoIFvRhgMnNM6UnqV6iFTm5J5wQSW3j3VFSqMoKZAnOX3Ed8VQCqQ1o5ko1uJPBv5MjSXBzkvcK4iq3aPXrgYn25eRMdWoO4SeZgftJh1YeY2HxusEWrR66m/A0YzIfTeil41I28Y+VgQtE6IlL3+ZWPpWsawm2sIySBT35WuctUANfm1UdFko8OpB08ZYNskYT3HSNJB3sbouCJc8psaQYbe81GRbPkDOuHxG2frCOBh0ONhFJgc77mlJ2PR/74bbZ457Ga7V+L+e6FEM9+taVl6z+C+z2QB2bdbzTZsFp7XZvoPeW+E8znfpl39vzgDc16z/MNwr+GrcHZOrw9PC7r1T9WtUXWXwXqdqaJeqnR4s38qEVSfw/VZZ00Btx3LcO17VfxtfaxYnZ2Dmh9sycrq2DE0ORz22DI9ny/AN8PeU2+mCf8sSzOeLMwD2qPyNvGDod1AHljMeYd/B6rwStGhfgkVW+RVZys9KffLdd9V/CBGsBP8VAoCq8mxbe01V2j0t3RJOpQ6U4RVCK9i5B2Knu1YeqD7++kPgN79OYO112bacpx6ksyHqWR2wR0wXPE0oKWa8KJITXb95QwSOsMBPj0A26fQtwtwqCVunhf2elIRzSt+IzLRw7dNsO69jHTZAJ0CBo2AYOHa9FTJDlK+csuxiUQi7R75nUPBOioKlQ1/tya7A0HHctivzfduuLNzTlY1AP+QHujJHUuIw7MaXrtoujh8C1wtH1Wn9VN6sL/d3ZrHlvqAiq2+M0fl/0LK/ppFVTZt5zk6E1pPcmF1WgIYc4xzbF6KNThqhme+MVIQmLjhCQ91Xd39EhGbmE+rs/aXiEHRitPrUaCstPzJTDZcdJo+8bpgcHjNMlsXmC9YyWmq+A4YffgM=</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2020-09-26T17:36:28.979Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.3.9 Chrome/83.0.4103.119 Electron/9.0.5 Safari/537.36" etag="68Ok2qUYxrkbxyWO_KpK" version="13.3.9" type="device"><diagram id="AtbbNPOhgf-C7VBxDybL" name="Page-1">7Vptc+I2EP41fGzGsrGBjwdJep3L5TKh114/dRRbgAfZcmU5QH99V7b8KgNOgjnSyRfGWuvNu8+unl0xsGbB9leOo9VX5hE6MA1vO7CuB6Y5dsbwKwW7TGAbw0yw5L6XiVApmPv/EiU0lDTxPRLXOgrGqPCjutBlYUhcUZNhztmm3m3BaH3VCC+JJpi7mOrSP31PrJTUsYfli8/EX67U0qZlOdmbAOe91afEK+yxTUVk3QysGWdMZE/BdkaoVF6umGzc7Z63xc44CUWXAcPd9n79+VuwwFMr+Gf8w/39b/sXNcszpon64hn15YTZlsUuVwTsPpKPSUDv/AWhfgitaUS4HxBBOLyhSvxQyqablS/IPMKuHLoBhIBsJQIKLQSPYDWBYQgv2pTiKPaf0lUNkHDiJjz2n8kjiTNwSClLhFxpVhhdChcw2VxtWE4WC87WhdVA3VP1rYQLst2rRFSYBjBNGHwJ30EXNaCwpsLzSDU3FXAYSraq4MLKhVgBcllMXZoMHpTVXmBBU7cgfAvHcuBXIrCHBYbHOeHw4R9mbTfr0Lg0s441s2q2q2g8Yn4o0i3Y04F93TAh42LFlizEtGrEEyl2PygPaLum7EmbsnVdj/tStaWp+ssf0H4kEfVdPCcfwXCPHe3RpXkN0m35ntzGOqzuurbRz/abiabrWz/0QPKFyF3PaBJLlZnGJ8/jJI4PWUJqC5yNfqL+MgTZExOCBfCChN4nyeOkjDJ3nYpg9z8U0NPGXy9EPfEarE9gviSHLDPe4xvwPSzhLjlGsXSjckKxAF+uU9YWG6mhDxKrJRishu8hp2HmbF9qVMPSxTbe4GmGZv1HIhIe9mF5FhF4NfVwvCKeGgevVbowlq2tLwpIwHOKiKuJXYULukI1wFzZyMwF19sqnq531VbF+9+GsqNQ2Y+yowBFh49c48qw7VE214mRZ+YZTz5FtlcNeeVEeUe2WMSkH3TqrPhCz4Ej6YZj173c7hbz0ai3E3bYzpYoY+skepWjxwAYUbg6TNwe9tNuFZfvL9jnLOJyor3tNHzu3NHe1qz+USc45Lgj5+KosaOb8KNQ8FK7ToYXZ9fReznqDsDyxKUC1JeyTf30+z8pu0E2UDdtT3rTdsupg6mbwFFKZJopeccKcoKB6VDYy/QJwpazTJ9wTLxGDafZB+/JTSRfyA1QmuimlFYjGFZkhpKFnDOGUOeHy7u0dW22ExnOktBL85g8W8myE7OSu6hcBVplZiIbu0rjZHlJR9x0YT+jXujPqA7MjuQH9I53lW7KG/eughpFYGSg6nTH+1tGA/LZDvZQOrt18LEs6mSMTi8wf1Q9O1EAVMTFy+EAeinuXR1L44MKb9Y9O+bAvdU98yvApuvcvT4FPk+V81X5rApTx5PmfkL/pOFs565z5p50+a51OGqNjUurJJn6Xc0jRHXJ7B6wu5YHkCHYoFJOfge1pVeVbif9eM6k7jlmTqdPTpvs9oVaedDJ/FIvZ3B1//C2+Hv8ruG88dfqiqJeQDQyXxd+tYmc4ZGJeua7ps53z4WX4m6qyOmy66exY/2cHK8z9iZdsWf3Aj6EmpGlWWroij5kNC+tmjP1DT+doc8SLk1CpaKStFzRrFB8cwWLEgi9htwPHIuMYn471xALrEC0lyVcWCDlGE0kB77npbUMLpMqXGZbOoHBiWAq8ULnYivWpM5WrLbCn9maY/XEViyd9N+TDQh+CyJKAqnnFguiqzSl9hKXSDPeE7FhfC05DaY01vubsv99Snoevssthc+MPrfNbMmec18uDrLi+g0elr77AoSowtU7w8cENfDRloM7Lfhonjod8AHN8k+6WTwo/+ps3fwH</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2020-12-09T19:10:59.836Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.7.9 Chrome/85.0.4183.121 Electron/10.1.3 Safari/537.36" etag="DNC0uyjONie9N8BitTrc" version="13.7.9" type="device"><diagram id="dVNmU7IUbBy7O8nTNUCA" name="Page-1">7Vtdd9o4EP01PIZjW/58JATSnl3SnNKmTV/2KLYCSoxFZRFwf30lLIOxvA6bgG3o9iG1RrIszR3dGY1EB/Rnq2sK59MRCVDYMbRg1QFXHcNwbZf/FYIkFViamQomFAepSN8KxvgXkkJNShc4QPFOQ0ZIyPB8V+iTKEI+25FBSslyt9kjCXe/OocTpAjGPgxV6TccsKmU2pa5rfiA8GQqP20AYKc1M5i1llOJpzAgy5wIDDqgTwlh6dNs1UehUF6mmPS94b/UbkZGUcT2eeHjcjBYfrnXpvpydGNG08Hdt48XnhzcCwwXcspytCzJdIACrhJZjEjE/7ukZBEFSHSs8RKhbEomJILh34TMuVDnwifEWCIBhQtGuGjKZqGsRSvMvovXu7oLZPmely+4wJLlq5Xsf11IcoVbRPEMMUSlTFWF1E5MFtRHFfN3LWlUkE4Qq2ropQ2FMnKfkKq+RoSPhya8AUUhZPhl136gNMPJpt0WKP4gsfovuNlN46bpeg43rWu2ETXPahVq2bhzqPVJFOOYocgXw4BRwP8KGYriRaxAytCK7QICQzyJ+LPPlSg0e/mCKMOcwHqyYoaDIFxjj2L8Cz6suxLqnxMcsfUMrcuOdSX64nDHKfKi60cSscx+SthGisT30KpSubLWMeT0pS/QDU16h2WOWl3JSNM8q2rHWkZuM8vo7abv7W36TlOm/5NQc4Ss5Hls/nP//FVb3cAfF0DRa8uUWDpqo1U6NE/QNksnoreKlT2VlXvzechJlGESdQT52KGg3QfKnybi6TOK54K4H3CIWdIsTR+AmW1QZGZTU5jZKyFmcDRidhRMbkkI6XDcvE/sk5DQ9bfBcAj4v8OAYGWebwOCp4Jg1+odjVPzjlmU/rp3bBkFmeeradCUpv3n2cP4r+uvo+9P/duBN/Z7I3BhuLUoluuTJulGyc2KYp+kdze1243SupTkS8WtUszVzHoin7Ed41o2xGL68sUga+GHMI6xnwplkzex15vMoFzvjZlB5bhzC27MCBXZoDJ/f72AFHJnwk3i5H29U3AzugUUN1O2CTuEr680jR3ySxEQBrvO7mU2a/9ciHwZVwR4fFxbb06UYoVv8RxlHfABpX2kdaePnllEr2QPbdYaJKjo9eJkdnM3Ot9IzSuCYKggOLWCoCsgfKLrzcuZQmArEGhqsHysdVDOYs1EcFlCVu9qmr2bkG06j16qJv3geXT56q2wxq2BeHbRQFy365m67timo1muC3Z7TGcoOymYwmZUb7eOMhdXo3VoXcfOp+svtK7WSvNwa7IO4HUdYLumoWuWYQO9YCuOW6t1WLUYw17wVaHy+uK2Dw3fuyi5oTOyGvTcrj21mqs7Fz1rrdKz4dSi1zYkG94Fm9HYqW/VsHPL444wHE247BLGZ5BScJVYy1b3Q2XHB0cLxtXsTs3hlmG5O8H4saKtStp6nd8OngUvD7ec7Jx9YyB6vQGWrl5z6k8hjs5g8XlWcfEBdfEd69io0qpyyv6QzBENxTI614SEZxeOUMsSc8fKCZXD0FBG4h28BfblLbNVDl5Xd/c/CHlGiBv9yfOLWzyWrjPZWYn+H5Rxdt0Cu2hu0yCol2bazi72vuzS2M25ynHnr8JACsNwfdP+c2/45eQ5xvGKzrMkhql1A6H/efePnOzOVdWRSr2BZJtv51aebryeomhXZklXN8wj8oRnJ88snlGIXgxLNWqr1nNCdSt63ke1XvGotgyCeo9qy2KX/y+clKOnhP8lub1joVd1eTwH3jXyn8kZe2a7mF8FJZ75WNF/1e8ichhc9T6dLwBW8c7cEb0IL25/E5rmP7e/rAWD3w==</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2020-12-09T13:52:47.728Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.7.9 Chrome/85.0.4183.121 Electron/10.1.3 Safari/537.36" etag="IWjZdE-D4wYd28FIHY1Q" version="13.7.9" type="device"><diagram id="dVNmU7IUbBy7O8nTNUCA" name="Page-1">5Vpbl5o6FP41Ps4sJBDw0fHS6WrtuMbWnj6dlUpGcgrEFeIg/fVNIIxg0LHreEH1QZOdC8n3sfe3CbZAL1x9YGjhj6iHg5ZpeKsW6LdM04Wu+JaGNDfYhpUb5ox4uam9NkzIb6yMhrIuiYfjSkdOacDJomqc0SjCM16xIcZoUu32QoPqVRdojjXDZIYC3fqdeNxXVmhb64ZHTOa+urQJAMxbQlT0VluJfeTRpGQCgxboMUp5XgpXPRxI8Apg8nHDLa1vK2M44vsM+JgMBsnXH4bfTkZfrMgfTL9/vGsDJ5/nFQVLtWe1XJ4WIGBPYKKqEY3EzwOjy8jDcmZD1CjjPp3TCAWfKV0IY1sY/8Ocp4pRtORUmHweBqpVX73aUEyXbIZ3LllhzxGbY76zp+JCbqB0EYXPB0xDzFkqOjAcIE5eq6Qjde/M3/qt0RUFBfBfgd25ZrDdZoFtta8YbMtoFtjFyktg9xFHwjLhlMkgaxqZOMQaBxyveBVBFJB5JMozgSBmwvCKGSciKHdVQ0g8L8jIwjH5jX5mU0m6FpREPNuc/dCy+3IuwU+cUyWnfqERLwiXdY8wIRuEylkTHPNd/MlV4NVOtFUrdNQQpXqdQgOSkoYAZfPL8mEciyDbvjhvKO7x972hUOPTe8PnxwTM4CwZTxnsUmxOvYDeme9D3TRca/fRbhSqeoQ5PKoyPPRoQFk2HxgOgficCG1wLrSHT+TlZRGyXzgcj4c2fH7999vdaaKDgJOl/8jx9x23qP/I6rCo9ldq/ryWlmtjzIjYrxSJzFgL4QGJq4XqzGmOofnFJyyvP80MJgykqP1kojSXJanH+MwqfBzVdSCsqK5baF5JdZ0a0QUHEN1dHl1i5rk76gV06TUO/r8OfPvT4m7SAvej5RC50C5ZK6eqaYRC2n84Ly3bODiOt7iwmqO6NTmqe9oUVVf4oQihWcC6KWaMDWbausPAkzJjue/nXg17eChOI/Z4lHbOlXhtcQNd0K8I7E6zwAb6nT0WKSWRl77KJAl2NtQY6GH/WGq8+5YoUdCN0/DLdHRLQd8p8njFi9M5Oy/6m4HHdIFZIAPKDTEDoX1vN40b/dGi8RoB99YIs1kaYcFrBttuFtj2Bb61uVywLzeMHA5CNXQsVacU9e32vVMN+661Ec9zwtXADS7eVvJ/klM98AxJIF+lTdKY4/C8KnwktQXVPKjutOjExxJmLQuj55tKgoC1kQTVnRfZp02C9FeaT0xu/IZ4sZ0NdwG6u1inZUV3lzENEBtObooXWOWlY+jecqwzvO0vqaqH3t2nS6NEw7+Gpe3HqmDj5KPmKe5AAUxU1//ry9OB9b8jweAP</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2020-09-16T06:37:51.139Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.3.9 Chrome/83.0.4103.119 Electron/9.0.5 Safari/537.36" etag="jUaRMcHumZJ9VrQBtutb" version="13.3.9" type="device"><diagram id="r-GLMkCP-4nqHRol76c5" name="Page-1">7Vzvd5o6GP5rPGe753QHCKD9WLXd1q3d7rzbun3ZiRCVDcGFWHV//U0giPCmrW1Vgvd+qIWXgG+evD+evIm0UG+6fE3xbHIV+yRsWYa/bKF+y7I6bod/CsEqEziGnQnGNPAzkVkIBsEfIoWGlM4DnySlhiyOQxbMykIvjiLisZIMUxovys1GcVj+1hkeEyAYeDiE0q+BzyZS6jp2ceENCcYT+dUWQm52ZYrz1rIryQT78WJDhM5bqEfjmGVH02WPhAK8HJjsvos7rq41oyRi29zw/vuH7s+/v3jL9u2778j5cUEvrRP5lFsczmWP+5/OrlqWG/JndoeUH43FUcvp9rA3IS2nL3vDVjlGNJ5HPhHfYvKWi0nAyGCGPXF1wY2CyyZsGsrLUOtcBUIZWW6IZC9ek3hKGF3xJsscY4motKk1wotihNpSNNkYG0fKsLSJ8frJBWr8QAL3CBAdAAnxuRXJ05iySTyOIxyeF9JuAZrBz4o27+N4JqH6SRhbSZfAcxaXgeT40dXN5sk38bBXTn7aX8qHZ2creZYwTNmZcA0u8EKcJIGXiy+C8MFxSuI59cg9aFjSTTEdE3ZPO5S1E1DdO+qUhJgFt2WH3PkYoqcMInfpmbgaBtGvnYzpMmA3xSjys28bV4oBFSerzdG9KQ/9t9LIa24HlquVIVggIl5/uVJExA/dy9RcYkr4/xCvCDWBCdUeGts1h0YE0BwM+luBadUOpqkbmDYA801/OzCRdmCiupN2G/o5J69cAr2Yd5GVAcFhMI5E3OSAEMoFAoiA08YzeWEa+H6W50kS/MHD9FEi7M7iIGJpX5yuIFP8WTwNJFlG2BXWnTLW5inE2lFgbe0L6w7AWn+WabuasczTJxCU42WZ+QTxQXphmlrRi3x62Dieqc+IIr1mDrnezWSMIMzVTXJMWJJoDmVE2qEJpzPN4YxVNGvnjCaczkjSCE2vaaTRNjUjjRaMq/qzxrahGWu0YIr5L9NGa+uqlF4kA7WfMIw60EZ9y5PbWgKytbKEXO9m0k0QH+smSFaTK5Sudmg2uURZRbN2umk50NUzugnBahrddB3N6CbqHFmGXVOv2jKsu22G1YtrudC76rMEc8MOCqt4wBK0Y907X+JNb+Uq49VGAxm3iid/FIKNekJ1DapT2THzQHvLcCrGlWlwx93V5CzvXqub+YW8q2Kza0yekT1cyGymfESv3/ZqT7VWvt0iHwnXAdHfVUR/VIFwdz6v0/zqKHx+90Fd7WbOHU76kJs9Nng4dsVkO+je4FFtf2/w2JXPI8VsRheft13NfN42ACb/M77n+bzdUManE/c/jui/86KZOsq224eJ/u3O46J/tf1hoj+svmgT/duGbtEfrjO/jUZBFAxx5HP5i09x7/xlS9QbLvjnIB6xEyECSDat8mJXRsJWlLnWO8gOUnqx4UyF999Urec1DWwwCUTQ7NFBsYb7Hnn3rWPA2qxi3YGGfVis4b5H3n10DFgDu+7UbdenKqztY8DaquzMQIpVnoNindfly1g7x4A1Oi1jrUqOh8XaAlh/6l+dNR7oNWK5USsS40HXfxxInnsfPwOc6/5Fj+lAg1QtStp7wwkuSqY4GdkerGfhhaknp8cW2hN8imVGFXxob/BB/qWDmVW3AddvZpA7aWxmAL66zcyFKVoHM6tu/6ndzFxYBdDYzAB8tZsZTJr9XvPJCVj4NSHO9iHJiQtnN3+lQBsn/K8fUPHui7XRGmeeR5Kk8cNQ3SJkwFEwVea+t2Fow6jKu98+iolP9ZcrCpM/6MSnDSMz7757DFhb1Y2GdRcF23CSybvfOQaszS2Y2b6w/vUZGz8ub7/609mif3NzeckW14o37vDen2oCNcBVgf7W9ddDmrUSakXphMxCjhcXXuFEQNh0zKu1QdPqwBxpHBJ0yAgL0LV4tcKz8LYd50G890VJlHDDakwB93Xj4XZPNYNbsVIpf9zgB7clrN3fc/Fmt66A/ESiLAh7SEasuLr+DaN8SjLDUVU2zAUwemUNeE+G1Zu4TPUsLk4VLUt3r7v5KtWSWwj/44eF6r04SkiUzBNNNLVepep5RGxC2VT0DcGUDQlmumiKypq+Pv+Hf/PHz/zToOT3nCTaaGoLTd+KcfdwInSNR7nCxiimC0x93hRPRcEkGiYzfexWAtkSr5kU8aNkES/CGHPFjSEOceSRl5ro7CjRXtCA8ZNecZh1KSGhuJxucqn+LItmXS0ay74/1q4annXMyuYt24ZzBktFqsy95R3Fro0a8s6dLqtl+hmQdCPXZCOOZ1YNsmft+adPWFbBy1UzRjgI51Q6sC+0nuaXSMjbBnGkSQeOIi31Um3ZnEZrL5PGAqOkFwYk3evpp3XXcKVJ93aXB5LMc8567/LW06e4TMPTQPWNKMo0oFoGeEoa4KfFq6CzDcHFC7XR+b8=</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2020-09-28T20:48:15.706Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.3.9 Chrome/83.0.4103.119 Electron/9.0.5 Safari/537.36" etag="TKZcQ3HFYxFyng5CRLCS" version="13.3.9" type="device"><diagram id="8GGXfNGBiCa5pNf0hmE1" name="Page-1">3Zpbc5s4FMc/jR+9gxAQ+zG202Zm006mmulunjIqKKBWRqyQb/n0K4EwYOHUzQ2cFwcdXTj66egvOGQE58vtZ4Gz5AuPCBu5TrQdwcXIdSfBRP1qw640+I5XGmJBo9IEagOij8QYHWNd0YjkrYaScyZp1jaGPE1JKFs2LATftJs9cNa+a4ZjYhlQiJlt/YdGMjHWwPfqimtC48Tc2oUwKGuWuGptppInOOKbhglejeBccC7Lq+V2TpiGV4Ep+306Urv3TJBUntJhu1k8TuU9unZCuvauxjeTCzQ2zq4xW5kZG2flrkIg+CqNiB7EGcHZJqGSoAyHunaj1lzZErlkqgTUZYTzpGhbFW6xlESkhcVViw9n5o5ESLI9OhWwB6Qii/AlkWKnmpgOcGKYmqhyfb8sbxpr5Js2SWN5QLUY2MRFvB+7JqcuDLw/AOl/CJDAfU+Q/NtF4uzuI+FHX++u78cEgE9j+KcguZAJj3mK2Q3nmSH2k0i5M3KCV5K34R7BpG7CVyIkT3hXaRAWMZFPtDNOk6glL/Y6CMKwpOu22rw6U2AxnVtQ1TBKVMnvIxPnWam0D3SrF+E4TSs0j8ah6x1s6Cq8GnEIO8IQvlUUnrCd9doiU0x5qsn1GJjuiYHpDSowLz4q5qAvzJ2HE3gaa03wqrbOwpVY70+gFyMnWyr/Nd319V3Dvtg2Kha7qpCqqRdd/vLVQ5Ux3DVr645FqdXzlgiq6BFhjJ0L8mpB0I39pYtedL0UAu8aDTJOU5k3Rr7VhoaWTqdtLfWCgwAqR6zDae/a8zeya21kBOyY6/OIgUM7YqpXnPMRv+BE8ZsO6owBdmx+EM4ADAq0/S6J4LA0wHP8lgZAp28NsJ/MkegIz16heW1obtAztKnFbJ4OnNn+8Okt0LxzE0HvVBGEgxJBcEJG7UxB+4MCbQc0GpoIHJw24KJvEbCzGvN0YI/pXnDwmA76hmYnJJEYODQA3w9a95uvHWiM6vkdYlMTlAd8GI11ljtUzfXL+0xjoCFml6ZiSaOoSFAIktNH/KMYSqumeTFW4/qzkb/QYymZzEvFrDXyRQlzMD18i7QT5l358jf77tB1rgdMM43ousU6+G+lPzXNNPKxoXypWjDyIOtadRWbv8UoeYbTyobEPVUdytHwUge2aev8/V39ICIUXO1x1VtNqTlAw1x417a+vsPz4w7PeSoFZ2xQ/qKj7qINlWHyDFc/2H4DHVmbva254fy32nB2yvobyZgChohOwtknw7kh9+EhclviJu8pcZOnidtPfedOvOtz9rsS70hLXIaSpnF5M/WjZcoozg9RqY2mKxTqXD3XuM6XBbKbPHCtt7/IrgQkqaQ8LQY+8zW0vmBOO4QKvI5QqWL9byNlBr/+5xt49T8=</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2020-07-13T12:16:18.319Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.3.9 Chrome/83.0.4103.119 Electron/9.0.5 Safari/537.36" etag="OlvApSiW3w7wMzPwl4Qs" version="13.3.9" type="device"><diagram id="r-GLMkCP-4nqHRol76c5" name="Page-1">5Vtbd+I2EP41nLN9SI4t3+AxQHa323DSQhs2+5KjYAU7MZYri0D211e2ZXyRSGjAyGFfEmtkWdL3zYxGI9ExBov1FwIjb4RdFHSA5q47xrADQNfusr+J4CUTWJqZCebEdzORXggm/k/EhRqXLn0XxZUXKcYB9aOqcIbDEM1oRQYJwavqaw84qPYawTkSBJMZDETp1Hepx6W2ZRYVX5E/93jXwDDsrGYB87f5VGIPunhVEhmXHWNAMKbZ02I9QEECXg5M1u7zltrNyAgK6S4N0OUZsoK7Qf+m5wR33+DkyrbPnOwrzzBY8hnzwdKXHALkMkR4ERPq4TkOYXBZSPsEL0MXJd1orFS8c4VxxIQ6Ez4iSl84vXBJMRN5dBHwWgZNlNQEfvjEitkQkn63TpWLYrwkM/7W1Y/r/uNfN7O18/zHD8O6+0y+gbNcZyCZI/oKDvaGEKbJCC8QJS+sHUEBpP5zdRyQ69R8816BOnvgwMtJeG2QJRKG44uRQEQBc4LZyvMpmkQwnf6KGV8V0q2QPSNC0bokEme9zm2Vay63Xd3k5VVhCQ4XeSUbsLT9cdpOUgWnC9clKI47wA5Y5/17wp7mydOI4cG8Apx56BA4CqBJoN2Ko6m3DEdgnLjVgx2tPpu3KrMHAgt/IhL7MU3mC7QJxeQgyrufE3DaprzW6SjvK0q5i/aaR9LeV4dZ4uFLgO9h0hDmbplFQZFy/1tX4U1wqUyFTQG66/vHJHxVDZVt16ACIlSmBCqjKahEYx8hCl1IYeIhEWGzVQ6a2auC5oiY6bYENKcp0Lon7iF7OzpIXZPzdhwH2RNYOFRUv5+2WlVtNVV7w7z/ElBj6PprJvqbIBYBacn3gfYVxl7K+j2DTgj4b3DCaVKj/c7wXCvH2dDexlnXjwr0qfsFfdfdvu6odAxA3O//ojwApQ5aF3loZgO2X/QKWuavgeivh1k81g/w7ClWjphdR8yx1CJmnLzBOzsavKHW4MVs9/Tiigmu8Fy51pp1re1J4oWuRG1BY2orGnpq4Uy0ybu2DDRLkp06Kma6mBUZtmuzalYRMySIHXe3CkSrvF6FLYDKqUXwypMhQAzgc62qb4faYqCO+TaGMm1rDkNxWy44NY3AcK4+8uvuoH8y59YYdobo3K4jRNjKjUPlaNVPK5UvBeYJna3L1YGnsd+M+sxjna7Le++qgB2tffo9aX5u8dJtqWa45l9OCy95IWTz/V4u3BZfSIpFs7SUt2sDxUAlxYZ4oNKKXGst1Qq0HWMt02rKFl65QqENWnFbAhhWDTRwLu7fZZ7cbMyTbw3qD3DB5AGHNPdFqTFTgp82l80OBapWA9WWaKIsGd2cJvb28sr6O73yxsMWTvW24lPlHtaFsbfp94D+NVfZli+h1n6Ry3vJypfQ0gJaLKf/bwl13lpD1TOsdAW1LKUMn4PmoyTlDOtqGXbUMlwmWDtNgi2V/OajLAUpg8BPT7LaFQXrhuqMoyWex4z18ySc81CaCfIf2B9+ycgPizhvICba0lcpWaKUaLokYiaEIUeroMLAn4fsecYQRIQJEnz9GQwueMXCd93MAFHs/0xvPGQ6HmE/pCkeVr9jDZNvMZuLM/M7VLBYixV7Yvgt5au5S2DifeUxSPhCQYzqtBV3DyVklbj86CTVTj5k93J166gsiXvLMduXa2ME3cKcPo2Ho4ucqwjHsc9w++3D06HnZ7z5sUqus2U6esdMP1riYcHYOC/4KOzkgeAF+zcaTj4+DfnvzTgNXYlRyI7+m2NBPG6YJkuNDRfJQhvex1E6c22Cwiory4hZTLaq/LtEcXIhhQVXJ0KTYVRokmQjpCdrjdFkixmeKZDRNCV+SsrwtL0ZqHkziR1tkpnHIUgMAaZMpP2TW8mJrOrvTNO9A3dWLH57mtaVfsFrXP4H</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2020-12-08T13:27:41.934Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.7.9 Chrome/85.0.4183.121 Electron/10.1.3 Safari/537.36" etag="KoO-qbn_-D3-EQ4XmbZC" version="13.7.9" type="device"><diagram id="4YhgUniWrUZ7E-1l1Vit" name="Page-1">zZddb5swFIZ/TS4rgQ0GbpOmqbZmmZptVXczGXwMJAYjx/narx8Uk49CpF5koTcIv+fY4PexfWCAR9luomiRTCUDMUAW2w3w/QAhn/jltRL2teBaTi3EKmW1ZB+FefoXjGgZdZ0yWJ0laimFTotzMZJ5DpE+06hScnuexqU4f2pBY2gJ84iKtvqSMp0YlbjOMfAIaZyYRyOMSR3JaJNtprJKKJPbEwmPB3ikpNT1XbYbgajMa4yp+z1ciB7eTEGuP9JhY3Nrki+yh18MZsNM3I8FuzOjbKhYmxk/yWhZKlOal1NT5tX1vjFEyXXOoBrSHuDhNkk1zAsaVdFtuQJKLdGZMGEucz03fav2Siu5PBiJqoxUiJEUUr2NjhkFn0eHzJMIiXwIeRlpT7uZAygNuxPJ2DABmYFW+zLFRHGzusyitJv29og4MFJyAtc1GjWLKj6MfLS9vDHOd1P4OZ140/DPbMmQxDtJFl+Xrx0URjJfQb5ar3pDwTlHUScKRkLikv+EgvSMArVQTEFTRjXtj4QfQTeJ0Hed0omrkHCsT0bCbqOYhYvqkEfWk5TLdXHrw8kFnzldHHwUYnKlHdHi0PvhhC9zeH65MQOwSwpeF4OAeJhei0Hw2faC01Gn4x5rA5ALtcELQutaJ9J7CjfcCZMNupMesYZh8APzx/zb7y+6q0zTKEnz+Nb2U+bR7oLgkOoLu7G/5XUHkQ+XZtS3/e168F0BB90HgtBmjFtdCGzLwwFcB8H7WtA7gnYpeIZCpBHVqcxvfghx7vtdCDDBAWZXQhDcDEHZPP4NvsVO/qnx+B8=</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2020-09-16T06:09:40.477Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.3.9 Chrome/83.0.4103.119 Electron/9.0.5 Safari/537.36" etag="sHnkidTp7u9zcfN8KY9n" version="13.3.9" type="device"><diagram id="8rHOqhjRuTpRrdjDaB_H" name="Page-1">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</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2020-11-10T11:26:58.592Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.3.9 Chrome/83.0.4103.119 Electron/9.0.5 Safari/537.36" etag="5mwQfGYF1CKKsFuXNXSz" version="13.3.9" type="device"><diagram id="dVNmU7IUbBy7O8nTNUCA" name="Page-1">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</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2020-11-10T12:12:02.743Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.3.9 Chrome/83.0.4103.119 Electron/9.0.5 Safari/537.36" etag="MSxRI1TswsuzONQAmqj_" version="13.3.9" type="device"><diagram id="dVNmU7IUbBy7O8nTNUCA" name="Page-1">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</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2020-11-10T12:28:00.841Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.3.9 Chrome/83.0.4103.119 Electron/9.0.5 Safari/537.36" etag="mZ2-PKVfA8hHRWFk_i7n" version="13.3.9" type="device"><diagram id="dVNmU7IUbBy7O8nTNUCA" name="Page-1">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</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2021-04-08T09:27:52.622Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.7.9 Chrome/85.0.4183.121 Electron/10.1.3 Safari/537.36" etag="F6-fK2rqGVaaWcVVMznQ" version="13.7.9" type="device"><diagram id="cKZVD0N--tm-yNMOju0u" name="Page-1">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</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2021-03-22T10:04:16.542Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.7.9 Chrome/85.0.4183.121 Electron/10.1.3 Safari/537.36" etag="z3SqxcdW-6z8LWrPNrLO" version="13.7.9" type="device"><diagram id="IuXuGYwBe3Z0u9ugAnWq" name="Page-1">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</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2020-11-19T06:26:40.615Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.7.9 Chrome/85.0.4183.121 Electron/10.1.3 Safari/537.36" etag="O00LtyC3OWsXNsGhaXB5" version="13.7.9" type="device"><diagram id="CfVtspSyxuViD4zbiw-o" name="Page-1">7Zxbd5s4EMc/jR/bA0iAefQlbrsnabvx2UufeohRbHYx8spyYu+nrzDiJuHgXEDixH5o0SAQ/GcYNL9YHoDJev+J+JvVDQ5QNLCMYD8A04Fl2Z7H/k0Mh9QA4DA1LEkYpCazMMzD/xE3Gty6CwO0rXSkGEc03FSNCxzHaEErNp8Q/Fjtdo+j6qgbf4kkw3zhR7L1rzCgK251bFjs+IzC5YoPbQHgpHvWftab38p25Qf4sWQCVwMwIRjTdGu9n6AoES8TJj1udmJvfmUExfScA8jDGH27/m14/cX8SSe/z/eT28UHfpYHP9rxO+YXSw+ZBATv4gAlJzEGYPy4Cimab/xFsveR+ZzZVnQdsZbJNreU4H9zqdg9jvkAiFC0P3nlZq4HCySE14iSA+uSHWBzCXkQmVl0PBYuySNmVfKGx20+j4JlfupCJ7bBpXqGbFaNbE7ERh3fY3ZPZf2c/3Y42/FhewzwEetg2pt9sZNtLZP//9gisj2KaxmjzSYKFz4NcbzNzs4uNh0g7S75imlMqw7xo3AZs+0F0xoRZkg8wU4bjfiOdRgEyeFjgtjV+XfHUyWe3uAwpkfh7PHAnibn2lGc3kGLvvaafW26Nb622vI1aPL1AkeYVHw9sMD9PWAf2cOfv0+/zdlB1+Ed8ZOrO8+xGjyEjuAYu8YxVo1jYFuOgX3MXZahOnfZLeWuJKxn2anuSB7whw0iD+EWk/eTxCxXcHrNs+J1+ag4reSwOcUkmT+xrd3d9kDRur/pzKp7z3SazrIpZUkmFLDJKG9iQld4iWM/uiqs46qQRZ9rjDdcvn8QpQc+s06Cvypu4qZJ7nwwmx1dntqzoY1aJ6A4GCUzbNaMcYxSyyxMbvp4BHMEOfydND7aWfMHH/XYmO7LPacH3kpVSG79adcypfCOLNATkrppP+qTJaJPTedOxApBEZt/PVQvpM7x/NDvSbYpYsy2qjEGgRA76YXxo4rwYbL6h1I3nsROjmPZdnUcKFQCQn/oPdmfbaRXUMRyrsnLw9vt5dvaO/NtbbY2/fQk3aa3oxsdtRMyKqiZ6dhdJtTMTyXpvv551G42n7xSwVNps53phNmsbKfTCVPGBvP5VMOYzJXSJiZlcjBf+4R+/TLpUUBKj7ojy+p0KqtcpN9Ob0Y9ktSymiXtNlLl8vrVQdpJsaVeuboKWzvZwBmgrVswYTZWqReq+kJn55WHNlTVrKsH3iFWhcIMRT1WNYd9TF/quaopV2oXsPrGXreFSkg5WM2ezAtZPZnRNCCrtiRTB2S1iY/K4p8qODQgqfmXL5pQKoD1wfFKlDoEw0pQQXFi8kYotQGNSv1dqAClWjJ+0TAPSG9o9Sw100l/mComUeXgypIJSz9hKrSble12CiGDFj1hqg11i0kZtPQQpkqPumqYaskcpmcwFZ7Bp7uNVJl26AlTxQJLvXK9oBGOkBrVw1SrLRpxganOUDeYmtHd9w5THfGL4sphKuhFqSamL/UwFciV2gWmvrHXXfErkKphKmjnq/Z9hqliRtMApjqSTF3A1H1ISwSUtX6U9hT8M2lk+PPtAGx6x28CUgGv9htBKnTrA+N5IPW5/HOYVSpn8k8WewoAKJCRiY7PrvhWVQ9AgUxMNAWgYuJTDpuATEX6CUDdM9Byt699GY7oCUBdT7eYlOFIDwGo9KirBqBAZic9A6CubhgvO7H2AFQsitQr1wuC4Gm3RB+2RRAuANTTbo0+vCzSTz2j3yL9XpRqYvpSD0DhZZl++781Yui2Th9eFuo3pTT1BBT2YimzlNLU0ycol6ua0icx6JRX+lAuSftJn0xDt8XMmR+1x09smq1ZVNo168D7x5+kh101f7Ll0rVn/Mk0dFvObNd8f1lLACVNStVL97KlmsbxUzYZ2+z3PTObKc9Z89LkrBLHrStxPpY/pZnunTiGViXO0398flVMDc+YzgxrQuoFM0HWLH7SNP17b/HDsODqFw==</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2020-09-16T06:11:17.184Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.3.9 Chrome/83.0.4103.119 Electron/9.0.5 Safari/537.36" etag="f9ipW_CZiGYg0OEGnKjk" version="13.3.9" type="device"><diagram id="e-1_SHGDbpEBjFpH4OKP" name="Page-1">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</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2020-09-16T06:12:27.163Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.3.9 Chrome/83.0.4103.119 Electron/9.0.5 Safari/537.36" etag="DHxOYV-_3pm9laraLwHY" version="13.3.9" type="device"><diagram id="e-1_SHGDbpEBjFpH4OKP" name="Page-1">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</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2020-12-08T20:31:30.042Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.7.9 Chrome/85.0.4183.121 Electron/10.1.3 Safari/537.36" etag="czag8t72b1-XHVAcCK5B" version="13.7.9" type="device"><diagram id="dVNmU7IUbBy7O8nTNUCA" name="Page-1">3VvbcqM4EP0aV+0+OCWuNo+OPc7M1jibGk/t7D4qRsGaBeQRIrHz9SOBuBiRhKRswLzEqCWE1Kf7qNVSRsY82N9QuNuuiIv8kQ7c/chYjHR9ak/5XyE4pAILmKnAo9hNRVohWONnJIVASmPsouioISPEZ3h3LNyQMEQbdiSDlJKn42YPxD/+6g56SBGsN9BXpT+wy7ZSaltmUfEZYW8rP60bhp3WBDBrLacSbaFLnkoi49PImFNCWPoU7OfIF8rLFJO+t3yhNh8ZRSFr8sK1fbv7fh0sFs/EAzeLv2Lv/nlsTq20n0fox3LOcrjskCkBuVwnshiSkP9cUxKHLhI9A14ilG2JR0LofyVkx4UaF/5EjB0kojBmhIu2LPBlrTp6OaGIxHSDXh2yIw0BUg+xV1pawEhbigmUPiL1c4NIgBg98AYU+ZDhx2PQobQdL29XaJc/SAW/S9l2N8pGe8z+5c9jcAUMQwr+E/1dTfLyYi8/kBQOpcIdophrAFEp+zh2lj5piJ3pOD3DbjJcRzEdq2fKnnbrKODKsqYlP9Fa9JH3wKb1CjZLN7uBLeKqYjOx3BedJrIlFjNIQQrdrMXGh1GEN6lQNhHdPJCQzYlPaDJSY7k0jIQdW1mr9H6tVZbekQsOAstJr7DMR17C8ivZ/I9DT4GUoT07BgT62AuFprnGBL1dPyLKMA+RZ7IiwK7rJ9ijCD/D+6QrAdOO4JAlk7GuR9ZC9MXhjlLkM5Ay+6mJZ6VIfA/tX9Vjtt1wnCu5ksn9hqZb0myfivDdlhH5thy4g3M5kgEG6UjFUqkLSIqQ8jxLZez82v4EM7q3vVU4v0Hf79iXsdHYIU8eTMpX74SJFwY40fRj8zOsil2lc5KvFabFUYCHUjPpOlXjy0fayB5rddZgiT5RzFpR9gl3DC8bQ3fLZd32wPYFl0Y7GB4p2P4Vi01/4lrjJ0lCM94kJDSAftGAP3niV5D1A0VoJFgq7fSeZpURI1RkMWQFH376wbR2YASvV+k94+036N04G73r6tr6fuBNAFTUZ9EhuP1ndQHAfiDcao75BFQw18ypgvmk1SVd7yiP09vYON+9NFiK+5VqyEd+FuJeBxyc2y9zYZkw5L7mXoA3n4CmAajQtKPStKa167N1ie5T4Yzv8O4SVmDBQYx7FRGdjs9M3IoVGIZqBWabRmA6He3FPs6seY6vQTZQ7xWz5iMvKfvGJ/fCf4DPI9raaPYJc8sQ53lURLse1/yu8zTFCXzB0auMmB28vcWIZ4tcc3sp4bPkhrFmie67Jq0zkZIGquFkHSu1miEynboQpOesZDVmpZ7lQp2OzijaUbbdM2WrQde3xUpEUpCRgG9NdPDtx+WT+7RK7jVJ53bD3dwSSprP8wlDpXbNAEr631bJvdVcQc5/JSA+H3aI+oI4BgsFsFUoalJ1LUPR1a2CkA9fXiuYGplAHJaICzlWJihOTJLSoVw64fWC7GJNg+tT4NSrSf2piaY5luq4+nE36XCVg5MPHIu8rpaScawRVzBk9Wn3eRIlLzmhrhIkMI0ufiGznepCpnW9S8mNsITLHfEhXa4Hy54TreoMk463KBZQ9/KtUOfHeS6//NmA53qWkgbqxnxAyjZ7pmx1831LZIZqEJknU+H0juOw3ATqE0/gjyUnVR24kME/B8vxU1u5qqTZ6rmmpreLjLpf/5uK04KhwqABDbyNwrkOKV671HT6+wSr2Gd4zHUTJYhWA9oF97eI0XjDYo6QWn8Bx1v14NeYyMuhl101h6nKls5pAmBeLP77J93HFP9DZXz6DQ==</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2020-12-08T21:01:36.322Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.7.9 Chrome/85.0.4183.121 Electron/10.1.3 Safari/537.36" etag="DsHvjmpYlMJra_hXTmvD" version="13.7.9" type="device"><diagram id="dVNmU7IUbBy7O8nTNUCA" name="Page-1">7Vpdc6IwFP01PrZDREAfrUq3s1rtuNNu9y2FFGghcUOs0l+/iYQKBqudVVF3+2CTm5DknnO/iNb0TjS/pnDiD4iLwlpdc+c1vVur15tmk38KQZIKDK2RCjwauKkILAXj4B1JoSal08BFcWEiIyRkwaQodAjGyGEFGaSUzIrTnklY3HUCPaQIxg4MVelD4DJfSk2jsRz4hgLPl1vXdd1MRyKYzZaqxD50ySwn0ns1vUMJYWkrmndQKMDLgEmfs9eMfpyMIsy2eeBm1uvNfjxqPpgNbhvY790/3FyAerrMGwynUmV5WpZkGCCXQyK7mGD+74qSKXaRWFjjPUKZTzyCYdgnZMKFgAtfEGOJJBROGeEin0WhHFUPL/WJyZQ66JMTt6QVQOoh9plmckFx+twOEptrRCLEaMInUBRCFrwVCYfSbryPeUtkeUOC+xWgzbMF2jgqoPWKLJrjS5Of4vlLTdMzweNCYGXd7lxukPaSfG+EaMAhQFQK98+cXpmL2KM+Ms3mXX/0Mnygv+w4GXYujM3E7cgdVhTeGcqlajWq9IaWgukAMehCBhVsGZqzIlgwDDzM2w7HRpjl1RuiLODJsS0HosB1w4X3oDh4h0+LpQQzExJgttDFuKoZXbEWpyJOWRFLPxPMMg9cz4HYD80/Nc2s0MgScpLVD5ZUfbZM25bMxH4+YWv7ikONUwv4WTjYHDf044r4QEF67HP9XS4jmH/YlFtbTTBthsLEnyhveaIFsZh0BZ1XJFpVesQOnKCla5dG0Q1AVm/n3ABoJX6g780PdIWddpxEt/eD6iNQh4SELvbWbVvnf7vhAWglRDSa1cYj0Dy1eJQVlpsrUOuo4hFQC5lBMr7ri+dwzCB2+BvtyccazVg1ca2uplwADmrjloL8iISQ2uMzjjVAJSIL8DkizIPycHK1D9i29gHHVfuAktoHcQAgQ1w66ArdEeXmdPIBx2pqW4Sb+kHNXC1thjQQJeeZBpumZhU4aLXUQNPYEwOl79ZqvD9gnPnqLcL624EtbhHMA0WZ0s3VW4RzhblZJczVXsYfFGdQ6U1jWXmSXg3EE4gLgJu/p+ILmkVUvZjJmNbmUzChEQyXE7Irhe9I6NHDDhGcyGX5KdOV0znVJ4iVuzclBZSwv31m/sjCubTQOmRaKPuuZVf82txAx4xQdALcbioG/o5201qh3VCvOPb12rE+eO+J9m57OP7nGddWGS9xdOOQjJe8/uyO8mvkvBL7P+vGCut7/GqFd5c/iFiM5X5Wovf+AA==</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2020-12-08T21:18:22.294Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.7.9 Chrome/85.0.4183.121 Electron/10.1.3 Safari/537.36" etag="nkZmbwmSw-UYJwW9k87P" version="13.7.9" type="device"><diagram name="Page-1" id="d9b1e647-80fa-b4a2-5024-87a742678bcc">3Zddk5owFIZ/DZc7EwIoXiqr215sd6a208tOgAiZhYSNwY/++p5A+HCVrp2p2tGL3eQ9h0N4nxODlhPkuydJivRZxDSzMIp3lvNoYeyPfPirhX0teMithUSyuJbsTliyX9SIyKgli+n6IFEJkSlWHIqR4JxG6kAjUortYdpKZId3LUhCj4RlRLJj9QeLVWpUG6Eu8ImyJDW39j0TCEn0mkhRcnM/Czur6lOHc9LUMvnrlMRi25OcueUEUghVj/JdQDNtbWNbfd1iINquW1KuzrnAG6/oiIQ0Qv4KuVH4YCpsSFbS5hFGGdSarQvC9YrV3rg0eiv1MmcrwdXDumI4hQTbL3ZdEEaJ/r8ETEzoAnZTEFZV16wzjCFteQzeFHq4VrSA+DZlii4LEmltC20HWqryDGa2WYVpJOzrOcuyQGRCVsUchHy0WJi8nr6oPvrxlBSvtIlwwWm7pr6djT9UKrrrScbeJypyquQeUkzUNaTNTrB9M992fdV2Q9pvKaMR08pJW7nDCQND9Ey6eJCutuVf0MU9unXN69Ade3P/BnTPwWuPr4XXuThe50Z4R+MguAFeZ/I/4XUvjte9FV4cuDfA691y985eePx1+5Lk/Ge6/j5P7M948ofjN2xYPAvFNsQAI/CioU8PkyM7pKosejDDQZJglTqkRTKWcBhHYCwFw2faUAYvR1MTyFkc68tnkkJrkbAqhWBeCMZVZYk3s7xHXatUom6/qvQAoBMYB5m925F45B0jQyeQOZdCNnymtqYvS7mh+hnE6iStbzRKOXsr4ZX3HpHh8cfM/GsiGz4nW9On8YbwSANBjA8Qg++jhHXMuuhdUnSx9yHFyTUpDh+HrelftMcYLeGUus+t5fnvoIyPT7BTWwv/PRSYdr9Lq1jvt78z/w0=</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2020-12-09T13:48:53.748Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.7.9 Chrome/85.0.4183.121 Electron/10.1.3 Safari/537.36" etag="BRnmFCJ5CmXEJeWs-28N" version="13.7.9" type="device"><diagram id="dVNmU7IUbBy7O8nTNUCA" name="Page-1">7Vvfd6I4FP5rfKwnIfzyUa125px1tqedM7Mzb6mkwk4k3RCrzl+/QYICoS5tAamuD625CSHc78vNzUfsofFyc8Pxkz9jHqE9A3ibHrruGYZru/JvbNgmBguYiWHBAy8xwYPhPvhNlBEo6yrwSJRrKBijInjKG+csDMlc5GyYc7bON3tkNH/XJ7wgmuF+jqlu/R54wldW2zIPFZ9IsPDVrQ2E7KRmidPW6lEiH3tsnTGhSQ+NOWMi+bbcjAmNnZc6Jrlu+kLtfmSchKLKBZ/Xk8n66w/gw/Xsixn6k2/fP19BoAB6xnSlnlkNV2xTJxBP+kQVQxbKfyPOVqFH4p6BLDEufLZgIaZ/MPYkjVAa/yZCbBWieCWYNPliSVUt2QTir/jyvgnT8o+4rm+o0vVG9b4rbDOFW8KDJRGEK5vuCeWciK34XD3EbAYff/2Mwq/znwGeSL4uJ+GVMVCcwnxBxFE/OUnL2BeZeyhX3xAmB8S3sgEnFIvgOc8frGi42LfbX3rLAjlqA6gZY6bMVxNmYLn5LpJnUlcd4JZfMsM4mHYkeA0h0vufjhAIDDKEuAJ9aLVICQQrU2LQEiUGBUogUIkSQ87xNtPsKW4QvZM05dPoNJR5ZKEYM8r47hZoOkXyI+2RxE4M4+gvK+YUR1EwT83TgO4ZF3ppIzUiaVH1O16F0isJJaHtpAbFSWClhgMpd6VttvQmWr7ANkvnZTmBrbppmaPLq7kBT0OOmkjwEscy5DAdVCAHPDSpnR3lTgZVydFSzLLMfMxyizErGWkdy1j5c55oFWuYda1kOt2KH+hEi0tnkXxFgnIyJI+PJwPlHQ7l2AwwwpEEKw5jNpXPNHrg8tsi/jb0PE6k88OFBrsgG5EHDdNgEcZ4Sa/GYXX0TLgI5HZuqCqWgefRHT9IFPzGD7uuYpxUciT7tUY96zruS1IiStiRJhspx8CL6MX3I5ujzk4jJDT6Vj6vM1FSXh92mmnq52f2mMVQWt9U05fq622Il5L4BlBInRMEplsAIN37ZACAoAQBoykE0iidQeBeyKl5rgCYBQBcHQC3Vf/racMw2i6/fJt1yfFvWFWqY2KDYlxybR0Vp01UTiRRdTYDgCUZQHnDutf/8mTfQajvZj6D/KR2UL7D+hSsYw+dYcutBCwQAQt3SQTAYZxpdDGvKNF0X59XFBY1CIySVa3VqJpK4mc2gTMSgJVo2KkEAPr7Yjv7f1RVHGopItiWltwWo0DTAsB5LhoZztl5TRI2KUmWu9ipSDqjdtHpXeHI/F8bKhcFP5q0jHQ9YUTZ/Jc0PSR6QlcW9loEA9cpxtTBibdLSN+u3lD2gCmNx70Kg3+k+XIUneJ7uqpyQnOCjqPh8yeXeXCX/N7oZlYX2SCAuspmNjRpjr83zqAiwzuZ3Z0eloZgMN38zHAdfWZY7WKgz4xbRjGf3p8vCEYehNKNod3m8gH19fuyEzFoVkzEYO37uPcBqc+mCwfS/qBA6kvThQPpfkwgjfOU3N4OpFFZIesYkOepY70DyKqqU8eATIeTAfITjvze4exD/jXFqbPQOnfGtqufdXC13BM2tQ07yqPce6Io7bkjrm90Q+CC/5aTmtqVHY3RGUjGPuOd0vGaRcQpKEiWrlW0igjUV5+74WxM2epyQHGKp4SAPk1aPQ4B9dxud0yLXQ4kxdPFJSdU2lUyTA2SqUwqIsF4p45sNXtyaFA4N1SyntSEiiwefjiXvDI+/PwQTf4F</diagram></mxfile>
\ No newline at end of file
<mxfile host="Electron" modified="2020-10-11T20:59:59.121Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.3.9 Chrome/83.0.4103.119 Electron/9.0.5 Safari/537.36" etag="_eW5q41AEVBIWzWX6GP9" version="13.3.9" type="device"><diagram id="dVNmU7IUbBy7O8nTNUCA" name="Page-1">5ZfRbpswFIafhstNgANJL5vQtJrablKqrbt04BQ8GQ4yJoE8/QwYAkWNOm0LUpoLgv9jH+P/MxwwyCoubgVNowcMgBu2GRQG8QzbXpCZOlZC2QiOqYVQsKCRrKOwYQfQoqnVnAWQDTpKRC5ZOhR9TBLw5UCjQuB+2O0F+XDWlIYwEjY+5WP1BwtkpFXXmR0Dd8DCSE9tE+I2kZi2vfVSsogGuO9J5MYgK4Eom7O4WAGvzGuNacat34h2VyYgke8ZsHQf06dl7HkHDM1b70sebg+fbNNp8uwoz/Wa9eXKsjUBAuWJbiaYqL+lwDwJoMpsqhYKGWGICeX3iKkSLSX+AilLTZTmEpUUyZjraDNJlfnN5Wgpw1z4cHINV3pnUBGCPNXTIp3xascCxiBFqUYK4FSy3fBaqN47Ydfv6K460Qb/kdnuhzLbntbs+Ycy25rW7MVZvFUOivK5Gv95tiCt8LMWurhX6AmaVtlvfQPB1JJBaHEiWOa0sK5Gd8Y9hkrY0kzRsc0nQZOM+pJhko24SijkkArlLEzUua88q5xd7kBIporotQ7ELAh4vQEgYwe6rVNV9qfIElmvz1kajlflUsyzBn+V+gUT2W4i7UeVHIrTuMbWFu37h653+n3EIm153vfKu6O1qF/Zzf+Fo33X6eFYq32wkShgevdXyFHUc5P1mqhfd9f8FYhZ63EHwhmDcM/LwRpxuM7K+PH7w8VScKzXFOZjCvPzUrBHFO7KFASvasTFcli8fixNz4GMOHwVqiBcLAPXfccTafZvGKjm8cOvjvU+n8nNbw==</diagram></mxfile>
\ No newline at end of file
Makefile
epserver
epwget
log_*
####
DPDK
#####
COMPILE
vim dpdk/config/common_linuxapp
#@rinku ADD FOLL
CONFIG_RTE_LIBRTE_MLX5_PMD=y
In case of numa.h not found error
sudo apt-get install libnuma-dev
RUN
ubuntu@linux:~/dpdk-stable-19.11.8/arm64-bluefield-linuxapp-gcc/build/app/test-pmd$
sudo ./testpmd -w 03:00.1 -- -i -a
OR
sudo ./testpmd -- -i -a
sudo ./testpmd -- --nb-cores=2 -i
testpmd> set fwd txonly
testpmd> port start 0
testpmd> port start 1
testpmd> set eth-peer 0 0c:42:a1:df:ac:41
testpmd> set eth-peer 1 0c:42:a1:df:ac:40
testpmd> start
testpmd> show port stats all
################
MTCP
IRON OUT CODE ISSUES
ubuntu@linux:~/dpdk-stable-19.11.8/arm64-bluefield-linuxapp-gcc/build/app/test-pmd$ sudo ./testpmd -w 03:00.1 -- -i -a
ubuntu@linux:~/mtcp-devel$ sudo ./setup_mtcp_dpdk_env.sh /home/ubuntu/dpdk-stable-19.11.8
export RTE_SDK=/home/ubuntu/dpdk-stable-19.11.8
export RTE_TARGET=arm64-bluefield-linuxapp-gcc
wget https://github.com/mtcp-stack/mtcp/archive/refs/heads/devel.zip
core.c: In function ‘mtcp_create_context’:
core.c:1332:4: error: ‘lcore_config’ undeclared (first use in this function)
1332 | lcore_config[master].ret = 0;
ubuntu@linux:~/mtcp-devel$ vim mtcp/src/core.c
if (master == whichCoreID(cpu)) {
//@rinku
//lcore_config[master].ret = 0;
//lcore_config[master].state = FINISHED;
/usr/include/aarch64-linux-gnu/bits/string_fortified.h:106:10: error: ‘__builtin_strncpy’ output may be truncated copying 1023 bytes from a string of length 1023 [-Werror=stringop-truncation]
106 | return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest));
ubuntu@linux:~/mtcp-devel$ vim mtcp/src/config.c
//@rinku
//strncpy(optstr, line, MAX_OPTLINE_LEN - 1);
memcpy(optstr, line, MAX_OPTLINE_LEN - 1);
ubuntu@linux:~/mtcp-devel$ vim mtcp/src/io_module.c
Comment the funct code for “probe_all_rte_devices” ; add return -1
COMPILE
export RTE_SDK=/home/ubuntu/dpdk-stable-19.11.8
export RTE_TARGET=arm64-bluefield-linuxapp-gcc
ubuntu@linux:~/mtcp-devel$ ./setup_mtcp_dpdk_env.sh [<path to $RTE_SDK>]
export RTE_SDK=/home/ubuntu/dpdk-stable-19.11.8
export RTE_TARGET=arm64-bluefield-linuxapp-gcc
ubuntu@linux:~/mtcp-devel$./configure --with-dpdk-lib=$RTE_SDK/$RTE_TARGET CFLAGS="-DMAX_CPUS=8" //Specify the max cpus which will run MTCP; use --disable-hwcsum when working in virtualized environment
ubuntu@linux:~/mtcp-devel$ make
configure: error: Could not find gmp.h
SOLUTION: sudo apt-get install libgmp-dev
Check the configurations in apps/example
epserver.conf for server-side configuration
epwget.conf for client-side configuration
Configure ~/mtcp-devel/apps/example/config/arp.conf
Configure ~/mtcp-devel/apps/example/config/route.conf
######
RUN THE MTCP APP
export RTE_SDK=/home/ubuntu/dpdk-stable-19.11.8
export RTE_TARGET=arm64-bluefield-linuxapp-gcc
sudo ./epserver -p /home/ubuntu/www -f epserver.conf
sudo ./epwget 192.168.220.35/example.txt 10000000 -N 8 -c 10000 -f epwget.conf
#######
REVERT BACK MTCP NIC CHANGES
./setup_linux_env.sh [<path to $RTE_SDK>]
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