Implemented retention time for DCO instances. Fixes #NX-757
authorEriks Jenkevics <eriks@netxms.org>
Thu, 16 Nov 2017 12:08:16 +0000 (14:08 +0200)
committerEriks Jenkevics <eriks@netxms.org>
Thu, 23 Nov 2017 15:52:07 +0000 (17:52 +0200)
18 files changed:
include/netxmsdb.h
include/nms_cscp.h
sql/schema.in
src/client/java/netxms-client/src/main/java/org/netxms/client/datacollection/DataCollectionObject.java
src/java/netxms-eclipse/DataCollection/src/org/netxms/ui/eclipse/datacollection/propertypages/InstanceDiscovery.java
src/java/netxms-eclipse/DataCollection/src/org/netxms/ui/eclipse/datacollection/views/DataCollectionEditor.java
src/libnxjava/java/base/netxms-base/src/main/java/org/netxms/base/NXCPCodes.java
src/server/core/dcitem.cpp
src/server/core/dcobject.cpp
src/server/core/dctable.cpp
src/server/core/dctarget.cpp
src/server/core/main.cpp
src/server/core/template.cpp
src/server/include/nms_core.h
src/server/include/nms_dcoll.h
src/server/tools/nxdbmgr/upgrade_v30.cpp
webui/webapp/DataCollection/src/org/netxms/ui/eclipse/datacollection/propertypages/InstanceDiscovery.java
webui/webapp/DataCollection/src/org/netxms/ui/eclipse/datacollection/views/DataCollectionEditor.java

index a6eebbc..5ef464b 100644 (file)
@@ -25,7 +25,7 @@
 
 #define DB_LEGACY_SCHEMA_VERSION       700
 #define DB_SCHEMA_VERSION_MAJOR        30
-#define DB_SCHEMA_VERSION_MINOR        12
+#define DB_SCHEMA_VERSION_MINOR        13
 
 #define DB_SCHEMA_VERSION_V30_MINOR    DB_SCHEMA_VERSION_MINOR
 
index a06d9e5..a90d945 100644 (file)
@@ -1217,6 +1217,7 @@ typedef struct
 #define VID_ZONE_SNMP_PORT_COUNT    ((UINT32)607)
 #define VID_INCLUDE_RAW_VALUES      ((UINT32)608)
 #define VID_JOB_CANCELED            ((UINT32)609)
+#define VID_INSTANCE_RETENTION      ((UINT32)610)
 
 // Base variabe for single threshold in message
 #define VID_THRESHOLD_BASE          ((UINT32)0x00800000)
index 137c002..377904f 100644 (file)
@@ -630,6 +630,7 @@ CREATE TABLE items
   samples integer not null,
   npe_name varchar(15) null,
   comments SQL_TEXT null,
+  instance_retention_time integer not null,
   PRIMARY KEY(item_id)
 ) TABLE_TYPE;
 
@@ -690,6 +691,7 @@ CREATE TABLE dc_tables
   instd_method integer not null,
   instd_data varchar(255) null,
   instd_filter SQL_TEXT null,
+  instance_retention_time integer not null,
   PRIMARY KEY(item_id)
 ) TABLE_TYPE;
 
index 3ff8191..5a7452e 100644 (file)
@@ -102,6 +102,7 @@ public abstract class DataCollectionObject
    private String instanceDiscoveryData;
    private String instanceDiscoveryFilter;
    private List<Long> accessList;
+   private int instanceRetentionTime;
 
        /**
         * Create data collection object from NXCP message
@@ -128,6 +129,7 @@ public abstract class DataCollectionObject
                perfTabSettings = msg.getFieldAsString(NXCPCodes.VID_PERFTAB_SETTINGS);
                snmpPort = msg.getFieldAsInt32(NXCPCodes.VID_SNMP_PORT);
                comments = msg.getFieldAsString(NXCPCodes.VID_COMMENTS);
+               instanceRetentionTime = msg.getFieldAsInt32(NXCPCodes.VID_INSTANCE_RETENTION);
                
                int count = msg.getFieldAsInt32(NXCPCodes.VID_NUM_SCHEDULES);
                schedules = new ArrayList<String>(count);
@@ -177,6 +179,7 @@ public abstract class DataCollectionObject
                comments = "";
       instance = "";
       accessList = new ArrayList<Long>(0);
+      instanceRetentionTime = -1;
        }
        
        /**
@@ -202,6 +205,7 @@ public abstract class DataCollectionObject
                        msg.setField(NXCPCodes.VID_PERFTAB_SETTINGS, perfTabSettings);
                msg.setFieldInt16(NXCPCodes.VID_SNMP_PORT, snmpPort);
                msg.setField(NXCPCodes.VID_COMMENTS, comments);
+               msg.setFieldInt32(NXCPCodes.VID_INSTANCE_RETENTION, instanceRetentionTime);
                
                msg.setFieldInt32(NXCPCodes.VID_NUM_SCHEDULES, schedules.size());
                long varId = NXCPCodes.VID_DCI_SCHEDULE_BASE;
@@ -734,4 +738,24 @@ public abstract class DataCollectionObject
    {
       accessList = list;
    }
+   
+   /**
+    * Get instance retention time
+    * 
+    * @return instance retention time
+    */
+   public int getInstanceRetentionTime()
+   {
+      return instanceRetentionTime;
+   }
+   
+   /**
+    * Set instance retention time
+    * 
+    * @param instanceRetentionTime the retention time to set
+    */
+   public void setInstanceRetentionTime(int instanceRetentionTime)
+   {
+      this.instanceRetentionTime = instanceRetentionTime;
+   }
 }
