This is an automated email from the ASF dual-hosted git repository. mmartell pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/geode-dotnet-core-client.git
commit 5468ffacf2ab2ee5aabbd7f0a5d18281ceef27c1 Author: Mike Martell <mmart...@pivotal.io> AuthorDate: Thu May 27 13:26:16 2021 -0700 Derive SessionStateCache from GeodeNativeObject --- NetCore.Session/NetCoreSessionState.cs | 594 +++++++++++++++++---------------- 1 file changed, 301 insertions(+), 293 deletions(-) diff --git a/NetCore.Session/NetCoreSessionState.cs b/NetCore.Session/NetCoreSessionState.cs index 19f03e9..cdd0260 100644 --- a/NetCore.Session/NetCoreSessionState.cs +++ b/NetCore.Session/NetCoreSessionState.cs @@ -7,338 +7,346 @@ using System.Threading.Tasks; namespace Apache.Geode.Session { - public class SessionStateValue - { - DateTime _lastAccessTimeUtc; - DateTime _expirationTimeUtc = DateTime.MinValue; - TimeSpan _spanUntilStale = TimeSpan.Zero; - private byte[] _value; - - public SessionStateValue() { } - public SessionStateValue(byte[] value) + public class SessionStateValue { - FromByteArray(value); - } + DateTime _lastAccessTimeUtc; + DateTime _expirationTimeUtc = DateTime.MinValue; + TimeSpan _spanUntilStale = TimeSpan.Zero; + private byte[] _value; - public byte[] Value - { - get { return _value; } - set { _value = value; } - } - public DateTime LastAccessTimeUtc - { - get { return _lastAccessTimeUtc; } - set { _lastAccessTimeUtc = value; } - } + public SessionStateValue() { } + public SessionStateValue(byte[] value) + { + FromByteArray(value); + } - public DateTime ExpirationTimeUtc - { - get { return _expirationTimeUtc; } - set { _expirationTimeUtc = value; } - } + public byte[] Value + { + get { return _value; } + set { _value = value; } + } + public DateTime LastAccessTimeUtc + { + get { return _lastAccessTimeUtc; } + set { _lastAccessTimeUtc = value; } + } - public TimeSpan SpanUntilStale - { - get { return _spanUntilStale; } - set { _spanUntilStale = value; } - } + public DateTime ExpirationTimeUtc + { + get { return _expirationTimeUtc; } + set { _expirationTimeUtc = value; } + } - public byte[] ToByteArray() - { - int neededBytes = 3*sizeof(long) + _value.Length; - byte[] byteArray = new byte[neededBytes]; - int byteIndex = 0; + public TimeSpan SpanUntilStale + { + get { return _spanUntilStale; } + set { _spanUntilStale = value; } + } - // Append LastAccessTimeUtc - Array.Copy(BitConverter.GetBytes(LastAccessTimeUtc.Ticks), 0, byteArray, byteIndex, sizeof(long)); - byteIndex += sizeof(long); + public byte[] ToByteArray() + { + int neededBytes = 3 * sizeof(long) + _value.Length; + byte[] byteArray = new byte[neededBytes]; + int byteIndex = 0; - // Append ExpirationTimeUtc - Array.Copy(BitConverter.GetBytes(ExpirationTimeUtc.Ticks), 0, byteArray, byteIndex, sizeof(long)); - byteIndex += sizeof(long); + // Append LastAccessTimeUtc + Array.Copy(BitConverter.GetBytes(LastAccessTimeUtc.Ticks), 0, byteArray, byteIndex, sizeof(long)); + byteIndex += sizeof(long); - // Append SpanUntilStale - Array.Copy(BitConverter.GetBytes(SpanUntilStale.Ticks), 0, byteArray, byteIndex, sizeof(long)); - byteIndex += sizeof(long); + // Append ExpirationTimeUtc + Array.Copy(BitConverter.GetBytes(ExpirationTimeUtc.Ticks), 0, byteArray, byteIndex, sizeof(long)); + byteIndex += sizeof(long); - // Append the value - Array.Copy(_value, 0, byteArray, byteIndex, _value.Length); - return byteArray; - } + // Append SpanUntilStale + Array.Copy(BitConverter.GetBytes(SpanUntilStale.Ticks), 0, byteArray, byteIndex, sizeof(long)); + byteIndex += sizeof(long); - public void FromByteArray(byte[] data) - { - int byteIndex = 0; + // Append the value + Array.Copy(_value, 0, byteArray, byteIndex, _value.Length); + return byteArray; + } - // Extract the LastAccessTimeUtc - LastAccessTimeUtc = DateTime.FromBinary(BitConverter.ToInt64(data, byteIndex)); - byteIndex += sizeof(long); + public void FromByteArray(byte[] data) + { + int byteIndex = 0; - // Extract the ExpirationTimeUtc - ExpirationTimeUtc = DateTime.FromBinary(BitConverter.ToInt64(data, byteIndex)); - byteIndex += sizeof(long); + // Extract the LastAccessTimeUtc + LastAccessTimeUtc = DateTime.FromBinary(BitConverter.ToInt64(data, byteIndex)); + byteIndex += sizeof(long); - // Extract the SpanUntilStale - SpanUntilStale = TimeSpan.FromTicks(BitConverter.ToInt64(data, byteIndex)); - byteIndex += sizeof(long); + // Extract the ExpirationTimeUtc + ExpirationTimeUtc = DateTime.FromBinary(BitConverter.ToInt64(data, byteIndex)); + byteIndex += sizeof(long); - // Extract the value - Value = new byte[data.Length - byteIndex]; - Array.Copy(data, byteIndex, _value, 0, data.Length - byteIndex); - } - } + // Extract the SpanUntilStale + SpanUntilStale = TimeSpan.FromTicks(BitConverter.ToInt64(data, byteIndex)); + byteIndex += sizeof(long); - public class SessionStateCache : IDistributedCache - { - private readonly Cache _cache; - private ILogger<SessionStateCache> _logger; - private static Region _region; - private string _regionName; - private readonly SemaphoreSlim _connectLock = new SemaphoreSlim(initialCount: 1, maxCount: 1); + // Extract the value + Value = new byte[data.Length - byteIndex]; + Array.Copy(data, byteIndex, _value, 0, data.Length - byteIndex); + } + } - public SessionStateCache(Cache cache, string regionName, ILogger<SessionStateCache> logger = null) + public class SessionStateCache : GeodeNativeObject, IDistributedCache { - _regionName = regionName ?? throw new ArgumentNullException(regionName); - _cache = cache ?? throw new ArgumentNullException(nameof(cache)); - _logger = logger; + private readonly Cache _cache; + private ILogger<SessionStateCache> _logger; + private static Region _region; + private string _regionName; + private readonly SemaphoreSlim _connectLock = new SemaphoreSlim(initialCount: 1, maxCount: 1); - _cache.PoolFactory.AddLocator("localhost", 10334); - _cache.PoolFactory.CreatePool("pool"); - } + public SessionStateCache(Cache cache, string regionName, ILogger<SessionStateCache> logger = null) + { + _regionName = regionName ?? throw new ArgumentNullException(regionName); + _cache = cache ?? throw new ArgumentNullException(nameof(cache)); + _logger = logger; - // Returns the SessionStateValue for key, or null if key doesn't exist - public SessionStateValue GetValueForKey(string key) - { - byte[] cacheValue = _region.GetByteArray(key); - - if (cacheValue != null) - { - return new SessionStateValue(cacheValue); - } - else - return null; - } + _cache.PoolFactory.AddLocator("localhost", 10334); + using var pool = _cache.PoolFactory.CreatePool("pool"); + } - public byte[] Get(string key) - { - if (key == null) - { - throw new ArgumentNullException(nameof(key)); - } - - Connect(); - - // Check for nonexistent key - SessionStateValue ssValue = GetValueForKey(key); - if (ssValue == null) - return null; - - // Check for expired key - DateTime nowUtc = DateTime.UtcNow; - if (ssValue.ExpirationTimeUtc != DateTime.MinValue && ssValue.ExpirationTimeUtc < nowUtc) - return null; - - // Check for stale key - if (ssValue.SpanUntilStale != TimeSpan.Zero && - nowUtc > (ssValue.LastAccessTimeUtc + ssValue.SpanUntilStale)) - return null; - - //LogDebug("Inserting against key [" + key + "] with absolute expiration: " + - // options.AbsoluteExpiration.Value.DateTime); - - // Update the times for sliding expirations - if (ssValue.SpanUntilStale != TimeSpan.Zero) - { - ssValue.LastAccessTimeUtc = nowUtc; - _region.PutByteArray(key, ssValue.ToByteArray()); - } - - return ssValue.Value; - } + // Returns the SessionStateValue for key, or null if key doesn't exist + public SessionStateValue GetValueForKey(string key) + { + byte[] cacheValue = _region.GetByteArray(key); + + if (cacheValue != null) + { + return new SessionStateValue(cacheValue); + } + else + return null; + } - public Task<byte[]> GetAsync(string key, CancellationToken token = default(CancellationToken)) - { - if (key == null) - { - throw new ArgumentNullException(nameof(key)); - } + public byte[] Get(string key) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + Connect(); + + // Check for nonexistent key + SessionStateValue ssValue = GetValueForKey(key); + if (ssValue == null) + return null; + + // Check for expired key + DateTime nowUtc = DateTime.UtcNow; + if (ssValue.ExpirationTimeUtc != DateTime.MinValue && ssValue.ExpirationTimeUtc < nowUtc) + return null; + + // Check for stale key + if (ssValue.SpanUntilStale != TimeSpan.Zero && + nowUtc > (ssValue.LastAccessTimeUtc + ssValue.SpanUntilStale)) + return null; + + //LogDebug("Inserting against key [" + key + "] with absolute expiration: " + + // options.AbsoluteExpiration.Value.DateTime); + + // Update the times for sliding expirations + if (ssValue.SpanUntilStale != TimeSpan.Zero) + { + ssValue.LastAccessTimeUtc = nowUtc; + _region.PutByteArray(key, ssValue.ToByteArray()); + } + + return ssValue.Value; + } - token.ThrowIfCancellationRequested(); + public Task<byte[]> GetAsync(string key, CancellationToken token = default(CancellationToken)) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } - return Task.Factory.StartNew(() => Get(key), token); - } + token.ThrowIfCancellationRequested(); - public void Refresh(string key) - { - if (key == null) - { - throw new ArgumentNullException(nameof(key)); - } - - Connect(); - - // Check for nonexistent key - SessionStateValue ssValue = GetValueForKey(key); - if (ssValue == null) - return; - - // Check for expired key - DateTime nowUtc = DateTime.UtcNow; - if (ssValue.ExpirationTimeUtc != DateTime.MinValue && ssValue.ExpirationTimeUtc < nowUtc) - return; - - // Check for stale key - if (ssValue.SpanUntilStale != TimeSpan.Zero && - nowUtc > (ssValue.LastAccessTimeUtc + ssValue.SpanUntilStale)) - return; - - //LogDebug("Inserting against key [" + key + "] with absolute expiration: " + - // options.AbsoluteExpiration.Value.DateTime); - - // Update the times for sliding expirations - if (ssValue.SpanUntilStale != TimeSpan.Zero) - { - ssValue.LastAccessTimeUtc = nowUtc; - _region.PutByteArray(key, ssValue.ToByteArray()); - } - } + return Task.Factory.StartNew(() => Get(key), token); + } - public Task RefreshAsync(string key, CancellationToken token = default(CancellationToken)) - { - if (key == null) - { - throw new ArgumentNullException(nameof(key)); - } + public void Refresh(string key) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + Connect(); + + // Check for nonexistent key + SessionStateValue ssValue = GetValueForKey(key); + if (ssValue == null) + return; + + // Check for expired key + DateTime nowUtc = DateTime.UtcNow; + if (ssValue.ExpirationTimeUtc != DateTime.MinValue && ssValue.ExpirationTimeUtc < nowUtc) + return; + + // Check for stale key + if (ssValue.SpanUntilStale != TimeSpan.Zero && + nowUtc > (ssValue.LastAccessTimeUtc + ssValue.SpanUntilStale)) + return; + + //LogDebug("Inserting against key [" + key + "] with absolute expiration: " + + // options.AbsoluteExpiration.Value.DateTime); + + // Update the times for sliding expirations + if (ssValue.SpanUntilStale != TimeSpan.Zero) + { + ssValue.LastAccessTimeUtc = nowUtc; + _region.PutByteArray(key, ssValue.ToByteArray()); + } + } - token.ThrowIfCancellationRequested(); + public Task RefreshAsync(string key, CancellationToken token = default(CancellationToken)) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } - return Task.Factory.StartNew(() => Refresh(key), token); - } + token.ThrowIfCancellationRequested(); - public void Remove(string key) - { - if (key == null) - { - throw new ArgumentNullException(nameof(key)); - } - - Connect(); - - // Until we return error codes - //if (!_cacheRegion.Remove(key)) - //{ - // throw new Exception("Failed to remove from cache"); - //} - _region.Remove(key); - } + return Task.Factory.StartNew(() => Refresh(key), token); + } - public Task RemoveAsync(string key, CancellationToken token = default(CancellationToken)) - { - if (key == null) - { - throw new ArgumentNullException(nameof(key)); - } + public void Remove(string key) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + Connect(); + + // Until we return error codes + //if (!_cacheRegion.Remove(key)) + //{ + // throw new Exception("Failed to remove from cache"); + //} + _region.Remove(key); + } - token.ThrowIfCancellationRequested(); + public Task RemoveAsync(string key, CancellationToken token = default(CancellationToken)) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } - return Task.Factory.StartNew(() => Remove(key), token); - } + token.ThrowIfCancellationRequested(); - public void Set(string key, byte[] value, DistributedCacheEntryOptions options) - { - if (key == null) - { - throw new ArgumentNullException(nameof(key)); - } - - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - Connect(); - - SessionStateValue ssValue = new SessionStateValue(); - ssValue.Value = value; - - DateTime nowUtc = DateTime.UtcNow; - ssValue.LastAccessTimeUtc = nowUtc; - - // No need to check stale or expired data when setting an absolute expiration. - // Think of if as setting a new key/value pair. Expired data will always be cleaned up - // when the CleanupExpiredData job runs. - - if (options.AbsoluteExpiration != null) - { - //LogDebug("Inserting against key [" + key + "] with absolute expiration: " + - // options.AbsoluteExpiration.Value.DateTime); - DateTimeOffset dto = options.AbsoluteExpiration.Value; - ssValue.ExpirationTimeUtc = dto.DateTime + dto.Offset; - } - - // If AbsoluteExpiration and AbsoluteExpirationRelativeToNow are set, use the latter. - if (options.AbsoluteExpirationRelativeToNow != null) - { - //LogDebug("Inserting against key [" + key + "] with absolute expiration: " + - // options.AbsoluteExpiration.Value.DateTime); - TimeSpan ts = options.AbsoluteExpirationRelativeToNow.Value; - ssValue.ExpirationTimeUtc = nowUtc + ts; - } - - if (options.SlidingExpiration != null) - { - //LogDebug("Inserting against key [" + key + "] with absolute expiration: " + - // options.AbsoluteExpiration.Value.DateTime); - ssValue.SpanUntilStale = options.SlidingExpiration.Value; - } - - _region.PutByteArray(key, ssValue.ToByteArray()); - return; - } + return Task.Factory.StartNew(() => Remove(key), token); + } - public Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = default(CancellationToken)) - { - if (key == null) - { - throw new ArgumentNullException(nameof(key)); - } + public void Set(string key, byte[] value, DistributedCacheEntryOptions options) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + Connect(); + + SessionStateValue ssValue = new SessionStateValue(); + ssValue.Value = value; + + DateTime nowUtc = DateTime.UtcNow; + ssValue.LastAccessTimeUtc = nowUtc; + + // No need to check stale or expired data when setting an absolute expiration. + // Think of if as setting a new key/value pair. Expired data will always be cleaned up + // when the CleanupExpiredData job runs. + + if (options.AbsoluteExpiration != null) + { + //LogDebug("Inserting against key [" + key + "] with absolute expiration: " + + // options.AbsoluteExpiration.Value.DateTime); + DateTimeOffset dto = options.AbsoluteExpiration.Value; + ssValue.ExpirationTimeUtc = dto.DateTime + dto.Offset; + } + + // If AbsoluteExpiration and AbsoluteExpirationRelativeToNow are set, use the latter. + if (options.AbsoluteExpirationRelativeToNow != null) + { + //LogDebug("Inserting against key [" + key + "] with absolute expiration: " + + // options.AbsoluteExpiration.Value.DateTime); + TimeSpan ts = options.AbsoluteExpirationRelativeToNow.Value; + ssValue.ExpirationTimeUtc = nowUtc + ts; + } + + if (options.SlidingExpiration != null) + { + //LogDebug("Inserting against key [" + key + "] with absolute expiration: " + + // options.AbsoluteExpiration.Value.DateTime); + ssValue.SpanUntilStale = options.SlidingExpiration.Value; + } + + _region.PutByteArray(key, ssValue.ToByteArray()); + return; + } - token.ThrowIfCancellationRequested(); + public Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = default(CancellationToken)) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } - return Task.Factory.StartNew(() => Set(key, value, options), token); - } + token.ThrowIfCancellationRequested(); - private void Connect() - { - if (_region != null) - { - return; - } - - _connectLock.Wait(); - try - { - var regionFactory = _cache.CreateRegionFactory(RegionShortcut.Proxy); - try + return Task.Factory.StartNew(() => Set(key, value, options), token); + } + + private void Connect() { - _logger?.LogTrace("Create CacheRegion"); - _region = regionFactory.CreateRegion(_regionName); - _logger?.LogTrace("CacheRegion created"); + if (_region != null) + { + return; + } + + _connectLock.Wait(); + RegionFactory regionFactory = null; + try + { + regionFactory = _cache.CreateRegionFactory(RegionShortcut.Proxy); + try + { + _logger?.LogTrace("Create CacheRegion"); + _region = regionFactory.CreateRegion(_regionName); + _logger?.LogTrace("CacheRegion created"); + } + catch (Exception e) + { + _logger?.LogInformation(e, "Create CacheRegion failed... now trying to get the region"); + } + } + finally + { + //regionFactory?.Dispose(); + _connectLock.Release(); + } } - catch (Exception e) + + protected override void DestroyContainedObject() { - _logger?.LogInformation(e, "Create CacheRegion failed... now trying to get the region"); + _region?.Dispose(); + _region = null; } - } - finally - { - _connectLock.Release(); - } } - } } \ No newline at end of file