* Fixed the ExpiringCache collection to remove an ambiguity of whether to use local timezone expiration dates or UTC expiration dates. Expiration time is now passed in as the number of seconds relative to the current time
* Minor performance improvement in ExpiringCache to avoid instantiating a List<> every time the cache purge timer runs git-svn-id: http://libopenmetaverse.googlecode.com/svn/libopenmetaverse/trunk@3421 52acb1d6-8a22-11de-b505-999d5b087335
This commit is contained in:
@@ -103,7 +103,7 @@ namespace OpenMetaverse
|
||||
|
||||
#region Public methods
|
||||
|
||||
public bool Add(TKey key, TValue value, DateTime expiration)
|
||||
public bool Add(TKey key, TValue value, double expirationSeconds)
|
||||
{
|
||||
if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
|
||||
throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
|
||||
@@ -116,7 +116,7 @@ namespace OpenMetaverse
|
||||
}
|
||||
else
|
||||
{
|
||||
TimedCacheKey<TKey> internalKey = new TimedCacheKey<TKey>(key, expiration);
|
||||
TimedCacheKey<TKey> internalKey = new TimedCacheKey<TKey>(key, DateTime.UtcNow + TimeSpan.FromSeconds(expirationSeconds));
|
||||
timedStorage.Add(internalKey, value);
|
||||
timedStorageIndex.Add(key, internalKey);
|
||||
return true;
|
||||
@@ -147,7 +147,7 @@ namespace OpenMetaverse
|
||||
finally { Monitor.Exit(syncRoot); }
|
||||
}
|
||||
|
||||
public bool AddOrUpdate(TKey key, TValue value, DateTime expiration)
|
||||
public bool AddOrUpdate(TKey key, TValue value, double expirationSeconds)
|
||||
{
|
||||
if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
|
||||
throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
|
||||
@@ -155,12 +155,12 @@ namespace OpenMetaverse
|
||||
{
|
||||
if (Contains(key))
|
||||
{
|
||||
Update(key, value, expiration);
|
||||
Update(key, value, expirationSeconds);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Add(key, value, expiration);
|
||||
Add(key, value, expirationSeconds);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -245,22 +245,6 @@ namespace OpenMetaverse
|
||||
}
|
||||
}
|
||||
|
||||
public TValue this[TKey key, DateTime expiration]
|
||||
{
|
||||
set
|
||||
{
|
||||
AddOrUpdate(key, value, expiration);
|
||||
}
|
||||
}
|
||||
|
||||
public TValue this[TKey key, TimeSpan slidingExpiration]
|
||||
{
|
||||
set
|
||||
{
|
||||
AddOrUpdate(key, value, slidingExpiration);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(TKey key)
|
||||
{
|
||||
if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
|
||||
@@ -327,7 +311,7 @@ namespace OpenMetaverse
|
||||
finally { Monitor.Exit(syncRoot); }
|
||||
}
|
||||
|
||||
public bool Update(TKey key, TValue value, DateTime expiration)
|
||||
public bool Update(TKey key, TValue value, double expirationSeconds)
|
||||
{
|
||||
if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
|
||||
throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
|
||||
@@ -343,7 +327,7 @@ namespace OpenMetaverse
|
||||
return false;
|
||||
}
|
||||
|
||||
TimedCacheKey<TKey> internalKey = new TimedCacheKey<TKey>(key, expiration);
|
||||
TimedCacheKey<TKey> internalKey = new TimedCacheKey<TKey>(key, DateTime.UtcNow + TimeSpan.FromSeconds(expirationSeconds));
|
||||
timedStorage.Add(internalKey, value);
|
||||
timedStorageIndex.Add(key, internalKey);
|
||||
return true;
|
||||
@@ -414,6 +398,9 @@ namespace OpenMetaverse
|
||||
// happening on the cache
|
||||
if (!Monitor.TryEnter(isPurging))
|
||||
return;
|
||||
|
||||
DateTime signalTime = DateTime.UtcNow;
|
||||
|
||||
try
|
||||
{
|
||||
// If we fail to acquire a lock on the synchronization root after MAX_LOCK_WAIT, skip this purge cycle
|
||||
@@ -421,14 +408,14 @@ namespace OpenMetaverse
|
||||
return;
|
||||
try
|
||||
{
|
||||
List<object> expiredItems = new List<object>();
|
||||
Lazy<List<object>> expiredItems = new Lazy<List<object>>();
|
||||
|
||||
foreach (TimedCacheKey<TKey> timedKey in timedStorage.Keys)
|
||||
{
|
||||
if (timedKey.ExpirationDate < e.SignalTime)
|
||||
if (timedKey.ExpirationDate < signalTime)
|
||||
{
|
||||
// Mark the object for purge
|
||||
expiredItems.Add(timedKey.Key);
|
||||
expiredItems.Value.Add(timedKey.Key);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -436,11 +423,14 @@ namespace OpenMetaverse
|
||||
}
|
||||
}
|
||||
|
||||
foreach (TKey key in expiredItems)
|
||||
if (expiredItems.IsValueCreated)
|
||||
{
|
||||
TimedCacheKey<TKey> timedKey = timedStorageIndex[key];
|
||||
timedStorageIndex.Remove(timedKey.Key);
|
||||
timedStorage.Remove(timedKey);
|
||||
foreach (TKey key in expiredItems.Value)
|
||||
{
|
||||
TimedCacheKey<TKey> timedKey = timedStorageIndex[key];
|
||||
timedStorageIndex.Remove(timedKey.Key);
|
||||
timedStorage.Remove(timedKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally { Monitor.Exit(syncRoot); }
|
||||
|
||||
100
OpenMetaverseTypes/Lazy.cs
Normal file
100
OpenMetaverseTypes/Lazy.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* - 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.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace OpenMetaverse
|
||||
{
|
||||
public class Lazy<T>
|
||||
{
|
||||
private T _value = default(T);
|
||||
private volatile bool _isValueCreated = false;
|
||||
private Func<T> _valueFactory = null;
|
||||
private object _lock;
|
||||
|
||||
public bool IsValueCreated { get { return _isValueCreated; } }
|
||||
|
||||
public Lazy()
|
||||
: this(() => Activator.CreateInstance<T>())
|
||||
{
|
||||
}
|
||||
|
||||
public Lazy(bool isThreadSafe)
|
||||
: this(() => Activator.CreateInstance<T>(), isThreadSafe)
|
||||
{
|
||||
}
|
||||
|
||||
public Lazy(Func<T> valueFactory) :
|
||||
this(valueFactory, true)
|
||||
{
|
||||
}
|
||||
|
||||
public Lazy(Func<T> valueFactory, bool isThreadSafe)
|
||||
{
|
||||
if (isThreadSafe)
|
||||
{
|
||||
this._lock = new object();
|
||||
}
|
||||
|
||||
this._valueFactory = valueFactory;
|
||||
}
|
||||
|
||||
|
||||
public T Value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this._isValueCreated)
|
||||
{
|
||||
if (this._lock != null)
|
||||
{
|
||||
Monitor.Enter(this._lock);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
T value = this._valueFactory.Invoke();
|
||||
this._valueFactory = null;
|
||||
Thread.MemoryBarrier();
|
||||
this._value = value;
|
||||
this._isValueCreated = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (this._lock != null)
|
||||
{
|
||||
Monitor.Exit(this._lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user