Added support for "maps" cli command that displays meta information for various …
…consistent maps in the system Change-Id: I63e590a8520ac9d1238efe4ad0033dcba939e472
Showing
10 changed files
with
214 additions
and
0 deletions
| 1 | +/* | ||
| 2 | + * Copyright 2015 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.cli.net; | ||
| 17 | + | ||
| 18 | +import java.util.List; | ||
| 19 | + | ||
| 20 | +import org.apache.karaf.shell.commands.Command; | ||
| 21 | +import org.onosproject.cli.AbstractShellCommand; | ||
| 22 | +import org.onosproject.store.service.MapInfo; | ||
| 23 | +import org.onosproject.store.service.StorageAdminService; | ||
| 24 | + | ||
| 25 | +import com.fasterxml.jackson.databind.JsonNode; | ||
| 26 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
| 27 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
| 28 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
| 29 | + | ||
| 30 | +/** | ||
| 31 | + * Command to list the various maps in the system. | ||
| 32 | + */ | ||
| 33 | +@Command(scope = "onos", name = "maps", | ||
| 34 | + description = "Lists information about consistent maps in the system") | ||
| 35 | +public class MapsListCommand extends AbstractShellCommand { | ||
| 36 | + | ||
| 37 | + // TODO: Add support to display different eventually | ||
| 38 | + // consistent maps as well. | ||
| 39 | + | ||
| 40 | + private static final String FMT = "%-20s %8s"; | ||
| 41 | + | ||
| 42 | + /** | ||
| 43 | + * Displays map info as text. | ||
| 44 | + * | ||
| 45 | + * @param mapInfo map descriptions | ||
| 46 | + */ | ||
| 47 | + private void displayMaps(List<MapInfo> mapInfo) { | ||
| 48 | + print("------------------------------"); | ||
| 49 | + print(FMT, "Name", "Size"); | ||
| 50 | + print("------------------------------"); | ||
| 51 | + | ||
| 52 | + | ||
| 53 | + for (MapInfo info : mapInfo) { | ||
| 54 | + print(FMT, info.name(), info.size()); | ||
| 55 | + } | ||
| 56 | + if (mapInfo.size() > 0) { | ||
| 57 | + print("------------------------------"); | ||
| 58 | + } | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + /** | ||
| 62 | + * Converts list of map info into a JSON object. | ||
| 63 | + * | ||
| 64 | + * @param mapInfo map descriptions | ||
| 65 | + */ | ||
| 66 | + private JsonNode json(List<MapInfo> mapInfo) { | ||
| 67 | + ObjectMapper mapper = new ObjectMapper(); | ||
| 68 | + ArrayNode maps = mapper.createArrayNode(); | ||
| 69 | + | ||
| 70 | + // Create a JSON node for each map | ||
| 71 | + mapInfo.stream() | ||
| 72 | + .forEach(info -> { | ||
| 73 | + ObjectNode map = mapper.createObjectNode(); | ||
| 74 | + map.put("name", info.name()) | ||
| 75 | + .put("size", info.size()); | ||
| 76 | + maps.add(map); | ||
| 77 | + }); | ||
| 78 | + | ||
| 79 | + return maps; | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + @Override | ||
| 83 | + protected void execute() { | ||
| 84 | + StorageAdminService storageAdminService = get(StorageAdminService.class); | ||
| 85 | + List<MapInfo> mapInfo = storageAdminService.getMapInfo(); | ||
| 86 | + if (outputJson()) { | ||
| 87 | + print("%s", json(mapInfo)); | ||
| 88 | + } else { | ||
| 89 | + displayMaps(mapInfo); | ||
| 90 | + } | ||
| 91 | + } | ||
| 92 | +} |
| ... | @@ -230,6 +230,9 @@ | ... | @@ -230,6 +230,9 @@ |
| 230 | <action class="org.onosproject.cli.net.PartitionsListCommand"/> | 230 | <action class="org.onosproject.cli.net.PartitionsListCommand"/> |
| 231 | </command> | 231 | </command> |
| 232 | <command> | 232 | <command> |
| 233 | + <action class="org.onosproject.cli.net.MapsListCommand"/> | ||
| 234 | + </command> | ||
| 235 | + <command> | ||
| 233 | <action class="org.onosproject.cli.net.ClusterDevicesCommand"/> | 236 | <action class="org.onosproject.cli.net.ClusterDevicesCommand"/> |
| 234 | <completers> | 237 | <completers> |
| 235 | <ref component-id="clusterIdCompleter"/> | 238 | <ref component-id="clusterIdCompleter"/> | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2015 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.store.service; | ||
| 17 | + | ||
| 18 | +/** | ||
| 19 | + * Metadata information for a consistent map. | ||
| 20 | + */ | ||
| 21 | +public class MapInfo { | ||
| 22 | + private final String name; | ||
| 23 | + private final int size; | ||
| 24 | + | ||
| 25 | + public MapInfo(String name, int size) { | ||
| 26 | + this.name = name; | ||
| 27 | + this.size = size; | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * Returns the name of the map. | ||
| 32 | + * | ||
| 33 | + * @return map name | ||
| 34 | + */ | ||
| 35 | + public String name() { | ||
| 36 | + return name; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + /** | ||
| 40 | + * Returns the number of entries in the map. | ||
| 41 | + * | ||
| 42 | + * @return map size | ||
| 43 | + */ | ||
| 44 | + public int size() { | ||
| 45 | + return size; | ||
| 46 | + } | ||
| 47 | +} |
| ... | @@ -28,4 +28,11 @@ public interface StorageAdminService { | ... | @@ -28,4 +28,11 @@ public interface StorageAdminService { |
| 28 | * @return list of partition information | 28 | * @return list of partition information |
| 29 | */ | 29 | */ |
| 30 | List<PartitionInfo> getPartitionInfo(); | 30 | List<PartitionInfo> getPartitionInfo(); |
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * Returns information about all the consistent maps in the system. | ||
| 34 | + * | ||
| 35 | + * @return list of map information | ||
| 36 | + */ | ||
| 37 | + List<MapInfo> getMapInfo(); | ||
| 31 | } | 38 | } | ... | ... |
| ... | @@ -44,7 +44,9 @@ import org.onosproject.store.cluster.impl.NodeInfo; | ... | @@ -44,7 +44,9 @@ import org.onosproject.store.cluster.impl.NodeInfo; |
| 44 | import org.onosproject.store.cluster.messaging.ClusterCommunicationService; | 44 | import org.onosproject.store.cluster.messaging.ClusterCommunicationService; |
| 45 | import org.onosproject.store.ecmap.EventuallyConsistentMapBuilderImpl; | 45 | import org.onosproject.store.ecmap.EventuallyConsistentMapBuilderImpl; |
| 46 | import org.onosproject.store.service.ConsistentMapBuilder; | 46 | import org.onosproject.store.service.ConsistentMapBuilder; |
| 47 | +import org.onosproject.store.service.ConsistentMapException; | ||
| 47 | import org.onosproject.store.service.EventuallyConsistentMapBuilder; | 48 | import org.onosproject.store.service.EventuallyConsistentMapBuilder; |
| 49 | +import org.onosproject.store.service.MapInfo; | ||
| 48 | import org.onosproject.store.service.PartitionInfo; | 50 | import org.onosproject.store.service.PartitionInfo; |
| 49 | import org.onosproject.store.service.StorageAdminService; | 51 | import org.onosproject.store.service.StorageAdminService; |
| 50 | import org.onosproject.store.service.StorageService; | 52 | import org.onosproject.store.service.StorageService; |
| ... | @@ -58,8 +60,10 @@ import java.util.Map; | ... | @@ -58,8 +60,10 @@ import java.util.Map; |
| 58 | import java.util.Set; | 60 | import java.util.Set; |
| 59 | import java.util.concurrent.CompletableFuture; | 61 | import java.util.concurrent.CompletableFuture; |
| 60 | import java.util.concurrent.CountDownLatch; | 62 | import java.util.concurrent.CountDownLatch; |
| 63 | +import java.util.concurrent.ExecutionException; | ||
| 61 | import java.util.concurrent.Executors; | 64 | import java.util.concurrent.Executors; |
| 62 | import java.util.concurrent.TimeUnit; | 65 | import java.util.concurrent.TimeUnit; |
| 66 | +import java.util.concurrent.TimeoutException; | ||
| 63 | import java.util.stream.Collectors; | 67 | import java.util.stream.Collectors; |
| 64 | 68 | ||
| 65 | import static org.slf4j.LoggerFactory.getLogger; | 69 | import static org.slf4j.LoggerFactory.getLogger; |
| ... | @@ -80,6 +84,7 @@ public class DatabaseManager implements StorageService, StorageAdminService { | ... | @@ -80,6 +84,7 @@ public class DatabaseManager implements StorageService, StorageAdminService { |
| 80 | private static final int DATABASE_STARTUP_TIMEOUT_SEC = 60; | 84 | private static final int DATABASE_STARTUP_TIMEOUT_SEC = 60; |
| 81 | private static final int RAFT_ELECTION_TIMEOUT = 3000; | 85 | private static final int RAFT_ELECTION_TIMEOUT = 3000; |
| 82 | private static final int RAFT_HEARTBEAT_TIMEOUT = 1500; | 86 | private static final int RAFT_HEARTBEAT_TIMEOUT = 1500; |
| 87 | + private static final int DATABASE_OPERATION_TIMEOUT_MILLIS = 5000; | ||
| 83 | 88 | ||
| 84 | private ClusterCoordinator coordinator; | 89 | private ClusterCoordinator coordinator; |
| 85 | private PartitionedDatabase partitionedDatabase; | 90 | private PartitionedDatabase partitionedDatabase; |
| ... | @@ -294,4 +299,33 @@ public class DatabaseManager implements StorageService, StorageAdminService { | ... | @@ -294,4 +299,33 @@ public class DatabaseManager implements StorageService, StorageAdminService { |
| 294 | public <K, V> ConsistentMapBuilder<K, V> consistentMapBuilder() { | 299 | public <K, V> ConsistentMapBuilder<K, V> consistentMapBuilder() { |
| 295 | return new DefaultConsistentMapBuilder<>(inMemoryDatabase, partitionedDatabase); | 300 | return new DefaultConsistentMapBuilder<>(inMemoryDatabase, partitionedDatabase); |
| 296 | } | 301 | } |
| 302 | + | ||
| 303 | + @Override | ||
| 304 | + public List<MapInfo> getMapInfo() { | ||
| 305 | + List<MapInfo> maps = Lists.newArrayList(); | ||
| 306 | + maps.addAll(getMapInfo(inMemoryDatabase)); | ||
| 307 | + maps.addAll(getMapInfo(partitionedDatabase)); | ||
| 308 | + return maps; | ||
| 309 | + } | ||
| 310 | + | ||
| 311 | + private List<MapInfo> getMapInfo(Database database) { | ||
| 312 | + return complete(database.tableNames()) | ||
| 313 | + .stream() | ||
| 314 | + .map(name -> new MapInfo(name, complete(database.size(name)))) | ||
| 315 | + .filter(info -> info.size() > 0) | ||
| 316 | + .collect(Collectors.toList()); | ||
| 317 | + } | ||
| 318 | + | ||
| 319 | + private static <T> T complete(CompletableFuture<T> future) { | ||
| 320 | + try { | ||
| 321 | + return future.get(DATABASE_OPERATION_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); | ||
| 322 | + } catch (InterruptedException e) { | ||
| 323 | + Thread.currentThread().interrupt(); | ||
| 324 | + throw new ConsistentMapException.Interrupted(); | ||
| 325 | + } catch (TimeoutException e) { | ||
| 326 | + throw new ConsistentMapException.Timeout(); | ||
| 327 | + } catch (ExecutionException e) { | ||
| 328 | + throw new ConsistentMapException(e.getCause()); | ||
| 329 | + } | ||
| 330 | + } | ||
| 297 | } | 331 | } |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -30,6 +30,12 @@ import org.onosproject.store.service.Versioned; | ... | @@ -30,6 +30,12 @@ import org.onosproject.store.service.Versioned; |
| 30 | */ | 30 | */ |
| 31 | public interface DatabaseProxy<K, V> { | 31 | public interface DatabaseProxy<K, V> { |
| 32 | 32 | ||
| 33 | + /** | ||
| 34 | + * Returns a set of all tables names. | ||
| 35 | + * @return A completable future to be completed with the result once complete. | ||
| 36 | + */ | ||
| 37 | + CompletableFuture<Set<String>> tableNames(); | ||
| 38 | + | ||
| 33 | /** | 39 | /** |
| 34 | * Gets the table size. | 40 | * Gets the table size. |
| 35 | * | 41 | * | ... | ... |
| ... | @@ -44,6 +44,9 @@ public interface DatabaseState<K, V> { | ... | @@ -44,6 +44,9 @@ public interface DatabaseState<K, V> { |
| 44 | public void init(StateContext<DatabaseState<K, V>> context); | 44 | public void init(StateContext<DatabaseState<K, V>> context); |
| 45 | 45 | ||
| 46 | @Query | 46 | @Query |
| 47 | + Set<String> tableNames(); | ||
| 48 | + | ||
| 49 | + @Query | ||
| 47 | int size(String tableName); | 50 | int size(String tableName); |
| 48 | 51 | ||
| 49 | @Query | 52 | @Query | ... | ... |
| ... | @@ -61,6 +61,11 @@ public class DefaultDatabase extends AbstractResource<Database> implements Datab | ... | @@ -61,6 +61,11 @@ public class DefaultDatabase extends AbstractResource<Database> implements Datab |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | @Override | 63 | @Override |
| 64 | + public CompletableFuture<Set<String>> tableNames() { | ||
| 65 | + return checkOpen(() -> proxy.tableNames()); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + @Override | ||
| 64 | public CompletableFuture<Integer> size(String tableName) { | 69 | public CompletableFuture<Integer> size(String tableName) { |
| 65 | return checkOpen(() -> proxy.size(tableName)); | 70 | return checkOpen(() -> proxy.size(tableName)); |
| 66 | } | 71 | } | ... | ... |
| ... | @@ -19,6 +19,7 @@ package org.onosproject.store.consistent.impl; | ... | @@ -19,6 +19,7 @@ package org.onosproject.store.consistent.impl; |
| 19 | import java.util.Arrays; | 19 | import java.util.Arrays; |
| 20 | import java.util.Collection; | 20 | import java.util.Collection; |
| 21 | import java.util.HashMap; | 21 | import java.util.HashMap; |
| 22 | +import java.util.HashSet; | ||
| 22 | import java.util.List; | 23 | import java.util.List; |
| 23 | import java.util.Map; | 24 | import java.util.Map; |
| 24 | import java.util.Map.Entry; | 25 | import java.util.Map.Entry; |
| ... | @@ -71,6 +72,11 @@ public class DefaultDatabaseState<K, V> implements DatabaseState<K, V> { | ... | @@ -71,6 +72,11 @@ public class DefaultDatabaseState<K, V> implements DatabaseState<K, V> { |
| 71 | } | 72 | } |
| 72 | 73 | ||
| 73 | @Override | 74 | @Override |
| 75 | + public Set<String> tableNames() { | ||
| 76 | + return new HashSet<>(tables.keySet()); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + @Override | ||
| 74 | public int size(String tableName) { | 80 | public int size(String tableName) { |
| 75 | return getTableMap(tableName).size(); | 81 | return getTableMap(tableName).size(); |
| 76 | } | 82 | } | ... | ... |
| ... | @@ -78,6 +78,17 @@ public class PartitionedDatabase implements Database { | ... | @@ -78,6 +78,17 @@ public class PartitionedDatabase implements Database { |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | @Override | 80 | @Override |
| 81 | + public CompletableFuture<Set<String>> tableNames() { | ||
| 82 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
| 83 | + Set<String> tableNames = Sets.newConcurrentHashSet(); | ||
| 84 | + return CompletableFuture.allOf(partitions | ||
| 85 | + .stream() | ||
| 86 | + .map(db -> db.tableNames().thenApply(tableNames::addAll)) | ||
| 87 | + .toArray(CompletableFuture[]::new)) | ||
| 88 | + .thenApply(v -> tableNames); | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + @Override | ||
| 81 | public CompletableFuture<Integer> size(String tableName) { | 92 | public CompletableFuture<Integer> size(String tableName) { |
| 82 | checkState(isOpen.get(), DB_NOT_OPEN); | 93 | checkState(isOpen.get(), DB_NOT_OPEN); |
| 83 | AtomicInteger totalSize = new AtomicInteger(0); | 94 | AtomicInteger totalSize = new AtomicInteger(0); | ... | ... |
-
Please register or login to post a comment