index 7d67eda..3603d0b 100644 (file)
@@ -27,6 +27,8 @@ import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Combo;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Spinner;
 import org.netxms.client.datacollection.DataCollectionObject;
 import org.netxms.ui.eclipse.datacollection.Messages;
 import org.netxms.ui.eclipse.datacollection.api.DataCollectionObjectEditor;
@@ -49,6 +51,9 @@ public class InstanceDiscovery extends DCIPropertyPageDialog
        private Combo discoveryMethod;
        private LabeledText discoveryData;
        private ScriptEditor filterScript;
+       private Group groupRetention;
+   private Combo instanceRetentionMode;
+       private Spinner instanceRetentionTime;
        
        /* (non-Javadoc)
         * @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite)
@@ -83,6 +88,8 @@ public class InstanceDiscovery extends DCIPropertyPageDialog
                      discoveryData.setLabel(getDataLabel(method));
                      discoveryData.setEnabled(method != DataCollectionObject.IDM_NONE);
                      filterScript.setEnabled(method != DataCollectionObject.IDM_NONE);
+            instanceRetentionMode.setEnabled(method != DataCollectionObject.IDM_NONE);
+                     instanceRetentionTime.setEnabled(method != DataCollectionObject.IDM_NONE && instanceRetentionMode.getSelectionIndex() > 0);
                        }
                        
                        @Override
@@ -100,7 +107,54 @@ public class InstanceDiscovery extends DCIPropertyPageDialog
       gd.grabExcessHorizontalSpace = true;
       discoveryData.setLayoutData(gd);
       discoveryData.setEnabled(dco.getInstanceDiscoveryMethod() != DataCollectionObject.IDM_NONE);
-     
+      
+      groupRetention = new Group(dialogArea, SWT.NONE);
+      groupRetention.setText("Instance retention");
+      gd = new GridData();
+      gd = new GridData();
+      gd.horizontalAlignment = SWT.FILL;
+      gd.verticalAlignment = SWT.FILL;
+      gd.horizontalSpan = 2;
+      groupRetention.setLayoutData(gd);
+      GridLayout retentionLayout = new GridLayout();
+      retentionLayout.numColumns = 2;
+      retentionLayout.horizontalSpacing = WidgetHelper.OUTER_SPACING;
+      groupRetention.setLayout(retentionLayout);
+      
+      gd = new GridData();
+      gd.grabExcessHorizontalSpace = true;
+      gd.horizontalAlignment = SWT.FILL;
+      instanceRetentionMode = WidgetHelper.createLabeledCombo(groupRetention, SWT.READ_ONLY, "Instance retention mode", gd);
+      instanceRetentionMode.add("Server default");
+      instanceRetentionMode.add("Custom");
+      instanceRetentionMode.select(dco.getInstanceRetentionTime() == -1 ? 0 : 1);
+      instanceRetentionMode.setEnabled(dco.getInstanceDiscoveryMethod() != DataCollectionObject.IDM_NONE);
+      instanceRetentionMode.addSelectionListener(new SelectionListener() {
+          /* (non-Javadoc)
+          * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+          */
+         @Override
+         public void widgetSelected(SelectionEvent e)
+         {
+            instanceRetentionTime.setEnabled(instanceRetentionMode.getSelectionIndex() == 1);
+         }
+         /* (non-Javadoc)
+          * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
+          */
+         @Override
+         public void widgetDefaultSelected(SelectionEvent e)
+         {
+           widgetSelected(e); 
+         }
+      });
+      
+      gd = new GridData();
+      gd.grabExcessHorizontalSpace = true;
+      gd.horizontalAlignment = SWT.FILL;
+      instanceRetentionTime = WidgetHelper.createLabeledSpinner(groupRetention, SWT.BORDER, "Instance retention time (days)", 0, 100,  new GridData());
+      instanceRetentionTime.setSelection(dco.getInstanceRetentionTime());
+      instanceRetentionTime.setEnabled(instanceRetentionMode.getSelectionIndex() > 0);
+      
       gd = new GridData();
       gd.horizontalAlignment = SWT.FILL;
       gd.verticalAlignment = SWT.FILL;
