Merge "Add filtering capability to config.ini in order to reference logging bridge...
[controller.git] / opendaylight / md-sal / statistics-manager / src / main / java / org / opendaylight / controller / md / statistics / manager / MultipartMessageManager.java
index 998d5d8faaf24fd09e10d6a5865f1a5c169e6d96..425a44946e064c97b44d27f42fdcdc8b1e2b9bc9 100644 (file)
  */
 package org.opendaylight.controller.md.statistics.manager;
 
+import java.util.Iterator;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.MultipartTransactionAware;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
 
+import com.google.common.base.Preconditions;
+
 /**
- * Main responsibility of the class is to manage multipart response 
+ * Main responsibility of the class is to manage multipart response
  * for multipart request. It also handles the flow aggregate request
- * and response mapping. 
+ * and response mapping.
  * @author avishnoi@in.ibm.com
  *
  */
-public class MultipartMessageManager {
-
+class MultipartMessageManager {
     /*
-     *  Map for tx id and type of request, to keep track of all the request sent 
-     *  by Statistics Manager. Statistics Manager won't entertain any multipart 
-     *  response for which it didn't send the request.  
+     *  Map for tx id and type of request, to keep track of all the request sent
+     *  by Statistics Manager. Statistics Manager won't entertain any multipart
+     *  response for which it didn't send the request.
      */
-    
-    private static Map<TransactionId,StatsRequestType> txIdToRequestTypeMap = new ConcurrentHashMap<TransactionId,StatsRequestType>();
+    private final Map<TxIdEntry,Long> txIdToRequestTypeMap = new ConcurrentHashMap<>();
     /*
      * Map to keep track of the request tx id for flow table statistics request.
      * Because flow table statistics multi part response do not contains the table id.
      */
-    private static Map<TransactionId,Short> txIdTotableIdMap = new ConcurrentHashMap<TransactionId,Short>();
-    
-    public MultipartMessageManager(){}
-    
-    public Short getTableIdForTxId(TransactionId id){
-        
-        return txIdTotableIdMap.get(id);
-        
+    private final Map<TxIdEntry,Short> txIdTotableIdMap = new ConcurrentHashMap<>();
+    private final long lifetimeNanos;
+
+    public MultipartMessageManager(long lifetimeNanos) {
+        this.lifetimeNanos = lifetimeNanos;
     }
-    
-    public void setTxIdAndTableIdMapEntry(TransactionId id,Short tableId){
-        txIdTotableIdMap.put(id, tableId);
+
+    private static final class TxIdEntry {
+        private final TransactionId txId;
+
+        public TxIdEntry(TransactionId txId) {
+            this.txId = txId;
+        }
+        public TransactionId getTxId() {
+            return txId;
+        }
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((txId == null) ? 0 : txId.hashCode());
+            return result;
+        }
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (!(obj instanceof TxIdEntry)) {
+                return false;
+            }
+            TxIdEntry other = (TxIdEntry) obj;
+
+            if (txId == null) {
+                if (other.txId != null) {
+                    return false;
+                }
+            } else if (!txId.equals(other.txId)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return "TxIdEntry [txId=" + txId + ']';
+        }
     }
-    
-    public void addTxIdToRequestTypeEntry (TransactionId id,StatsRequestType type){
-        txIdToRequestTypeMap.put(id, type);
+
+    public void recordExpectedTableTransaction(TransactionId id, Short tableId) {
+        recordExpectedTransaction(id);
+        txIdTotableIdMap.put(new TxIdEntry(id), Preconditions.checkNotNull(tableId));
     }
-    public StatsRequestType removeTxId(TransactionId id){
-        return txIdToRequestTypeMap.remove(id);
+
+    public Short isExpectedTableTransaction(TransactionAware transaction) {
+        Boolean more = null;
+        if (transaction instanceof MultipartTransactionAware) {
+            more = ((MultipartTransactionAware)transaction).isMoreReplies();
+        }
+
+        if (!isExpectedTransaction(transaction, more)) {
+            return null;
+        }
+
+        final TxIdEntry key = new TxIdEntry(transaction.getTransactionId());
+        if (more != null && more.booleanValue()) {
+            return txIdTotableIdMap.get(key);
+        } else {
+            return txIdTotableIdMap.remove(key);
+        }
     }
-    
-    public enum StatsRequestType{
-        ALL_FLOW,
-        AGGR_FLOW,
-        ALL_PORT,
-        ALL_FLOW_TABLE,
-        ALL_QUEUE_STATS,
-        ALL_GROUP,
-        ALL_METER,
-        GROUP_DESC,
-        METER_CONFIG
+
+    public void recordExpectedTransaction(TransactionId id) {
+        TxIdEntry entry = new TxIdEntry(Preconditions.checkNotNull(id));
+        txIdToRequestTypeMap.put(entry, getExpiryTime());
+    }
+
+    private boolean isExpectedTransaction(TransactionAware transaction, Boolean more) {
+        final TxIdEntry entry = new TxIdEntry(transaction.getTransactionId());
+        if (more != null && more.booleanValue()) {
+            return txIdToRequestTypeMap.containsKey(entry);
+        } else {
+            return txIdToRequestTypeMap.remove(entry) != null;
+        }
+    }
+
+    public boolean isExpectedTransaction(TransactionAware transaction) {
+        Boolean more = null;
+        if (transaction instanceof MultipartTransactionAware) {
+            more = ((MultipartTransactionAware)transaction).isMoreReplies();
+        }
+
+        return isExpectedTransaction(transaction, more);
+    }
+
+    private Long getExpiryTime() {
+        return System.nanoTime() + lifetimeNanos;
+    }
+
+    public void cleanStaleTransactionIds() {
+        final long now = System.nanoTime();
+
+        for (Iterator<TxIdEntry> it = txIdToRequestTypeMap.keySet().iterator();it.hasNext();){
+            TxIdEntry txIdEntry = it.next();
+
+            Long expiryTime = txIdToRequestTypeMap.get(txIdEntry);
+            if(now > expiryTime){
+                it.remove();
+                txIdTotableIdMap.remove(txIdEntry);
+            }
+        }
     }
 }