implemented iterator for hash map class; new agent parameter Agent.DataCollectorQueueSize
authorVictor Kirhenshtein <victor@netxms.org>
Wed, 23 Dec 2015 10:10:05 +0000 (12:10 +0200)
committerVictor Kirhenshtein <victor@netxms.org>
Wed, 23 Dec 2015 10:10:05 +0000 (12:10 +0200)
include/nms_agent.h
include/nms_util.h
include/uthash.h
src/agent/core/datacoll.cpp
src/agent/core/getparam.cpp
src/libnetxms/array.cpp
src/libnetxms/hashmapbase.cpp
tests/test-libnetxms/test-libnetxms.cpp

index 42911bc..944a712 100644 (file)
 #define DCIDESC_AGENT_ACTIVECONNECTIONS           _T("Number of active connections to agent")
 #define DCIDESC_AGENT_AUTHENTICATIONFAILURES      _T("Number of authentication failures")
 #define DCIDESC_AGENT_CONFIG_SERVER               _T("Configuration server address set on agent startup")
+#define DCIDESC_AGENT_DATACOLLQUEUESIZE           _T("Agent data collector queue size")
 #define DCIDESC_AGENT_FAILEDREQUESTS              _T("Number of failed requests to agent")
 #define DCIDESC_AGENT_GENERATED_TRAPS             _T("Number of traps generated by agent")
 #define DCIDESC_AGENT_IS_SUBAGENT_LOADED          _T("Check if given subagent is loaded")
index 36d90fd..d085dc5 100644 (file)
@@ -346,6 +346,32 @@ public:
        void shrink(int chars = 1);
 };
 
+/**
+ * Abstract iterator class (to be implemented by actual iterable class)
+ */
+class LIBNETXMS_EXPORTABLE AbstractIterator
+{
+public:
+   virtual bool hasNext() = 0;
+   virtual void *next() = 0;
+};
+
+/**
+ * Iterator class (public interface for iteration)
+ */
+template <class T> class Iterator
+{
+private:
+   AbstractIterator *m_worker;
+
+public:
+   Iterator(AbstractIterator *worker) { m_worker = worker; }
+   ~Iterator() { delete m_worker; }
+
+   bool hasNext() { return m_worker->hasNext(); }
+   T *next() { return (T *)m_worker->next(); }
+};
+
 /**
  * Dynamic array class
  */
@@ -392,6 +418,22 @@ public:
        bool isOwner() const { return m_objectOwner; }
 };
 
+/**
+ * Array iterator class
+ */
+class LIBNETXMS_EXPORTABLE ArrayIterator : public AbstractIterator
+{
+private:
+   const Array *m_array;
+   int m_pos;
+
+public:
+   ArrayIterator(const Array *array);
+
+   virtual bool hasNext();
+   virtual void *next();
+};
+
 /**
  * Template class for dynamic array which holds objects
  */
@@ -414,6 +456,8 @@ public:
    void remove(T *object) { Array::remove((void *)object); }
        void unlink(int index) { Array::unlink(index); }
    void unlink(T *object) { Array::unlink((void *)object); }
+
+   Iterator<T> *iterator() const { return new Iterator<T>(new ArrayIterator(this)); }
 };
 
 /**
@@ -654,12 +698,14 @@ struct HashMapEntry;
  */
 class LIBNETXMS_EXPORTABLE HashMapBase
 {
+   friend class HashMapIterator;
+
 private:
    HashMapEntry *m_data;
        bool m_objectOwner;
    unsigned int m_keylen;
 
-       HashMapEntry *find(const void *key);
+       HashMapEntry *find(const void *key) const;
        void destroyObject(void *object) { if (object != NULL) m_objectDestructor(object); }
 
 protected:
@@ -667,11 +713,11 @@ protected:
 
        HashMapBase(bool objectOwner, unsigned int keylen);
 
-       void *_get(const void *key);
+       void *_get(const void *key) const;
        void _set(const void *key, void *value);
        void _remove(const void *key);
 
-   bool _contains(const void *key) { return find(key) != NULL; }
+   bool _contains(const void *key) const { return find(key) != NULL; }
 
 public:
    virtual ~HashMapBase();
@@ -679,10 +725,27 @@ public:
    void setOwner(bool owner) { m_objectOwner = owner; }
        void clear();
 
-       int size();
+       int size() const;
+
+   EnumerationCallbackResult forEach(EnumerationCallbackResult (*cb)(const void *, const void *, void *), void *userData) const;
+   const void *findElement(bool (*comparator)(const void *, const void *, void *), void *userData) const;
+};
 
-   EnumerationCallbackResult forEach(EnumerationCallbackResult (*cb)(const void *, const void *, void *), void *userData);
-   const void *findElement(bool (*comparator)(const void *, const void *, void *), void *userData);
+/**
+ * Hash map iterator
+ */
+class LIBNETXMS_EXPORTABLE HashMapIterator : public AbstractIterator
+{
+private:
+   HashMapBase *m_hashMap;
+   HashMapEntry *m_curr;
+   HashMapEntry *m_next;
+
+public:
+   HashMapIterator(HashMapBase *hashMap);
+
+   virtual bool hasNext();
+   virtual void *next();
 };
 
 /**
@@ -700,6 +763,8 @@ public:
        void set(const K& key, V *value) { _set(&key, (void *)value); }
    void remove(const K& key) { _remove(&key); }
    bool contains(const K& key) { return _contains(&key); }
+
+   Iterator<V> *iterator() { return new Iterator<V>(new HashMapIterator(this)); }
 };
 
 /**
index 7cf335d..f5e324a 100644 (file)
@@ -861,13 +861,29 @@ do {
             (HASH_BLOOM_BYTELEN)))
 
 #ifdef NO_DECLTYPE
+
 #define HASH_ITER(hh,head,el,tmp)                                                \
 for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL);       \
   el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) 
+
+#define HASH_ITER_START(hh,head,el,tmp)                                          \
+do { (el)=(head); (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); } while(0)
+
+#define HASH_ITER_NEXT(hh,el,tmp)                                                \
+do { (el)=(tmp); (*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL); } while(0)
+
 #else
+
 #define HASH_ITER(hh,head,el,tmp)                                                \
 for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL);                 \
   el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL))
+
+#define HASH_ITER_START(hh,head,el,tmp)                                          \
+do { (el)=(head); (tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); } while(0)
+
+#define HASH_ITER_NEXT(hh,el,tmp)                                                \
+do { (el)=(tmp); (tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL); } while(0)
+
 #endif
 
 /* obtain a count of items in the hash */
index 25826bf..598a1a8 100644 (file)
@@ -1254,3 +1254,23 @@ void ClearDataCollectionConfiguration()
    s_serverSyncStatus.clear();
    MutexUnlock(s_serverSyncStatusLock);
 }
+
+/**
+ * Handler for data collector queue size
+ */
+LONG H_DataCollectorQueueSize(const TCHAR *cmd, const TCHAR *arg, TCHAR *value, AbstractCommSession *session)
+{
+   if (!s_dataCollectorStarted)
+      return SYSINFO_RC_UNSUPPORTED;
+
+   UINT32 count = 0;
+   MutexLock(s_serverSyncStatusLock);
+   Iterator<ServerSyncStatus> *it = s_serverSyncStatus.iterator();
+   while(it->hasNext())
+      count += (UINT32)it->next()->queueSize;
+   delete it;
+   MutexUnlock(s_serverSyncStatusLock);
+
+   ret_uint(value, count);
+   return SYSINFO_RC_SUCCESS;
+}
index 0bda2ad..d3af7ef 100644 (file)
 /**
  * Parameter handlers
  */
-LONG H_ActiveConnections(const TCHAR *cmd, const TCHAR *arg, TCHAR *pValue, AbstractCommSession *session);
+LONG H_ActiveConnections(const TCHAR *cmd, const TCHAR *arg, TCHAR *value, AbstractCommSession *session);
 LONG H_AgentTraps(const TCHAR *cmd, const TCHAR *arg, TCHAR *value, AbstractCommSession *session);
 LONG H_AgentUptime(const TCHAR *cmd, const TCHAR *arg, TCHAR *value, AbstractCommSession *session);
 LONG H_CRC32(const TCHAR *cmd, const TCHAR *arg, TCHAR *value, AbstractCommSession *session);
+LONG H_DataCollectorQueueSize(const TCHAR *cmd, const TCHAR *arg, TCHAR *value, AbstractCommSession *session);
 LONG H_DirInfo(const TCHAR *cmd, const TCHAR *arg, TCHAR *value, AbstractCommSession *session);
 LONG H_FileTime(const TCHAR *cmd, const TCHAR *arg, TCHAR *value, AbstractCommSession *session);