@@ -165,6 +219,10 @@ public class InstanceDiscovery extends DCIPropertyPageDialog
           dco.setInstanceDiscoveryMethod(discoveryMethod.getSelectionIndex());
           dco.setInstanceDiscoveryData(discoveryData.getText());
           dco.setInstanceDiscoveryFilter(filterScript.getText());
+          if (instanceRetentionMode.getSelectionIndex() == 0)
+             dco.setInstanceRetentionTime(-1);
+          else
+             dco.setInstanceRetentionTime(instanceRetentionTime.getSelection());
                editor.modify();
        }
 
@@ -200,5 +258,7 @@ public class InstanceDiscovery extends DCIPropertyPageDialog
                discoveryData.setEnabled(false);
                filterScript.setText(""); //$NON-NLS-1$
                filterScript.setEnabled(false);
+               instanceRetentionMode.select(0);
+               instanceRetentionTime.setSelection(0);
        }
 }
index 8ab8bc5..2b84901 100644 (file)
@@ -612,6 +612,7 @@ public class DataCollectionEditor extends ViewPart
                                                {
                                                        ((DataCollectionObject)dci).setStatus(newStatus);
                                                        viewer.update(dci, null);
+                     new DataCollectionObjectEditor((DataCollectionObject)dci).modify();
                                                }
                                        }
                                });
index 9b08b5e..ab87c26 100644 (file)
@@ -997,6 +997,7 @@ public class NXCPCodes
    public static final long VID_ZONE_SNMP_PORT_COUNT = 607;
    public static final long VID_INCLUDE_RAW_VALUES = 608;
    public static final long VID_JOB_CANCELED = 609;
+   public static final long VID_INSTANCE_RETENTION = 610;
 
        public static final long VID_ACL_USER_BASE = 0x00001000L;
        public static final long VID_ACL_USER_LAST = 0x00001FFFL;
index 4961795..ac750b0 100644 (file)
@@ -148,6 +148,7 @@ DCItem::DCItem(DB_HANDLE hdb, DB_RESULT hResult, int iRow, Template *pNode) : DC
    m_comments = DBGetField(hResult, iRow, 27, NULL, 0);
    m_guid = DBGetFieldGUID(hResult, iRow, 28);
    DBGetField(hResult, iRow, 29, m_predictionEngine, MAX_NPE_NAME_LEN);
+   m_instanceRetentionTime = DBGetFieldLong(hResult, iRow, 30);
 
    // Load last raw value from database
        TCHAR szQuery[256];
@@ -323,7 +324,7 @@ bool DCItem::saveToDatabase(DB_HANDLE hdb)
                           _T("unit_multiplier=?,custom_units_name=?,perftab_settings=?,")
                      _T("system_tag=?,snmp_port=?,snmp_raw_value_type=?,")
                                          _T("instd_method=?,instd_data=?,instd_filter=?,samples=?,")
