Madan Jampani

Added support for "maps" cli command that displays meta information for various …

…consistent maps in the system

Change-Id: I63e590a8520ac9d1238efe4ad0033dcba939e472
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);
......