diff --git a/cli/src/main/java/org/onosproject/cli/net/MapsListCommand.java b/cli/src/main/java/org/onosproject/cli/net/MapsListCommand.java new file mode 100644 index 0000000000..13e886704a --- /dev/null +++ b/cli/src/main/java/org/onosproject/cli/net/MapsListCommand.java @@ -0,0 +1,92 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.cli.net; + +import java.util.List; + +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.store.service.MapInfo; +import org.onosproject.store.service.StorageAdminService; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Command to list the various maps in the system. + */ +@Command(scope = "onos", name = "maps", + description = "Lists information about consistent maps in the system") +public class MapsListCommand extends AbstractShellCommand { + + // TODO: Add support to display different eventually + // consistent maps as well. + + private static final String FMT = "%-20s %8s"; + + /** + * Displays map info as text. + * + * @param mapInfo map descriptions + */ + private void displayMaps(List mapInfo) { + print("------------------------------"); + print(FMT, "Name", "Size"); + print("------------------------------"); + + + for (MapInfo info : mapInfo) { + print(FMT, info.name(), info.size()); + } + if (mapInfo.size() > 0) { + print("------------------------------"); + } + } + + /** + * Converts list of map info into a JSON object. + * + * @param mapInfo map descriptions + */ + private JsonNode json(List mapInfo) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode maps = mapper.createArrayNode(); + + // Create a JSON node for each map + mapInfo.stream() + .forEach(info -> { + ObjectNode map = mapper.createObjectNode(); + map.put("name", info.name()) + .put("size", info.size()); + maps.add(map); + }); + + return maps; + } + + @Override + protected void execute() { + StorageAdminService storageAdminService = get(StorageAdminService.class); + List mapInfo = storageAdminService.getMapInfo(); + if (outputJson()) { + print("%s", json(mapInfo)); + } else { + displayMaps(mapInfo); + } + } +} diff --git a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml index e065d315e0..4c0497bd57 100644 --- a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml +++ b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml @@ -229,6 +229,9 @@ + + + diff --git a/core/api/src/main/java/org/onosproject/store/service/MapInfo.java b/core/api/src/main/java/org/onosproject/store/service/MapInfo.java new file mode 100644 index 0000000000..5db1704976 --- /dev/null +++ b/core/api/src/main/java/org/onosproject/store/service/MapInfo.java @@ -0,0 +1,47 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.store.service; + +/** + * Metadata information for a consistent map. + */ +public class MapInfo { + private final String name; + private final int size; + + public MapInfo(String name, int size) { + this.name = name; + this.size = size; + } + + /** + * Returns the name of the map. + * + * @return map name + */ + public String name() { + return name; + } + + /** + * Returns the number of entries in the map. + * + * @return map size + */ + public int size() { + return size; + } +} diff --git a/core/api/src/main/java/org/onosproject/store/service/StorageAdminService.java b/core/api/src/main/java/org/onosproject/store/service/StorageAdminService.java index 427b95361c..572867cbf3 100644 --- a/core/api/src/main/java/org/onosproject/store/service/StorageAdminService.java +++ b/core/api/src/main/java/org/onosproject/store/service/StorageAdminService.java @@ -28,4 +28,11 @@ public interface StorageAdminService { * @return list of partition information */ List getPartitionInfo(); + + /** + * Returns information about all the consistent maps in the system. + * + * @return list of map information + */ + List getMapInfo(); } diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java index b939780890..39d1bab703 100644 --- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java +++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java @@ -44,7 +44,9 @@ import org.onosproject.store.cluster.impl.NodeInfo; import org.onosproject.store.cluster.messaging.ClusterCommunicationService; import org.onosproject.store.ecmap.EventuallyConsistentMapBuilderImpl; import org.onosproject.store.service.ConsistentMapBuilder; +import org.onosproject.store.service.ConsistentMapException; import org.onosproject.store.service.EventuallyConsistentMapBuilder; +import org.onosproject.store.service.MapInfo; import org.onosproject.store.service.PartitionInfo; import org.onosproject.store.service.StorageAdminService; import org.onosproject.store.service.StorageService; @@ -58,8 +60,10 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; import static org.slf4j.LoggerFactory.getLogger; @@ -80,6 +84,7 @@ public class DatabaseManager implements StorageService, StorageAdminService { private static final int DATABASE_STARTUP_TIMEOUT_SEC = 60; private static final int RAFT_ELECTION_TIMEOUT = 3000; private static final int RAFT_HEARTBEAT_TIMEOUT = 1500; + private static final int DATABASE_OPERATION_TIMEOUT_MILLIS = 5000; private ClusterCoordinator coordinator; private PartitionedDatabase partitionedDatabase; @@ -294,4 +299,33 @@ public class DatabaseManager implements StorageService, StorageAdminService { public ConsistentMapBuilder consistentMapBuilder() { return new DefaultConsistentMapBuilder<>(inMemoryDatabase, partitionedDatabase); } + + @Override + public List getMapInfo() { + List maps = Lists.newArrayList(); + maps.addAll(getMapInfo(inMemoryDatabase)); + maps.addAll(getMapInfo(partitionedDatabase)); + return maps; + } + + private List getMapInfo(Database database) { + return complete(database.tableNames()) + .stream() + .map(name -> new MapInfo(name, complete(database.size(name)))) + .filter(info -> info.size() > 0) + .collect(Collectors.toList()); + } + + private static T complete(CompletableFuture future) { + try { + return future.get(DATABASE_OPERATION_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new ConsistentMapException.Interrupted(); + } catch (TimeoutException e) { + throw new ConsistentMapException.Timeout(); + } catch (ExecutionException e) { + throw new ConsistentMapException(e.getCause()); + } + } } \ No newline at end of file diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java index 20b736f777..3ea06fb91a 100644 --- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java +++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java @@ -30,6 +30,12 @@ import org.onosproject.store.service.Versioned; */ public interface DatabaseProxy { + /** + * Returns a set of all tables names. + * @return A completable future to be completed with the result once complete. + */ + CompletableFuture> tableNames(); + /** * Gets the table size. * diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java index 1863496eb8..097261d240 100644 --- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java +++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java @@ -43,6 +43,9 @@ public interface DatabaseState { @Initializer public void init(StateContext> context); + @Query + Set tableNames(); + @Query int size(String tableName); diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java index 9ffd1e8af4..c14e57cdb2 100644 --- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java +++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java @@ -60,6 +60,11 @@ public class DefaultDatabase extends AbstractResource implements Datab return supplier.get(); } + @Override + public CompletableFuture> tableNames() { + return checkOpen(() -> proxy.tableNames()); + } + @Override public CompletableFuture size(String tableName) { return checkOpen(() -> proxy.size(tableName)); diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java index 837852d3f5..e63a3d83f7 100644 --- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java +++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java @@ -19,6 +19,7 @@ package org.onosproject.store.consistent.impl; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -70,6 +71,11 @@ public class DefaultDatabaseState implements DatabaseState { return table; } + @Override + public Set tableNames() { + return new HashSet<>(tables.keySet()); + } + @Override public int size(String tableName) { return getTableMap(tableName).size(); diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java index cb4ddfce69..ad049e6cec 100644 --- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java +++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java @@ -77,6 +77,17 @@ public class PartitionedDatabase implements Database { return isOpen.get(); } + @Override + public CompletableFuture> tableNames() { + checkState(isOpen.get(), DB_NOT_OPEN); + Set tableNames = Sets.newConcurrentHashSet(); + return CompletableFuture.allOf(partitions + .stream() + .map(db -> db.tableNames().thenApply(tableNames::addAll)) + .toArray(CompletableFuture[]::new)) + .thenApply(v -> tableNames); + } + @Override public CompletableFuture size(String tableName) { checkState(isOpen.get(), DB_NOT_OPEN);