-                                         _T("comments=?,guid=?,npe_name=? WHERE item_id=?"));
+                                         _T("comments=?,guid=?,npe_name=?,instance_retention_time=? WHERE item_id=?"));
        }
    else
        {
@@ -333,8 +334,8 @@ bool DCItem::saveToDatabase(DB_HANDLE hdb)
                  _T("transformation,description,instance,template_item_id,flags,")
                  _T("resource_id,proxy_node,base_units,unit_multiplier,")
                           _T("custom_units_name,perftab_settings,system_tag,snmp_port,snmp_raw_value_type,")
-                                         _T("instd_method,instd_data,instd_filter,samples,comments,guid,npe_name,item_id) VALUES ")
-                          _T("(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
+                                         _T("instd_method,instd_data,instd_filter,samples,comments,guid,npe_name,instance_retention_time,item_id) VALUES ")
+                          _T("(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
        }
        if (hStmt == NULL)
                return false;
@@ -371,7 +372,8 @@ bool DCItem::saveToDatabase(DB_HANDLE hdb)
    DBBind(hStmt, 28, DB_SQLTYPE_TEXT, m_comments, DB_BIND_STATIC);
    DBBind(hStmt, 29, DB_SQLTYPE_VARCHAR, m_guid);
    DBBind(hStmt, 30, DB_SQLTYPE_VARCHAR, m_predictionEngine, DB_BIND_STATIC);
-       DBBind(hStmt, 31, DB_SQLTYPE_INTEGER, m_id);
+   DBBind(hStmt, 31, DB_SQLTYPE_INTEGER, m_instanceRetentionTime);
+       DBBind(hStmt, 32, DB_SQLTYPE_INTEGER, m_id);
 
    bool bResult = DBExecute(hStmt);
        DBFreeStatement(hStmt);
@@ -1509,6 +1511,7 @@ void DCItem::createExportRecord(String &str)
                           _T("\t\t\t\t\t<snmpRawValueType>%d</snmpRawValueType>\n")
                           _T("\t\t\t\t\t<snmpPort>%d</snmpPort>\n")
                           _T("\t\t\t\t\t<instanceDiscoveryMethod>%d</instanceDiscoveryMethod>\n"),
+                          _T("\t\t\t\t\t<instanceRetentionTime>%d</instanceRetentionTime>\n"),
                                                                  (int)m_id, (const TCHAR *)m_guid.toString(),
                                                                  (const TCHAR *)EscapeStringForXML2(m_name),
                           (const TCHAR *)EscapeStringForXML2(m_description),
@@ -1516,7 +1519,8 @@ void DCItem::createExportRecord(String &str)
                           (const TCHAR *)EscapeStringForXML2(m_instance),
                           (const TCHAR *)EscapeStringForXML2(m_systemTag),
                                                                  (int)m_deltaCalculation, (int)m_flags,
-                                                                 (int)m_snmpRawValueType, (int)m_snmpPort, (int)m_instanceDiscoveryMethod);
+                                                                 (int)m_snmpRawValueType, (int)m_snmpPort, (int)m_instanceDiscoveryMethod),
+                                                                 m_instanceRetentionTime;
 
        if (m_transformationScriptSource != NULL)
        {
index 3f66992..3b430ef 100644 (file)
@@ -71,6 +71,8 @@ DCObject::DCObject()
    m_instanceFilter = NULL;
    m_instance[0] = 0;
    m_accessList = new IntegerArray<UINT32>(0, 16);
+   m_instanceRetentionTime = -1;
+   m_lastAttemptToRemove = 0;
 }
 
 /**
@@ -117,6 +119,7 @@ DCObject::DCObject(const DCObject *pSrc)
    setInstanceFilter(pSrc->m_instanceFilterSource);
    _tcscpy(m_instance, pSrc->m_instance);
    m_accessList = new IntegerArray<UINT32>(pSrc->m_accessList);
+   m_instanceRetentionTime = pSrc->m_instanceRetentionTime;
 }
 
 /**
@@ -163,6 +166,8 @@ DCObject::DCObject(UINT32 dwId, const TCHAR *szName, int iSource,
    m_instanceFilter = NULL;
    m_instance[0] = 0;
    m_accessList = new IntegerArray<UINT32>(0, 16);
+   m_instanceRetentionTime = -1;
+   m_lastAttemptToRemove = 0;
 }
 
 /**
@@ -229,6 +234,8 @@ DCObject::DCObject(ConfigEntry *config, Template *owner)
    setInstanceFilter(config->getSubEntryValue(_T("instanceFilter")));
    nx_strncpy(m_instance, config->getSubEntryValue(_T("instance"), 0, _T("")), MAX_DB_STRING);
    m_accessList = new IntegerArray<UINT32>(0, 16);
+   m_instanceRetentionTime = config->getSubEntryValueAsInt(_T("instanceRetentionTime"), 0, -1);
+   m_lastAttemptToRemove = 0;
 }
 
 /**
@@ -726,6 +733,7 @@ void DCObject::createMessage(NXCPMessage *pMsg)
       pMsg->setField(VID_INSTD_FILTER, m_instanceFilterSource);
    pMsg->setField(VID_INSTANCE, m_instance);
    pMsg->setFieldFromInt32Array(VID_ACL, m_accessList);
+   pMsg->setField(VID_INSTANCE_RETENTION, m_instanceRetentionTime);
    unlock();
 }
 
@@ -795,6 +803,8 @@ void DCObject::updateFromMessage(NXCPMessage *pMsg)
    m_accessList->clear();
    pMsg->getFieldAsInt32Array(VID_ACL, m_accessList);
 
+   m_instanceRetentionTime = pMsg->getFieldAsInt32(VID_INSTANCE_RETENTION);
+
        unlock();
 }
 
@@ -935,6 +945,7 @@ void DCObject::updateFromTemplate(DCObject *src)
       delete_and_null(m_instanceFilter);
       setInstanceFilter(src->m_instanceFilterSource);
    }
+   m_instanceRetentionTime = src->m_instanceRetentionTime;
 
        unlock();
 }
@@ -1093,6 +1104,7 @@ void DCObject::updateFromImport(ConfigEntry *config)
    m_instanceDiscoveryData = _tcsdup_ex(value);
    setInstanceFilter(config->getSubEntryValue(_T("instanceFilter")));
    nx_strncpy(m_instance, config->getSubEntryValue(_T("instance"), 0, _T("")), MAX_DB_STRING);
+   m_instanceRetentionTime = config->getSubEntryValueAsInt(_T("instanceRetentionTime"), 0, -1);
 
    unlock();
 }
@@ -1381,6 +1393,7 @@ json_t *DCObject::toJson()
    json_object_set_new(root, "instanceFilter", json_string_t(m_instanceFilterSource));
    json_object_set_new(root, "instance", json_string_t(m_instance));
    json_object_set_new(root, "accessList", m_accessList->toJson());
+   json_object_set_new(root, "instanceRetentionTime", json_integer(m_instanceRetentionTime));
    return root;
 }
 
index aa858bd..f0dfe8f 100644 (file)
@@ -193,6 +193,7 @@ DCTable::DCTable(DB_HANDLE hdb, DB_RESULT hResult, int iRow, Template *pNode) :
    setInstanceFilter(pszTmp);
    free(pszTmp);
    DBGetField(hResult, iRow, 21, m_instance, MAX_DB_STRING);
+   m_instanceRetentionTime = DBGetFieldLong(hResult, iRow, 22);
 
    m_owner = pNode;
        m_columns = new ObjectArray<DCTableColumn>(8, 8, true);
@@ -490,7 +491,7 @@ bool DCTable::saveToDatabase(DB_HANDLE hdb)
                                       _T("description=?,flags=?,source=?,snmp_port=?,polling_interval=?,")
                              _T("retention_time=?,status=?,system_tag=?,resource_id=?,proxy_node=?,")
                                                                          _T("perftab_settings=?,transformation_script=?,comments=?,guid=?,")
-                                                                         _T("instd_method=?,instd_data=?,instd_filter=?,instance=? WHERE item_id=?"));
+                                                                         _T("instd_method=?,instd_data=?,instd_filter=?,instance=?,instance_retention_time=? WHERE item_id=?"));
        }
        else
        {
@@ -498,8 +499,8 @@ bool DCTable::saveToDatabase(DB_HANDLE hdb)
                                       _T("description,flags,source,snmp_port,polling_interval,")
                                       _T("retention_time,status,system_tag,resource_id,proxy_node,perftab_settings,")
                                                                          _T("transformation_script,comments,guid,")
-                                                                         _T("instd_method,instd_data,instd_filter,instance,item_id) ")
-                                                                         _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
+                                                                         _T("instd_method,instd_data,instd_filter,instance,instance_retention_time,item_id) ")
+                                                                         _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
        }
        if (hStmt == NULL)
                return FALSE;
@@ -528,7 +529,8 @@ bool DCTable::saveToDatabase(DB_HANDLE hdb)
    DBBind(hStmt, 20, DB_SQLTYPE_VARCHAR, m_instanceDiscoveryData, DB_BIND_STATIC);
    DBBind(hStmt, 21, DB_SQLTYPE_TEXT, m_instanceFilterSource, DB_BIND_STATIC);
    DBBind(hStmt, 22, DB_SQLTYPE_VARCHAR, m_instance, DB_BIND_STATIC);
-   DBBind(hStmt, 23, DB_SQLTYPE_INTEGER, m_id);
+   DBBind(hStmt, 23, DB_SQLTYPE_INTEGER, m_instanceRetentionTime);
+   DBBind(hStmt, 24, DB_SQLTYPE_INTEGER, m_id);
 
        bool result = DBExecute(hStmt);
        DBFreeStatement(hStmt);
@@ -987,13 +989,14 @@ void DCTable::createExportRecord(String &str)
                           _T("\t\t\t\t\t<snmpPort>%d</snmpPort>\n")
                           _T("\t\t\t\t\t<instanceDiscoveryMethod>%d</instanceDiscoveryMethod>\n")
                           _T("\t\t\t\t\t<instance>%s</instance>\n"),
+                          _T("\t\t\t\t\t<instanceRetentionTime>%d</instanceRetentionTime>\n"),
                                                                  (int)m_id, (const TCHAR *)m_guid.toString(),
                                                                  (const TCHAR *)EscapeStringForXML2(m_name),
                           (const TCHAR *)EscapeStringForXML2(m_description),
                           (int)m_source, m_iPollingInterval, m_iRetentionTime,
                           (const TCHAR *)EscapeStringForXML2(m_systemTag),
                                                                  (int)m_flags, (int)m_snmpPort, (int)m_instanceDiscoveryMethod,
-                                                                 (const TCHAR *)EscapeStringForXML2(m_instance));
+                                                                 (const TCHAR *)EscapeStringForXML2(m_instance)), m_instanceRetentionTime;
 
        if (m_transformationScriptSource != NULL)
        {
index 67f331f..69a5c20 100644 (file)
@@ -1638,7 +1638,7 @@ bool DataCollectionTarget::updateInstances(DCObject *root, StringMap *instances,
       if (instances->forEach(FindInstanceCallback, (void *)dcoInstance) == _STOP)
       {
          // found, remove value from instances
-         DbgPrintf(5, _T("DataCollectionTarget::updateInstances(%s [%u], %s [%u]): instance \"%s\" found"),
+         nxlog_debug(5, _T("DataCollectionTarget::updateInstances(%s [%u], %s [%u]): instance \"%s\" found"),
                    m_name, m_id, root->getName(), root->getId(), dcoInstance);
          const TCHAR *name = instances->get(dcoInstance);
          if (_tcscmp(name, object->getInstance()))
@@ -1648,15 +1648,35 @@ bool DataCollectionTarget::updateInstances(DCObject *root, StringMap *instances,
             changed = true;
          }
          instances->remove(dcoInstance);
+
+         if (object->getLastAttemptToRemove() > 0)
+         {
+            object->setLastAttemptToRemove(0);
+            object->setStatus(ITEM_STATUS_ACTIVE, false);
+         }
       }
       else
       {
-         // not found, delete DCO
-         DbgPrintf(5, _T("DataCollectionTarget::updateInstances(%s [%u], %s [%u]): instance \"%s\" not found, instance DCO will be deleted"),
-                   m_name, m_id, root->getName(), root->getId(), dcoInstance);
-         sendPollerMsg(requestId, _T("      Existing instance \"%s\" not found and will be deleted\r\n"), dcoInstance);
-         deleteList.add(object->getId());
-         changed = true;
+         if (object->getLastAttemptToRemove() == 0)
+         {
+            object->setLastAttemptToRemove(time(NULL));
+            object->setStatus(ITEM_STATUS_DISABLED, false);
+            nxlog_debug(5, _T("DataCollectionTarget::updateInstances(%s [%u], %s [%u]): instance \"%s\" not found, last failure time updated"),
+                      m_name, m_id, root->getName(), root->getId(), dcoInstance);
+            sendPollerMsg(requestId, _T("      Existing instance \"%s\" not found, last failure time updated\r\n"), dcoInstance);
+         }
+
+         time_t retentionTime = ((object->getInstanceRetentionTime() != -1) ? object->getInstanceRetentionTime() : g_instanceRetentionTime) * 86400;
+
+         if ((time(NULL) - object->getLastAttemptToRemove()) > retentionTime)
+         {
+            // not found, delete DCO
+            nxlog_debug(5, _T("DataCollectionTarget::updateInstances(%s [%u], %s [%u]): instance \"%s\" not found, instance DCO will be deleted"),
+                      m_name, m_id, root->getName(), root->getId(), dcoInstance);
+            sendPollerMsg(requestId, _T("      Existing instance \"%s\" not found and will be deleted\r\n"), dcoInstance);
+            deleteList.add(object->getId());
+            changed = true;
+         }
       }
    }
 
index a532fcd..baa566f 100644 (file)
@@ -159,6 +159,7 @@ UINT32 g_lockTimeout = 60000;   // Default timeout for acquiring mutex
 UINT32 g_agentCommandTimeout = 4000;  // Default timeout for requests to agent
 UINT32 g_thresholdRepeatInterval = 0;  // Disabled by default
 int g_requiredPolls = 1;
+INT32 g_instanceRetentionTime = 0; // Default instance retention time
 DB_DRIVER g_dbDriver = NULL;
 ThreadPool NXCORE_EXPORTABLE *g_mainThreadPool = NULL;
 INT16 g_defaultAgentCacheMode = AGENT_CACHE_OFF;
@@ -375,6 +376,7 @@ static void LoadGlobalConfig()
        g_thresholdRepeatInterval = ConfigReadInt(_T("ThresholdRepeatInterval"), 0);
        g_requiredPolls = ConfigReadInt(_T("PollCountForStatusChange"), 1);
        g_offlineDataRelevanceTime = ConfigReadInt(_T("OfflineDataRelevanceTime"), 86400);
+       g_instanceRetentionTime = ConfigReadInt(_T("InstanceRetentionTime"), 0); // Config values are in days
 
        UINT32 snmpTimeout = ConfigReadInt(_T("SNMPRequestTimeout"), 1500);
    SnmpSetDefaultTimeout(snmpTimeout);
index 85dfc23..6fcba24 100644 (file)
@@ -467,8 +467,8 @@ void Template::loadItemsFromDB(DB_HANDLE hdb)
               _T("instance,template_item_id,flags,resource_id,")
               _T("proxy_node,base_units,unit_multiplier,custom_units_name,")
                   _T("perftab_settings,system_tag,snmp_port,snmp_raw_value_type,")
-                                 _T("instd_method,instd_data,instd_filter,samples,comments,guid,npe_name ")
-                                 _T("FROM items WHERE node_id=?"));
+                                 _T("instd_method,instd_data,instd_filter,samples,comments,guid,npe_name, ")
+                                 _T("instance_retention_time FROM items WHERE node_id=?"));
        if (hStmt != NULL)
        {
                DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
@@ -488,7 +488,7 @@ void Template::loadItemsFromDB(DB_HANDLE hdb)
                                  _T("description,flags,source,snmp_port,polling_interval,retention_time,")
               _T("status,system_tag,resource_id,proxy_node,perftab_settings,")
               _T("transformation_script,comments,guid,instd_method,instd_data,")
-              _T("instd_filter,instance FROM dc_tables WHERE node_id=?"));
+              _T("instd_filter,instance,instance_retention_time FROM dc_tables WHERE node_id=?"));
        if (hStmt != NULL)
        {
                DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
index 7d53e22..5947b5c 100644 (file)
@@ -1311,6 +1311,7 @@ extern UINT32 g_thresholdRepeatInterval;
 extern int g_requiredPolls;
 extern UINT32 g_slmPollingInterval;
 extern UINT32 g_offlineDataRelevanceTime;
+extern INT32 g_instanceRetentionTime;
 
 extern TCHAR g_szDbDriver[];
 extern TCHAR g_szDbDrvParams[];
index f8a5750..e105c3d 100644 (file)
@@ -218,6 +218,8 @@ protected:
    NXSL_Program *m_instanceFilter;
    TCHAR m_instance[MAX_DB_STRING];
    IntegerArray<UINT32> *m_accessList;
+   time_t m_lastAttemptToRemove;       // If instance is not found, the time is updated
+   INT32 m_instanceRetentionTime;   // Retention time if instance is not found
 
    void lock() { MutexLock(m_hMutex); }
    bool tryLock() { return MutexTryLock(m_hMutex); }
@@ -337,6 +339,10 @@ public:
    void expandInstance();
    bool hasValue();
    bool hasAccess(UINT32 userId);
+
+   time_t getLastAttemptToRemove() const { return m_lastAttemptToRemove; }
+   void setLastAttemptToRemove(time_t time) { m_lastAttemptToRemove = time; }
+   INT32 getInstanceRetentionTime() const { return m_instanceRetentionTime; }
 };
 
 /**
index 1c848f4..ea15e22 100644 (file)
 #include "nxdbmgr.h"
 
 /**
+ * Upgrade from 30.12 to 30.13
+ */
+static bool H_UpgradeFromV12()
+{
+   static const TCHAR *batch =
+            _T("ALTER TABLE items ADD instance_retention_time integer\n")
+            _T("ALTER TABLE dc_tables ADD instance_retention_time integer\n")
+            _T("UPDATE items SET instance_retention_time=-1\n")
+            _T("UPDATE dc_tables SET instance_retention_time=-1\n")
+            _T("INSERT INTO config (var_name,var_value,default_value,is_visible,need_server_restart,is_public,data_type,description) ")
+            _T("VALUES ('InstanceRetentionTime','0','0',1,1,'Y','I','Time, in days, for instance DCO retention')\n")
+            _T("<END>");
+   CHK_EXEC(SQLBatch(batch));
+
+   CHK_EXEC(DBSetNotNullConstraint(g_hCoreDB, _T("items"), _T("instance_retention_time")));
+   CHK_EXEC(DBSetNotNullConstraint(g_hCoreDB, _T("dc_tables"), _T("instance_retention_time")));
+
+   CHK_EXEC(SetMinorSchemaVersion(13));
+   return true;
+}
+
+/**
  * Upgrade from 30.11 to 30.12
  */
 static bool H_UpgradeFromV11()
