2025-01-25 04:38:09 +08:00

491 lines
14 KiB
C#

using System;
using System.Collections.Generic;
using System.Text;
namespace Thousandto.Core.Base
{
public interface IGcSweepingStrategy
{
bool Sweepable();
bool Sweepable(object value);
}
public interface IGcGenerationStrategy
{
int GetMaxGenerationCount();
bool NextGeneration(int gen, int lived);
bool Collectable(int gen, int last);
}
public class GcGenerationStrategy : IGcGenerationStrategy
{
public const int MAX_GENERATION_INDEX = 32;
public static int Now()
{
return System.Environment.TickCount;
}
public int GetMaxGenerationCount()
{
return MAX_GENERATION_INDEX;
}
public bool NextGeneration(int gen, int lived)
{
return lived > 60000 * gen;
}
public bool Collectable(int gen, int last)
{
return Now() - last > 60000 * gen;
}
public static GcGenerationStrategy sharedInstance = new GcGenerationStrategy();
}
public class GcSweepingStrategy : IGcSweepingStrategy
{
int _past = 0;
int _interval = 0;
internal const int DefaultInterval = 8000; //8s
public GcSweepingStrategy(int intervalMS = 0)
{
if (intervalMS <= 0)
{
intervalMS = DefaultInterval;
}
_interval = intervalMS;
_past = System.Environment.TickCount;
}
public virtual bool Sweepable(object value)
{
return true;
}
public virtual bool Sweepable()
{
bool result = false;
int now = System.Environment.TickCount;
if (now - _past > _interval)
{
result = true;
_past = now;
}
return result;
}
}
public enum DataCacheCollectableFlag
{
None = 0,
No = 1,
Yes = 2,
Collectable = 4,
Touching = 8,
}
public class DataCache<TKey, TValue>
{
class Item
{
internal TValue value = default(TValue);
internal int lastTouchedTime = 0;
internal int livedTime = 0;
internal int generation = 0;
internal bool immortal = false;
internal DataCache<TKey, TValue> owner;
internal void Assign(TValue source, int gen = 1, int now = 0)
{
if (now <= 0)
{
now = GcGenerationStrategy.Now();
}
value = source;
generation = gen;
lastTouchedTime = now;
livedTime = 0;
}
internal void Touch()
{
var n = GcGenerationStrategy.Now();
var e = n - lastTouchedTime;
lastTouchedTime = n;
livedTime += e;
if (owner._gen.NextGeneration(generation, livedTime) && generation + 1 <= owner._gen.GetMaxGenerationCount())
{
++generation;
}
}
internal Item(TValue source, DataCache<TKey, TValue> _owner)
{
owner = _owner;
Assign(source, 1, GcGenerationStrategy.Now());
}
internal bool Collectable()
{
return immortal == false && owner._gen.Collectable(generation, lastTouchedTime);
}
}
IGcSweepingStrategy _sweeper = null;
IGcGenerationStrategy _gen = null;
MyAction<TValue> _releaseValueFunc = null;
MyFunc<TValue, DataCacheCollectableFlag> _collectableFunc = null;
Dictionary<TKey, Item> _tank = null;
Dictionary<TKey, Item> tank
{
get
{
if (_tank == null)
{
_tank = new Dictionary<TKey, Item>();
}
return _tank;
}
}
public DataCache(int sweepIntervalMS = -1,
IGcSweepingStrategy sweeper = null,
IGcGenerationStrategy gen = null,
MyAction<TValue> valueReleaser = null,
MyFunc<TValue, DataCacheCollectableFlag> collectableFunc = null)
{
_sweeper = sweeper;
_releaseValueFunc = valueReleaser;
_collectableFunc = collectableFunc;
if (_sweeper == null)
{
if (sweepIntervalMS < 0)
{
sweepIntervalMS = GcSweepingStrategy.DefaultInterval;
}
_sweeper = new GcSweepingStrategy(sweepIntervalMS);
}
_gen = gen ?? GcGenerationStrategy.sharedInstance;
}
~DataCache()
{
Clear();
}
Item GetItem(TKey key)
{
Item item = null;
if (_tank != null && _tank.TryGetValue(key, out item))
{
item.Touch();
return item;
}
else
{
return null;
}
}
void _ReleaseValue(TValue value)
{
if (_releaseValueFunc != null)
{
_releaseValueFunc(value);
value = default(TValue);
}
}
int _DoSweep(bool force)
{
int result = 0;
if (_tank != null)
{
List<TKey> _removeList = null;
var e = _tank.GetEnumerator();
try
{
while (e.MoveNext())
{
var item = e.Current;
if (force)
{
item.Value.immortal = false;
}
if (item.Value.Collectable())
{
if (_collectableFunc != null)
{
var ret = _collectableFunc(item.Value.value);
if (ret != DataCacheCollectableFlag.None)
{
if ((ret & DataCacheCollectableFlag.No) != 0)
{
if ((ret & DataCacheCollectableFlag.Touching) != 0)
{
item.Value.Touch();
}
continue;
}
}
}
if (_removeList == null)
{
_removeList = new List<TKey>();
}
_ReleaseValue(item.Value.value);
_removeList.Add(item.Key);
}
}
}
finally
{
e.Dispose();
}
if (_removeList != null)
{
for (int i = 0; i < _removeList.Count; ++i)
{
if (_tank.Remove(_removeList[i]))
{
result += 1;
}
}
}
}
return result;
}
public bool SetImmortal(TKey key, bool enable = true)
{
var item = GetItem(key);
if (item != null)
{
item.immortal = enable;
return true;
}
return false;
}
public TValue Get(TKey key, bool sweep = true)
{
var item = GetItem(key);
var ret = item != null ? item.value : default(TValue);
if (sweep)
{
Sweep();
}
return ret;
}
public bool Remove(TKey key)
{
Item item = null;
if (_tank != null && _tank.TryGetValue(key, out item))
{
if (_releaseValueFunc != null)
{
_releaseValueFunc(item.value);
}
return _tank.Remove(key);
}
return false;
}
public bool Add(TKey key, TValue value)
{
if (value == null)
{
return false;
}
var dict = tank;
Item item = null;
if (dict.TryGetValue(key, out item))
{
item.Touch();
return false;
}
item = new Item(value, this);
dict.Add(key, item);
return true;
}
public bool TryGetValue(TKey key, out TValue value, bool sweep = true)
{
if (_tank != null)
{
Item item = null;
if (_tank.TryGetValue(key, out item))
{
item.Touch();
value = item.value;
if (sweep)
{
Sweep();
}
return true;
}
}
value = default(TValue);
return false;
}
public void Clear()
{
if (_tank != null)
{
if (_releaseValueFunc != null)
{
var e = _tank.GetEnumerator();
try
{
while (e.MoveNext())
{
_releaseValueFunc(e.Current.Value.value);
}
}
finally
{
e.Dispose();
}
}
_tank.Clear();
_tank = null;
}
}
public int Count
{
get
{
if (_tank != null)
{
return _tank.Count;
}
return 0;
}
}
public int ForEachValue(MyAction<TValue> func)
{
int count = 0;
if (_tank != null)
{
var e = _tank.GetEnumerator();
try
{
while (e.MoveNext())
{
func(e.Current.Value.value);
++count;
}
}
finally
{
e.Dispose();
}
}
return count;
}
public int ForEach<TCtx>(MyAction<TKey, TValue, TCtx> func, TCtx ctx = null) where TCtx : class
{
int count = 0;
if (_tank != null)
{
var e = _tank.GetEnumerator();
try
{
while (e.MoveNext())
{
func(e.Current.Key, e.Current.Value.value, ctx);
++count;
}
}
finally
{
e.Dispose();
}
}
return count;
}
public int Clear(MyFunc<int, int, int, bool> func)
{
int result = 0;
if (_tank != null)
{
List<TKey> _removeList = null;
var e = _tank.GetEnumerator();
try
{
while (e.MoveNext())
{
var item = e.Current;
bool skip = func(item.Value.generation, item.Value.lastTouchedTime, item.Value.livedTime);
if (!skip)
{
if (_removeList == null)
{
_removeList = new List<TKey>();
}
_ReleaseValue(item.Value.value);
_removeList.Add(item.Key);
}
}
}
finally
{
e.Dispose();
}
if (_removeList != null)
{
for (int i = 0; i < _removeList.Count; ++i)
{
if (_tank.Remove(_removeList[i]))
{
result += 1;
}
}
}
}
return result;
}
public int Sweep(bool force = false)
{
int result = 0;
if (force || _sweeper.Sweepable())
{
result = _DoSweep(force);
}
return result;
}
}
public class DataCacheLit<TKey, TValue> : DataCache<TKey, object>
{
public bool Add(TKey key, TValue value)
{
return base.Add(key, value);
}
public bool TryGetValue(TKey key, out TValue value, bool sweep = true)
{
object _value = null;
value = default(TValue);
var r = base.TryGetValue(key, out _value, sweep);
if (r)
{
try
{
value = (TValue)_value;
}
catch (Exception e)
{
System.Diagnostics.Trace.Fail(e.Message,e.StackTrace);
}
}
return r;
}
}
}