Thomas Vachuska

Merge remote-tracking branch 'origin/master'

Showing 27 changed files with 1446 additions and 9 deletions
...@@ -28,11 +28,15 @@ public class DefaultEventSinkRegistryTest { ...@@ -28,11 +28,15 @@ public class DefaultEventSinkRegistryTest {
28 private DefaultEventSinkRegistry registry; 28 private DefaultEventSinkRegistry registry;
29 29
30 private static class FooEvent extends TestEvent { 30 private static class FooEvent extends TestEvent {
31 - public FooEvent(String subject) { super(Type.FOO, subject); } 31 + public FooEvent(String subject) {
32 + super(Type.FOO, subject);
33 + }
32 } 34 }
33 35
34 private static class BarEvent extends TestEvent { 36 private static class BarEvent extends TestEvent {
35 - public BarEvent(String subject) { super(Type.BAR, subject); } 37 + public BarEvent(String subject) {
38 + super(Type.BAR, subject);
39 + }
36 } 40 }
37 41
38 private static class FooSink implements EventSink<FooEvent> { 42 private static class FooSink implements EventSink<FooEvent> {
......
...@@ -44,6 +44,24 @@ ...@@ -44,6 +44,24 @@
44 <version>${project.version}</version> 44 <version>${project.version}</version>
45 </dependency> 45 </dependency>
46 46
47 + <dependency>
48 + <groupId>net.kuujo.copycat</groupId>
49 + <artifactId>copycat</artifactId>
50 + <version>0.4.0-SNAPSHOT</version>
51 + </dependency>
52 +
53 + <dependency>
54 + <groupId>net.kuujo.copycat</groupId>
55 + <artifactId>copycat-chronicle</artifactId>
56 + <version>0.4.0-SNAPSHOT</version>
57 + </dependency>
58 +
59 + <dependency>
60 + <groupId>net.kuujo.copycat</groupId>
61 + <artifactId>copycat-tcp</artifactId>
62 + <version>0.4.0-SNAPSHOT</version>
63 + </dependency>
64 +
47 <dependency> 65 <dependency>
48 <groupId>com.fasterxml.jackson.core</groupId> 66 <groupId>com.fasterxml.jackson.core</groupId>
49 <artifactId>jackson-databind</artifactId> 67 <artifactId>jackson-databind</artifactId>
......
1 +package org.onlab.onos.store.service;
2 +
3 +import java.util.List;
4 +
5 +/**
6 + * Service for running administrative tasks on a Database.
7 + */
8 +public interface DatabaseAdminService {
9 +
10 + /**
11 + * Creates a new table.
12 + * Table creation is idempotent. Attempting to create a table
13 + * that already exists will be a noop.
14 + * @param name table name.
15 + * @return true if the table was created by this call, false otherwise.
16 + */
17 + public boolean createTable(String name);
18 +
19 + /**
20 + * Lists all the tables in the database.
21 + * @return list of table names.
22 + */
23 + public List<String> listTables();
24 +
25 + /**
26 + * Deletes a table from the database.
27 + * @param name name of the table to delete.
28 + */
29 + public void dropTable(String name);
30 +
31 + /**
32 + * Deletes all tables from the database.
33 + */
34 + public void dropAllTables();
35 +}
1 +package org.onlab.onos.store.service;
2 +
3 +/**
4 + * Base exception type for database failures.
5 + */
6 +@SuppressWarnings("serial")
7 +public class DatabaseException extends RuntimeException {
8 + public DatabaseException(String message, Throwable t) {
9 + super(message, t);
10 + }
11 +
12 + public DatabaseException(String message) {
13 + super(message);
14 + }
15 +
16 + public DatabaseException(Throwable t) {
17 + super(t);
18 + }
19 +
20 + public DatabaseException() {
21 + };
22 +}
...\ No newline at end of file ...\ No newline at end of file
1 +package org.onlab.onos.store.service;
2 +
3 +import java.util.List;
4 +
5 +public interface DatabaseService {
6 +
7 + /**
8 + * Performs a read on the database.
9 + * @param request read request.
10 + * @return ReadResult
11 + * @throws DatabaseException
12 + */
13 + ReadResult read(ReadRequest request);
14 +
15 + /**
16 + * Performs a batch read operation on the database.
17 + * The main advantage of batch read operation is parallelization.
18 + * @param batch batch of read requests to execute.
19 + * @return
20 + */
21 + List<OptionalResult<ReadResult, DatabaseException>> batchRead(List<ReadRequest> batch);
22 +
23 + /**
24 + * Performs a write operation on the database.
25 + * @param request
26 + * @return write result.
27 + * @throws DatabaseException
28 + */
29 + WriteResult write(WriteRequest request);
30 +
31 + /**
32 + * Performs a batch write operation on the database.
33 + * Batch write provides transactional semantics. Either all operations
34 + * succeed or none of them do.
35 + * @param batch batch of write requests to execute as a transaction.
36 + * @return result of executing the batch write operation.
37 + */
38 + List<OptionalResult<WriteResult, DatabaseException>> batchWrite(List<WriteRequest> batch);
39 +}
1 +package org.onlab.onos.store.service;
2 +
3 +/**
4 + * Exception thrown when an operation (read or write) is requested for
5 + * a table that does not exist.
6 + */
7 +@SuppressWarnings("serial")
8 +public class NoSuchTableException extends DatabaseException {
9 +}
...\ No newline at end of file ...\ No newline at end of file
1 +package org.onlab.onos.store.service;
2 +
3 +/**
4 + * Exception that indicates a optimistic lock failure.
5 + */
6 +@SuppressWarnings("serial")
7 +public class OptimisticLockException extends PreconditionFailedException {
8 +}
1 +package org.onlab.onos.store.service;
2 +
3 +/**
4 + * A container object which either has a result or an exception.
5 + * <p>
6 + * If a result is present, get() will return it otherwise get() will throw
7 + * the exception that was encountered in the process of generating the result.
8 + *
9 + * @param <R> type of result.
10 + * @param <E> exception encountered in generating the result.
11 + */
12 +public interface OptionalResult<R, E extends Throwable> {
13 +
14 + /**
15 + * Returns the result.
16 + * @return result
17 + * @throws E if there is no valid result.
18 + */
19 + public R get();
20 +
21 + /**
22 + * Returns true if there is a valid result.
23 + * @return true is yes, false otherwise.
24 + */
25 + public boolean hasValidResult();
26 +}
1 +package org.onlab.onos.store.service;
2 +
3 +/**
4 + * Exception that indicates a precondition failure.
5 + * <ul>Scenarios that can cause this exception:
6 + * <li>An operation that attempts to write a new value iff the current value is equal
7 + * to some specified value.</li>
8 + * <li>An operation that attempts to write a new value iff the current version
9 + * matches a specified value</li>
10 + * </ul>
11 + */
12 +@SuppressWarnings("serial")
13 +public class PreconditionFailedException extends DatabaseException {
14 +}
1 +package org.onlab.onos.store.service;
2 +
3 +/**
4 + * Database read request.
5 + */
6 +public class ReadRequest {
7 +
8 + private final String tableName;
9 + private final String key;
10 +
11 + public ReadRequest(String tableName, String key) {
12 + this.tableName = tableName;
13 + this.key = key;
14 + }
15 +
16 + /**
17 + * Return the name of the table.
18 + * @return table name.
19 + */
20 + public String tableName() {
21 + return tableName;
22 + }
23 +
24 + /**
25 + * Returns the key.
26 + * @return key.
27 + */
28 + public String key() {
29 + return key;
30 + }
31 +
32 + @Override
33 + public String toString() {
34 + return "ReadRequest [tableName=" + tableName + ", key=" + key + "]";
35 + }
36 +}
...\ No newline at end of file ...\ No newline at end of file
1 +package org.onlab.onos.store.service;
2 +
3 +import org.onlab.onos.store.service.impl.VersionedValue;
4 +
5 +/**
6 + * Database read result.
7 + */
8 +public class ReadResult {
9 +
10 + private final String tableName;
11 + private final String key;
12 + private final VersionedValue value;
13 +
14 + public ReadResult(String tableName, String key, VersionedValue value) {
15 + this.tableName = tableName;
16 + this.key = key;
17 + this.value = value;
18 + }
19 +
20 + /**
21 + * Database table name.
22 + * @return
23 + */
24 + public String tableName() {
25 + return tableName;
26 + }
27 +
28 + /**
29 + * Database table key.
30 + * @return key.
31 + */
32 + public String key() {
33 + return key;
34 + }
35 +
36 + /**
37 + * value associated with the key.
38 + * @return non-null value if the table contains one, null otherwise.
39 + */
40 + public VersionedValue value() {
41 + return value;
42 + }
43 +}
1 +package org.onlab.onos.store.service;
2 +
3 +/**
4 + * Exception that indicates a write operation is aborted.
5 + * Aborted operations do not mutate database state is any form.
6 + */
7 +@SuppressWarnings("serial")
8 +public class WriteAborted extends DatabaseException {
9 +}
1 +package org.onlab.onos.store.service;
2 +
3 +import static com.google.common.base.Preconditions.checkArgument;
4 +
5 +import java.util.Objects;
6 +
7 +/**
8 + * Database write request.
9 + */
10 +public class WriteRequest {
11 +
12 + private final String tableName;
13 + private final String key;
14 + private final byte[] newValue;
15 + private final long previousVersion;
16 + private final byte[] oldValue;
17 +
18 + public WriteRequest(String tableName, String key, byte[] newValue) {
19 + this(tableName, key, newValue, -1, null);
20 + }
21 +
22 + public WriteRequest(String tableName, String key, byte[] newValue, long previousVersion) {
23 + this(tableName, key, newValue, previousVersion, null);
24 + checkArgument(previousVersion >= 0);
25 + }
26 +
27 + public WriteRequest(String tableName, String key, byte[] newValue, byte[] oldValue) {
28 + this(tableName, key, newValue, -1, oldValue);
29 + }
30 +
31 + private WriteRequest(String tableName, String key, byte[] newValue, long previousVersion, byte[] oldValue) {
32 +
33 + checkArgument(tableName != null);
34 + checkArgument(key != null);
35 + checkArgument(newValue != null);
36 +
37 + this.tableName = tableName;
38 + this.key = key;
39 + this.newValue = newValue;
40 + this.previousVersion = previousVersion;
41 + this.oldValue = oldValue;
42 + }
43 +
44 + public String tableName() {
45 + return tableName;
46 + }
47 +
48 + public String key() {
49 + return key;
50 + }
51 +
52 + public byte[] newValue() {
53 + return newValue;
54 + }
55 +
56 + public long previousVersion() {
57 + return previousVersion;
58 + }
59 +
60 + public byte[] oldValue() {
61 + return oldValue;
62 + }
63 +
64 + @Override
65 + public String toString() {
66 + return "WriteRequest [tableName=" + tableName + ", key=" + key
67 + + ", newValue=" + newValue
68 + + ", previousVersion=" + previousVersion
69 + + ", oldValue=" + oldValue;
70 + }
71 +
72 + @Override
73 + public int hashCode() {
74 + return Objects.hash(key, tableName, previousVersion);
75 + }
76 +
77 + @Override
78 + public boolean equals(Object obj) {
79 + if (this == obj) {
80 + return true;
81 + }
82 + if (obj == null) {
83 + return false;
84 + }
85 + if (getClass() != obj.getClass()) {
86 + return false;
87 + }
88 + WriteRequest other = (WriteRequest) obj;
89 + return Objects.equals(this.key, other.key) &&
90 + Objects.equals(this.tableName, other.tableName) &&
91 + Objects.equals(this.previousVersion, other.previousVersion);
92 + }
93 +}
1 +package org.onlab.onos.store.service;
2 +
3 +import org.onlab.onos.store.service.impl.VersionedValue;
4 +
5 +/**
6 + * Database write result.
7 + */
8 +public class WriteResult {
9 +
10 + private final String tableName;
11 + private final String key;
12 + private final VersionedValue previousValue;
13 +
14 + public WriteResult(String tableName, String key, VersionedValue previousValue) {
15 + this.tableName = tableName;
16 + this.key = key;
17 + this.previousValue = previousValue;
18 + }
19 +
20 + public String tableName() {
21 + return tableName;
22 + }
23 +
24 + public String key() {
25 + return key;
26 + }
27 +
28 + public VersionedValue previousValue() {
29 + return previousValue;
30 + }
31 +}
1 +package org.onlab.onos.store.service.impl;
2 +
3 +import java.util.Arrays;
4 +import java.util.List;
5 +import java.util.UUID;
6 +import java.util.concurrent.CompletableFuture;
7 +import java.util.concurrent.ExecutionException;
8 +
9 +import net.kuujo.copycat.protocol.Response.Status;
10 +import net.kuujo.copycat.protocol.SubmitRequest;
11 +import net.kuujo.copycat.protocol.SubmitResponse;
12 +import net.kuujo.copycat.spi.protocol.ProtocolClient;
13 +
14 +import org.apache.commons.lang3.RandomUtils;
15 +import org.onlab.netty.Endpoint;
16 +import org.onlab.netty.NettyMessagingService;
17 +import org.onlab.onos.store.service.DatabaseException;
18 +import org.onlab.onos.store.service.ReadRequest;
19 +import org.onlab.onos.store.service.WriteRequest;
20 +
21 +public class DatabaseClient {
22 +
23 + private final Endpoint copycatEp;
24 + ProtocolClient client;
25 + NettyMessagingService messagingService;
26 +
27 + public DatabaseClient(Endpoint copycatEp) {
28 + this.copycatEp = copycatEp;
29 + }
30 +
31 + private static String nextId() {
32 + return UUID.randomUUID().toString();
33 + }
34 +
35 + public void activate() throws Exception {
36 + messagingService = new NettyMessagingService(RandomUtils.nextInt(10000, 40000));
37 + messagingService.activate();
38 + client = new NettyProtocolClient(copycatEp, messagingService);
39 + }
40 +
41 + public void deactivate() throws Exception {
42 + messagingService.deactivate();
43 + }
44 +
45 + public boolean createTable(String tableName) {
46 +
47 + SubmitRequest request =
48 + new SubmitRequest(
49 + nextId(),
50 + "createTable",
51 + Arrays.asList(tableName));
52 + CompletableFuture<SubmitResponse> future = client.submit(request);
53 + try {
54 + return (boolean) future.get().result();
55 + } catch (InterruptedException | ExecutionException e) {
56 + throw new DatabaseException(e);
57 + }
58 + }
59 +
60 + public void dropTable(String tableName) {
61 +
62 + SubmitRequest request =
63 + new SubmitRequest(
64 + nextId(),
65 + "dropTable",
66 + Arrays.asList(tableName));
67 + CompletableFuture<SubmitResponse> future = client.submit(request);
68 + try {
69 + if (future.get().status() == Status.OK) {
70 + throw new DatabaseException(future.get().toString());
71 + }
72 +
73 + } catch (InterruptedException | ExecutionException e) {
74 + throw new DatabaseException(e);
75 + }
76 + }
77 +
78 + public void dropAllTables() {
79 +
80 + SubmitRequest request =
81 + new SubmitRequest(
82 + nextId(),
83 + "dropAllTables",
84 + Arrays.asList());
85 + CompletableFuture<SubmitResponse> future = client.submit(request);
86 + try {
87 + if (future.get().status() != Status.OK) {
88 + throw new DatabaseException(future.get().toString());
89 + }
90 + } catch (InterruptedException | ExecutionException e) {
91 + throw new DatabaseException(e);
92 + }
93 + }
94 +
95 + @SuppressWarnings("unchecked")
96 + public List<String> listTables() {
97 +
98 + SubmitRequest request =
99 + new SubmitRequest(
100 + nextId(),
101 + "listTables",
102 + Arrays.asList());
103 + CompletableFuture<SubmitResponse> future = client.submit(request);
104 + try {
105 + return (List<String>) future.get().result();
106 + } catch (InterruptedException | ExecutionException e) {
107 + throw new DatabaseException(e);
108 + }
109 + }
110 +
111 + @SuppressWarnings("unchecked")
112 + public List<InternalReadResult> batchRead(List<ReadRequest> requests) {
113 +
114 + SubmitRequest request = new SubmitRequest(
115 + nextId(),
116 + "read",
117 + Arrays.asList(requests));
118 +
119 + CompletableFuture<SubmitResponse> future = client.submit(request);
120 + try {
121 + List<InternalReadResult> internalReadResults = (List<InternalReadResult>) future.get().result();
122 + return internalReadResults;
123 + } catch (InterruptedException | ExecutionException e) {
124 + throw new DatabaseException(e);
125 + }
126 + }
127 +
128 + @SuppressWarnings("unchecked")
129 + public List<InternalWriteResult> batchWrite(List<WriteRequest> requests) {
130 +
131 + SubmitRequest request = new SubmitRequest(
132 + nextId(),
133 + "write",
134 + Arrays.asList(requests));
135 +
136 + CompletableFuture<SubmitResponse> future = client.submit(request);
137 + try {
138 + List<InternalWriteResult> internalWriteResults = (List<InternalWriteResult>) future.get().result();
139 + return internalWriteResults;
140 + } catch (InterruptedException | ExecutionException e) {
141 + throw new DatabaseException(e);
142 + }
143 + }
144 +}
1 +package org.onlab.onos.store.service.impl;
2 +
3 +import static org.slf4j.LoggerFactory.getLogger;
4 +
5 +import java.util.ArrayList;
6 +import java.util.Arrays;
7 +import java.util.List;
8 +
9 +import net.kuujo.copycat.Copycat;
10 +import net.kuujo.copycat.StateMachine;
11 +import net.kuujo.copycat.cluster.TcpCluster;
12 +import net.kuujo.copycat.cluster.TcpClusterConfig;
13 +import net.kuujo.copycat.cluster.TcpMember;
14 +import net.kuujo.copycat.log.ChronicleLog;
15 +import net.kuujo.copycat.log.Log;
16 +
17 +import org.apache.felix.scr.annotations.Activate;
18 +import org.apache.felix.scr.annotations.Component;
19 +import org.apache.felix.scr.annotations.Reference;
20 +import org.apache.felix.scr.annotations.ReferenceCardinality;
21 +import org.apache.felix.scr.annotations.Service;
22 +import org.onlab.netty.Endpoint;
23 +import org.onlab.onos.cluster.ClusterService;
24 +import org.onlab.onos.cluster.ControllerNode;
25 +import org.onlab.onos.store.service.DatabaseAdminService;
26 +import org.onlab.onos.store.service.DatabaseException;
27 +import org.onlab.onos.store.service.DatabaseService;
28 +import org.onlab.onos.store.service.NoSuchTableException;
29 +import org.onlab.onos.store.service.OptimisticLockException;
30 +import org.onlab.onos.store.service.OptionalResult;
31 +import org.onlab.onos.store.service.PreconditionFailedException;
32 +import org.onlab.onos.store.service.ReadRequest;
33 +import org.onlab.onos.store.service.ReadResult;
34 +import org.onlab.onos.store.service.WriteAborted;
35 +import org.onlab.onos.store.service.WriteRequest;
36 +import org.onlab.onos.store.service.WriteResult;
37 +import org.slf4j.Logger;
38 +
39 +import com.google.common.collect.Lists;
40 +
41 +/**
42 + * Strongly consistent and durable state management service based on
43 + * Copycat implementation of Raft consensus protocol.
44 + */
45 +@Component(immediate = true)
46 +@Service
47 +public class DatabaseManager implements DatabaseService, DatabaseAdminService {
48 +
49 + private final Logger log = getLogger(getClass());
50 +
51 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
52 + ClusterService clusterService;
53 +
54 + public static final String LOG_FILE_PREFIX = "onos-copy-cat-log";
55 +
56 + private Copycat copycat;
57 + private DatabaseClient client;
58 +
59 + @Activate
60 + public void activate() {
61 + TcpMember localMember =
62 + new TcpMember(
63 + clusterService.getLocalNode().ip().toString(),
64 + clusterService.getLocalNode().tcpPort());
65 + List<TcpMember> remoteMembers = Lists.newArrayList();
66 +
67 + for (ControllerNode node : clusterService.getNodes()) {
68 + TcpMember member = new TcpMember(node.ip().toString(), node.tcpPort());
69 + if (!member.equals(localMember)) {
70 + remoteMembers.add(member);
71 + }
72 + }
73 +
74 + // Configure the cluster.
75 + TcpClusterConfig config = new TcpClusterConfig();
76 +
77 + config.setLocalMember(localMember);
78 + config.setRemoteMembers(remoteMembers.toArray(new TcpMember[]{}));
79 +
80 + // Create the cluster.
81 + TcpCluster cluster = new TcpCluster(config);
82 +
83 + StateMachine stateMachine = new DatabaseStateMachine();
84 + ControllerNode thisNode = clusterService.getLocalNode();
85 + Log consensusLog = new ChronicleLog(LOG_FILE_PREFIX + "_" + thisNode.id());
86 +
87 + copycat = new Copycat(stateMachine, consensusLog, cluster, new NettyProtocol());
88 + copycat.start();
89 +
90 + client = new DatabaseClient(new Endpoint(localMember.host(), localMember.port()));
91 +
92 + log.info("Started.");
93 + }
94 +
95 + @Activate
96 + public void deactivate() {
97 + copycat.stop();
98 + }
99 +
100 + @Override
101 + public boolean createTable(String name) {
102 + return client.createTable(name);
103 + }
104 +
105 + @Override
106 + public void dropTable(String name) {
107 + client.dropTable(name);
108 + }
109 +
110 + @Override
111 + public void dropAllTables() {
112 + client.dropAllTables();
113 + }
114 +
115 + @Override
116 + public List<String> listTables() {
117 + return client.listTables();
118 + }
119 +
120 + @Override
121 + public ReadResult read(ReadRequest request) {
122 + return batchRead(Arrays.asList(request)).get(0).get();
123 + }
124 +
125 + @Override
126 + public List<OptionalResult<ReadResult, DatabaseException>> batchRead(
127 + List<ReadRequest> batch) {
128 + List<OptionalResult<ReadResult, DatabaseException>> readResults = new ArrayList<>(batch.size());
129 + for (InternalReadResult internalReadResult : client.batchRead(batch)) {
130 + if (internalReadResult.status() == InternalReadResult.Status.NO_SUCH_TABLE) {
131 + readResults.add(new DatabaseOperationResult<ReadResult, DatabaseException>(
132 + new NoSuchTableException()));
133 + } else {
134 + readResults.add(new DatabaseOperationResult<ReadResult, DatabaseException>(
135 + internalReadResult.result()));
136 + }
137 + }
138 + return readResults;
139 + }
140 +
141 + @Override
142 + public WriteResult write(WriteRequest request) {
143 + return batchWrite(Arrays.asList(request)).get(0).get();
144 + }
145 +
146 + @Override
147 + public List<OptionalResult<WriteResult, DatabaseException>> batchWrite(
148 + List<WriteRequest> batch) {
149 + List<OptionalResult<WriteResult, DatabaseException>> writeResults = new ArrayList<>(batch.size());
150 + for (InternalWriteResult internalWriteResult : client.batchWrite(batch)) {
151 + if (internalWriteResult.status() == InternalWriteResult.Status.NO_SUCH_TABLE) {
152 + writeResults.add(new DatabaseOperationResult<WriteResult, DatabaseException>(
153 + new NoSuchTableException()));
154 + } else if (internalWriteResult.status() == InternalWriteResult.Status.OPTIMISTIC_LOCK_FAILURE) {
155 + writeResults.add(new DatabaseOperationResult<WriteResult, DatabaseException>(
156 + new OptimisticLockException()));
157 + } else if (internalWriteResult.status() == InternalWriteResult.Status.PREVIOUS_VALUE_MISMATCH) {
158 + // TODO: throw a different exception?
159 + writeResults.add(new DatabaseOperationResult<WriteResult, DatabaseException>(
160 + new PreconditionFailedException()));
161 + } else if (internalWriteResult.status() == InternalWriteResult.Status.ABORTED) {
162 + writeResults.add(new DatabaseOperationResult<WriteResult, DatabaseException>(
163 + new WriteAborted()));
164 + } else {
165 + writeResults.add(new DatabaseOperationResult<WriteResult, DatabaseException>(
166 + internalWriteResult.result()));
167 + }
168 + }
169 + return writeResults;
170 +
171 + }
172 +
173 + private class DatabaseOperationResult<R, E extends DatabaseException> implements OptionalResult<R, E> {
174 +
175 + private final R result;
176 + private final DatabaseException exception;
177 +
178 + public DatabaseOperationResult(R result) {
179 + this.result = result;
180 + this.exception = null;
181 + }
182 +
183 + public DatabaseOperationResult(DatabaseException exception) {
184 + this.result = null;
185 + this.exception = exception;
186 + }
187 +
188 + @Override
189 + public R get() {
190 + if (result != null) {
191 + return result;
192 + }
193 + throw exception;
194 + }
195 +
196 + @Override
197 + public boolean hasValidResult() {
198 + return result != null;
199 + }
200 +
201 + @Override
202 + public String toString() {
203 + if (result != null) {
204 + return result.toString();
205 + } else {
206 + return exception.toString();
207 + }
208 + }
209 + }
210 +}
1 +package org.onlab.onos.store.service.impl;
2 +
3 +import java.util.ArrayList;
4 +import java.util.List;
5 +import java.util.Map;
6 +import java.util.Set;
7 +
8 +import net.kuujo.copycat.Command;
9 +import net.kuujo.copycat.Query;
10 +import net.kuujo.copycat.StateMachine;
11 +
12 +import org.onlab.onos.store.serializers.KryoSerializer;
13 +import org.onlab.onos.store.service.ReadRequest;
14 +import org.onlab.onos.store.service.ReadResult;
15 +import org.onlab.onos.store.service.WriteRequest;
16 +import org.onlab.onos.store.service.WriteResult;
17 +import org.onlab.util.KryoNamespace;
18 +
19 +import com.google.common.collect.Maps;
20 +
21 +public class DatabaseStateMachine implements StateMachine {
22 +
23 + public static final KryoSerializer SERIALIZER = new KryoSerializer() {
24 + @Override
25 + protected void setupKryoPool() {
26 + serializerPool = KryoNamespace.newBuilder()
27 + .register(VersionedValue.class)
28 + .register(State.class)
29 + .register(NettyProtocol.COMMON)
30 + .build()
31 + .populate(1);
32 + }
33 + };
34 +
35 + private State state = new State();
36 +
37 + @Command
38 + public boolean createTable(String tableName) {
39 + return state.getTables().putIfAbsent(tableName, Maps.newHashMap()) == null;
40 + }
41 +
42 + @Command
43 + public boolean dropTable(String tableName) {
44 + return state.getTables().remove(tableName) != null;
45 + }
46 +
47 + @Command
48 + public boolean dropAllTables() {
49 + state.getTables().clear();
50 + return true;
51 + }
52 +
53 + @Query
54 + public Set<String> listTables() {
55 + return state.getTables().keySet();
56 + }
57 +
58 + @Query
59 + public List<InternalReadResult> read(List<ReadRequest> requests) {
60 + List<InternalReadResult> results = new ArrayList<>(requests.size());
61 + for (ReadRequest request : requests) {
62 + Map<String, VersionedValue> table = state.getTables().get(request.tableName());
63 + if (table == null) {
64 + results.add(new InternalReadResult(InternalReadResult.Status.NO_SUCH_TABLE, null));
65 + continue;
66 + }
67 + VersionedValue value = table.get(request.key());
68 + results.add(new InternalReadResult(
69 + InternalReadResult.Status.OK,
70 + new ReadResult(
71 + request.tableName(),
72 + request.key(),
73 + value)));
74 + }
75 + return results;
76 + }
77 +
78 + @Command
79 + public List<InternalWriteResult> write(List<WriteRequest> requests) {
80 + boolean abort = false;
81 + List<InternalWriteResult.Status> validationResults = new ArrayList<>(requests.size());
82 + for (WriteRequest request : requests) {
83 + Map<String, VersionedValue> table = state.getTables().get(request.tableName());
84 + if (table == null) {
85 + validationResults.add(InternalWriteResult.Status.NO_SUCH_TABLE);
86 + abort = true;
87 + continue;
88 + }
89 + VersionedValue value = table.get(request.key());
90 + if (value == null) {
91 + if (request.oldValue() != null) {
92 + validationResults.add(InternalWriteResult.Status.PREVIOUS_VALUE_MISMATCH);
93 + abort = true;
94 + continue;
95 + } else if (request.previousVersion() >= 0) {
96 + validationResults.add(InternalWriteResult.Status.OPTIMISTIC_LOCK_FAILURE);
97 + abort = true;
98 + continue;
99 + }
100 + }
101 + if (request.previousVersion() >= 0 && value.version() != request.previousVersion()) {
102 + validationResults.add(InternalWriteResult.Status.OPTIMISTIC_LOCK_FAILURE);
103 + abort = true;
104 + continue;
105 + }
106 +
107 + validationResults.add(InternalWriteResult.Status.OK);
108 + }
109 +
110 + List<InternalWriteResult> results = new ArrayList<>(requests.size());
111 +
112 + if (abort) {
113 + for (InternalWriteResult.Status validationResult : validationResults) {
114 + if (validationResult == InternalWriteResult.Status.OK) {
115 + results.add(new InternalWriteResult(InternalWriteResult.Status.ABORTED, null));
116 + } else {
117 + results.add(new InternalWriteResult(validationResult, null));
118 + }
119 + }
120 + return results;
121 + }
122 +
123 + for (WriteRequest request : requests) {
124 + Map<String, VersionedValue> table = state.getTables().get(request.tableName());
125 + synchronized (table) {
126 + VersionedValue previousValue =
127 + table.put(request.key(), new VersionedValue(request.newValue(), state.nextVersion()));
128 + results.add(new InternalWriteResult(
129 + InternalWriteResult.Status.OK,
130 + new WriteResult(request.tableName(), request.key(), previousValue)));
131 + }
132 + }
133 + return results;
134 + }
135 +
136 + public class State {
137 +
138 + private final Map<String, Map<String, VersionedValue>> tables =
139 + Maps.newHashMap();
140 + private long versionCounter = 1;
141 +
142 + Map<String, Map<String, VersionedValue>> getTables() {
143 + return tables;
144 + }
145 +
146 + long nextVersion() {
147 + return versionCounter++;
148 + }
149 + }
150 +
151 + @Override
152 + public byte[] takeSnapshot() {
153 + try {
154 + return SERIALIZER.encode(state);
155 + } catch (Exception e) {
156 + e.printStackTrace();
157 + return null;
158 + }
159 + }
160 +
161 + @Override
162 + public void installSnapshot(byte[] data) {
163 + try {
164 + this.state = SERIALIZER.decode(data);
165 + } catch (Exception e) {
166 + e.printStackTrace();
167 + }
168 + }
169 +}
1 +package org.onlab.onos.store.service.impl;
2 +
3 +import org.onlab.onos.store.service.ReadResult;
4 +
5 +public class InternalReadResult {
6 +
7 + public enum Status {
8 + OK,
9 + NO_SUCH_TABLE
10 + }
11 +
12 + private final Status status;
13 + private final ReadResult result;
14 +
15 + public InternalReadResult(Status status, ReadResult result) {
16 + this.status = status;
17 + this.result = result;
18 + }
19 +
20 + public Status status() {
21 + return status;
22 + }
23 +
24 + public ReadResult result() {
25 + return result;
26 + }
27 +
28 + @Override
29 + public String toString() {
30 + return "InternalReadResult [status=" + status + ", result=" + result
31 + + "]";
32 + }
33 +}
...\ No newline at end of file ...\ No newline at end of file
1 +package org.onlab.onos.store.service.impl;
2 +
3 +import org.onlab.onos.store.service.WriteResult;
4 +
5 +public class InternalWriteResult {
6 +
7 + public enum Status {
8 + OK,
9 + ABORTED,
10 + NO_SUCH_TABLE,
11 + OPTIMISTIC_LOCK_FAILURE,
12 + PREVIOUS_VALUE_MISMATCH
13 + }
14 +
15 + private final Status status;
16 + private final WriteResult result;
17 +
18 + public InternalWriteResult(Status status, WriteResult result) {
19 + this.status = status;
20 + this.result = result;
21 + }
22 +
23 + public Status status() {
24 + return status;
25 + }
26 +
27 + public WriteResult result() {
28 + return result;
29 + }
30 +}
1 +package org.onlab.onos.store.service.impl;
2 +
3 +import java.util.ArrayList;
4 +import java.util.Arrays;
5 +import java.util.Collection;
6 +import java.util.HashMap;
7 +import java.util.HashSet;
8 +import java.util.LinkedList;
9 +import java.util.Vector;
10 +
11 +import net.kuujo.copycat.cluster.TcpClusterConfig;
12 +import net.kuujo.copycat.cluster.TcpMember;
13 +import net.kuujo.copycat.internal.log.ConfigurationEntry;
14 +import net.kuujo.copycat.internal.log.CopycatEntry;
15 +import net.kuujo.copycat.internal.log.OperationEntry;
16 +import net.kuujo.copycat.internal.log.SnapshotEntry;
17 +import net.kuujo.copycat.protocol.PingRequest;
18 +import net.kuujo.copycat.protocol.PingResponse;
19 +import net.kuujo.copycat.protocol.PollRequest;
20 +import net.kuujo.copycat.protocol.PollResponse;
21 +import net.kuujo.copycat.protocol.Response.Status;
22 +import net.kuujo.copycat.protocol.SubmitRequest;
23 +import net.kuujo.copycat.protocol.SubmitResponse;
24 +import net.kuujo.copycat.protocol.SyncRequest;
25 +import net.kuujo.copycat.protocol.SyncResponse;
26 +import net.kuujo.copycat.spi.protocol.Protocol;
27 +import net.kuujo.copycat.spi.protocol.ProtocolClient;
28 +import net.kuujo.copycat.spi.protocol.ProtocolServer;
29 +
30 +import org.onlab.onos.store.serializers.ImmutableListSerializer;
31 +import org.onlab.onos.store.serializers.ImmutableMapSerializer;
32 +import org.onlab.onos.store.serializers.ImmutableSetSerializer;
33 +import org.onlab.onos.store.serializers.KryoSerializer;
34 +import org.onlab.onos.store.service.ReadRequest;
35 +import org.onlab.onos.store.service.ReadResult;
36 +import org.onlab.onos.store.service.WriteRequest;
37 +import org.onlab.onos.store.service.WriteResult;
38 +import org.onlab.util.KryoNamespace;
39 +
40 +import com.esotericsoftware.kryo.Kryo;
41 +import com.esotericsoftware.kryo.io.Input;
42 +import com.esotericsoftware.kryo.serializers.CollectionSerializer;
43 +import com.google.common.collect.ImmutableList;
44 +import com.google.common.collect.ImmutableMap;
45 +import com.google.common.collect.ImmutableSet;
46 +
47 +/**
48 + * {@link Protocol} based on {@link org.onlab.netty.NettyMessagingService}.
49 + */
50 +public class NettyProtocol implements Protocol<TcpMember> {
51 +
52 + public static final String COPYCAT_PING = "copycat-raft-consensus-ping";
53 + public static final String COPYCAT_SYNC = "copycat-raft-consensus-sync";
54 + public static final String COPYCAT_POLL = "copycat-raft-consensus-poll";
55 + public static final String COPYCAT_SUBMIT = "copycat-raft-consensus-submit";
56 +
57 + // TODO: make this configurable.
58 + public static final long RETRY_INTERVAL_MILLIS = 2000;
59 +
60 + private static final KryoNamespace COPYCAT = KryoNamespace.newBuilder()
61 + .register(PingRequest.class)
62 + .register(PingResponse.class)
63 + .register(PollRequest.class)
64 + .register(PollResponse.class)
65 + .register(SyncRequest.class)
66 + .register(SyncResponse.class)
67 + .register(SubmitRequest.class)
68 + .register(SubmitResponse.class)
69 + .register(Status.class)
70 + .register(ConfigurationEntry.class)
71 + .register(SnapshotEntry.class)
72 + .register(CopycatEntry.class)
73 + .register(OperationEntry.class)
74 + .register(TcpClusterConfig.class)
75 + .register(TcpMember.class)
76 + .build();
77 +
78 + // TODO: Move to the right place.
79 + private static final KryoNamespace CRAFT = KryoNamespace.newBuilder()
80 + .register(ReadRequest.class)
81 + .register(WriteRequest.class)
82 + .register(InternalReadResult.class)
83 + .register(InternalWriteResult.class)
84 + .register(InternalReadResult.Status.class)
85 + .register(WriteResult.class)
86 + .register(ReadResult.class)
87 + .register(InternalWriteResult.Status.class)
88 + .register(VersionedValue.class)
89 + .build();
90 +
91 + public static final KryoNamespace COMMON = KryoNamespace.newBuilder()
92 + .register(Arrays.asList().getClass(), new CollectionSerializer() {
93 + @Override
94 + @SuppressWarnings("rawtypes")
95 + protected Collection<?> create(Kryo kryo, Input input, Class<Collection> type) {
96 + return new ArrayList();
97 + }
98 + })
99 + .register(ImmutableMap.class, new ImmutableMapSerializer())
100 + .register(ImmutableList.class, new ImmutableListSerializer())
101 + .register(ImmutableSet.class, new ImmutableSetSerializer())
102 + .register(
103 + Vector.class,
104 + ArrayList.class,
105 + Arrays.asList().getClass(),
106 + HashMap.class,
107 + HashSet.class,
108 + LinkedList.class,
109 + byte[].class)
110 + .build();
111 +
112 + public static final KryoSerializer SERIALIZER = new KryoSerializer() {
113 + @Override
114 + protected void setupKryoPool() {
115 + serializerPool = KryoNamespace.newBuilder()
116 + .register(COPYCAT)
117 + .register(COMMON)
118 + .register(CRAFT)
119 + .build()
120 + .populate(1);
121 + }
122 + };
123 +
124 + private NettyProtocolServer server = null;
125 +
126 + // FIXME: This is a total hack.Assumes
127 + // ProtocolServer is initialized before ProtocolClient
128 + protected NettyProtocolServer getServer() {
129 + if (server == null) {
130 + throw new IllegalStateException("ProtocolServer is not initialized yet!");
131 + }
132 + return server;
133 + }
134 +
135 + @Override
136 + public ProtocolServer createServer(TcpMember member) {
137 + server = new NettyProtocolServer(member);
138 + return server;
139 + }
140 +
141 + @Override
142 + public ProtocolClient createClient(TcpMember member) {
143 + return new NettyProtocolClient(this, member);
144 + }
145 +}
1 +package org.onlab.onos.store.service.impl;
2 +
3 +import static org.slf4j.LoggerFactory.getLogger;
4 +
5 +import java.io.IOException;
6 +import java.util.concurrent.CompletableFuture;
7 +import java.util.concurrent.ExecutionException;
8 +import java.util.concurrent.ScheduledExecutorService;
9 +import java.util.concurrent.ScheduledThreadPoolExecutor;
10 +import java.util.concurrent.ThreadFactory;
11 +import java.util.concurrent.TimeUnit;
12 +import java.util.concurrent.TimeoutException;
13 +
14 +import net.kuujo.copycat.cluster.TcpMember;
15 +import net.kuujo.copycat.protocol.PingRequest;
16 +import net.kuujo.copycat.protocol.PingResponse;
17 +import net.kuujo.copycat.protocol.PollRequest;
18 +import net.kuujo.copycat.protocol.PollResponse;
19 +import net.kuujo.copycat.protocol.SubmitRequest;
20 +import net.kuujo.copycat.protocol.SubmitResponse;
21 +import net.kuujo.copycat.protocol.SyncRequest;
22 +import net.kuujo.copycat.protocol.SyncResponse;
23 +import net.kuujo.copycat.spi.protocol.ProtocolClient;
24 +
25 +import org.onlab.netty.Endpoint;
26 +import org.onlab.netty.NettyMessagingService;
27 +import org.slf4j.Logger;
28 +
29 +import com.google.common.util.concurrent.ThreadFactoryBuilder;
30 +
31 +/**
32 + * {@link NettyMessagingService} based Copycat protocol client.
33 + */
34 +public class NettyProtocolClient implements ProtocolClient {
35 +
36 + private final Logger log = getLogger(getClass());
37 + private static final ThreadFactory THREAD_FACTORY =
38 + new ThreadFactoryBuilder().setNameFormat("copycat-netty-messaging-%d").build();
39 +
40 + // Remote endpoint, this client instance is used
41 + // for communicating with.
42 + private final Endpoint remoteEp;
43 + private final NettyMessagingService messagingService;
44 +
45 + // TODO: Is 10 the right number of threads?
46 + private static final ScheduledExecutorService THREAD_POOL =
47 + new ScheduledThreadPoolExecutor(10, THREAD_FACTORY);
48 +
49 + public NettyProtocolClient(NettyProtocol protocol, TcpMember member) {
50 + this(new Endpoint(member.host(), member.port()), protocol.getServer().getNettyMessagingService());
51 + }
52 +
53 + public NettyProtocolClient(Endpoint remoteEp, NettyMessagingService messagingService) {
54 + this.remoteEp = remoteEp;
55 + this.messagingService = messagingService;
56 + }
57 +
58 + @Override
59 + public CompletableFuture<PingResponse> ping(PingRequest request) {
60 + return requestReply(request);
61 + }
62 +
63 + @Override
64 + public CompletableFuture<SyncResponse> sync(SyncRequest request) {
65 + return requestReply(request);
66 + }
67 +
68 + @Override
69 + public CompletableFuture<PollResponse> poll(PollRequest request) {
70 + return requestReply(request);
71 + }
72 +
73 + @Override
74 + public CompletableFuture<SubmitResponse> submit(SubmitRequest request) {
75 + return requestReply(request);
76 + }
77 +
78 + @Override
79 + public CompletableFuture<Void> connect() {
80 + return CompletableFuture.completedFuture(null);
81 + }
82 +
83 + @Override
84 + public CompletableFuture<Void> close() {
85 + return CompletableFuture.completedFuture(null);
86 + }
87 +
88 + public <I> String messageType(I input) {
89 + Class<?> clazz = input.getClass();
90 + if (clazz.equals(PollRequest.class)) {
91 + return NettyProtocol.COPYCAT_POLL;
92 + } else if (clazz.equals(SyncRequest.class)) {
93 + return NettyProtocol.COPYCAT_SYNC;
94 + } else if (clazz.equals(SubmitRequest.class)) {
95 + return NettyProtocol.COPYCAT_SUBMIT;
96 + } else if (clazz.equals(PingRequest.class)) {
97 + return NettyProtocol.COPYCAT_PING;
98 + } else {
99 + throw new IllegalArgumentException("Unknown class " + clazz.getName());
100 + }
101 +
102 + }
103 +
104 + private <I, O> CompletableFuture<O> requestReply(I request) {
105 + CompletableFuture<O> future = new CompletableFuture<>();
106 + THREAD_POOL.schedule(new RPCTask<I, O>(request, future), 0, TimeUnit.MILLISECONDS);
107 + return future;
108 + }
109 +
110 + private class RPCTask<I, O> implements Runnable {
111 +
112 + private final String messageType;
113 + private final byte[] payload;
114 +
115 + private final CompletableFuture<O> future;
116 +
117 + public RPCTask(I request, CompletableFuture<O> future) {
118 + this.messageType = messageType(request);
119 + this.payload = NettyProtocol.SERIALIZER.encode(request);
120 + this.future = future;
121 + }
122 +
123 + @Override
124 + public void run() {
125 + try {
126 + byte[] response = messagingService
127 + .sendAndReceive(remoteEp, messageType, payload)
128 + .get(NettyProtocol.RETRY_INTERVAL_MILLIS, TimeUnit.MILLISECONDS);
129 + future.complete(NettyProtocol.SERIALIZER.decode(response));
130 +
131 + } catch (IOException | InterruptedException | ExecutionException | TimeoutException e) {
132 + if (messageType.equals(NettyProtocol.COPYCAT_SYNC) ||
133 + messageType.equals(NettyProtocol.COPYCAT_PING)) {
134 + log.warn("Request to {} failed. Will retry "
135 + + "in {} ms", remoteEp, NettyProtocol.RETRY_INTERVAL_MILLIS);
136 + THREAD_POOL.schedule(
137 + this,
138 + NettyProtocol.RETRY_INTERVAL_MILLIS,
139 + TimeUnit.MILLISECONDS);
140 + } else {
141 + future.completeExceptionally(e);
142 + }
143 + } catch (Exception e) {
144 + future.completeExceptionally(e);
145 + }
146 + }
147 + }
148 +}
1 +package org.onlab.onos.store.service.impl;
2 +
3 +import static org.slf4j.LoggerFactory.getLogger;
4 +
5 +import java.io.IOException;
6 +import java.util.concurrent.CompletableFuture;
7 +
8 +import net.kuujo.copycat.cluster.TcpMember;
9 +import net.kuujo.copycat.protocol.PingRequest;
10 +import net.kuujo.copycat.protocol.PollRequest;
11 +import net.kuujo.copycat.protocol.RequestHandler;
12 +import net.kuujo.copycat.protocol.SubmitRequest;
13 +import net.kuujo.copycat.protocol.SyncRequest;
14 +import net.kuujo.copycat.spi.protocol.ProtocolServer;
15 +
16 +import org.onlab.netty.Message;
17 +import org.onlab.netty.MessageHandler;
18 +import org.onlab.netty.NettyMessagingService;
19 +import org.slf4j.Logger;
20 +
21 +/**
22 + * {@link NettyMessagingService} based Copycat protocol server.
23 + */
24 +public class NettyProtocolServer implements ProtocolServer {
25 +
26 + private final Logger log = getLogger(getClass());
27 +
28 + private final NettyMessagingService messagingService;
29 + private RequestHandler handler;
30 +
31 +
32 + public NettyProtocolServer(TcpMember member) {
33 + messagingService = new NettyMessagingService(member.host(), member.port());
34 +
35 + messagingService.registerHandler(NettyProtocol.COPYCAT_PING, new CopycatMessageHandler<PingRequest>());
36 + messagingService.registerHandler(NettyProtocol.COPYCAT_SYNC, new CopycatMessageHandler<SyncRequest>());
37 + messagingService.registerHandler(NettyProtocol.COPYCAT_POLL, new CopycatMessageHandler<PollRequest>());
38 + messagingService.registerHandler(NettyProtocol.COPYCAT_SUBMIT, new CopycatMessageHandler<SubmitRequest>());
39 + }
40 +
41 + protected NettyMessagingService getNettyMessagingService() {
42 + return messagingService;
43 + }
44 +
45 + @Override
46 + public void requestHandler(RequestHandler handler) {
47 + this.handler = handler;
48 + }
49 +
50 + @Override
51 + public CompletableFuture<Void> listen() {
52 + try {
53 + messagingService.activate();
54 + return CompletableFuture.completedFuture(null);
55 + } catch (Exception e) {
56 + CompletableFuture<Void> future = new CompletableFuture<>();
57 + future.completeExceptionally(e);
58 + return future;
59 + }
60 + }
61 +
62 + @Override
63 + public CompletableFuture<Void> close() {
64 + CompletableFuture<Void> future = new CompletableFuture<>();
65 + try {
66 + messagingService.deactivate();
67 + future.complete(null);
68 + return future;
69 + } catch (Exception e) {
70 + future.completeExceptionally(e);
71 + return future;
72 + }
73 + }
74 +
75 + private class CopycatMessageHandler<T> implements MessageHandler {
76 +
77 + @Override
78 + public void handle(Message message) throws IOException {
79 + T request = NettyProtocol.SERIALIZER.decode(message.payload());
80 + if (request.getClass().equals(PingRequest.class)) {
81 + handler.ping((PingRequest) request).whenComplete((response, error) -> {
82 + try {
83 + message.respond(NettyProtocol.SERIALIZER.encode(response));
84 + } catch (Exception e) {
85 + log.error("Failed to respond to ping request", e);
86 + }
87 + });
88 + } else if (request.getClass().equals(PollRequest.class)) {
89 + handler.poll((PollRequest) request).whenComplete((response, error) -> {
90 + try {
91 + message.respond(NettyProtocol.SERIALIZER.encode(response));
92 + } catch (Exception e) {
93 + log.error("Failed to respond to poll request", e);
94 + }
95 + });
96 + } else if (request.getClass().equals(SyncRequest.class)) {
97 + handler.sync((SyncRequest) request).whenComplete((response, error) -> {
98 + try {
99 + message.respond(NettyProtocol.SERIALIZER.encode(response));
100 + } catch (Exception e) {
101 + log.error("Failed to respond to sync request", e);
102 + }
103 + });
104 + } else if (request.getClass().equals(SubmitRequest.class)) {
105 + handler.submit((SubmitRequest) request).whenComplete((response, error) -> {
106 + try {
107 + message.respond(NettyProtocol.SERIALIZER.encode(response));
108 + } catch (Exception e) {
109 + log.error("Failed to respond to submit request", e);
110 + }
111 + });
112 + }
113 + }
114 + }
115 +}
1 +package org.onlab.onos.store.service.impl;
2 +
3 +import java.util.Arrays;
4 +
5 +/**
6 + * Wrapper object that holds the object (as byte array) and its version.
7 + */
8 +public class VersionedValue {
9 +
10 + private final byte[] value;
11 + private final long version;
12 +
13 + /**
14 + * Creates a new instance with the specified value and version.
15 + * @param value
16 + * @param version
17 + */
18 + public VersionedValue(byte[] value, long version) {
19 + this.value = value;
20 + this.version = version;
21 + }
22 +
23 + /**
24 + * Returns the value.
25 + * @return value.
26 + */
27 + public byte[] value() {
28 + return value;
29 + }
30 +
31 + /**
32 + * Returns the version.
33 + * @return version.
34 + */
35 + public long version() {
36 + return version;
37 + }
38 +
39 + @Override
40 + public String toString() {
41 + return "VersionedValue [value=" + Arrays.toString(value) + ", version="
42 + + version + "]";
43 + }
44 +}
...@@ -32,9 +32,15 @@ public class RoleReplyInfo { ...@@ -32,9 +32,15 @@ public class RoleReplyInfo {
32 this.genId = genId; 32 this.genId = genId;
33 this.xid = xid; 33 this.xid = xid;
34 } 34 }
35 - public RoleState getRole() { return role; } 35 + public RoleState getRole() {
36 - public U64 getGenId() { return genId; } 36 + return role;
37 - public long getXid() { return xid; } 37 + }
38 + public U64 getGenId() {
39 + return genId;
40 + }
41 + public long getXid() {
42 + return xid;
43 + }
38 @Override 44 @Override
39 public String toString() { 45 public String toString() {
40 return "[Role:" + role + " GenId:" + genId + " Xid:" + xid + "]"; 46 return "[Role:" + role + " GenId:" + genId + " Xid:" + xid + "]";
......
...@@ -347,7 +347,7 @@ class RoleManager implements RoleHandler { ...@@ -347,7 +347,7 @@ class RoleManager implements RoleHandler {
347 347
348 RoleState role = null; 348 RoleState role = null;
349 OFNiciraControllerRole ncr = nrr.getRole(); 349 OFNiciraControllerRole ncr = nrr.getRole();
350 - switch(ncr) { 350 + switch (ncr) {
351 case ROLE_MASTER: 351 case ROLE_MASTER:
352 role = RoleState.MASTER; 352 role = RoleState.MASTER;
353 break; 353 break;
...@@ -383,7 +383,7 @@ class RoleManager implements RoleHandler { ...@@ -383,7 +383,7 @@ class RoleManager implements RoleHandler {
383 throws SwitchStateException { 383 throws SwitchStateException {
384 OFControllerRole cr = rrmsg.getRole(); 384 OFControllerRole cr = rrmsg.getRole();
385 RoleState role = null; 385 RoleState role = null;
386 - switch(cr) { 386 + switch (cr) {
387 case ROLE_EQUAL: 387 case ROLE_EQUAL:
388 role = RoleState.EQUAL; 388 role = RoleState.EQUAL;
389 break; 389 break;
......
...@@ -414,7 +414,7 @@ ...@@ -414,7 +414,7 @@
414 <plugin> 414 <plugin>
415 <groupId>org.apache.felix</groupId> 415 <groupId>org.apache.felix</groupId>
416 <artifactId>maven-bundle-plugin</artifactId> 416 <artifactId>maven-bundle-plugin</artifactId>
417 - <version>2.3.7</version> 417 + <version>2.5.3</version>
418 <extensions>true</extensions> 418 <extensions>true</extensions>
419 </plugin> 419 </plugin>
420 420
...@@ -493,6 +493,12 @@ ...@@ -493,6 +493,12 @@
493 <artifactId>onos-build-conf</artifactId> 493 <artifactId>onos-build-conf</artifactId>
494 <version>1.0</version> 494 <version>1.0</version>
495 </dependency> 495 </dependency>
496 + <!-- For Java 8 lambda support-->
497 + <dependency>
498 + <groupId>com.puppycrawl.tools</groupId>
499 + <artifactId>checkstyle</artifactId>
500 + <version>5.9</version>
501 + </dependency>
496 </dependencies> 502 </dependencies>
497 <configuration> 503 <configuration>
498 <configLocation>onos/checkstyle.xml</configLocation> 504 <configLocation>onos/checkstyle.xml</configLocation>
......
...@@ -50,7 +50,7 @@ public class MessageDecoder extends ReplayingDecoder<DecoderState> { ...@@ -50,7 +50,7 @@ public class MessageDecoder extends ReplayingDecoder<DecoderState> {
50 ByteBuf buffer, 50 ByteBuf buffer,
51 List<Object> out) throws Exception { 51 List<Object> out) throws Exception {
52 52
53 - switch(state()) { 53 + switch (state()) {
54 case READ_HEADER_VERSION: 54 case READ_HEADER_VERSION:
55 int headerVersion = buffer.readInt(); 55 int headerVersion = buffer.readInt();
56 checkState(headerVersion == MessageEncoder.HEADER_VERSION, "Unexpected header version"); 56 checkState(headerVersion == MessageEncoder.HEADER_VERSION, "Unexpected header version");
......