Wait for Leader to appear
- DatabaseClient: wait for Leader before DB access - DatabaseManager: wait for Leader before activate Change-Id: I5102e7cae1d33f49662bf452b1fba020173a51a0
Showing
2 changed files
with
51 additions
and
9 deletions
| 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 | } | ... | ... |
-
Please register or login to post a comment