Enabled leadership service implementation based on consistent map + added precon…
…dition checks to partitioned database. Change-Id: Ia76f8479d9113e7ad67e583e4ca157e62a1cabc7
Showing
5 changed files
with
39 additions
and
5 deletions
... | @@ -73,7 +73,7 @@ import static org.onlab.util.Tools.groupedThreads; | ... | @@ -73,7 +73,7 @@ import static org.onlab.util.Tools.groupedThreads; |
73 | * the current leader (e.g., for informational purpose). | 73 | * the current leader (e.g., for informational purpose). |
74 | * </p> | 74 | * </p> |
75 | */ | 75 | */ |
76 | -@Component(immediate = true) | 76 | +@Component(immediate = true, enabled = false) |
77 | @Service | 77 | @Service |
78 | public class HazelcastLeadershipService implements LeadershipService { | 78 | public class HazelcastLeadershipService implements LeadershipService { |
79 | private static final Logger log = | 79 | private static final Logger log = | ... | ... |
... | @@ -145,7 +145,7 @@ public class DatabaseManager implements StorageService, StorageAdminService { | ... | @@ -145,7 +145,7 @@ public class DatabaseManager implements StorageService, StorageAdminService { |
145 | }); | 145 | }); |
146 | try { | 146 | try { |
147 | if (!latch.await(DATABASE_STARTUP_TIMEOUT_SEC, TimeUnit.SECONDS)) { | 147 | if (!latch.await(DATABASE_STARTUP_TIMEOUT_SEC, TimeUnit.SECONDS)) { |
148 | - log.warn("Timeed out watiing for database to initialize."); | 148 | + log.warn("Timed out waiting for database to initialize."); |
149 | } | 149 | } |
150 | } catch (InterruptedException e) { | 150 | } catch (InterruptedException e) { |
151 | Thread.currentThread().interrupt(); | 151 | Thread.currentThread().interrupt(); | ... | ... |
... | @@ -52,7 +52,7 @@ import com.google.common.collect.Sets; | ... | @@ -52,7 +52,7 @@ import com.google.common.collect.Sets; |
52 | * detection capabilities to detect and purge stale locks. | 52 | * detection capabilities to detect and purge stale locks. |
53 | * TODO: Ensure lock safety and liveness. | 53 | * TODO: Ensure lock safety and liveness. |
54 | */ | 54 | */ |
55 | -@Component(immediate = true, enabled = false) | 55 | +@Component(immediate = true, enabled = true) |
56 | @Service | 56 | @Service |
57 | public class DistributedLeadershipManager implements LeadershipService { | 57 | public class DistributedLeadershipManager implements LeadershipService { |
58 | 58 | ... | ... |
... | @@ -36,6 +36,8 @@ import com.google.common.collect.Sets; | ... | @@ -36,6 +36,8 @@ import com.google.common.collect.Sets; |
36 | 36 | ||
37 | import net.kuujo.copycat.cluster.internal.coordinator.ClusterCoordinator; | 37 | import net.kuujo.copycat.cluster.internal.coordinator.ClusterCoordinator; |
38 | 38 | ||
39 | +import static com.google.common.base.Preconditions.checkState; | ||
40 | + | ||
39 | /** | 41 | /** |
40 | * A database that partitions the keys across one or more database partitions. | 42 | * A database that partitions the keys across one or more database partitions. |
41 | */ | 43 | */ |
... | @@ -44,11 +46,21 @@ public class PartitionedDatabase implements DatabaseProxy<String, byte[]>, Parti | ... | @@ -44,11 +46,21 @@ public class PartitionedDatabase implements DatabaseProxy<String, byte[]>, Parti |
44 | private Partitioner<String> partitioner; | 46 | private Partitioner<String> partitioner; |
45 | private final ClusterCoordinator coordinator; | 47 | private final ClusterCoordinator coordinator; |
46 | private final Map<String, Database> partitions = Maps.newConcurrentMap(); | 48 | private final Map<String, Database> partitions = Maps.newConcurrentMap(); |
49 | + private final AtomicBoolean isOpen = new AtomicBoolean(false); | ||
50 | + private static final String DB_NOT_OPEN = "Database is not open"; | ||
47 | 51 | ||
48 | protected PartitionedDatabase(ClusterCoordinator coordinator) { | 52 | protected PartitionedDatabase(ClusterCoordinator coordinator) { |
49 | this.coordinator = coordinator; | 53 | this.coordinator = coordinator; |
50 | } | 54 | } |
51 | 55 | ||
56 | + /** | ||
57 | + * Returns true if the database is open. | ||
58 | + * @return true if open, false otherwise | ||
59 | + */ | ||
60 | + public boolean isOpen() { | ||
61 | + return isOpen.get(); | ||
62 | + } | ||
63 | + | ||
52 | @Override | 64 | @Override |
53 | public void registerPartition(String name, Database partition) { | 65 | public void registerPartition(String name, Database partition) { |
54 | partitions.put(name, partition); | 66 | partitions.put(name, partition); |
... | @@ -61,6 +73,7 @@ public class PartitionedDatabase implements DatabaseProxy<String, byte[]>, Parti | ... | @@ -61,6 +73,7 @@ public class PartitionedDatabase implements DatabaseProxy<String, byte[]>, Parti |
61 | 73 | ||
62 | @Override | 74 | @Override |
63 | public CompletableFuture<Integer> size(String tableName) { | 75 | public CompletableFuture<Integer> size(String tableName) { |
76 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
64 | AtomicInteger totalSize = new AtomicInteger(0); | 77 | AtomicInteger totalSize = new AtomicInteger(0); |
65 | return CompletableFuture.allOf(partitions | 78 | return CompletableFuture.allOf(partitions |
66 | .values() | 79 | .values() |
... | @@ -72,16 +85,19 @@ public class PartitionedDatabase implements DatabaseProxy<String, byte[]>, Parti | ... | @@ -72,16 +85,19 @@ public class PartitionedDatabase implements DatabaseProxy<String, byte[]>, Parti |
72 | 85 | ||
73 | @Override | 86 | @Override |
74 | public CompletableFuture<Boolean> isEmpty(String tableName) { | 87 | public CompletableFuture<Boolean> isEmpty(String tableName) { |
88 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
75 | return size(tableName).thenApply(size -> size == 0); | 89 | return size(tableName).thenApply(size -> size == 0); |
76 | } | 90 | } |
77 | 91 | ||
78 | @Override | 92 | @Override |
79 | public CompletableFuture<Boolean> containsKey(String tableName, String key) { | 93 | public CompletableFuture<Boolean> containsKey(String tableName, String key) { |
94 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
80 | return partitioner.getPartition(tableName, key).containsKey(tableName, key); | 95 | return partitioner.getPartition(tableName, key).containsKey(tableName, key); |
81 | } | 96 | } |
82 | 97 | ||
83 | @Override | 98 | @Override |
84 | public CompletableFuture<Boolean> containsValue(String tableName, byte[] value) { | 99 | public CompletableFuture<Boolean> containsValue(String tableName, byte[] value) { |
100 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
85 | AtomicBoolean containsValue = new AtomicBoolean(false); | 101 | AtomicBoolean containsValue = new AtomicBoolean(false); |
86 | return CompletableFuture.allOf(partitions | 102 | return CompletableFuture.allOf(partitions |
87 | .values() | 103 | .values() |
... | @@ -93,21 +109,25 @@ public class PartitionedDatabase implements DatabaseProxy<String, byte[]>, Parti | ... | @@ -93,21 +109,25 @@ public class PartitionedDatabase implements DatabaseProxy<String, byte[]>, Parti |
93 | 109 | ||
94 | @Override | 110 | @Override |
95 | public CompletableFuture<Versioned<byte[]>> get(String tableName, String key) { | 111 | public CompletableFuture<Versioned<byte[]>> get(String tableName, String key) { |
112 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
96 | return partitioner.getPartition(tableName, key).get(tableName, key); | 113 | return partitioner.getPartition(tableName, key).get(tableName, key); |
97 | } | 114 | } |
98 | 115 | ||
99 | @Override | 116 | @Override |
100 | public CompletableFuture<Versioned<byte[]>> put(String tableName, String key, byte[] value) { | 117 | public CompletableFuture<Versioned<byte[]>> put(String tableName, String key, byte[] value) { |
118 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
101 | return partitioner.getPartition(tableName, key).put(tableName, key, value); | 119 | return partitioner.getPartition(tableName, key).put(tableName, key, value); |
102 | } | 120 | } |
103 | 121 | ||
104 | @Override | 122 | @Override |
105 | public CompletableFuture<Versioned<byte[]>> remove(String tableName, String key) { | 123 | public CompletableFuture<Versioned<byte[]>> remove(String tableName, String key) { |
124 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
106 | return partitioner.getPartition(tableName, key).remove(tableName, key); | 125 | return partitioner.getPartition(tableName, key).remove(tableName, key); |
107 | } | 126 | } |
108 | 127 | ||
109 | @Override | 128 | @Override |
110 | public CompletableFuture<Void> clear(String tableName) { | 129 | public CompletableFuture<Void> clear(String tableName) { |
130 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
111 | return CompletableFuture.allOf(partitions | 131 | return CompletableFuture.allOf(partitions |
112 | .values() | 132 | .values() |
113 | .stream() | 133 | .stream() |
... | @@ -117,6 +137,7 @@ public class PartitionedDatabase implements DatabaseProxy<String, byte[]>, Parti | ... | @@ -117,6 +137,7 @@ public class PartitionedDatabase implements DatabaseProxy<String, byte[]>, Parti |
117 | 137 | ||
118 | @Override | 138 | @Override |
119 | public CompletableFuture<Set<String>> keySet(String tableName) { | 139 | public CompletableFuture<Set<String>> keySet(String tableName) { |
140 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
120 | Set<String> keySet = Sets.newConcurrentHashSet(); | 141 | Set<String> keySet = Sets.newConcurrentHashSet(); |
121 | return CompletableFuture.allOf(partitions | 142 | return CompletableFuture.allOf(partitions |
122 | .values() | 143 | .values() |
... | @@ -128,6 +149,7 @@ public class PartitionedDatabase implements DatabaseProxy<String, byte[]>, Parti | ... | @@ -128,6 +149,7 @@ public class PartitionedDatabase implements DatabaseProxy<String, byte[]>, Parti |
128 | 149 | ||
129 | @Override | 150 | @Override |
130 | public CompletableFuture<Collection<Versioned<byte[]>>> values(String tableName) { | 151 | public CompletableFuture<Collection<Versioned<byte[]>>> values(String tableName) { |
152 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
131 | List<Versioned<byte[]>> values = new CopyOnWriteArrayList<>(); | 153 | List<Versioned<byte[]>> values = new CopyOnWriteArrayList<>(); |
132 | return CompletableFuture.allOf(partitions | 154 | return CompletableFuture.allOf(partitions |
133 | .values() | 155 | .values() |
... | @@ -139,6 +161,7 @@ public class PartitionedDatabase implements DatabaseProxy<String, byte[]>, Parti | ... | @@ -139,6 +161,7 @@ public class PartitionedDatabase implements DatabaseProxy<String, byte[]>, Parti |
139 | 161 | ||
140 | @Override | 162 | @Override |
141 | public CompletableFuture<Set<Entry<String, Versioned<byte[]>>>> entrySet(String tableName) { | 163 | public CompletableFuture<Set<Entry<String, Versioned<byte[]>>>> entrySet(String tableName) { |
164 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
142 | Set<Entry<String, Versioned<byte[]>>> entrySet = Sets.newConcurrentHashSet(); | 165 | Set<Entry<String, Versioned<byte[]>>> entrySet = Sets.newConcurrentHashSet(); |
143 | return CompletableFuture.allOf(partitions | 166 | return CompletableFuture.allOf(partitions |
144 | .values() | 167 | .values() |
... | @@ -150,31 +173,37 @@ public class PartitionedDatabase implements DatabaseProxy<String, byte[]>, Parti | ... | @@ -150,31 +173,37 @@ public class PartitionedDatabase implements DatabaseProxy<String, byte[]>, Parti |
150 | 173 | ||
151 | @Override | 174 | @Override |
152 | public CompletableFuture<Versioned<byte[]>> putIfAbsent(String tableName, String key, byte[] value) { | 175 | public CompletableFuture<Versioned<byte[]>> putIfAbsent(String tableName, String key, byte[] value) { |
176 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
153 | return partitioner.getPartition(tableName, key).putIfAbsent(tableName, key, value); | 177 | return partitioner.getPartition(tableName, key).putIfAbsent(tableName, key, value); |
154 | } | 178 | } |
155 | 179 | ||
156 | @Override | 180 | @Override |
157 | public CompletableFuture<Boolean> remove(String tableName, String key, byte[] value) { | 181 | public CompletableFuture<Boolean> remove(String tableName, String key, byte[] value) { |
182 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
158 | return partitioner.getPartition(tableName, key).remove(tableName, key, value); | 183 | return partitioner.getPartition(tableName, key).remove(tableName, key, value); |
159 | } | 184 | } |
160 | 185 | ||
161 | @Override | 186 | @Override |
162 | public CompletableFuture<Boolean> remove(String tableName, String key, long version) { | 187 | public CompletableFuture<Boolean> remove(String tableName, String key, long version) { |
188 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
163 | return partitioner.getPartition(tableName, key).remove(tableName, key, version); | 189 | return partitioner.getPartition(tableName, key).remove(tableName, key, version); |
164 | } | 190 | } |
165 | 191 | ||
166 | @Override | 192 | @Override |
167 | public CompletableFuture<Boolean> replace(String tableName, String key, byte[] oldValue, byte[] newValue) { | 193 | public CompletableFuture<Boolean> replace(String tableName, String key, byte[] oldValue, byte[] newValue) { |
194 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
168 | return partitioner.getPartition(tableName, key).replace(tableName, key, oldValue, newValue); | 195 | return partitioner.getPartition(tableName, key).replace(tableName, key, oldValue, newValue); |
169 | } | 196 | } |
170 | 197 | ||
171 | @Override | 198 | @Override |
172 | public CompletableFuture<Boolean> replace(String tableName, String key, long oldVersion, byte[] newValue) { | 199 | public CompletableFuture<Boolean> replace(String tableName, String key, long oldVersion, byte[] newValue) { |
200 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
173 | return partitioner.getPartition(tableName, key).replace(tableName, key, oldVersion, newValue); | 201 | return partitioner.getPartition(tableName, key).replace(tableName, key, oldVersion, newValue); |
174 | } | 202 | } |
175 | 203 | ||
176 | @Override | 204 | @Override |
177 | public CompletableFuture<Boolean> atomicBatchUpdate(List<UpdateOperation<String, byte[]>> updates) { | 205 | public CompletableFuture<Boolean> atomicBatchUpdate(List<UpdateOperation<String, byte[]>> updates) { |
206 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
178 | Map<Database, List<UpdateOperation<String, byte[]>>> perPartitionUpdates = Maps.newHashMap(); | 207 | Map<Database, List<UpdateOperation<String, byte[]>>> perPartitionUpdates = Maps.newHashMap(); |
179 | for (UpdateOperation<String, byte[]> update : updates) { | 208 | for (UpdateOperation<String, byte[]> update : updates) { |
180 | Database partition = partitioner.getPartition(update.tableName(), update.key()); | 209 | Database partition = partitioner.getPartition(update.tableName(), update.key()); |
... | @@ -207,12 +236,15 @@ public class PartitionedDatabase implements DatabaseProxy<String, byte[]>, Parti | ... | @@ -207,12 +236,15 @@ public class PartitionedDatabase implements DatabaseProxy<String, byte[]>, Parti |
207 | .stream() | 236 | .stream() |
208 | .map(Database::open) | 237 | .map(Database::open) |
209 | .toArray(CompletableFuture[]::new)) | 238 | .toArray(CompletableFuture[]::new)) |
210 | - .thenApply(v -> this)); | 239 | + .thenApply(v -> { |
240 | + isOpen.set(true); | ||
241 | + return this; })); | ||
211 | 242 | ||
212 | } | 243 | } |
213 | 244 | ||
214 | @Override | 245 | @Override |
215 | public CompletableFuture<Void> close() { | 246 | public CompletableFuture<Void> close() { |
247 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
216 | CompletableFuture<Void> closePartitions = CompletableFuture.allOf(partitions | 248 | CompletableFuture<Void> closePartitions = CompletableFuture.allOf(partitions |
217 | .values() | 249 | .values() |
218 | .stream() | 250 | .stream() | ... | ... |
... | @@ -33,6 +33,8 @@ import org.onosproject.net.intent.Key; | ... | @@ -33,6 +33,8 @@ import org.onosproject.net.intent.Key; |
33 | import org.slf4j.Logger; | 33 | import org.slf4j.Logger; |
34 | import org.slf4j.LoggerFactory; | 34 | import org.slf4j.LoggerFactory; |
35 | 35 | ||
36 | +import com.google.common.base.Objects; | ||
37 | + | ||
36 | import java.util.List; | 38 | import java.util.List; |
37 | import java.util.concurrent.Executors; | 39 | import java.util.concurrent.Executors; |
38 | import java.util.concurrent.ScheduledExecutorService; | 40 | import java.util.concurrent.ScheduledExecutorService; |
... | @@ -169,7 +171,7 @@ public class PartitionManager implements PartitionService { | ... | @@ -169,7 +171,7 @@ public class PartitionManager implements PartitionService { |
169 | public void event(LeadershipEvent event) { | 171 | public void event(LeadershipEvent event) { |
170 | Leadership leadership = event.subject(); | 172 | Leadership leadership = event.subject(); |
171 | 173 | ||
172 | - if (leadership.leader().equals(clusterService.getLocalNode().id()) && | 174 | + if (Objects.equal(leadership.leader(), clusterService.getLocalNode().id()) && |
173 | leadership.topic().startsWith(ELECTION_PREFIX)) { | 175 | leadership.topic().startsWith(ELECTION_PREFIX)) { |
174 | 176 | ||
175 | // See if we need to let some partitions go | 177 | // See if we need to let some partitions go | ... | ... |
-
Please register or login to post a comment