Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
290 lines (237 sloc) 10 KB
/*<FILE_LICENSE>
* NFX (.NET Framework Extension) Unistack Library
* Copyright 2003-2018 Agnicore Inc. portions ITAdapter Corp. Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
</FILE_LICENSE>*/
/*
* Author: Dmitriy Khmaladze, Spring 2015 dmitriy@itadapter.com
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using NFX.Environment;
using NFX.Serialization.JSON;
namespace NFX.ApplicationModel.Pile
{
/// <summary>
/// Provides config options for cache tables
/// </summary>
[Serializable]
public sealed class TableOptions : INamed
{
public const long INITIAL_CAPACITY_DEFAULT = 256 * 16;
public const long INITIAL_CAPACITY_MIN = 1024;
public const double GROWTH_FACTOR_DEFAULT = 2.0d;
public const double GROWTH_FACTOR_MIN = 1.20d;
public const double GROWTH_FACTOR_MAX = 4.0d;
public const double SHRINK_FACTOR_DEFAULT = 0.75d;
public const double SHRINK_FACTOR_MIN = 0.50d;
public const double SHRINK_FACTOR_MAX = 0.90d;
public const double LOAD_FACTOR_LWM_DEFAULT = 0.50d;
public const double LOAD_FACTOR_LWM_MIN = 0.10d;
public const double LOAD_FACTOR_LWM_MAX = 0.70d;
public const double LOAD_FACTOR_HWM_DEFAULT = 0.70d;
public const double LOAD_FACTOR_HWM_MIN = 0.45d;
public const double LOAD_FACTOR_HWM_MAX = 0.95d;
public const int DEFAULT_MAX_AGE_SEC_DEFAULT = 15 * 60;
public TableOptions(IConfigSectionNode node, bool nameRequired = true)
{
if (nameRequired)
if (node==null || node.AttrByName(Configuration.CONFIG_NAME_ATTR).Value.IsNullOrWhiteSpace())
throw new PileException(StringConsts.ARGUMENT_ERROR + "TableOptions.ctor($name=null|Empty)");
ConfigAttribute.Apply(this, node);
if (this.m_Name.IsNullOrWhiteSpace())
m_Name = Guid.NewGuid().ToString();
}
public TableOptions(string name)
{
if (name.IsNullOrWhiteSpace())
throw new PileException(StringConsts.ARGUMENT_ERROR + "TableOptions.ctor(name=null|Empty)");
m_Name = name;
}
[Config("$name")]internal string m_Name;
private long m_InitialCapacity = INITIAL_CAPACITY_DEFAULT;
private long m_MinimumCapacity;
private long m_MaximumCapacity;
private double m_GrowthFactor = GROWTH_FACTOR_DEFAULT;
private double m_ShrinkFactor = SHRINK_FACTOR_DEFAULT;
private double m_LoadFactorLWM = LOAD_FACTOR_LWM_DEFAULT;
private double m_LoadFactorHWM = LOAD_FACTOR_HWM_DEFAULT;
private int m_DefaultMaxAgeSec = DEFAULT_MAX_AGE_SEC_DEFAULT;
public string Name { get{ return m_Name;} }
/// <summary>
/// How many elements a table may have at minimum, the property is checked at shrinking.
/// Zero = no limit.
/// The value is dependent on bucket count, so the actual table capacity is bucket-dependent
/// </summary>
[Config]
public long MinimumCapacity
{
get{ return m_MinimumCapacity;}
set { m_MinimumCapacity = value < 0 ? 0 : value;}
}
/// <summary>
/// How many elements a table may have at maximum, the property is checked at growth.
/// Zero = no limit
/// </summary>
[Config]
public long MaximumCapacity
{
get{ return m_MaximumCapacity;}
set { m_MaximumCapacity = value < 0 ? 0 : value;}
}
/// <summary>
/// How many elements an empty table should contain. The value is dependent on bucket count, so the actual table capacity is bucket-dependent
/// </summary>
[Config]
public long InitialCapacity
{
get{ return m_InitialCapacity;}
set { m_InitialCapacity = value < INITIAL_CAPACITY_MIN ? INITIAL_CAPACITY_MIN : value;}
}
/// <summary>
/// Defines the factor of growth - how much does a table grow when HWM is reached. The number has to be at least 1.2d
/// </summary>
[Config]
public double GrowthFactor
{
get{ return m_GrowthFactor;}
set { m_GrowthFactor = value < GROWTH_FACTOR_MIN ? GROWTH_FACTOR_MIN : value > GROWTH_FACTOR_MAX ? GROWTH_FACTOR_MAX : value;}
}
/// <summary>
/// Defines the factor of shrinking - how much does a table shrink when LWM is reached. The number has to be at most 0.7d
/// </summary>
[Config]
public double ShrinkFactor
{
get{ return m_ShrinkFactor;}
set { m_ShrinkFactor = value < SHRINK_FACTOR_MIN ? SHRINK_FACTOR_MIN : value > SHRINK_FACTOR_MAX ? SHRINK_FACTOR_MAX : value;}
}
/// <summary>
/// Defines the load factor below which the shrinking is triggered
/// </summary>
[Config]
public double LoadFactorLWM
{
get{ return m_LoadFactorLWM;}
set { m_LoadFactorLWM = value < LOAD_FACTOR_LWM_MIN ? LOAD_FACTOR_LWM_MIN : value > LOAD_FACTOR_LWM_MAX ? LOAD_FACTOR_LWM_MAX : value;}
}
/// <summary>
/// Defines the load factor above which the growth is triggered
/// </summary>
[Config]
public double LoadFactorHWM
{
get{ return m_LoadFactorHWM;}
set { m_LoadFactorHWM = value < LOAD_FACTOR_HWM_MIN ? LOAD_FACTOR_HWM_MIN : value > LOAD_FACTOR_HWM_MAX ? LOAD_FACTOR_HWM_MAX : value;}
}
/// <summary>
/// Specifies default max age length which is applied to cache items if Put() does not specify particular max age
/// </summary>
[Config]
public int DefaultMaxAgeSec
{
get { return m_DefaultMaxAgeSec;}
set { m_DefaultMaxAgeSec = value > 0 ? value : 0;}
}
/// <summary>
/// True to include instrumentation details per table
/// </summary>
[Config]
public bool DetailedInstrumentation
{
get; set;
}
/// <summary>
/// Defines how table handles collisions.
/// Note: this property can only be supplied to table ctor, the changes are ignored after the table has created
/// </summary>
[Config(Default = CollisionMode.Speculative)]
public CollisionMode CollisionMode{ get; set; }
/// <summary>
/// Allows to get/set options as external parameters
/// </summary>
public object AsExternalParameter
{
get
{
var mc = new MemoryConfiguration();
mc.Create("opt");
foreach(var pi in this.GetType().GetProperties().Where(p => Attribute.IsDefined(p, typeof(ConfigAttribute))))
{
mc.Root.AddAttributeNode(pi.Name, pi.GetValue(this));
}
return CoreConsts.EXT_PARAM_CONTENT_LACONIC + mc.ToLaconicString(CodeAnalysis.Laconfig.LaconfigWritingOptions.Compact);
}
set
{
try
{
if (value==null) return;
if (value is IConfigSectionNode)
{
var name = m_Name;
ConfigAttribute.Apply(this, value as IConfigSectionNode);
m_Name = name;
}
ConfigSectionNode node = null;
if (value is JSONDataMap)
node = ((JSONDataMap)value).ToConfigNode();
else
{
var str = value.ToString();
if (str.IsNullOrWhiteSpace()) return;
if (str.StartsWith(CoreConsts.EXT_PARAM_CONTENT_LACONIC))
{
str = str.Remove(0, CoreConsts.EXT_PARAM_CONTENT_LACONIC.Length);
node = str.AsLaconicConfig();
if (node==null) node = ("opt{"+str+"}").AsLaconicConfig(handling: ConvertErrorHandling.Throw);
}
else
{
if (str.StartsWith(CoreConsts.EXT_PARAM_CONTENT_JSON))
str = str.Remove(0, CoreConsts.EXT_PARAM_CONTENT_JSON.Length);
var map = JSONReader.DeserializeDataObject( str ) as JSONDataMap;
if (map==null)
throw new PileException(str);
node = map.ToConfigNode();
}
}
var wasname = m_Name;
ConfigAttribute.Apply(this, node);
m_Name = wasname;
}
catch(Exception error)
{
throw new PileException(StringConsts.ARGUMENT_ERROR + GetType().Name+".AsExternalParameter.set({0})".Args(value) + error.ToMessageWithType());
}
}
}
/// <summary>
/// Makes an identical copy of this instance
/// </summary>
public TableOptions Clone()
{
using(var ms = new MemoryStream())
{
var ser = new Serialization.Slim.SlimSerializer();
ser.Serialize(ms, this);
ms.Position = 0;
return ser.Deserialize(ms) as TableOptions;
}
}
}
}