Uploaded image for project: 'iBatis for .NET'
  1. iBatis for .NET
  2. IBATISNET-285

flushInterval ist calculated wrong

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • DataMapper 1.6.1
    • DataMapper 1.6.2
    • DataMapper
    • None

    Description

      We noticed that if the flushInterval like in

      <cacheModels>
      <cacheModel id="NavigationCache" implementation="MEMORY" readOnly="false" serialize="true">
      <!-- User bekommen Kopien aus dem Cache -->
      <flushInterval minutes="1"/>
      <property name="Type" value="STRONG"/>
      </cacheModel>
      </cacheModels>

      is provided it results in a completely wrong number. There are two bugs that lead to a wrong result. The first one is very minor because it decreases the given interval time by about ten milliseconds. The second one is more severe: It results in a somewhat twice the time of the cache interval given in the configuration.

      Bug #1: The negative default value is being added

      in FlushInterval.cs you find the following code:

      private long _interval = CacheModel.NO_FLUSH_INTERVAL; // equals -99999

      //................

      public void Initialize()
      {

      if (_milliseconds != 0)

      { _interval += (_milliseconds * TimeSpan.TicksPerMillisecond) ; }

      if (_seconds != 0)

      { _interval += (_seconds * TimeSpan.TicksPerSecond) ; }

      if (_minutes != 0)

      { _interval += (_minutes * TimeSpan.TicksPerMinute) ; }

      if (_hours != 0)

      { _interval += (_hours * TimeSpan.TicksPerHour) ; }

      if (_interval == 0)

      { _interval = CacheModel.NO_FLUSH_INTERVAL; }

      }

      The result in our case is -99999+600000000 = 599900001.

      Granted that the effect is only about 10 Milliseconds but still, it is wrong

      Bug #2: FlushInterval.initialize() is called twice during initialization

      If you follow the Deserialization of the DomSqlMapBuilder in ConfigureSQLMap() you will find the following code,which calls CacheModelDeSerializer.Deserialize():

      #region Load CacheModels

      if (_configScope.IsCacheModelsEnabled)
      {
      CacheModel cacheModel;
      foreach (XmlNode xmlNode in _configScope.SqlMapDocument.SelectNodes( ApplyMappingNamespacePrefix(XML_CACHE_MODEL), _configScope.XmlNamespaceManager))
      {
      cacheModel = CacheModelDeSerializer.Deserialize(xmlNode, _configScope);
      cacheModel.Id = _configScope.ApplyNamespace(cacheModel.Id);

      // Attach ExecuteEventHandler
      foreach(XmlNode flushOn in xmlNode.SelectNodes( ApplyMappingNamespacePrefix(XML_FLUSH_ON_EXECUTE), _configScope.XmlNamespaceManager ))
      {
      string statementName = flushOn.Attributes["statement"].Value;
      if (_configScope.UseStatementNamespaces)

      { statementName = _configScope.ApplyNamespace(statementName); }

      // delay registering statements to cache model until all sqlMap files have been processed
      IList statementNames = (IList)_configScope.CacheModelFlushOnExecuteStatements[cacheModel.Id];
      if (statementNames == null)

      { statementNames = new ArrayList(); }

      statementNames.Add(statementName);
      _configScope.CacheModelFlushOnExecuteStatements[cacheModel.Id] = statementNames;
      }

      // Get Properties
      foreach(XmlNode propertie in xmlNode.SelectNodes( ApplyMappingNamespacePrefix(XML_PROPERTY), _configScope.XmlNamespaceManager))

      { string name = propertie.Attributes["name"].Value; string value = propertie.Attributes["value"].Value; cacheModel.AddProperty(name, value); }

      cacheModel.Initialize();

      _configScope.SqlMapper.AddCache( cacheModel );
      }
      }

      The issue is that CacheModelDeSerializer.Deserialize(xmlNode, _configScope); has the following implementation

      int count = node.ChildNodes.Count;
      for(int i=0;i<count;i++)
      {
      if (node.ChildNodes[i].LocalName=="flushInterval")

      { FlushInterval flush = new FlushInterval(); NameValueCollection props = NodeUtils.ParseAttributes(node.ChildNodes[i], configScope.Properties); flush.Hours = NodeUtils.GetIntAttribute(props, "hours", 0); flush.Milliseconds = NodeUtils.GetIntAttribute(props, "milliseconds", 0); flush.Minutes = NodeUtils.GetIntAttribute(props, "minutes", 0); flush.Seconds = NodeUtils.GetIntAttribute(props, "seconds", 0); flush.Initialize(); model.FlushInterval = flush; }

      }

      and therefore calls flush.Initialize() as soon as it find an property "flushInterval". So far so good as this results in getting the above number: 599900001

      However, back again in ConfigureSQLMap further down it calls cacheModel.Initialize(); which in turn calls _flushInterval.Initialize(); again adding another 600000000 resulting in 1199900001, almost twice of what we wanted.

      The initialization-Method must no be called twice.

      Attachments

        Activity

          People

            gilles Gilles Bayon
            stefan.hoehn Stefan Hoehn
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: