added StringSet class; implemented per-instance table thresholds states
authorVictor Kirhenshtein <victor@netxms.org>
Fri, 23 Aug 2013 18:01:44 +0000 (18:01 +0000)
committerVictor Kirhenshtein <victor@netxms.org>
Fri, 23 Aug 2013 18:01:44 +0000 (18:01 +0000)
include/netxms-version.h
include/nms_util.h
src/java/netxms-client/src/main/java/org/netxms/client/NXCSession.java
src/java/netxms-client/src/main/java/org/netxms/client/datacollection/TableThreshold.java
src/libnetxms/Makefile.am
src/libnetxms/libnetxms.vcproj
src/libnetxms/strmap.cpp
src/libnetxms/strset.cpp [new file with mode: 0644]
src/server/core/dctable.cpp
src/server/core/dctthreshold.cpp
src/server/include/nms_dcoll.h

index 2f614e7..2bcf0ca 100644 (file)
@@ -36,7 +36,7 @@
 /**
  * Current client-server protocol version
  */
-#define CLIENT_PROTOCOL_VERSION           37
+#define CLIENT_PROTOCOL_VERSION           38
 
 /**
  * Current mobile device protocol version
index ed1ea89..e8ba136 100644 (file)
@@ -342,6 +342,33 @@ public:
    void splitAndAdd(const TCHAR *src, const TCHAR *separator);
 };
 
+/**
+ * Entry of string set
+ */
+struct StringSetEntry;
+
+/**
+ * String set class
+ */
+class LIBNETXMS_EXPORTABLE StringSet
+{
+private:
+   StringSetEntry *m_data;
+
+public:
+   StringSet();
+   ~StringSet();
+
+   void add(const TCHAR *str);
+   void remove(const TCHAR *str);
+   void clear();
+
+   int size();
+   bool exist(const TCHAR *str);
+
+   void forEach(bool (*cb)(const TCHAR *, void *), void *userData);
+};
+
 /**
  * Dynamic array class
  */
index bda49cf..7f109e7 100644 (file)
@@ -171,7 +171,7 @@ public class NXCSession implements Session, ScriptLibraryManager, UserManager, S
 {\r
        // Various public constants\r
        public static final int DEFAULT_CONN_PORT = 4701;\r
-       public static final int CLIENT_PROTOCOL_VERSION = 37;\r
+       public static final int CLIENT_PROTOCOL_VERSION = 38;\r
 \r
        // Authentication types\r
        public static final int AUTH_TYPE_PASSWORD = 0;\r
index 75c7e6c..1bb5482 100644 (file)
@@ -32,7 +32,6 @@ public class TableThreshold
        private long id;
        private int activationEvent;
        private int deactivationEvent;
-       private boolean active;
        private List<List<TableCondition>> conditions;
        private long nextVarId;
        
@@ -44,7 +43,6 @@ public class TableThreshold
                id = 0;
                activationEvent = 0;
                deactivationEvent = 0;
-               active = false;
                conditions = new ArrayList<List<TableCondition>>(0);
        }
        
@@ -58,7 +56,6 @@ public class TableThreshold
                id = src.id;
                activationEvent = src.activationEvent;
                deactivationEvent = src.deactivationEvent;
