Bug 1340 : Resolving TableUpdate handling that was not in complaince with RFC 7047. 68/8868/1
authorMadhu Venugopal <mavenugo@gmail.com>
Wed, 9 Jul 2014 18:53:51 +0000 (11:53 -0700)
committerMadhu Venugopal <mavenugo@gmail.com>
Wed, 9 Jul 2014 18:53:51 +0000 (11:53 -0700)
1. Introduced RowUpdate class as per RFC 7047
2. Modified TableUpdate to use RowUpdate
3. Modified the parsing logic to make use of the new TableUpdate/RowUpdates
4. Modified the users of Monitor Updates to make use of the new TableUpdate
5. Removed an unnecessary redirection/ complexity in the NodeDB class
6. Adjusted and added support in the IT to handle multiple Rows in a single update.

Change-Id: I8c74d904e2c33087335825923830ef275cc818ac
Signed-off-by: Madhu Venugopal <mavenugo@gmail.com>
library/src/main/java/org/opendaylight/ovsdb/lib/message/TableUpdate.java
library/src/main/java/org/opendaylight/ovsdb/lib/schema/TableSchema.java
library/src/test/java/org/opendaylight/ovsdb/lib/OvsdbClientTestIT.java
plugin/src/main/java/org/opendaylight/ovsdb/plugin/InventoryService.java
plugin/src/main/java/org/opendaylight/ovsdb/plugin/NodeDB.java
schemas/Open_vSwitch/src/test/java/org/opendaylight/ovsdb/schema/openvswitch/MonitorTestCases.java

index b127456c85edbe27387212641c63aeb00a415338..6895ee4a07c00123fbacc526cacaec4af533e060 100644 (file)
@@ -6,49 +6,88 @@
  *  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  *  * and is available at http://www.eclipse.org/legal/epl-v10.html
  *  *
- *  * Authors : Ashwin Raveendran
+ *  * Authors : Ashwin Raveendran, Madhu Venugopal
  *
  */
 
 package org.opendaylight.ovsdb.lib.message;
 
+import java.util.Map;
+
 import org.opendaylight.ovsdb.lib.notation.Row;
 import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.lib.schema.TableSchema;
 
