Ayaka Koshibe

refactored MastershipStore to not use ILock

Change-Id: Ic254f6faddba3427d3380910ca90d3d65a29f40b
package org.onlab.onos.store.mastership.impl;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.onlab.onos.cluster.NodeId;
import org.onlab.onos.net.MastershipRole;
/**
* A structure that holds node mastership roles associated with a
* {@link DeviceId}. This structure needs to be locked through IMap.
*/
public class RoleValue {
Map<MastershipRole, List<NodeId>> value;
public RoleValue() {
value.put(MastershipRole.MASTER, new LinkedList<NodeId>());
value.put(MastershipRole.STANDBY, new LinkedList<NodeId>());
value.put(MastershipRole.NONE, new LinkedList<NodeId>());
}
public Map<MastershipRole, List<NodeId>> value() {
return Collections.unmodifiableMap(value);
}
public List<NodeId> nodesOfRole(MastershipRole type) {
return value.get(type);
}
public NodeId get(MastershipRole type) {
return value.get(type).isEmpty() ? null : value.get(type).get(0);
}
public boolean contains(MastershipRole type, NodeId nodeId) {
return value.get(type).contains(nodeId);
}
/**
* Associates a node to a certain role.
*
* @param type the role
* @param nodeId the node ID of the node to associate
*/
public void add(MastershipRole type, NodeId nodeId) {
List<NodeId> nodes = value.get(type);
if (!nodes.contains(nodeId)) {
nodes.add(nodeId);
}
}
/**
* Removes a node from a certain role.
*
* @param type the role
* @param nodeId the ID of the node to remove
* @return
*/
public boolean remove(MastershipRole type, NodeId nodeId) {
List<NodeId> nodes = value.get(type);
if (!nodes.isEmpty()) {
return nodes.remove(nodeId);
} else {
return false;
}
}
/**
* Reassigns a node from one role to another. If the node was not of the
* old role, it will still be assigned the new role.
*
* @param nodeId the Node ID of node changing roles
* @param from the old role
* @param to the new role
*/
// might want to add anyways as default behavior
public void reassign(NodeId nodeId, MastershipRole from, MastershipRole to) {
remove(from, nodeId);
add(to, nodeId);
}
/**
* Replaces a node in one role with another node. Even if there is no node to
* replace, the new node is associated to the role.
*
* @param from the old NodeId to replace
* @param to the new NodeId
* @param type the role associated with the old NodeId
*/
// might want to add anyways as default behavior
public void replace(NodeId from, NodeId to, MastershipRole type) {
remove(type, from);
add(type, to);
}
}
......@@ -27,6 +27,7 @@ import org.onlab.onos.mastership.MastershipStoreDelegate;
import org.onlab.onos.mastership.MastershipTerm;
import org.onlab.onos.mastership.MastershipEvent.Type;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.MastershipRole;
import org.onlab.onos.store.common.StoreManager;
import org.onlab.onos.store.common.StoreService;
import org.onlab.onos.store.common.TestStoreManager;
......@@ -101,7 +102,7 @@ public class DistributedMastershipStoreTest {
@Test
public void getMaster() {
assertTrue("wrong store state:", dms.masters.isEmpty());
assertTrue("wrong store state:", dms.roleMap.isEmpty());
testStore.put(DID1, N1, true, false, false);
assertEquals("wrong master:", N1, dms.getMaster(DID1));
......@@ -110,7 +111,7 @@ public class DistributedMastershipStoreTest {
@Test
public void getDevices() {
assertTrue("wrong store state:", dms.masters.isEmpty());
assertTrue("wrong store state:", dms.roleMap.isEmpty());
testStore.put(DID1, N1, true, false, false);
testStore.put(DID2, N1, true, false, false);
......@@ -161,7 +162,7 @@ public class DistributedMastershipStoreTest {
assertEquals("wrong event:", Type.MASTER_CHANGED, dms.setMaster(N2, DID2).type());
assertEquals("wrong term", MastershipTerm.of(N2, 0), dms.getTermFor(DID2));
//disconnect and reconnect - sign of failing re-election or single-instance channel
testStore.reset(true, false, false);
dms.roleMap.clear();
dms.setMaster(N2, DID2);
assertEquals("wrong term", MastershipTerm.of(N2, 1), dms.getTermFor(DID2));
}
......@@ -191,13 +192,15 @@ public class DistributedMastershipStoreTest {
assertEquals("wrong role for node:", NONE, dms.getRole(N2, DID1));
assertEquals("wrong role for node:", NONE, dms.getRole(N1, DID1));
assertEquals("wrong number of retired nodes", 2, dms.unusable.size());
assertEquals("wrong number of retired nodes", 2,
dms.roleMap.get(DID1).nodesOfRole(NONE).size());
//bring nodes back
assertEquals("wrong role for NONE:", MASTER, dms.requestRole(DID1));
testStore.setCurrent(CN1);
assertEquals("wrong role for NONE:", STANDBY, dms.requestRole(DID1));
assertEquals("wrong number of backup nodes", 1, dms.standbys.size());
assertEquals("wrong number of backup nodes", 1,
dms.roleMap.get(DID1).nodesOfRole(STANDBY).size());
//NONE - nothing happens
assertNull("wrong event:", dms.relinquishRole(N1, DID2));
......@@ -238,55 +241,44 @@ public class DistributedMastershipStoreTest {
//helper to populate master/backup structures
public void put(DeviceId dev, NodeId node,
boolean master, boolean backup, boolean term) {
byte [] n = serialize(node);
byte [] d = serialize(dev);
RoleValue rv = dms.roleMap.get(dev);
if (rv == null) {
rv = new RoleValue();
dms.roleMap.put(dev, rv);
}
if (master) {
dms.masters.put(d, n);
dms.unusable.put(d, n);
dms.standbys.remove(d, n);
rv.add(MASTER, node);
rv.reassign(node, STANDBY, NONE);
}
if (backup) {
dms.standbys.put(d, n);
dms.masters.remove(d, n);
dms.unusable.remove(d, n);
rv.add(STANDBY, node);
rv.remove(MASTER, node);
rv.remove(NONE, node);
}
if (term) {
dms.terms.put(d, 0);
dms.terms.put(dev, 0);
}
}
//a dumb utility function.
public void dump() {
System.out.println("standbys");
for (Map.Entry<byte [], byte []> e : standbys.entrySet()) {
System.out.println(deserialize(e.getKey()) + ":" + deserialize(e.getValue()));
}
System.out.println("unusable");
for (Map.Entry<byte [], byte []> e : unusable.entrySet()) {
System.out.println(deserialize(e.getKey()) + ":" + deserialize(e.getValue()));
}
}
//clears structures
public void reset(boolean store, boolean backup, boolean term) {
if (store) {
dms.masters.clear();
dms.unusable.clear();
}
if (backup) {
dms.standbys.clear();
}
if (term) {
dms.terms.clear();
for (Map.Entry<DeviceId, RoleValue> el : dms.roleMap.entrySet()) {
System.out.println("DID: " + el.getKey());
for (MastershipRole role : MastershipRole.values()) {
System.out.println(role.toString() + ":");
for (NodeId n : el.getValue().nodesOfRole(role)) {
System.out.println("\t" + n);
}
}
}
}
//increment term for a device
public void increment(DeviceId dev) {
Integer t = dms.terms.get(serialize(dev));
Integer t = dms.terms.get(dev);
if (t != null) {
dms.terms.put(serialize(dev), ++t);
dms.terms.put(dev, ++t);
}
}
......
......@@ -19,7 +19,6 @@ import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.Element;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.LinkKey;
import org.onlab.onos.net.MastershipRole;
import org.onlab.onos.net.Port;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.device.DefaultDeviceDescription;
......@@ -27,6 +26,7 @@ import org.onlab.onos.net.device.DefaultPortDescription;
import org.onlab.onos.net.link.DefaultLinkDescription;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.store.Timestamp;
import org.onlab.onos.store.mastership.impl.RoleValue;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.util.KryoPool;
......@@ -66,7 +66,7 @@ public final class KryoPoolUtil {
DefaultDevice.class,
DefaultDeviceDescription.class,
DefaultLinkDescription.class,
MastershipRole.class,
RoleValue.class,
Port.class,
DefaultPortDescription.class,
Element.class,
......@@ -84,7 +84,7 @@ public final class KryoPoolUtil {
.register(ConnectPoint.class, new ConnectPointSerializer())
.register(DefaultLink.class, new DefaultLinkSerializer())
.register(MastershipTerm.class, new MastershipTermSerializer())
.register(MastershipRole.class, new MastershipRoleSerializer())
.register(RoleValue.class, new RoleValueSerializer())
.build();
......
package org.onlab.onos.store.serializers;
import java.util.List;
import java.util.Map;
import org.onlab.onos.cluster.NodeId;
import org.onlab.onos.net.MastershipRole;
import org.onlab.onos.store.mastership.impl.RoleValue;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
/**
* Serializer for RoleValues used by {@link DistributedMastershipStore}
*/
public class RoleValueSerializer extends Serializer<RoleValue> {
//RoleValues are assumed to hold a Map of MastershipRoles (an enum)
//to a List of NodeIds.
@Override
public RoleValue read(Kryo kryo, Input input, Class<RoleValue> type) {
RoleValue rv = new RoleValue();
int size = input.readInt();
for (int i = 0; i < size; i++) {
MastershipRole role = MastershipRole.values()[input.readInt()];
int s = input.readInt();
for (int j = 0; j < s; j++) {
rv.add(role, new NodeId(input.readString()));
}
}
return rv;
}
@Override
public void write(Kryo kryo, Output output, RoleValue type) {
output.writeInt(type.value().size());
for (Map.Entry<MastershipRole, List<NodeId>> el :
type.value().entrySet()) {
output.writeInt(el.getKey().ordinal());
List<NodeId> nodes = el.getValue();
output.writeInt(nodes.size());
for (NodeId n : nodes) {
output.writeString(n.toString());
}
}
}
}
......@@ -26,6 +26,7 @@ import org.onlab.onos.net.MastershipRole;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.SparseAnnotations;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.store.mastership.impl.RoleValue;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.util.KryoPool;
......@@ -58,6 +59,13 @@ public class KryoSerializerTest {
.remove("A1")
.set("B3", "b3")
.build();
private static final RoleValue RV = new RoleValue();
static {
RV.add(MastershipRole.MASTER, new NodeId("node1"));
RV.add(MastershipRole.STANDBY, new NodeId("node2"));
RV.add(MastershipRole.STANDBY, new NodeId("node3"));
RV.add(MastershipRole.NONE, new NodeId("node4"));
};
private static KryoPool kryos;
......
......@@ -2,6 +2,7 @@ package org.onlab.onos.store.trivial.impl;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
......@@ -97,7 +98,14 @@ public class SimpleMastershipStore
@Override
public List<NodeId> getNodes(DeviceId deviceId) {
return null;
List<NodeId> nodes = new ArrayList<>();
nodes.addAll(backups);
if (!nodes.contains(masterMap.get(deviceId))) {
nodes.add(masterMap.get(deviceId));
}
return Collections.unmodifiableList(nodes);
}
@Override
......