-               active = src.active;
                conditions = new ArrayList<List<TableCondition>>(src.conditions.size());
                for(List<TableCondition> sl : src.conditions)
                {
@@ -79,7 +76,6 @@ public class TableThreshold
        {
                long varId = baseId;
                id = msg.getVariableAsInt64(varId++);
-               active = msg.getVariableAsBoolean(varId++);
                activationEvent = msg.getVariableAsInteger(varId++);
                deactivationEvent = msg.getVariableAsInteger(varId++);
                
@@ -228,12 +224,4 @@ public class TableThreshold
        {
                return id;
        }
-
-       /**
-        * @return the active
-        */
-       public boolean isActive()
-       {
-               return active;
-       }
 }
index eb0038d..7dba71c 100644 (file)
@@ -3,8 +3,8 @@ SOURCES = agent.cpp array.cpp base64.cpp config.cpp crypto.cpp dirw_unix.c \
          icmp.cpp log.cpp main.cpp md5.cpp message.cpp msgwq.cpp net.cpp \
          nxcp.cpp qsort.c queue.cpp rwlock.cpp scandir.c serial.cpp \
          sha1.cpp string.cpp stringlist.cpp strmap.cpp strmapbase.cpp \
-         strtoll.c strtoull.c table.cpp threads.cpp tools.cpp unicode.cpp \
-         uuid.c wcstoll.c wcstoull.c xml.cpp wcscasecmp.cpp
+         strset.cpp strtoll.c strtoull.c table.cpp threads.cpp tools.cpp \
+         unicode.cpp uuid.c wcstoll.c wcstoull.c xml.cpp wcscasecmp.cpp
 
 lib_LTLIBRARIES = libnetxms.la
 
index 69aa72a..8d8061b 100644 (file)
                                RelativePath=".\strmapbase.cpp"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath=".\strset.cpp"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath=".\strtoll.c"\r
                                >\r
index 253b4f1..1ddd8c6 100644 (file)
@@ -1,7 +1,7 @@
 /* 
 ** NetXMS - Network Management System
 ** NetXMS Foundation Library
-** Copyright (C) 2003-2012 Victor Kirhenshtein
+** Copyright (C) 2003-2013 Victor Kirhenshtein
 **
 ** This program is free software; you can redistribute it and/or modify
 ** it under the terms of the GNU Lesser General Public License as published
diff --git a/src/libnetxms/strset.cpp b/src/libnetxms/strset.cpp
new file mode 100644 (file)
index 0000000..942d8c3
--- /dev/null
@@ -0,0 +1,125 @@
+/* 
+** NetXMS - Network Management System
+** NetXMS Foundation Library
+** Copyright (C) 2003-2013 Victor Kirhenshtein
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published
+** by the Free Software Foundation; either version 3 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** File: strset.cpp
+**
+**/
+
+#include "libnetxms.h"
+#include <uthash.h>
+
+/**
+ * Entry
+ */
+struct StringSetEntry
+{
+   UT_hash_handle hh;
+   TCHAR *str;
+};
+
+/**
+ * Constructor
+ */
+StringSet::StringSet()
+{
+   m_data = NULL;
+}
+
+/**
+ * Destructor
+ */
+StringSet::~StringSet()
+{
+   clear();
+}
+
+/**
+ * Add string to set
+ */
+void StringSet::add(const TCHAR *str)
+{
+   StringSetEntry *entry;
+   int keyLen = (int)(_tcslen(str) * sizeof(TCHAR));
+   HASH_FIND(hh, m_data, str, keyLen, entry);
+   if (entry == NULL)
+   {
+      entry = (StringSetEntry *)malloc(sizeof(StringSetEntry));
+      entry->str = _tcsdup(str);
+      HASH_ADD_KEYPTR(hh, m_data, entry->str, keyLen, entry);
+   }
+}
+
+/**
+ * Remove string from set
+ */
+void StringSet::remove(const TCHAR *str)
+{
+   StringSetEntry *entry;
+   int keyLen = (int)(_tcslen(str) * sizeof(TCHAR));
+   HASH_FIND(hh, m_data, str, keyLen, entry);
+   if (entry != NULL)
+   {
+      HASH_DEL(m_data, entry);
+   }
+}
+
+/**
+ * Clear set
+ */
+void StringSet::clear()
+{
+   StringSetEntry *entry, *tmp;
+   HASH_ITER(hh, m_data, entry, tmp)
+   {
+      HASH_DEL(m_data, entry);
+      free(entry->str);
+      free(entry);
+   }
+}
+
+/**
+ * Check if given string is in set
+ */
+bool StringSet::exist(const TCHAR *str)
+{
+   StringSetEntry *entry;
+   int keyLen = (int)(_tcslen(str) * sizeof(TCHAR));
+   HASH_FIND(hh, m_data, str, keyLen, entry);
+   return entry != NULL;
+}
+
+/**
+ * Get set size
+ */
+int StringSet::size()
+{
+   return HASH_COUNT(m_data);
+}
+
+/**
+ * Enumerate entries
+ */
+void StringSet::forEach(bool (*cb)(const TCHAR *, void *), void *userData)
+{
+   StringSetEntry *entry, *tmp;
+   HASH_ITER(hh, m_data, entry, tmp)
+   {
+      cb(entry->str, userData);
+   }
+}
index 35685e2..19f7b9e 100644 (file)
@@ -555,7 +555,7 @@ BOOL DCTable::saveToDB(DB_HANDLE hdb)
  */
 bool DCTable::loadThresholds()
 {
-   DB_STATEMENT hStmt = DBPrepare(g_hCoreDB, _T("SELECT id,current_state,activation_event,deactivation_event FROM dct_thresholds WHERE table_id=? ORDER BY sequence_number"));
+   DB_STATEMENT hStmt = DBPrepare(g_hCoreDB, _T("SELECT id,activation_event,deactivation_event FROM dct_thresholds WHERE table_id=? ORDER BY sequence_number"));
    if (hStmt == NULL)
       return false;
 
index 3436d97..5bd19f7 100644 (file)
@@ -309,7 +309,7 @@ DCTableThreshold::DCTableThreshold()
    m_groups = new ObjectArray<DCTableConditionGroup>(4, 4, true);
    m_activationEvent = EVENT_THRESHOLD_REACHED;
    m_deactivationEvent = EVENT_THRESHOLD_REARMED;
-   m_currentState = false;
+   m_activeKeys = new StringSet;
 }
 
 /**
@@ -323,21 +323,21 @@ DCTableThreshold::DCTableThreshold(DCTableThreshold *src)
       m_groups->add(new DCTableConditionGroup(src->m_groups->get(i)));
    m_activationEvent = src->m_activationEvent;
    m_deactivationEvent = src->m_deactivationEvent;
-   m_currentState = false;
+   m_activeKeys = new StringSet;
 }
 
 /**
  * Create table threshold from database
- * Expected column order: id,current_state,activation_event,deactivation_event
+ * Expected column order: id,activation_event,deactivation_event
  */
 DCTableThreshold::DCTableThreshold(DB_RESULT hResult, int row)
 {
    m_id = DBGetFieldLong(hResult, row, 0);
-   m_currentState = DBGetFieldLong(hResult, row, 1) ? true : false;
-   m_activationEvent = DBGetFieldULong(hResult, row, 2);
-   m_deactivationEvent = DBGetFieldULong(hResult, row, 3);
+   m_activationEvent = DBGetFieldULong(hResult, row, 1);
+   m_deactivationEvent = DBGetFieldULong(hResult, row, 2);
    m_groups = new ObjectArray<DCTableConditionGroup>(4, 4, true);
    loadConditions();
+   m_activeKeys = new StringSet;
 }
 
 /**
@@ -349,7 +349,6 @@ DCTableThreshold::DCTableThreshold(CSCPMessage *msg, UINT32 *baseId)
    m_id = msg->GetVariableLong(varId++);
    if (m_id == 0)
       m_id = CreateUniqueId(IDG_THRESHOLD);
-   m_currentState = false;
    m_activationEvent = msg->GetVariableLong(varId++);
    m_deactivationEvent = msg->GetVariableLong(varId++);
    int count = (int)msg->GetVariableLong(varId++);
@@ -357,6 +356,7 @@ DCTableThreshold::DCTableThreshold(CSCPMessage *msg, UINT32 *baseId)
    *baseId = varId;
    for(int i = 0; i < count; i++)
       m_groups->add(new DCTableConditionGroup(msg, baseId));
+   m_activeKeys = new StringSet;
 }
 
 /**
@@ -382,6 +382,7 @@ DCTableThreshold::DCTableThreshold(ConfigEntry *e)
        {
        m_groups = new ObjectArray<DCTableConditionGroup>(4, 4, true);
        }
+   m_activeKeys = new StringSet;
 }
 
 /**
@@ -429,6 +430,7 @@ void DCTableThreshold::loadConditions()
 DCTableThreshold::~DCTableThreshold()
 {
    delete m_groups;
+   delete m_activeKeys;
 }
 
 /**
@@ -436,16 +438,15 @@ DCTableThreshold::~DCTableThreshold()
  */
 bool DCTableThreshold::saveToDatabase(DB_HANDLE hdb, UINT32 tableId, int seq)
 {
-   DB_STATEMENT hStmt = DBPrepare(hdb, _T("INSERT INTO dct_thresholds (id,table_id,sequence_number,current_state,activation_event,deactivation_event) VALUES (?,?,?,?,?,?)"));
+   DB_STATEMENT hStmt = DBPrepare(hdb, _T("INSERT INTO dct_thresholds (id,table_id,sequence_number,activation_event,deactivation_event) VALUES (?,?,?,?,?)"));
    if (hStmt == NULL)
       return false;
 
    DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
    DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, tableId);
    DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, (INT32)seq);
