flushInterval ist calculated wrong
----------------------------------
Key: IBATISNET-285
URL: https://issues.apache.org/jira/browse/IBATISNET-285
Project: iBatis for .NET
Issue Type: Bug
Components: DataMapper
Affects Versions: DataMapper 1.6.1
Reporter: Stefan Hoehn
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.
--
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.