Yuta HIGUCHI

Wait for Leader to appear

- DatabaseClient: wait for Leader before DB access
- DatabaseManager: wait for Leader before activate

Change-Id: I5102e7cae1d33f49662bf452b1fba020173a51a0
1 package org.onlab.onos.store.service.impl; 1 package org.onlab.onos.store.service.impl;
2 2
3 import static com.google.common.base.Preconditions.checkNotNull; 3 import static com.google.common.base.Preconditions.checkNotNull;
4 +import static org.slf4j.LoggerFactory.getLogger;
4 5
5 import java.util.List; 6 import java.util.List;
6 import java.util.Map; 7 import java.util.Map;
7 import java.util.Set; 8 import java.util.Set;
8 import java.util.concurrent.CompletableFuture; 9 import java.util.concurrent.CompletableFuture;
10 +import java.util.concurrent.CountDownLatch;
9 import java.util.concurrent.ExecutionException; 11 import java.util.concurrent.ExecutionException;
12 +import java.util.concurrent.TimeUnit;
10 13
11 import net.kuujo.copycat.Copycat; 14 import net.kuujo.copycat.Copycat;
15 +import net.kuujo.copycat.event.EventHandler;
16 +import net.kuujo.copycat.event.LeaderElectEvent;
12 17
13 import org.onlab.onos.store.service.BatchReadRequest; 18 import org.onlab.onos.store.service.BatchReadRequest;
14 import org.onlab.onos.store.service.BatchWriteRequest; 19 import org.onlab.onos.store.service.BatchWriteRequest;
...@@ -16,20 +21,54 @@ import org.onlab.onos.store.service.DatabaseException; ...@@ -16,20 +21,54 @@ import org.onlab.onos.store.service.DatabaseException;
16 import org.onlab.onos.store.service.ReadResult; 21 import org.onlab.onos.store.service.ReadResult;
17 import org.onlab.onos.store.service.VersionedValue; 22 import org.onlab.onos.store.service.VersionedValue;
18 import org.onlab.onos.store.service.WriteResult; 23 import org.onlab.onos.store.service.WriteResult;
24 +import org.slf4j.Logger;
19 25
20 /** 26 /**
21 * Client for interacting with the Copycat Raft cluster. 27 * Client for interacting with the Copycat Raft cluster.
22 */ 28 */
23 public class DatabaseClient { 29 public class DatabaseClient {
24 30
31 + private final Logger log = getLogger(getClass());
32 +
25 private final Copycat copycat; 33 private final Copycat copycat;
26 34
27 public DatabaseClient(Copycat copycat) { 35 public DatabaseClient(Copycat copycat) {
28 this.copycat = checkNotNull(copycat); 36 this.copycat = checkNotNull(copycat);
29 } 37 }
30 38
31 - public boolean createTable(String tableName) { 39 + public void waitForLeader() {
40 + if (copycat.leader() != null) {
41 + return;
42 + }
43 +
44 + log.info("No leader in cluster, waiting for election.");
45 + final CountDownLatch latch = new CountDownLatch(1);
46 + final EventHandler<LeaderElectEvent> leaderLsnr = new EventHandler<LeaderElectEvent>() {
47 +
48 + @Override
49 + public void handle(LeaderElectEvent event) {
50 + log.info("Leader chosen: {}", event);
51 + latch.countDown();
52 + }
53 + };
54 +
55 + copycat.event(LeaderElectEvent.class).registerHandler(leaderLsnr);
56 + try {
57 + while (copycat.leader() == null) {
58 + latch.await(200, TimeUnit.MILLISECONDS);
59 + }
60 + log.info("Leader appeared: {}", copycat.leader());
61 + return;
62 + } catch (InterruptedException e) {
63 + log.error("Interrupted while waiting for Leader", e);
64 + Thread.currentThread().interrupt();
65 + } finally {
66 + copycat.event(LeaderElectEvent.class).unregisterHandler(leaderLsnr);
67 + }
68 + }
32 69
70 + public boolean createTable(String tableName) {
71 + waitForLeader();
33 CompletableFuture<Boolean> future = copycat.submit("createTable", tableName); 72 CompletableFuture<Boolean> future = copycat.submit("createTable", tableName);
34 try { 73 try {
35 return future.get(); 74 return future.get();
...@@ -39,7 +78,7 @@ public class DatabaseClient { ...@@ -39,7 +78,7 @@ public class DatabaseClient {
39 } 78 }
40 79
41 public boolean createTable(String tableName, int ttlMillis) { 80 public boolean createTable(String tableName, int ttlMillis) {
42 - 81 + waitForLeader();
43 CompletableFuture<Boolean> future = copycat.submit("createTableWithExpiration", tableName); 82 CompletableFuture<Boolean> future = copycat.submit("createTableWithExpiration", tableName);
44 try { 83 try {
45 return future.get(); 84 return future.get();
...@@ -49,7 +88,7 @@ public class DatabaseClient { ...@@ -49,7 +88,7 @@ public class DatabaseClient {
49 } 88 }
50 89
51 public void dropTable(String tableName) { 90 public void dropTable(String tableName) {
52 - 91 + waitForLeader();
53 CompletableFuture<Void> future = copycat.submit("dropTable", tableName); 92 CompletableFuture<Void> future = copycat.submit("dropTable", tableName);
54 try { 93 try {
55 future.get(); 94 future.get();
...@@ -59,7 +98,7 @@ public class DatabaseClient { ...@@ -59,7 +98,7 @@ public class DatabaseClient {
59 } 98 }
60 99
61 public void dropAllTables() { 100 public void dropAllTables() {
62 - 101 + waitForLeader();
63 CompletableFuture<Void> future = copycat.submit("dropAllTables"); 102 CompletableFuture<Void> future = copycat.submit("dropAllTables");
64 try { 103 try {
65 future.get(); 104 future.get();
...@@ -69,7 +108,7 @@ public class DatabaseClient { ...@@ -69,7 +108,7 @@ public class DatabaseClient {
69 } 108 }
70 109
71 public Set<String> listTables() { 110 public Set<String> listTables() {
72 - 111 + waitForLeader();
73 CompletableFuture<Set<String>> future = copycat.submit("listTables"); 112 CompletableFuture<Set<String>> future = copycat.submit("listTables");
74 try { 113 try {
75 return future.get(); 114 return future.get();
...@@ -79,7 +118,7 @@ public class DatabaseClient { ...@@ -79,7 +118,7 @@ public class DatabaseClient {
79 } 118 }
80 119
81 public List<ReadResult> batchRead(BatchReadRequest batchRequest) { 120 public List<ReadResult> batchRead(BatchReadRequest batchRequest) {
82 - 121 + waitForLeader();
83 CompletableFuture<List<ReadResult>> future = copycat.submit("read", batchRequest); 122 CompletableFuture<List<ReadResult>> future = copycat.submit("read", batchRequest);
84 try { 123 try {
85 return future.get(); 124 return future.get();
...@@ -89,7 +128,7 @@ public class DatabaseClient { ...@@ -89,7 +128,7 @@ public class DatabaseClient {
89 } 128 }
90 129
91 public List<WriteResult> batchWrite(BatchWriteRequest batchRequest) { 130 public List<WriteResult> batchWrite(BatchWriteRequest batchRequest) {
92 - 131 + waitForLeader();
93 CompletableFuture<List<WriteResult>> future = copycat.submit("write", batchRequest); 132 CompletableFuture<List<WriteResult>> future = copycat.submit("write", batchRequest);
94 try { 133 try {
95 return future.get(); 134 return future.get();
...@@ -99,6 +138,7 @@ public class DatabaseClient { ...@@ -99,6 +138,7 @@ public class DatabaseClient {
99 } 138 }
100 139
101 public Map<String, VersionedValue> getAll(String tableName) { 140 public Map<String, VersionedValue> getAll(String tableName) {
141 + waitForLeader();
102 CompletableFuture<Map<String, VersionedValue>> future = copycat.submit("getAll", tableName); 142 CompletableFuture<Map<String, VersionedValue>> future = copycat.submit("getAll", tableName);
103 try { 143 try {
104 return future.get(); 144 return future.get();
......
...@@ -10,6 +10,7 @@ import java.util.HashSet; ...@@ -10,6 +10,7 @@ import java.util.HashSet;
10 import java.util.Map; 10 import java.util.Map;
11 import java.util.Set; 11 import java.util.Set;
12 import java.util.concurrent.CountDownLatch; 12 import java.util.concurrent.CountDownLatch;
13 +import java.util.concurrent.ExecutionException;
13 import java.util.concurrent.TimeUnit; 14 import java.util.concurrent.TimeUnit;
14 15
15 import net.kuujo.copycat.Copycat; 16 import net.kuujo.copycat.Copycat;
...@@ -99,7 +100,7 @@ public class DatabaseManager implements DatabaseService, DatabaseAdminService { ...@@ -99,7 +100,7 @@ public class DatabaseManager implements DatabaseService, DatabaseAdminService {
99 private boolean autoAddMember = false; 100 private boolean autoAddMember = false;
100 101
101 @Activate 102 @Activate
102 - public void activate() { 103 + public void activate() throws InterruptedException, ExecutionException {
103 104
104 // TODO: Not every node should be part of the consensus ring. 105 // TODO: Not every node should be part of the consensus ring.
105 106
...@@ -176,9 +177,10 @@ public class DatabaseManager implements DatabaseService, DatabaseAdminService { ...@@ -176,9 +177,10 @@ public class DatabaseManager implements DatabaseService, DatabaseAdminService {
176 177
177 copycat.event(LeaderElectEvent.class).registerHandler(expirationTracker); 178 copycat.event(LeaderElectEvent.class).registerHandler(expirationTracker);
178 179
179 - copycat.start(); 180 + copycat.start().get();
180 181
181 client = new DatabaseClient(copycat); 182 client = new DatabaseClient(copycat);
183 + client.waitForLeader();
182 184
183 log.info("Started."); 185 log.info("Started.");
184 } 186 }
......