-   DBBind(hStmt, 4, DB_SQLTYPE_VARCHAR, m_currentState ? _T("1") : _T("0"), DB_BIND_STATIC);
-   DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, m_activationEvent);
-   DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, m_deactivationEvent);
+   DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, m_activationEvent);
+   DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, m_deactivationEvent);
    DBExecute(hStmt);
    DBFreeStatement(hStmt);
 
@@ -478,7 +479,6 @@ UINT32 DCTableThreshold::fillMessage(CSCPMessage *msg, UINT32 baseId)
 {
    UINT32 varId = baseId;
    msg->SetVariable(varId++, m_id);
-   msg->SetVariable(varId++, (UINT16)(m_currentState ? 1 : 0));
    msg->SetVariable(varId++, m_activationEvent);
    msg->SetVariable(varId++, m_deactivationEvent);
    msg->SetVariable(varId++, (UINT32)m_groups->size());
@@ -491,13 +491,36 @@ UINT32 DCTableThreshold::fillMessage(CSCPMessage *msg, UINT32 baseId)
 
 /**
  * Check threshold
+ * Method will return the following codes:
+ *    THRESHOLD_REACHED - when value match the threshold condition while previous check doesn't
+ *    THRESHOLD_REARMED - when value doesn't match the threshold condition while previous check do
+ *    NO_ACTION - when there are no changes in value match to threshold's condition
  */
-bool DCTableThreshold::check(Table *value, int row)
+int DCTableThreshold::check(Table *value, int row)
 {
+   TCHAR instance[MAX_RESULT_LENGTH];
+   value->buildInstanceString(row, instance, MAX_RESULT_LENGTH);
+
    for(int i = 0; i < m_groups->size(); i++)
+   {
       if (m_groups->get(i)->check(value, row))
-         return true;
-   return false;
+      {
+         if (m_activeKeys->exist(instance))
+         {
+            return NO_ACTION;
+         }
+         m_activeKeys->add(instance);
+         return THRESHOLD_REACHED;
+      }
+   }
+
+   // no match
+   if (m_activeKeys->exist(instance))
+   {
+      m_activeKeys->remove(instance);
+      return THRESHOLD_REARMED;
+   }
+   return NO_ACTION;
 }
 
 /**
index 8511e67..ce8810c 100644 (file)
@@ -489,7 +489,7 @@ private:
    ObjectArray<DCTableConditionGroup> *m_groups;
    UINT32 m_activationEvent;
    UINT32 m_deactivationEvent;
-   bool m_currentState;
+   StringSet *m_activeKeys;
 
    void loadConditions();
 
@@ -501,7 +501,7 @@ public:
    DCTableThreshold(ConfigEntry *e);
    ~DCTableThreshold();
 
-   bool check(Table *value, int row);
+   int check(Table *value, int row);
 
    bool saveToDatabase(DB_HANDLE hdb, UINT32 tableId, int seq);
 
@@ -510,7 +510,6 @@ public:
    void createNXMPRecord(String &str, int id);
 
    UINT32 getId() { return m_id; }
-   bool getCurrentState() { return m_currentState; }
 };
 
 /**