@@ -561,6 +583,7 @@ static struct
    bool (* upgradeProc)();
 } s_dbUpgradeMap[] =
 {
+   { 12, 30, 13, H_UpgradeFromV12 },
    { 11, 30, 12, H_UpgradeFromV11 },
    { 10, 30, 11, H_UpgradeFromV10 },
    { 9, 30, 10, H_UpgradeFromV9 },
index 7d67eda..3603d0b 100644 (file)
@@ -27,6 +27,8 @@ import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Combo;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Spinner;
 import org.netxms.client.datacollection.DataCollectionObject;
 import org.netxms.ui.eclipse.datacollection.Messages;
 import org.netxms.ui.eclipse.datacollection.api.DataCollectionObjectEditor;
@@ -49,6 +51,9 @@ public class InstanceDiscovery extends DCIPropertyPageDialog
        private Combo discoveryMethod;
        private LabeledText discoveryData;
        private ScriptEditor filterScript;
+       private Group groupRetention;
+   private Combo instanceRetentionMode;
+       private Spinner instanceRetentionTime;
        
        /* (non-Javadoc)
         * @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite)
@@ -83,6 +88,8 @@ public class InstanceDiscovery extends DCIPropertyPageDialog
                      discoveryData.setLabel(getDataLabel(method));
                      discoveryData.setEnabled(method != DataCollectionObject.IDM_NONE);
                      filterScript.setEnabled(method != DataCollectionObject.IDM_NONE);
+            instanceRetentionMode.setEnabled(method != DataCollectionObject.IDM_NONE);
+                     instanceRetentionTime.setEnabled(method != DataCollectionObject.IDM_NONE && instanceRetentionMode.getSelectionIndex() > 0);
                        }
                        
                        @Override
@@ -100,7 +107,54 @@ public class InstanceDiscovery extends DCIPropertyPageDialog
       gd.grabExcessHorizontalSpace = true;
       discoveryData.setLayoutData(gd);
       discoveryData.setEnabled(dco.getInstanceDiscoveryMethod() != DataCollectionObject.IDM_NONE);
-     
+      
+      groupRetention = new Group(dialogArea, SWT.NONE);
+      groupRetention.setText("Instance retention");
+      gd = new GridData();
+      gd = new GridData();
+      gd.horizontalAlignment = SWT.FILL;
+      gd.verticalAlignment = SWT.FILL;
+      gd.horizontalSpan = 2;
+      groupRetention.setLayoutData(gd);
+      GridLayout retentionLayout = new GridLayout();
+      retentionLayout.numColumns = 2;
+      retentionLayout.horizontalSpacing = WidgetHelper.OUTER_SPACING;
+      groupRetention.setLayout(retentionLayout);
+      
+      gd = new GridData();
+      gd.grabExcessHorizontalSpace = true;
+      gd.horizontalAlignment = SWT.FILL;
+      instanceRetentionMode = WidgetHelper.createLabeledCombo(groupRetention, SWT.READ_ONLY, "Instance retention mode", gd);
+      instanceRetentionMode.add("Server default");
+      instanceRetentionMode.add("Custom");
+      instanceRetentionMode.select(dco.getInstanceRetentionTime() == -1 ? 0 : 1);
+      instanceRetentionMode.setEnabled(dco.getInstanceDiscoveryMethod() != DataCollectionObject.IDM_NONE);
+      instanceRetentionMode.addSelectionListener(new SelectionListener() {
+          /* (non-Javadoc)
+          * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+          */
+         @Override
+         public void widgetSelected(SelectionEvent e)
+         {
+            instanceRetentionTime.setEnabled(instanceRetentionMode.getSelectionIndex() == 1);
+         }
+         /* (non-Javadoc)
+          * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
+          */
+         @Override
+         public void widgetDefaultSelected(SelectionEvent e)
+         {
+           widgetSelected(e); 
+         }
+      });
+      
+      gd = new GridData();
+      gd.grabExcessHorizontalSpace = true;
+      gd.horizontalAlignment = SWT.FILL;
+      instanceRetentionTime = WidgetHelper.createLabeledSpinner(groupRetention, SWT.BORDER, "Instance retention time (days)", 0, 100,  new GridData());
+      instanceRetentionTime.setSelection(dco.getInstanceRetentionTime());
+      instanceRetentionTime.setEnabled(instanceRetentionMode.getSelectionIndex() > 0);
+      
       gd = new GridData();
       gd.horizontalAlignment = SWT.FILL;
       gd.verticalAlignment = SWT.FILL;