+import com.google.common.collect.Maps;
+
 public class TableUpdate<E extends TableSchema<E>> {
-    private UUID uuid;
-    private Row<E> old;
-    private Row<E> new_;
+    private Map<UUID, RowUpdate<E>> rows;
 
-    public TableUpdate(UUID uuid) {
-        super();
-        this.uuid = uuid;
+    public Map<UUID, RowUpdate<E>> getRows() {
+        return rows;
     }
 
-    public UUID getUuid() {
-        return this.uuid;
+    public class RowUpdate <E extends TableSchema<E>> {
+        private UUID uuid;
+        private Row<E> old;
+        private Row<E> new_;
+
+        public RowUpdate (UUID uuid, Row<E> old, Row<E> new_) {
+            this.uuid = uuid;
+            this.old = old;
+            this.new_ = new_;
+        }
+
+        public UUID getUuid() {
+            return this.uuid;
+        }
+
+        public Row<E> getOld() {
+            return old;
+        }
+
+        public void setOld(Row<E> old) {
+            this.old = old;
+        }
+
+        public Row<E> getNew() {
+            return new_;
+        }
+
+        public void setNew(Row<E> new_) {
+            this.new_ = new_;
+        }
+
+        @Override
+        public String toString() {
+            return "RowUpdate [uuid=" + uuid + ", old=" + old + ", new_=" + new_
+                    + "]";
+        }
     }
 
-    public Row<E> getOld() {
-        return old;
+    public TableUpdate() {
+        super();
+        rows = Maps.newHashMap();
     }
 
-    public void setOld(Row<E> old) {
-        this.old = old;
+    public void addRow(UUID uuid, Row<E> old, Row<E> new_) {
+        rows.put(uuid, new RowUpdate<E>(uuid, old, new_));
     }
 
-    public Row<E> getNew() {
-        return new_;
+    public Row<E> getOld(UUID uuid) {
+        RowUpdate<E> rowUpdate = rows.get(uuid);
+        if (rowUpdate == null) return null;
+        return rowUpdate.getOld();
     }
 
-    public void setNew(Row<E> new_) {
-        this.new_ = new_;
+    public Row<E> getNew(UUID uuid) {
+        RowUpdate<E> rowUpdate = rows.get(uuid);
+        if (rowUpdate == null) return null;
+        return rowUpdate.getNew();
     }
 
     @Override
     public String toString() {
-        return "TableUpdate [uuid=" + uuid + ", old=" + old + ", new_=" + new_
-                + "]";
+        return "TableUpdate [" + rows + "]";
     }
 }
index f34c4842aeef4836a70c465d8602e112a6f13f63..3e430deecde96409c857d679f1dd466035854b25 100644 (file)
 package org.opendaylight.ovsdb.lib.schema;
 
 import java.lang.reflect.Constructor;
+import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
-import java.util.ArrayList;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 
 import org.opendaylight.ovsdb.lib.message.TableUpdate;
@@ -124,20 +125,20 @@ public abstract class TableSchema<E extends TableSchema<E>> {
     }
 
     public TableUpdate<E> updatesFromJson(JsonNode value) {
+        TableUpdate<E> tableUpdate = new TableUpdate<>();
+        Iterator<Entry<String, JsonNode>> fields = value.fields();
+        while (fields.hasNext()) {
+            Map.Entry<String, JsonNode> idOldNew = fields.next();
+            String uuid = idOldNew.getKey();
 
-        Map.Entry<String, JsonNode> idOldNew = value.fields().next();
-        String uuid = idOldNew.getKey();
-
-        ObjectNode new_ = (ObjectNode) idOldNew.getValue().get("new");
-        ObjectNode old = (ObjectNode) idOldNew.getValue().get("old");
+            ObjectNode new_ = (ObjectNode) idOldNew.getValue().get("new");
+            ObjectNode old = (ObjectNode) idOldNew.getValue().get("old");
 
-        Row<E> newRow = new_ != null ? createRow(new_) : null;
-        Row<E> oldRow = old != null ? createRow(old) : null;
-
-        TableUpdate<E> tableUpdate = new TableUpdate<>(new UUID(uuid));
-        tableUpdate.setNew(newRow);
-        tableUpdate.setOld(oldRow);
+            Row<E> newRow = new_ != null ? createRow(new_) : null;
+            Row<E> oldRow = old != null ? createRow(old) : null;
 
+            tableUpdate.addRow(new UUID(uuid), oldRow, newRow);
+        }
         return tableUpdate;
     }
 
index 4f272bbb83f9283af95b8c46af503e0f2dd0bf49..bc0a077e07d2da7da18119bcb35d022e071bb275 100644 (file)
@@ -83,6 +83,7 @@ public class OvsdbClientTestIT extends OvsdbTestBase {
         List<MonitorRequest<GenericTableSchema>> monitorRequests = Lists.newArrayList();
         ColumnSchema<GenericTableSchema, Set<Integer>> flood_vlans = bridge.multiValuedColumn("flood_vlans", Integer.class);
         ColumnSchema<GenericTableSchema, Map<String, String>> externalIds = bridge.multiValuedColumn("external_ids", String.class, String.class);
+        ColumnSchema<GenericTableSchema, String> name = bridge.column("name", String.class);
         MonitorRequestBuilder<GenericTableSchema> builder = MonitorRequestBuilder.builder(bridge);
         if (filter) {
             builder.addColumn(bridge.column("name"))
@@ -120,79 +121,37 @@ public class OvsdbClientTestIT extends OvsdbTestBase {
         Assert.assertTrue(result instanceof TableUpdates);
         updates = (TableUpdates) result;
         TableUpdate<GenericTableSchema> update = updates.getUpdate(bridge);
-        Row<GenericTableSchema> aNew = update.getNew();
-        if (filter) {
-            Assert.assertEquals(builder.getColumns().size(), aNew.getColumns().size());
-        } else {
-            // As per RFC7047, Section 4.1.5 : If "columns" is omitted, all columns in the table, except for "_uuid", are monitored.
-            Assert.assertEquals(bridge.getColumns().size() - 1, aNew.getColumns().size());
-        }
-        for (Column<GenericTableSchema, ?> column: aNew.getColumns()) {
-            if (column.getSchema().equals(flood_vlans)) {
-                // Test for the 5 flood_vlans inserted in Bridge br-test in createBridgeTransaction
-                Set<Integer> data = column.getData(flood_vlans);
-                Assert.assertTrue(!data.isEmpty());
-                Assert.assertEquals(5, data.size());
-            } else if (column.getSchema().equals(externalIds)) {
-                // Test for the {"key", "value"} external_ids inserted in Bridge br-test in createBridgeTransaction
-                Map<String, String> data = column.getData(externalIds);
-                Assert.assertNotNull(data.get("key"));
-                Assert.assertEquals("value", data.get("key"));
-                // Test for {"key2", "value2"} external_ids mutation-inserted in Bridge br-test in createBridgeTransaction
-                Assert.assertNotNull(data.get("key2"));
-                Assert.assertEquals("value2", data.get("key2"));
-            }
-        }
-    }
-
-    /*
-     * Ideally we should be using selectOpenVSwitchTableUuid() instead of this method.
-     * But Row.java needs some Jackson Jitsu to obtain the appropriate Row Json mapped to Java object
-     * for Select operation.
-     * Hence using the Monitor approach to obtain the uuid of the open_vSwitch table entry.
-     * Replace this method with selectOpenVSwitchTableUuid() once it is functional,
-     */
-    private UUID getOpenVSwitchTableUuid() throws ExecutionException, InterruptedException {
-        Assert.assertNotNull(dbSchema);
-        GenericTableSchema ovsTable = dbSchema.table("Open_vSwitch", GenericTableSchema.class);
-        List<MonitorRequest<GenericTableSchema>> monitorRequests = Lists.newArrayList();
-        ColumnSchema<GenericTableSchema, UUID> _uuid = ovsTable.column("_uuid", UUID.class);
-
-        monitorRequests.add(
-                MonitorRequestBuilder.builder(ovsTable)
-                        .addColumn(_uuid)
-                        .with(new MonitorSelect(true, true, true, true))
-                        .build());
-
-        final List<Object> results = Lists.newArrayList();
-
-        TableUpdates updates = ovs.monitor(dbSchema, monitorRequests, new MonitorCallBack() {
-            @Override
-            public void update(TableUpdates result, DatabaseSchema dbSchema) {
-                results.add(result);
+        Assert.assertTrue(update.getRows().size() > 0);
+        for (UUID uuid : update.getRows().keySet()) {
+            Row<GenericTableSchema> aNew = update.getNew(uuid);
+            if (!aNew.getColumn(name).getData().equals(testBridgeName)) continue;
+            if (filter) {
+                Assert.assertEquals(builder.getColumns().size(), aNew.getColumns().size());
+            } else {
+                // As per RFC7047, Section 4.1.5 : If "columns" is omitted, all columns in the table, except for "_uuid", are monitored.
+                Assert.assertEquals(bridge.getColumns().size() - 1, aNew.getColumns().size());
             }
-
-            @Override
-            public void exception(Throwable t) {
-                results.add(t);
-                System.out.println("t = " + t);
+            for (Column<GenericTableSchema, ?> column: aNew.getColumns()) {
+                if (column.getSchema().equals(flood_vlans)) {
+                    // Test for the 5 flood_vlans inserted in Bridge br-test in createBridgeTransaction
+                    Set<Integer> data = column.getData(flood_vlans);
+                    Assert.assertNotNull(data);
+                    Assert.assertTrue(!data.isEmpty());
+                    Assert.assertEquals(5, data.size());
+                } else if (column.getSchema().equals(externalIds)) {
+                    // Test for the {"key", "value"} external_ids inserted in Bridge br-test in createBridgeTransaction
+                    Map<String, String> data = column.getData(externalIds);
+                    Assert.assertNotNull(data);
+                    Assert.assertNotNull(data.get("key"));
+                    Assert.assertEquals("value", data.get("key"));
+                    // Test for {"key2", "value2"} external_ids mutation-inserted in Bridge br-test in createBridgeTransaction
+                    Assert.assertNotNull(data.get("key2"));
+                    Assert.assertEquals("value2", data.get("key2"));
+                }
             }
-        });
-
-        if (updates != null) results.add(updates);
-        for (int i = 0; i < 3 ; i++) { //wait 5 seconds to get a result
-            if (!results.isEmpty()) break;
-            System.out.println("waiting on monitor response for open_vSwtich Table...");
-            Thread.sleep(1000);
+            return;
         }
-
-        Assert.assertTrue(!results.isEmpty());
-        Object result = results.get(0); // open_vSwitch table has just 1 row.
-        Assert.assertTrue(result instanceof TableUpdates);
-        updates = (TableUpdates) result;
-        TableUpdate<GenericTableSchema> update = updates.getUpdate(ovsTable);
-        Assert.assertNotNull(update.getUuid());
-        return update.getUuid();
+        Assert.fail("Bridge being monitored :"+testBridgeName+" Not found");
     }
 
     /*
index 0f9c565f384e6c1bb423273a5a4663597a595f7b..4c92c0be51f9c665d8ff4f66bd6792dd096ba926 100644 (file)
@@ -35,6 +35,7 @@ import org.opendaylight.controller.sal.utils.ServiceHelper;
 import org.opendaylight.ovsdb.lib.message.TableUpdate;
 import org.opendaylight.ovsdb.lib.message.TableUpdates;
 import org.opendaylight.ovsdb.lib.notation.Row;
+import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -174,29 +175,31 @@ public class InventoryService implements IPluginInInventoryService, InventorySer
         for (String tableName : tableUpdates.getUpdates().keySet()) {
             Map<String, Row> tCache = db.getTableCache(databaseName, tableName);
             TableUpdate update = tableUpdates.getUpdates().get(tableName);
+            for (UUID uuid : (Set<UUID>)update.getRows().keySet()) {
 
-            if (update.getNew() != null) {
-                boolean isNewRow = (tCache == null || tCache.get(update.getUuid().toString()) == null) ? true : false;
-                db.updateRow(databaseName, tableName, update.getUuid().toString(), update.getNew());
+            if (update.getNew(uuid) != null) {
+                boolean isNewRow = (tCache == null || tCache.get(uuid.toString()) == null) ? true : false;
+                db.updateRow(databaseName, tableName, uuid.toString(), update.getNew(uuid));
                 if (isNewRow) {
-                    this.handleOpenVSwitchSpecialCase(n, databaseName, tableName, update);
-                    if (inventoryListener != null) inventoryListener.rowAdded(n, tableName, update.getUuid().toString(), update.getNew());
+                    this.handleOpenVSwitchSpecialCase(n, databaseName, tableName, uuid);
+                    if (inventoryListener != null) inventoryListener.rowAdded(n, tableName, uuid.toString(), update.getNew(uuid));
                 } else {
-                    if (inventoryListener != null) inventoryListener.rowUpdated(n, tableName, update.getUuid().toString(), update.getOld(), update.getNew());
+                    if (inventoryListener != null) inventoryListener.rowUpdated(n, tableName, uuid.toString(), update.getOld(uuid), update.getNew(uuid));
                 }
-            } else if (update.getOld() != null){
+            } else if (update.getOld(uuid) != null){
                 if (tCache != null) {
-                    if (inventoryListener != null) inventoryListener.rowRemoved(n, tableName, update.getUuid().toString(), update.getOld(), update.getNew());
+                    if (inventoryListener != null) inventoryListener.rowRemoved(n, tableName, uuid.toString(), update.getOld(uuid), update.getNew(uuid));
                 }
-                db.removeRow(databaseName, tableName, update.getUuid().toString());
+                db.removeRow(databaseName, tableName, uuid.toString());
+            }
             }
         }
     }
 
-    private void handleOpenVSwitchSpecialCase(Node node, String databaseName, String tableName, TableUpdate update) {
+    private void handleOpenVSwitchSpecialCase(Node node, String databaseName, String tableName, UUID uuid) {
         if (OvsVswitchdSchemaConstants.shouldConfigureController(databaseName, tableName)) {
             try {
-                if (configurationService != null) configurationService.setOFController(node, update.getUuid().toString());
+                if (configurationService != null) configurationService.setOFController(node, uuid.toString());
             } catch (InterruptedException | ExecutionException e) {
                 e.printStackTrace();
             }
index 5948a1a22edfd41bcb702d123ee975911029f473..59dc3a9fd12e666515a540c4f4448da46969bed9 100644 (file)
@@ -9,26 +9,23 @@
  */
 package org.opendaylight.ovsdb.plugin;
 
+import java.util.Collection;
 import java.util.Map;
 import java.util.concurrent.ConcurrentMap;
 
 import org.apache.commons.collections.MapUtils;
+import org.opendaylight.ovsdb.lib.notation.Column;
 import org.opendaylight.ovsdb.lib.notation.Row;
 
 import com.google.common.collect.Maps;
 
 public class NodeDB {
-    ConcurrentMap<String, ConcurrentMap<String, TableDB>> dbCache = Maps.newConcurrentMap();
+    ConcurrentMap<String, TableDB> dbCache = Maps.newConcurrentMap();
 
-    public ConcurrentMap<String, ConcurrentMap<String,Row>> getDatabase(String dbName) {
-        ConcurrentMap<String, TableDB> tdbMap = dbCache.get(dbName);
-        if (tdbMap == null) return null;
-        ConcurrentMap<String, ConcurrentMap<String,Row>> retMap = Maps.newConcurrentMap();
-        for (String tableName : tdbMap.keySet()) {
-            TableDB tdb = tdbMap.get(tableName);
-            if (tdb != null && tdb.getTableCache(tableName) != null) retMap.put(tableName, tdb.getTableCache(tableName));
-        }
-        return retMap;
+    public ConcurrentMap<String, ConcurrentMap<String, Row>> getDatabase(String dbName) {
+        TableDB tdb = dbCache.get(dbName);
+        if (tdb == null) return null;
+        return tdb.getTableCache();
     }
 
     public ConcurrentMap<String, Row> getTableCache(String dbName, String tableName) {
@@ -37,42 +34,51 @@ public class NodeDB {
         return tdbMap.get(tableName);
     }
 
-    private void setDBCache(String dbName,  ConcurrentMap<String, TableDB> table) {
+    private void setDBCache(String dbName,  TableDB table) {
         dbCache.put(dbName, table);
     }
 
     public Row getRow (String dbName, String tableName, String uuid) {
-        ConcurrentMap<String, ConcurrentMap<String, Row>> db = getDatabase(dbName);
-        if (db == null) return null;
-        ConcurrentMap<String, Row> tdb = db.get(tableName);
+        ConcurrentMap<String, Row> tdb = this.getTableCache(dbName, tableName);
         if (tdb == null) return null;
         return tdb.get(uuid);
     }
 
     public void updateRow(String dbName, String tableName, String uuid, Row row) {
-        ConcurrentMap<String, TableDB> db = dbCache.get(dbName);
+        TableDB db = dbCache.get(dbName);
         if (db == null) {
-            db = Maps.newConcurrentMap();
+            db = new TableDB();
             setDBCache(dbName, db);
         }
-        TableDB tdb = db.get(tableName);
-        if (tdb == null) {
-            tdb = new TableDB();
-            db.put(tableName, tdb);
-        }
-        tdb.updateRow(tableName, uuid, row);
+        db.updateRow(tableName, uuid, row);
     }
 
     public void removeRow(String dbName, String tableName, String uuid) {
-        ConcurrentMap<String, TableDB> db = dbCache.get(dbName);
+        TableDB db = dbCache.get(dbName);
         if (db == null) return;
-        TableDB tdb = db.get(tableName);
-        if (tdb == null) return;
-        tdb.removeRow(tableName, uuid);
+        db.removeRow(tableName, uuid);
     }
 
     public void printTableCache() {
-        MapUtils.debugPrint(System.out, null, dbCache);
+        for (String dbName : dbCache.keySet()) {
+            System.out.println("Database "+dbName);
+            ConcurrentMap<String, ConcurrentMap<String,Row>> tableDB = this.getDatabase(dbName);
+            if (tableDB == null) continue;
+            for (String tableName : tableDB.keySet()) {
+                ConcurrentMap<String, Row> tableRows = this.getTableCache(dbName, tableName);
+                System.out.println("\t Table "+tableName);
+                for (String uuid : tableRows.keySet()) {
+                    Row row = tableRows.get(uuid);
+                    Collection<Column> columns = row.getColumns();
+                    System.out.print("\t\t"+uuid+ "==");
+                    for (Column column : columns) {
+                        if (column.getData() != null) System.out.print(column.getSchema().getName()+" : "+ column.getData());
+                    }
+                    System.out.println("");
+                }
+                System.out.println("-----------------------------------------------------------");
+            }
+        }
     }
 
     public class TableDB {
index ee7fde930d747c31baa984cd5a1e0d4811988074..fc51bb381ba7218fbd78495ee8d3b2a553e2edfe 100644 (file)
@@ -108,14 +108,16 @@ public class MonitorTestCases extends OpenVswitchSchemaTestBase {
         for (String tableName : updates.getUpdates().keySet()) {
             Map<UUID, Row> tUpdate = OpenVswitchSchemaSuiteIT.getTableCache().get(tableName);
             TableUpdate update = updates.getUpdates().get(tableName);
-            if (update.getNew() != null) {
-                if (tUpdate == null) {
-                    tUpdate = new HashMap<>();
-                    OpenVswitchSchemaSuiteIT.getTableCache().put(tableName, tUpdate);
+            for (UUID uuid : (Set<UUID>)update.getRows().keySet()) {
+                if (update.getNew(uuid) != null) {
+                    if (tUpdate == null) {
+                        tUpdate = new HashMap<>();
+                        OpenVswitchSchemaSuiteIT.getTableCache().put(tableName, tUpdate);
+                    }
+                    tUpdate.put(uuid, update.getNew(uuid));
+                } else {
+                    tUpdate.remove(uuid);
                 }
-                tUpdate.put(update.getUuid(), update.getNew());
-            } else {
-                tUpdate.remove(update.getUuid());
             }
         }
     }