-LONG H_IsSubagentLoaded(const TCHAR *pszCmd, const TCHAR *pArg, TCHAR *pValue, AbstractCommSession *session);
+LONG H_IsSubagentLoaded(const TCHAR *cmd, const TCHAR *arg, TCHAR *value, AbstractCommSession *session);
 LONG H_MD5Hash(const TCHAR *cmd, const TCHAR *arg, TCHAR *value, AbstractCommSession *session);
 LONG H_SHA1Hash(const TCHAR *cmd, const TCHAR *arg, TCHAR *value, AbstractCommSession *session);
 LONG H_SubAgentList(const TCHAR *cmd, const TCHAR *arg, StringList *value, AbstractCommSession *session);
@@ -223,6 +224,7 @@ static NETXMS_SUBAGENT_PARAM m_stdParams[] =
    { _T("Agent.ActiveConnections"), H_ActiveConnections, NULL, DCI_DT_UINT, DCIDESC_AGENT_ACTIVECONNECTIONS },
    { _T("Agent.AuthenticationFailures"), H_UIntPtr, (TCHAR *)&m_dwAuthenticationFailures, DCI_DT_UINT, DCIDESC_AGENT_AUTHENTICATIONFAILURES },
    { _T("Agent.ConfigurationServer"), H_StringConstant, g_szConfigServer, DCI_DT_STRING, DCIDESC_AGENT_CONFIG_SERVER },
+   { _T("Agent.DataCollectorQueueSize"), H_DataCollectorQueueSize, NULL, DCI_DT_UINT, DCIDESC_AGENT_DATACOLLQUEUESIZE },
    { _T("Agent.FailedRequests"), H_UIntPtr, (TCHAR *)&m_dwFailedRequests, DCI_DT_UINT, DCIDESC_AGENT_FAILEDREQUESTS },
    { _T("Agent.GeneratedTraps"), H_AgentTraps, _T("G"), DCI_DT_UINT64, DCIDESC_AGENT_GENERATED_TRAPS },
    { _T("Agent.IsSubagentLoaded(*)"), H_IsSubagentLoaded, NULL, DCI_DT_INT, DCIDESC_AGENT_IS_SUBAGENT_LOADED },
index ee45634..77587a9 100644 (file)
@@ -229,3 +229,32 @@ void *Array::find(const void *key, int (*cb)(const void *, const void *)) const
 {
    return bsearch(key, m_data, m_size, m_elementSize, cb);
 }
+
+/**
+ * Array iterator
+ */
+ArrayIterator::ArrayIterator(const Array *array)
+{
+   m_array = array;
+   m_pos = -1;
+}
+
+/**
+ * Next element availability indicator
+ */
+bool ArrayIterator::hasNext()
+{
+   return (m_pos + 1) < m_array->size();
+}
+
+/**
+ * Get next element
+ */
+void *ArrayIterator::next()
+{
+   if ((m_pos + 1) >= m_array->size())
+      return NULL;
+
+   m_pos++;
+   return m_array->get(m_pos);
+}
index 7d850ea..5ece01c 100644 (file)
@@ -93,7 +93,7 @@ void HashMapBase::clear()
 /**
  * Find entry index by key
  */