@@ -165,6 +219,10 @@ public class InstanceDiscovery extends DCIPropertyPageDialog
           dco.setInstanceDiscoveryMethod(discoveryMethod.getSelectionIndex());
           dco.setInstanceDiscoveryData(discoveryData.getText());
           dco.setInstanceDiscoveryFilter(filterScript.getText());
+          if (instanceRetentionMode.getSelectionIndex() == 0)
+             dco.setInstanceRetentionTime(-1);
+          else
+             dco.setInstanceRetentionTime(instanceRetentionTime.getSelection());
                editor.modify();
        }
 
@@ -200,5 +258,7 @@ public class InstanceDiscovery extends DCIPropertyPageDialog
                discoveryData.setEnabled(false);
                filterScript.setText(""); //$NON-NLS-1$
                filterScript.setEnabled(false);
+               instanceRetentionMode.select(0);
+               instanceRetentionTime.setSelection(0);
        }
 }
index 103bbc5..ecde866 100644 (file)
@@ -612,6 +612,7 @@ public class DataCollectionEditor extends ViewPart
                                                {
                                                        ((DataCollectionObject)dci).setStatus(newStatus);
                                                        viewer.update(dci, null);
+                     new DataCollectionObjectEditor((DataCollectionObject)dci).modify();
                                                }
                                        }
                                });