Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@
/**
* Represents a runtime exception happens on distributed storage layer of LightChain.
*/
public class LightChainDistributedStorageException extends Exception{}
public class LightChainDistributedStorageException extends Exception {
public LightChainDistributedStorageException(String e) {
}
}
41 changes: 40 additions & 1 deletion src/main/java/model/lightchain/Identifier.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
import java.util.Arrays;

import io.ipfs.multibase.Multibase;
import org.jetbrains.annotations.NotNull;

/**
* Represents a 32-byte unique identifier for an entity. Normally is computed as the hash value of the entity.
*/
public class Identifier implements Serializable {
public class Identifier implements Serializable, Comparable<Identifier> {
public static final int Size = 32;
private final byte[] value;

Expand Down Expand Up @@ -78,4 +79,42 @@ public int comparedTo(Identifier other) {
int result = Arrays.compare(this.value, other.value);
return Integer.compare(result, 0);
}

/**
* Compares this object with the specified object for order. Returns a
* negative integer, zero, or a positive integer as this object is less
* than, equal to, or greater than the specified object.
*
* <p>The implementor must ensure {@link Integer#signum
* signum}{@code (x.compareTo(y)) == -signum(y.compareTo(x))} for
* all {@code x} and {@code y}. (This implies that {@code
* x.compareTo(y)} must throw an exception if and only if {@code
* y.compareTo(x)} throws an exception.)
*
* <p>The implementor must also ensure that the relation is transitive:
* {@code (x.compareTo(y) > 0 && y.compareTo(z) > 0)} implies
* {@code x.compareTo(z) > 0}.
*
* <p>Finally, the implementor must ensure that {@code
* x.compareTo(y)==0} implies that {@code signum(x.compareTo(z))
* == signum(y.compareTo(z))}, for all {@code z}.
*
* @param o the object to be compared.
* @return a negative integer, zero, or a positive integer as this object
* is less than, equal to, or greater than the specified object.
* @throws NullPointerException if the specified object is null
* @throws ClassCastException if the specified object's type prevents it
* from being compared to this object.
* @apiNote It is strongly recommended, but <i>not</i> strictly required that
* {@code (x.compareTo(y)==0) == (x.equals(y))}. Generally speaking, any
* class that implements the {@code Comparable} interface and violates
* this condition should clearly indicate this fact. The recommended
* language is "Note: this class has a natural ordering that is
* inconsistent with equals."
*/
@Override
public int compareTo(@NotNull Identifier o) {
int result = Arrays.compare(this.value, o.value);
return Integer.compare(result, 0);
}
}
11 changes: 11 additions & 0 deletions src/main/java/network/NetworkAdapter.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package network;

import java.util.ArrayList;

import model.Entity;
import model.exceptions.LightChainDistributedStorageException;
import model.exceptions.LightChainNetworkingException;
Expand Down Expand Up @@ -38,4 +40,13 @@ public interface NetworkAdapter {
* @throws LightChainDistributedStorageException any unhappy path taken on retrieving the Entity.
*/
Entity get(Identifier identifier, String namespace) throws LightChainDistributedStorageException;

/**
* Retrieves all entities stored on the underlying DHT of nodes that stored on this channel.
*
* @param namespace the namespace on which this query is resolved.
* @return list of all entities stored on this channel from underlying DHT.
* @throws LightChainDistributedStorageException any unhappy path taken on retrieving the Entities.
*/
ArrayList<Entity> allEntities(String namespace) throws LightChainDistributedStorageException;
}
5 changes: 3 additions & 2 deletions src/test/java/networking/MockConduit.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public void unicast(Entity e, Identifier target) throws LightChainNetworkingExce
*/
@Override
public void put(Entity e) throws LightChainDistributedStorageException {
this.networkAdapter.put(e, channel);

}

Expand All @@ -66,12 +67,12 @@ public void put(Entity e) throws LightChainDistributedStorageException {
*/
@Override
public Entity get(Identifier identifier) throws LightChainDistributedStorageException {
return null;
return this.networkAdapter.get(identifier, channel);
}

@Override
public ArrayList<Entity> allEntities() throws LightChainDistributedStorageException {
return null;
return this.networkAdapter.allEntities(channel);
}

public boolean hasSent(Identifier entityId) {
Expand Down
128 changes: 124 additions & 4 deletions src/test/java/networking/stub/Hub.java
Original file line number Diff line number Diff line change
@@ -1,39 +1,133 @@
package networking.stub;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import model.Entity;
import model.exceptions.LightChainDistributedStorageException;
import model.lightchain.Identifier;
import network.Network;

/**
* Models the core communication part of the networking layer that allows stub network instances to talk to each other.
*/
public class Hub {
private final ReentrantReadWriteLock lock;
private final String channel1 = "test-network-channel-1";
private final String channel2 = "test-network-channel-2";
private final List<Identifier> identifierSet;
private final ConcurrentHashMap<Identifier, Network> networks;
private final ConcurrentHashMap<Identifier, ConcurrentHashMap<Identifier, Entity>> channelMap1;
private final ConcurrentHashMap<Identifier, ConcurrentHashMap<Identifier, Entity>> channelMap2;

/**
* Create a hub.
*/
public Hub() {
this.lock = new ReentrantReadWriteLock();
this.networks = new ConcurrentHashMap<>();
this.channelMap1 = new ConcurrentHashMap<>();
this.channelMap2 = new ConcurrentHashMap<>();
this.identifierSet = new ArrayList<>();
}

/**
* Registeration of a network to the Hub.
*
* @param identifier identifier of network.
* @param network to be registered.
* @param network to be registered.
*/
public void registerNetwork(Identifier identifier, Network network) {
networks.put(identifier, network);
networks.putIfAbsent(identifier, network);
channelMap1.putIfAbsent(identifier, new ConcurrentHashMap<>());
channelMap2.putIfAbsent(identifier, new ConcurrentHashMap<>());
identifierSet.add(identifier);
sortMaps();

}

/**
* Sort the identifier of networks.
*/
public void sortMaps() {
Collections.sort(identifierSet);
}

/**
* Put Entity to Node.
*
* @param e entitiy.
* @param namespace channel name.
*/
public void putEntityToChannel(Entity e, String namespace) throws LightChainDistributedStorageException {
try {
lock.writeLock().lock();
Identifier identifierOfNetwork = binarySearch(e.id());
if (namespace.equals(channel1)) {
channelMap1.get(identifierOfNetwork).put(e.id(), e);
} else if (namespace.equals(channel2)) {
channelMap2.get(identifierOfNetwork).put(e.id(), e);
} else {
throw new LightChainDistributedStorageException("entity could not be put the given channel");
}
} finally {
lock.writeLock().unlock();
}
}

/**
* Get entity from channel.
*
* @param identifier of entity.
* @param namespace channel name.
* @return entity.
*/
public Entity getEntityFromChannel(Identifier identifier, String namespace)
throws LightChainDistributedStorageException {
try {
lock.readLock().lock();
Identifier identifierOfNetwork = binarySearch(identifier);
if (namespace.equals(channel1)) {
return channelMap1.get(identifierOfNetwork).get(identifier);
} else if (namespace.equals(channel2)) {
return channelMap2.get(identifierOfNetwork).get(identifier);
} else {
throw new LightChainDistributedStorageException("could not get the entity");
}
} finally {
lock.readLock().unlock();
}
}

/**
* Get the identifier of the network that store the entity.
*
* @param identifier identifier of the entity to be stored.
* @return identifier of the network that store the entity.
*/
public Identifier binarySearch(Identifier identifier) {
int left = 0;
int right = identifierSet.size() - 1;
while (left + 1 < right) {
int mid = left + (right - left) / 2;
if (identifierSet.get(mid).compareTo(identifier) == 0) {
return identifierSet.get(mid);
}
if (identifier.compareTo(identifierSet.get(mid)) > 0) {
left = mid;
} else {
right = mid;
}
}
return identifierSet.get(left);
}

/**
* Transfer entity from to another network on the same channel.
*
* @param entity entity to be transferred.
* @param target identifier of target.
* @param entity entity to be transferred.
* @param target identifier of target.
* @param channel channel on which the entity is delivered to target.
*/
public void transferEntity(Entity entity, Identifier target, String channel) throws IllegalStateException {
Expand All @@ -54,4 +148,30 @@ public void transferEntity(Entity entity, Identifier target, String channel) thr
private StubNetwork getNetwork(Identifier identifier) {
return (StubNetwork) networks.get(identifier);
}

/**
* Retrieves all entities stored on the underlying DHT of nodes that stored on this channel.
*
* @param namespace the namespace on which this query is resolved.
* @return list of all entities stored on this channel from underlying DHT.
* @throws LightChainDistributedStorageException any unhappy path taken on retrieving the Entities.
*/
public ArrayList<Entity> getAllEntities(String namespace) throws LightChainDistributedStorageException {
ArrayList<Entity> allEntities = new ArrayList<>();
if (namespace.equals(channel1)) {
for (Identifier identifier : channelMap1.keySet()) {
List<Entity> entityList = new ArrayList<>(channelMap1.get(identifier).values());
allEntities.addAll(entityList);
}
return allEntities;
} else if (namespace.equals(channel2)) {
for (Identifier identifier : channelMap2.keySet()) {
List<Entity> entityList = new ArrayList<>(channelMap2.get(identifier).values());
allEntities.addAll(entityList);
}
return allEntities;
} else {
throw new LightChainDistributedStorageException("could not get the entities");
}
}
}
21 changes: 18 additions & 3 deletions src/test/java/networking/stub/StubNetwork.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package networking.stub;

import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;

import model.Entity;
Expand All @@ -17,6 +18,8 @@
* A mock implementation of networking layer as a test util.
*/
public class StubNetwork implements Network, NetworkAdapter {
private final String channel1 = "test-network-channel-1";
private final String channel2 = "test-network-channel-2";
private final ConcurrentHashMap<String, Engine> engines;
private final Hub hub;
private final Identifier identifier;
Expand Down Expand Up @@ -98,7 +101,6 @@ public void unicast(Entity e, Identifier target, String channel) throws LightCha
} catch (IllegalStateException ex) {
throw new LightChainNetworkingException("stub network could not transfer entity", ex);
}

}

/**
Expand All @@ -110,7 +112,7 @@ public void unicast(Entity e, Identifier target, String channel) throws LightCha
*/
@Override
public void put(Entity e, String namespace) throws LightChainDistributedStorageException {

this.hub.putEntityToChannel(e, namespace);
}

/**
Expand All @@ -124,6 +126,19 @@ public void put(Entity e, String namespace) throws LightChainDistributedStorageE
*/
@Override
public Entity get(Identifier identifier, String namespace) throws LightChainDistributedStorageException {
return null;
return this.hub.getEntityFromChannel(identifier, namespace);
}

/**
* Retrieves all entities stored on the underlying DHT of nodes that stored on this channel.
*
* @param namespace the namespace on which this query is resolved.
* @return list of all entities stored on this channel from underlying DHT.
* @throws LightChainDistributedStorageException any unhappy path taken on retrieving the Entities.
*/
@Override
public ArrayList<Entity> allEntities(String namespace) throws LightChainDistributedStorageException {
return this.hub.getAllEntities(namespace);
}

}
Loading