-HashMapEntry *HashMapBase::find(const void *key)
+HashMapEntry *HashMapBase::find(const void *key) const
 {
        if (key == NULL)
                return NULL;
@@ -133,7 +133,7 @@ void HashMapBase::_set(const void *key, void *value)
 /**
  * Get value by key
  */
-void *HashMapBase::_get(const void *key)
+void *HashMapBase::_get(const void *key) const
 {
    HashMapEntry *entry;
    HASH_FIND(hh, m_data, key, m_keylen, entry);
@@ -161,7 +161,7 @@ void HashMapBase::_remove(const void *key)
  * Enumerate entries
  * Returns true if whole map was enumerated and false if enumeration was aborted by callback.
  */
-EnumerationCallbackResult HashMapBase::forEach(EnumerationCallbackResult (*cb)(const void *, const void *, void *), void *userData)
+EnumerationCallbackResult HashMapBase::forEach(EnumerationCallbackResult (*cb)(const void *, const void *, void *), void *userData) const
 {
    EnumerationCallbackResult result = _CONTINUE;
    HashMapEntry *entry, *tmp;
@@ -179,7 +179,7 @@ EnumerationCallbackResult HashMapBase::forEach(EnumerationCallbackResult (*cb)(c
 /**
  * Find entry
  */
-const void *HashMapBase::findElement(bool (*comparator)(const void *, const void *, void *), void *userData)
+const void *HashMapBase::findElement(bool (*comparator)(const void *, const void *, void *), void *userData) const
 {
    const void *result = NULL;
    HashMapEntry *entry, *tmp;
@@ -197,7 +197,50 @@ const void *HashMapBase::findElement(bool (*comparator)(const void *, const void
 /**
  * Get size
  */
-int HashMapBase::size()
+int HashMapBase::size() const
 {
    return HASH_COUNT(m_data);
 }
+
+/**
+ * Hash map iterator
+ */
+HashMapIterator::HashMapIterator(HashMapBase *hashMap)
+{
+   m_hashMap = hashMap;
+   m_curr = NULL;
+   m_next = NULL;
+}
+
+/**
+ * Next element availability indicator
+ */
+bool HashMapIterator::hasNext()
+{
+   if (m_hashMap->m_data == NULL)
+      return false;
+
+   return (m_curr != NULL) ? (m_next != NULL) : true;
+}
+
+/**
+ * Get next element
+ */
+void *HashMapIterator::next()
+{
+   if (m_hashMap->m_data == NULL)
+      return NULL;
+
+   if (m_curr == NULL)  // iteration not started
+   {
+      HASH_ITER_START(hh, m_hashMap->m_data, m_curr, m_next);
+   }
+   else
+   {
+      if (m_next == NULL)
+         return NULL;
+
+      HASH_ITER_NEXT(hh, m_curr, m_next);
+   }
+   return m_curr->value;
+}
index e9434e3..5bd23d5 100644 (file)
@@ -447,14 +447,86 @@ static void TestHashMap()
    AssertTrue(!_tcscmp(s->getBuffer(), _T("REPLACE")));
    EndTest();
 
+   StartTest(_T("HashMap: iterator"));
+   Iterator<String> *it = hashMap->iterator();
+   AssertTrue(it->hasNext());
+   s = it->next();
+   AssertNotNull(s);
+   AssertNotNull(it->next());
+   AssertNotNull(it->next());
+   AssertFalse(it->hasNext());
+   AssertNull(it->next());
+   AssertFalse(it->hasNext());
+   delete it;
+   EndTest();
+
    StartTest(_T("HashMap: remove"));
    hashMap->remove(k3);
    AssertNull(hashMap->get(k3));
    EndTest();
 
+   StartTest(_T("HashMap: clear"));
+   hashMap->clear();
+   AssertEquals(hashMap->size(), 0);
+   it = hashMap->iterator();
+   AssertFalse(it->hasNext());
+   AssertNull(it->next());
+   delete it;
+   EndTest();
+
    delete hashMap;
 }
 
+/**
+ * Test array
+ */
+static void TestObjectArray()
+{
+   StartTest(_T("ObjectArray: create"));
+   ObjectArray<String> *array = new ObjectArray<String>(16, 16, true);
+   AssertEquals(array->size(), 0);
+   EndTest();
+
+   StartTest(_T("ObjectArray: add/get"));
+   array->add(new String(_T("value 1")));
+   array->add(new String(_T("value 2")));
+   array->add(new String(_T("value 3")));
+   array->add(new String(_T("value 4")));
+   AssertEquals(array->size(), 4);
+   AssertNull(array->get(4));
+   AssertNotNull(array->get(1));
+   AssertTrue(!_tcscmp(array->get(1)->getBuffer(), _T("value 2")));
+   EndTest();
+
+   StartTest(_T("ObjectArray: replace"));
+   array->replace(0, new String(_T("replace")));
+   AssertEquals(array->size(), 4);
+   AssertTrue(!_tcscmp(array->get(0)->getBuffer(), _T("replace")));
+   EndTest();
+
+   StartTest(_T("ObjectArray: remove"));
+   array->remove(0);
+   AssertEquals(array->size(), 3);
+   AssertTrue(!_tcscmp(array->get(0)->getBuffer(), _T("value 2")));
+   EndTest();
+
+   StartTest(_T("ObjectArray: iterator"));
+   Iterator<String> *it = array->iterator();
+   AssertTrue(it->hasNext());
+   String *s = it->next();
+   AssertTrue(!_tcscmp(s->getBuffer(), _T("value 2")));
+   s = it->next();
+   AssertTrue(!_tcscmp(s->getBuffer(), _T("value 3")));
+   s = it->next();
+   AssertTrue(!_tcscmp(s->getBuffer(), _T("value 4")));
+   s = it->next();
+   AssertNull(s);
+   delete it;
+   EndTest();
+
+   delete array;
+}
+
 /**
  * main()
  */
@@ -475,5 +547,6 @@ int main(int argc, char *argv[])
    TestItoa();
    TestQueue();
    TestHashMap();
+   TestObjectArray();
    return 0;
 }