123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570 |
- /*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * - Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- * - Neither the name of the openmetaverse.org nor the names
- * of its contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
- // this is a lighter alternative to libomv, no sliding option
- using System;
- using System.Threading;
- using System.Collections.Generic;
- using Timer = System.Threading.Timer;
- using System.Runtime.InteropServices;
- namespace OpenSim.Framework
- {
- public sealed class ExpiringCacheOS<TKey1, TValue1> : IDisposable
- {
- private const int MINEXPIRECHECK = 500;
- private Timer m_purgeTimer;
- private ReaderWriterLockSlim m_rwLock;
- private readonly Dictionary<TKey1, int> m_expireControl;
- private readonly Dictionary<TKey1, TValue1> m_values;
- TValue1[] valuesArrayCache = null;
- private readonly double m_startTS;
- private readonly int m_expire;
- public ExpiringCacheOS()
- {
- m_expireControl = new Dictionary<TKey1, int>();
- m_values = new Dictionary<TKey1, TValue1>();
- m_rwLock = new ReaderWriterLockSlim();
- m_expire = MINEXPIRECHECK;
- m_startTS = Util.GetTimeStampMS();
- }
- public ExpiringCacheOS(int expireCheckTimeinMS)
- {
- m_expireControl = new Dictionary<TKey1, int>();
- m_values = new Dictionary<TKey1, TValue1>();
- m_rwLock = new ReaderWriterLockSlim();
- m_startTS = Util.GetTimeStampMS();
- m_expire = (expireCheckTimeinMS > MINEXPIRECHECK) ? m_expire = expireCheckTimeinMS : MINEXPIRECHECK;
- }
- [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
- private void CheckTimer()
- {
- if (m_purgeTimer == null)
- {
- m_purgeTimer = new Timer(Purge, null, m_expire, Timeout.Infinite);
- }
- }
- [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
- private void DisposeTimer()
- {
- if (m_purgeTimer != null)
- {
- m_purgeTimer.Dispose();
- m_purgeTimer = null;
- }
- }
- ~ExpiringCacheOS()
- {
- Dispose(false);
- }
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
- private void Dispose(bool disposing)
- {
- if (m_rwLock != null)
- {
- DisposeTimer();
- m_rwLock.Dispose();
- m_rwLock = null;
- }
- }
- private void Purge(object ignored)
- {
- bool gotLock = false;
- try
- {
- try { }
- finally
- {
- m_rwLock.EnterUpgradeableReadLock();
- gotLock = true;
- }
- if (m_expireControl.Count == 0)
- {
- DisposeTimer();
- return;
- }
- int now = (int)(Util.GetTimeStampMS() - m_startTS);
- List<TKey1> expired = new List<TKey1>(m_expireControl.Count);
- foreach(KeyValuePair<TKey1, int> kvp in m_expireControl)
- {
- int expire = kvp.Value;
- if(expire > 0 && expire < now)
- expired.Add(kvp.Key);
- }
- if(expired.Count > 0)
- {
- bool gotWriteLock = false;
- try
- {
- try { }
- finally
- {
- m_rwLock.EnterWriteLock();
- gotWriteLock = true;
- }
- valuesArrayCache = null;
- foreach (TKey1 key in expired)
- {
- m_expireControl.Remove(key);
- m_values.Remove(key);
- }
- }
- finally
- {
- if (gotWriteLock)
- m_rwLock.ExitWriteLock();
- }
- if (m_expireControl.Count == 0)
- DisposeTimer();
- else
- m_purgeTimer.Change(m_expire, Timeout.Infinite);
- }
- else
- m_purgeTimer.Change(m_expire, Timeout.Infinite);
- }
- finally
- {
- if (gotLock)
- m_rwLock.ExitUpgradeableReadLock();
- }
- }
- [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
- public void AddOrUpdate(TKey1 key, TValue1 val)
- {
- Add(key, val);
- }
- public void Add(TKey1 key, TValue1 val)
- {
- bool gotLock = false;
- int now = (int)(Util.GetTimeStampMS() - m_startTS) + m_expire;
- try
- {
- try { }
- finally
- {
- m_rwLock.EnterWriteLock();
- gotLock = true;
- }
- m_expireControl[key] = now;
- m_values[key] = val;
- valuesArrayCache = null;
- CheckTimer();
- }
- finally
- {
- if (gotLock)
- m_rwLock.ExitWriteLock();
- }
- }
- [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
- public void AddOrUpdate(TKey1 key, TValue1 val, int expireSeconds)
- {
- Add(key, val, expireSeconds * 1000);
- }
- [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
- public void AddOrUpdate(TKey1 key, TValue1 val, double expireSeconds)
- {
- Add(key, val, (int)(expireSeconds * 1000));
- }
- public void Add(TKey1 key, TValue1 val, int expireMS)
- {
- bool gotLock = false;
- int now;
- if (expireMS > 0)
- {
- expireMS = (expireMS > m_expire) ? expireMS : m_expire;
- now = (int)(Util.GetTimeStampMS() - m_startTS) + expireMS;
- }
- else
- now = int.MinValue;
- try
- {
- try { }
- finally
- {
- m_rwLock.EnterWriteLock();
- gotLock = true;
- }
- m_expireControl[key] = now;
- m_values[key] = val;
- valuesArrayCache = null;
- CheckTimer();
- }
- finally
- {
- if (gotLock)
- m_rwLock.ExitWriteLock();
- }
- }
- public bool Remove(TKey1 key)
- {
- bool success;
- bool gotLock = false;
- try
- {
- try {}
- finally
- {
- m_rwLock.EnterWriteLock();
- gotLock = true;
- }
- success = m_expireControl.Remove(key);
- success |= m_values.Remove(key);
- if(success)
- valuesArrayCache = null;
- if (m_expireControl.Count == 0)
- DisposeTimer();
- }
- finally
- {
- if (gotLock)
- m_rwLock.ExitWriteLock();
- }
- return success;
- }
- public void Clear()
- {
- bool gotLock = false;
- try
- {
- try {}
- finally
- {
- m_rwLock.EnterWriteLock();
- gotLock = true;
- }
- DisposeTimer();
- m_expireControl.Clear();
- m_values.Clear();
- valuesArrayCache = null;
- }
- finally
- {
- if (gotLock)
- m_rwLock.ExitWriteLock();
- }
- }
- public int Count
- {
- get { return m_expireControl.Count; }
- }
- [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
- public bool Contains(TKey1 key)
- {
- return ContainsKey(key);
- }
- public bool ContainsKey(TKey1 key)
- {
- bool gotLock = false;
- try
- {
- try { }
- finally
- {
- m_rwLock.EnterReadLock();
- gotLock = true;
- }
- return m_expireControl.ContainsKey(key);
- }
- finally
- {
- if (gotLock)
- m_rwLock.ExitReadLock();
- }
- }
- [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
- public bool Contains(TKey1 key, int expireMS)
- {
- return ContainsKey(key, expireMS);
- }
- public bool ContainsKey(TKey1 key, int expireMS)
- {
- bool gotLock = false;
- try
- {
- try { }
- finally
- {
- m_rwLock.EnterUpgradeableReadLock();
- gotLock = true;
- }
- if(m_expireControl.ContainsKey(key))
- {
- bool gotWriteLock = false;
- try
- {
- try { }
- finally
- {
- m_rwLock.EnterWriteLock();
- gotWriteLock = true;
- }
- int now;
- if(expireMS > 0)
- {
- expireMS = (expireMS > m_expire) ? expireMS : m_expire;
- now = (int)(Util.GetTimeStampMS() - m_startTS) + expireMS;
- }
- else
- now = int.MinValue;
- m_expireControl[key] = now;
- return true;
- }
- finally
- {
- if (gotWriteLock)
- m_rwLock.ExitWriteLock();
- }
- }
- return false;
- }
- finally
- {
- if (gotLock)
- m_rwLock.ExitUpgradeableReadLock();
- }
- }
- public bool TryGetValue(TKey1 key, out TValue1 value)
- {
- bool gotLock = false;
- try
- {
- try {}
- finally
- {
- m_rwLock.EnterReadLock();
- gotLock = true;
- }
- return m_values.TryGetValue(key, out value);
- }
- finally
- {
- if (gotLock)
- m_rwLock.ExitReadLock();
- }
- }
- public bool TryGetValue(TKey1 key, int expireMS, out TValue1 value)
- {
- bool success;
- bool gotLock = false;
- try
- {
- try { }
- finally
- {
- m_rwLock.EnterUpgradeableReadLock();
- gotLock = true;
- }
- success = m_values.TryGetValue(key, out value);
- if(success)
- {
- bool gotWriteLock = false;
- try
- {
- try { }
- finally
- {
- m_rwLock.EnterWriteLock();
- gotWriteLock = true;
- }
- int now;
- if(expireMS > 0)
- {
- expireMS = (expireMS > m_expire) ? expireMS : m_expire;
- now = (int)(Util.GetTimeStampMS() - m_startTS) + expireMS;
- }
- else
- now = int.MinValue;
- m_expireControl[key] = now;
- }
- finally
- {
- if (gotWriteLock)
- m_rwLock.ExitWriteLock();
- }
- }
- }
- finally
- {
- if (gotLock)
- m_rwLock.ExitUpgradeableReadLock();
- }
- return success;
- }
- public ref TValue1 TryGetOrDefaultValue(TKey1 key, out bool existed)
- {
- bool gotLock = false;
- try
- {
- try { }
- finally
- {
- m_rwLock.ExitUpgradeableReadLock();
- gotLock = true;
- }
- return ref CollectionsMarshal.GetValueRefOrAddDefault(m_values, key, out existed);
- }
- finally
- {
- if (gotLock)
- m_rwLock.ExitUpgradeableReadLock();
- }
- }
- public ref TValue1 TryGetOrDefaultValue(TKey1 key, int expireMS, out bool existed)
- {
- bool gotLock = false;
- try
- {
- try { }
- finally
- {
- m_rwLock.EnterWriteLock();
- gotLock = true;
- }
- ref TValue1 ret = ref CollectionsMarshal.GetValueRefOrAddDefault(m_values, key, out existed);
- int now;
- if (expireMS > 0)
- {
- expireMS = (expireMS > m_expire) ? expireMS : m_expire;
- now = (int)(Util.GetTimeStampMS() - m_startTS) + expireMS;
- }
- else
- now = int.MinValue;
- m_expireControl[key] = now;
- return ref ret;
- }
- finally
- {
- if (gotLock)
- m_rwLock.EnterWriteLock();
- }
- }
- public TValue1[] Values
- {
- get
- {
- bool gotLock = false;
- try
- {
- try { }
- finally
- {
- m_rwLock.EnterUpgradeableReadLock();
- gotLock = true;
- }
- if(valuesArrayCache == null)
- {
- valuesArrayCache = new TValue1[m_values.Count];
- m_values.Values.CopyTo(valuesArrayCache, 0);
- }
- return valuesArrayCache;
- }
- finally
- {
- if (gotLock)
- m_rwLock.ExitUpgradeableReadLock();
- }
- }
- }
- /*
- public ICollection<TKey1> Keys
- {
- get
- {
- bool gotLock = false;
- try
- {
- try { }
- finally
- {
- m_rwLock.EnterUpgradeableReadLock();
- gotLock = true;
- }
- return m_values.Keys;
- }
- finally
- {
- if (gotLock)
- m_rwLock.ExitUpgradeableReadLock();
- }
- }
- }
- */
- }
- }
|